diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-07-18 19:53:16 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-18 19:53:16 +0200 |
commit | 9b610fda0df5d0f0b0c64242e37441ad1b384aac (patch) | |
tree | 0ea14b15f2e6546f37fe18d8ac3dc83077ec0e55 /arch/powerpc/platforms | |
parent | b8f8c3cf0a4ac0632ec3f0e15e9dc0c29de917af (diff) | |
parent | 5b664cb235e97afbf34db9c4d77f08ebd725335e (diff) |
Merge branch 'linus' into timers/nohz
Diffstat (limited to 'arch/powerpc/platforms')
84 files changed, 2888 insertions, 560 deletions
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index 6abe91357ee..249ba01c667 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -17,6 +17,15 @@ config EBONY help This option enables support for the IBM PPC440GP evaluation board. +config SAM440EP + bool "Sam440ep" + depends on 44x + default n + select 440EP + select PCI + help + This option enables support for the ACube Sam440ep board. + config SEQUOIA bool "Sequoia" depends on 44x @@ -102,6 +111,22 @@ config YOSEMITE # help # This option enables support for the IBM PPC440GX evaluation board. +config XILINX_VIRTEX440_GENERIC_BOARD + bool "Generic Xilinx Virtex 440 board" + depends on 44x + default n + select XILINX_VIRTEX_5_FXT + help + This option enables generic support for Xilinx Virtex based boards + that use a 440 based processor in the Virtex 5 FXT FPGA architecture. + + The generic virtex board support matches any device tree which + specifies 'xlnx,virtex440' in its compatible field. This includes + the Xilinx ML5xx reference designs using the powerpc core. + + Most Virtex 5 designs should use this unless it needs to do some + special configuration at board probe time. + # 44x specific CPU modules, selected based on the board above. config 440EP bool @@ -152,3 +177,13 @@ config 460EX # 44x errata/workaround config symbols, selected by the CPU models above config IBM440EP_ERR42 bool + +# Xilinx specific config options. +config XILINX_VIRTEX + bool + +# Xilinx Virtex 5 FXT FPGA architecture, selected by a Xilinx board above +config XILINX_VIRTEX_5_FXT + bool + select XILINX_VIRTEX + diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile index 774165f9acd..8d0b1a192d6 100644 --- a/arch/powerpc/platforms/44x/Makefile +++ b/arch/powerpc/platforms/44x/Makefile @@ -3,9 +3,11 @@ obj-$(CONFIG_EBONY) += ebony.o obj-$(CONFIG_TAISHAN) += taishan.o obj-$(CONFIG_BAMBOO) += bamboo.o obj-$(CONFIG_YOSEMITE) += bamboo.o +obj-$(CONFIG_SAM440EP) += sam440ep.o obj-$(CONFIG_SEQUOIA) += sequoia.o obj-$(CONFIG_KATMAI) += katmai.o obj-$(CONFIG_RAINIER) += rainier.o obj-$(CONFIG_WARP) += warp.o obj-$(CONFIG_WARP) += warp-nand.o obj-$(CONFIG_CANYONLANDS) += canyonlands.o +obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o diff --git a/arch/powerpc/platforms/44x/sam440ep.c b/arch/powerpc/platforms/44x/sam440ep.c new file mode 100644 index 00000000000..47f10e64773 --- /dev/null +++ b/arch/powerpc/platforms/44x/sam440ep.c @@ -0,0 +1,79 @@ +/* + * Sam440ep board specific routines based off bamboo.c code + * original copyrights below + * + * Wade Farnsworth <wfarnsworth@mvista.com> + * Copyright 2004 MontaVista Software Inc. + * + * Rewritten and ported to the merged powerpc tree: + * Josh Boyer <jwboyer@linux.vnet.ibm.com> + * Copyright 2007 IBM Corporation + * + * Modified from bamboo.c for sam440ep: + * Copyright 2008 Giuseppe Coviello <gicoviello@gmail.com> + * + * 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. + */ +#include <linux/init.h> +#include <linux/of_platform.h> + +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/udbg.h> +#include <asm/time.h> +#include <asm/uic.h> +#include <asm/pci-bridge.h> +#include <asm/ppc4xx.h> +#include <linux/i2c.h> + +static __initdata struct of_device_id sam440ep_of_bus[] = { + { .compatible = "ibm,plb4", }, + { .compatible = "ibm,opb", }, + { .compatible = "ibm,ebc", }, + {}, +}; + +static int __init sam440ep_device_probe(void) +{ + of_platform_bus_probe(NULL, sam440ep_of_bus, NULL); + + return 0; +} +machine_device_initcall(sam440ep, sam440ep_device_probe); + +static int __init sam440ep_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "acube,sam440ep")) + return 0; + + ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; + + return 1; +} + +define_machine(sam440ep) { + .name = "Sam440ep", + .probe = sam440ep_probe, + .progress = udbg_progress, + .init_IRQ = uic_init_tree, + .get_irq = uic_get_irq, + .restart = ppc4xx_reset_system, + .calibrate_decr = generic_calibrate_decr, +}; + +static struct i2c_board_info sam440ep_rtc_info = { + .type = "m41st85", + .addr = 0x68, + .irq = -1, +}; + +static int sam440ep_setup_rtc(void) +{ + return i2c_register_board_info(0, &sam440ep_rtc_info, 1); +} +machine_device_initcall(sam440ep, sam440ep_setup_rtc); diff --git a/arch/powerpc/platforms/44x/virtex.c b/arch/powerpc/platforms/44x/virtex.c new file mode 100644 index 00000000000..68637faf70a --- /dev/null +++ b/arch/powerpc/platforms/44x/virtex.c @@ -0,0 +1,60 @@ +/* + * Xilinx Virtex 5FXT based board support, derived from + * the Xilinx Virtex (IIpro & 4FX) based board support + * + * Copyright 2007 Secret Lab Technologies Ltd. + * Copyright 2008 Xilinx, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/init.h> +#include <linux/of_platform.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/time.h> +#include <asm/xilinx_intc.h> +#include <asm/reg.h> +#include <asm/ppc4xx.h> +#include "44x.h" + +static struct of_device_id xilinx_of_bus_ids[] __initdata = { + { .compatible = "simple-bus", }, + { .compatible = "xlnx,plb-v46-1.00.a", }, + { .compatible = "xlnx,plb-v46-1.02.a", }, + { .compatible = "xlnx,plb-v34-1.01.a", }, + { .compatible = "xlnx,plb-v34-1.02.a", }, + { .compatible = "xlnx,opb-v20-1.10.c", }, + { .compatible = "xlnx,dcr-v29-1.00.a", }, + { .compatible = "xlnx,compound", }, + {} +}; + +static int __init virtex_device_probe(void) +{ + of_platform_bus_probe(NULL, xilinx_of_bus_ids, NULL); + + return 0; +} +machine_device_initcall(virtex, virtex_device_probe); + +static int __init virtex_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "xlnx,virtex440")) + return 0; + + return 1; +} + +define_machine(virtex) { + .name = "Xilinx Virtex440", + .probe = virtex_probe, + .init_IRQ = xilinx_intc_init_tree, + .get_irq = xilinx_intc_get_irq, + .calibrate_decr = generic_calibrate_decr, + .restart = ppc4xx_reset_system, +}; diff --git a/arch/powerpc/platforms/44x/warp-nand.c b/arch/powerpc/platforms/44x/warp-nand.c index 9150318cfc5..e55746b824b 100644 --- a/arch/powerpc/platforms/44x/warp-nand.c +++ b/arch/powerpc/platforms/44x/warp-nand.c @@ -11,8 +11,10 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/nand.h> #include <linux/mtd/ndfc.h> +#include <linux/of.h> #include <asm/machdep.h> + #ifdef CONFIG_MTD_NAND_NDFC #define CS_NAND_0 1 /* use chip select 1 for NAND device 0 */ @@ -35,13 +37,23 @@ static struct mtd_partition nand_parts[] = { { .name = "root", .offset = 0x0200000, - .size = 0x3400000 + .size = 0x3E00000 + }, + { + .name = "persistent", + .offset = 0x4000000, + .size = 0x4000000 }, { - .name = "user", - .offset = 0x3600000, - .size = 0x0A00000 + .name = "persistent1", + .offset = 0x8000000, + .size = 0x4000000 }, + { + .name = "persistent2", + .offset = 0xC000000, + .size = 0x4000000 + } }; struct ndfc_controller_settings warp_ndfc_settings = { @@ -67,27 +79,22 @@ static struct platform_device warp_ndfc_device = { .resource = &warp_ndfc, }; -static struct nand_ecclayout nand_oob_16 = { - .eccbytes = 3, - .eccpos = { 0, 1, 2, 3, 6, 7 }, - .oobfree = { {.offset = 8, .length = 16} } -}; - +/* Do NOT set the ecclayout: let it default so it is correct for both + * 64M and 256M flash chips. + */ static struct platform_nand_chip warp_nand_chip0 = { .nr_chips = 1, .chip_offset = CS_NAND_0, .nr_partitions = ARRAY_SIZE(nand_parts), .partitions = nand_parts, - .chip_delay = 50, - .ecclayout = &nand_oob_16, + .chip_delay = 20, .priv = &warp_chip0_settings, }; static struct platform_device warp_nand_device = { .name = "ndfc-chip", .id = 0, - .num_resources = 1, - .resource = &warp_ndfc, + .num_resources = 0, .dev = { .platform_data = &warp_nand_chip0, .parent = &warp_ndfc_device.dev, @@ -96,6 +103,28 @@ static struct platform_device warp_nand_device = { static int warp_setup_nand_flash(void) { + struct device_node *np; + + /* Try to detect a rev A based on NOR size. */ + np = of_find_compatible_node(NULL, NULL, "cfi-flash"); + if (np) { + struct property *pp; + + pp = of_find_property(np, "reg", NULL); + if (pp && (pp->length == 12)) { + u32 *v = pp->value; + if (v[2] == 0x4000000) { + /* Rev A = 64M NAND */ + warp_nand_chip0.nr_partitions = 3; + + nand_parts[1].size = 0x3000000; + nand_parts[2].offset = 0x3200000; + nand_parts[2].size = 0x0e00000; + } + } + of_node_put(np); + } + platform_device_register(&warp_ndfc_device); platform_device_register(&warp_nand_device); diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c index 39cf6150a72..9565995cba7 100644 --- a/arch/powerpc/platforms/44x/warp.c +++ b/arch/powerpc/platforms/44x/warp.c @@ -12,6 +12,9 @@ #include <linux/init.h> #include <linux/of_platform.h> #include <linux/kthread.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/delay.h> #include <asm/machdep.h> #include <asm/prom.h> @@ -27,6 +30,18 @@ static __initdata struct of_device_id warp_of_bus[] = { {}, }; +static __initdata struct i2c_board_info warp_i2c_info[] = { + { I2C_BOARD_INFO("ad7414", 0x4a) } +}; + +static int __init warp_arch_init(void) +{ + /* This should go away once support is moved to the dts. */ + i2c_register_board_info(0, warp_i2c_info, ARRAY_SIZE(warp_i2c_info)); + return 0; +} +machine_arch_initcall(warp, warp_arch_init); + static int __init warp_device_probe(void) { of_platform_bus_probe(NULL, warp_of_bus, NULL); @@ -52,61 +67,232 @@ define_machine(warp) { }; -#define LED_GREEN (0x80000000 >> 0) -#define LED_RED (0x80000000 >> 1) +/* I am not sure this is the best place for this... */ +static int __init warp_post_info(void) +{ + struct device_node *np; + void __iomem *fpga; + u32 post1, post2; + + /* Sighhhh... POST information is in the sd area. */ + np = of_find_compatible_node(NULL, NULL, "pika,fpga-sd"); + if (np == NULL) + return -ENOENT; + + fpga = of_iomap(np, 0); + of_node_put(np); + if (fpga == NULL) + return -ENOENT; + + post1 = in_be32(fpga + 0x40); + post2 = in_be32(fpga + 0x44); + + iounmap(fpga); + + if (post1 || post2) + printk(KERN_INFO "Warp POST %08x %08x\n", post1, post2); + else + printk(KERN_INFO "Warp POST OK\n"); + + return 0; +} +machine_late_initcall(warp, warp_post_info); + + +#ifdef CONFIG_SENSORS_AD7414 + +static LIST_HEAD(dtm_shutdown_list); +static void __iomem *dtm_fpga; +static void __iomem *gpio_base; + + +struct dtm_shutdown { + struct list_head list; + void (*func)(void *arg); + void *arg; +}; -/* This is for the power LEDs 1 = on, 0 = off, -1 = leave alone */ -void warp_set_power_leds(int green, int red) +int pika_dtm_register_shutdown(void (*func)(void *arg), void *arg) { - static void __iomem *gpio_base = NULL; - unsigned leds; - - if (gpio_base == NULL) { - struct device_node *np; - - /* Power LEDS are on the second GPIO controller */ - np = of_find_compatible_node(NULL, NULL, "ibm,gpio-440EP"); - if (np) - np = of_find_compatible_node(np, NULL, "ibm,gpio-440EP"); - if (np == NULL) { - printk(KERN_ERR __FILE__ ": Unable to find gpio\n"); - return; + struct dtm_shutdown *shutdown; + + shutdown = kmalloc(sizeof(struct dtm_shutdown), GFP_KERNEL); + if (shutdown == NULL) + return -ENOMEM; + + shutdown->func = func; + shutdown->arg = arg; + + list_add(&shutdown->list, &dtm_shutdown_list); + + return 0; +} + +int pika_dtm_unregister_shutdown(void (*func)(void *arg), void *arg) +{ + struct dtm_shutdown *shutdown; + + list_for_each_entry(shutdown, &dtm_shutdown_list, list) + if (shutdown->func == func && shutdown->arg == arg) { + list_del(&shutdown->list); + kfree(shutdown); + return 0; + } + + return -EINVAL; +} + +static irqreturn_t temp_isr(int irq, void *context) +{ + struct dtm_shutdown *shutdown; + + local_irq_disable(); + + /* Run through the shutdown list. */ + list_for_each_entry(shutdown, &dtm_shutdown_list, list) + shutdown->func(shutdown->arg); + + printk(KERN_EMERG "\n\nCritical Temperature Shutdown\n"); + + while (1) { + if (dtm_fpga) { + unsigned reset = in_be32(dtm_fpga + 0x14); + out_be32(dtm_fpga + 0x14, reset); } - gpio_base = of_iomap(np, 0); - of_node_put(np); - if (gpio_base == NULL) { - printk(KERN_ERR __FILE__ ": Unable to map gpio"); - return; + if (gpio_base) { + unsigned leds = in_be32(gpio_base); + + /* green off, red toggle */ + leds &= ~0x80000000; + leds ^= 0x40000000; + + out_be32(gpio_base, leds); } + + mdelay(500); + } +} + +static int pika_setup_leds(void) +{ + struct device_node *np; + const u32 *gpios; + int len; + + np = of_find_compatible_node(NULL, NULL, "linux,gpio-led"); + if (!np) { + printk(KERN_ERR __FILE__ ": Unable to find gpio-led\n"); + return -ENOENT; } - leds = in_be32(gpio_base); + gpios = of_get_property(np, "gpios", &len); + of_node_put(np); + if (!gpios || len < 4) { + printk(KERN_ERR __FILE__ + ": Unable to get gpios property (%d)\n", len); + return -ENOENT; + } - switch (green) { - case 0: leds &= ~LED_GREEN; break; - case 1: leds |= LED_GREEN; break; + np = of_find_node_by_phandle(gpios[0]); + if (!np) { + printk(KERN_ERR __FILE__ ": Unable to find gpio\n"); + return -ENOENT; } - switch (red) { - case 0: leds &= ~LED_RED; break; - case 1: leds |= LED_RED; break; + + gpio_base = of_iomap(np, 0); + of_node_put(np); + if (!gpio_base) { + printk(KERN_ERR __FILE__ ": Unable to map gpio"); + return -ENOMEM; } - out_be32(gpio_base, leds); + return 0; } -EXPORT_SYMBOL(warp_set_power_leds); +static void pika_setup_critical_temp(struct i2c_client *client) +{ + struct device_node *np; + int irq, rc; + + /* Do this before enabling critical temp interrupt since we + * may immediately interrupt. + */ + pika_setup_leds(); + + /* These registers are in 1 degree increments. */ + i2c_smbus_write_byte_data(client, 2, 65); /* Thigh */ + i2c_smbus_write_byte_data(client, 3, 55); /* Tlow */ + + np = of_find_compatible_node(NULL, NULL, "adi,ad7414"); + if (np == NULL) { + printk(KERN_ERR __FILE__ ": Unable to find ad7414\n"); + return; + } + + irq = irq_of_parse_and_map(np, 0); + of_node_put(np); + if (irq == NO_IRQ) { + printk(KERN_ERR __FILE__ ": Unable to get ad7414 irq\n"); + return; + } + + rc = request_irq(irq, temp_isr, 0, "ad7414", NULL); + if (rc) { + printk(KERN_ERR __FILE__ + ": Unable to request ad7414 irq %d = %d\n", irq, rc); + return; + } +} + +static inline void pika_dtm_check_fan(void __iomem *fpga) +{ + static int fan_state; + u32 fan = in_be32(fpga + 0x34) & (1 << 14); + + if (fan_state != fan) { + fan_state = fan; + if (fan) + printk(KERN_WARNING "Fan rotation error detected." + " Please check hardware.\n"); + } +} -#ifdef CONFIG_SENSORS_AD7414 static int pika_dtm_thread(void __iomem *fpga) { - extern int ad7414_get_temp(int index); + struct i2c_adapter *adap; + struct i2c_client *client; + + /* We loop in case either driver was compiled as a module and + * has not been insmoded yet. + */ + while (!(adap = i2c_get_adapter(0))) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + } + + while (1) { + list_for_each_entry(client, &adap->clients, list) + if (client->addr == 0x4a) + goto found_it; + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + } + +found_it: + i2c_put_adapter(adap); + + pika_setup_critical_temp(client); + + printk(KERN_INFO "PIKA DTM thread running.\n"); while (!kthread_should_stop()) { - int temp = ad7414_get_temp(0); + u16 temp = swab16(i2c_smbus_read_word_data(client, 0)); + out_be32(fpga + 0x20, temp); - out_be32(fpga, temp); + pika_dtm_check_fan(fpga); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); @@ -115,37 +301,44 @@ static int pika_dtm_thread(void __iomem *fpga) return 0; } + static int __init pika_dtm_start(void) { struct task_struct *dtm_thread; struct device_node *np; - struct resource res; - void __iomem *fpga; np = of_find_compatible_node(NULL, NULL, "pika,fpga"); if (np == NULL) return -ENOENT; - /* We do not call of_iomap here since it would map in the entire - * fpga space, which is over 8k. - */ - if (of_address_to_resource(np, 0, &res)) { - of_node_put(np); - return -ENOENT; - } + dtm_fpga = of_iomap(np, 0); of_node_put(np); - - fpga = ioremap(res.start, 0x24); - if (fpga == NULL) + if (dtm_fpga == NULL) return -ENOENT; - dtm_thread = kthread_run(pika_dtm_thread, fpga + 0x20, "pika-dtm"); + dtm_thread = kthread_run(pika_dtm_thread, dtm_fpga, "pika-dtm"); if (IS_ERR(dtm_thread)) { - iounmap(fpga); + iounmap(dtm_fpga); return PTR_ERR(dtm_thread); } return 0; } -device_initcall(pika_dtm_start); +machine_late_initcall(warp, pika_dtm_start); + +#else /* !CONFIG_SENSORS_AD7414 */ + +int pika_dtm_register_shutdown(void (*func)(void *arg), void *arg) +{ + return 0; +} + +int pika_dtm_unregister_shutdown(void (*func)(void *arg), void *arg) +{ + return 0; +} + #endif + +EXPORT_SYMBOL(pika_dtm_register_shutdown); +EXPORT_SYMBOL(pika_dtm_unregister_shutdown); diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig index 4c0da0c079e..c62f893ede1 100644 --- a/arch/powerpc/platforms/512x/Kconfig +++ b/arch/powerpc/platforms/512x/Kconfig @@ -2,18 +2,29 @@ config PPC_MPC512x bool select FSL_SOC select IPIC - default n + select PPC_CLOCK config PPC_MPC5121 bool select PPC_MPC512x - default n config MPC5121_ADS bool "Freescale MPC5121E ADS" depends on PPC_MULTIPLATFORM && PPC32 select DEFAULT_UIMAGE select PPC_MPC5121 + select MPC5121_ADS_CPLD help This option enables support for the MPC5121E ADS board. - default n + +config MPC5121_GENERIC + bool "Generic support for simple MPC5121 based boards" + depends on PPC_MULTIPLATFORM && PPC32 + select DEFAULT_UIMAGE + select PPC_MPC5121 + help + This option enables support for simple MPC5121 based boards + which do not need custom platform specific setup. + + Compatible boards include: Protonic LVT base boards (ZANMCU + and VICVT2). diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile index 232c89f2039..90be2f5717e 100644 --- a/arch/powerpc/platforms/512x/Makefile +++ b/arch/powerpc/platforms/512x/Makefile @@ -1,4 +1,6 @@ # # Makefile for the Freescale PowerPC 512x linux kernel. # -obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o +obj-y += clock.o mpc512x_shared.o +obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o mpc5121_ads_cpld.o +obj-$(CONFIG_MPC5121_GENERIC) += mpc5121_generic.o diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c new file mode 100644 index 00000000000..f416014ee72 --- /dev/null +++ b/arch/powerpc/platforms/512x/clock.c @@ -0,0 +1,729 @@ +/* + * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: John Rigby <jrigby@freescale.com> + * + * Implements the clk api defined in include/linux/clk.h + * + * Original based on linux/arch/arm/mach-integrator/clock.c + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/string.h> +#include <linux/clk.h> +#include <linux/mutex.h> +#include <linux/io.h> + +#include <linux/of_platform.h> +#include <asm/mpc512x.h> +#include <asm/clk_interface.h> + +#undef CLK_DEBUG + +static int clocks_initialized; + +#define CLK_HAS_RATE 0x1 /* has rate in MHz */ +#define CLK_HAS_CTRL 0x2 /* has control reg and bit */ + +struct clk { + struct list_head node; + char name[32]; + int flags; + struct device *dev; + unsigned long rate; + struct module *owner; + void (*calc) (struct clk *); + struct clk *parent; + int reg, bit; /* CLK_HAS_CTRL */ + int div_shift; /* only used by generic_div_clk_calc */ +}; + +static LIST_HEAD(clocks); +static DEFINE_MUTEX(clocks_mutex); + +static struct clk *mpc5121_clk_get(struct device *dev, const char *id) +{ + struct clk *p, *clk = ERR_PTR(-ENOENT); + int dev_match = 0; + int id_match = 0; + + if (dev == NULL && id == NULL) + return NULL; + + mutex_lock(&clocks_mutex); + list_for_each_entry(p, &clocks, node) { + if (dev && dev == p->dev) + dev_match++; + if (strcmp(id, p->name) == 0) + id_match++; + if ((dev_match || id_match) && try_module_get(p->owner)) { + clk = p; + break; + } + } + mutex_unlock(&clocks_mutex); + + return clk; +} + +#ifdef CLK_DEBUG +static void dump_clocks(void) +{ + struct clk *p; + + mutex_lock(&clocks_mutex); + printk(KERN_INFO "CLOCKS:\n"); + list_for_each_entry(p, &clocks, node) { + printk(KERN_INFO " %s %ld", p->name, p->rate); + if (p->parent) + printk(KERN_INFO " %s %ld", p->parent->name, + p->parent->rate); + if (p->flags & CLK_HAS_CTRL) + printk(KERN_INFO " reg/bit %d/%d", p->reg, p->bit); + printk("\n"); + } + mutex_unlock(&clocks_mutex); +} +#define DEBUG_CLK_DUMP() dump_clocks() +#else +#define DEBUG_CLK_DUMP() +#endif + + +static void mpc5121_clk_put(struct clk *clk) +{ + module_put(clk->owner); +} + +#define NRPSC 12 + +struct mpc512x_clockctl { + u32 spmr; /* System PLL Mode Reg */ + u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */ + u32 scfr1; /* System Clk Freq Reg 1 */ + u32 scfr2; /* System Clk Freq Reg 2 */ + u32 reserved; + u32 bcr; /* Bread Crumb Reg */ + u32 pccr[NRPSC]; /* PSC Clk Ctrl Reg 0-11 */ + u32 spccr; /* SPDIF Clk Ctrl Reg */ + u32 cccr; /* CFM Clk Ctrl Reg */ + u32 dccr; /* DIU Clk Cnfg Reg */ +}; + +struct mpc512x_clockctl __iomem *clockctl; + +static int mpc5121_clk_enable(struct clk *clk) +{ + unsigned int mask; + + if (clk->flags & CLK_HAS_CTRL) { + mask = in_be32(&clockctl->sccr[clk->reg]); + mask |= 1 << clk->bit; + out_be32(&clockctl->sccr[clk->reg], mask); + } + return 0; +} + +static void mpc5121_clk_disable(struct clk *clk) +{ + unsigned int mask; + + if (clk->flags & CLK_HAS_CTRL) { + mask = in_be32(&clockctl->sccr[clk->reg]); + mask &= ~(1 << clk->bit); + out_be32(&clockctl->sccr[clk->reg], mask); + } +} + +static unsigned long mpc5121_clk_get_rate(struct clk *clk) +{ + if (clk->flags & CLK_HAS_RATE) + return clk->rate; + else + return 0; +} + +static long mpc5121_clk_round_rate(struct clk *clk, unsigned long rate) +{ + return rate; +} + +static int mpc5121_clk_set_rate(struct clk *clk, unsigned long rate) +{ + return 0; +} + +static int clk_register(struct clk *clk) +{ + mutex_lock(&clocks_mutex); + list_add(&clk->node, &clocks); + mutex_unlock(&clocks_mutex); + return 0; +} + +static unsigned long spmf_mult(void) +{ + /* + * Convert spmf to multiplier + */ + static int spmf_to_mult[] = { + 68, 1, 12, 16, + 20, 24, 28, 32, + 36, 40, 44, 48, + 52, 56, 60, 64 + }; + int spmf = (clockctl->spmr >> 24) & 0xf; + return spmf_to_mult[spmf]; +} + +static unsigned long sysdiv_div_x_2(void) +{ + /* + * Convert sysdiv to divisor x 2 + * Some divisors have fractional parts so + * multiply by 2 then divide by this value + */ + static int sysdiv_to_div_x_2[] = { + 4, 5, 6, 7, + 8, 9, 10, 14, + 12, 16, 18, 22, + 20, 24, 26, 30, + 28, 32, 34, 38, + 36, 40, 42, 46, + 44, 48, 50, 54, + 52, 56, 58, 62, + 60, 64, 66, + }; + int sysdiv = (clockctl->scfr2 >> 26) & 0x3f; + return sysdiv_to_div_x_2[sysdiv]; +} + +static unsigned long ref_to_sys(unsigned long rate) +{ + rate *= spmf_mult(); + rate *= 2; + rate /= sysdiv_div_x_2(); + + return rate; +} + +static unsigned long sys_to_ref(unsigned long rate) +{ + rate *= sysdiv_div_x_2(); + rate /= 2; + rate /= spmf_mult(); + + return rate; +} + +static long ips_to_ref(unsigned long rate) +{ + int ips_div = (clockctl->scfr1 >> 23) & 0x7; + + rate *= ips_div; /* csb_clk = ips_clk * ips_div */ + rate *= 2; /* sys_clk = csb_clk * 2 */ + return sys_to_ref(rate); +} + +static unsigned long devtree_getfreq(char *clockname) +{ + struct device_node *np; + const unsigned int *prop; + unsigned int val = 0; + + np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr"); + if (np) { + prop = of_get_property(np, clockname, NULL); + if (prop) + val = *prop; + of_node_put(np); + } + return val; +} + +static void ref_clk_calc(struct clk *clk) +{ + unsigned long rate; + + rate = devtree_getfreq("bus-frequency"); + if (rate == 0) { + printk(KERN_ERR "No bus-frequency in dev tree\n"); + clk->rate = 0; + return; + } + clk->rate = ips_to_ref(rate); +} + +static struct clk ref_clk = { + .name = "ref_clk", + .calc = ref_clk_calc, +}; + + +static void sys_clk_calc(struct clk *clk) +{ + clk->rate = ref_to_sys(ref_clk.rate); +} + +static struct clk sys_clk = { + .name = "sys_clk", + .calc = sys_clk_calc, +}; + +static void diu_clk_calc(struct clk *clk) +{ + int diudiv_x_2 = clockctl->scfr1 & 0xff; + unsigned long rate; + + rate = sys_clk.rate; + + rate *= 2; + rate /= diudiv_x_2; + + clk->rate = rate; +} + +static void half_clk_calc(struct clk *clk) +{ + clk->rate = clk->parent->rate / 2; +} + +static void generic_div_clk_calc(struct clk *clk) +{ + int div = (clockctl->scfr1 >> clk->div_shift) & 0x7; + + clk->rate = clk->parent->rate / div; +} + +static void unity_clk_calc(struct clk *clk) +{ + clk->rate = clk->parent->rate; +} + +static struct clk csb_clk = { + .name = "csb_clk", + .calc = half_clk_calc, + .parent = &sys_clk, +}; + +static void e300_clk_calc(struct clk *clk) +{ + int spmf = (clockctl->spmr >> 16) & 0xf; + int ratex2 = clk->parent->rate * spmf; + + clk->rate = ratex2 / 2; +} + +static struct clk e300_clk = { + .name = "e300_clk", + .calc = e300_clk_calc, + .parent = &csb_clk, +}; + +static struct clk ips_clk = { + .name = "ips_clk", + .calc = generic_div_clk_calc, + .parent = &csb_clk, + .div_shift = 23, +}; + +/* + * Clocks controlled by SCCR1 (.reg = 0) + */ +static struct clk lpc_clk = { + .name = "lpc_clk", + .flags = CLK_HAS_CTRL, + .reg = 0, + .bit = 30, + .calc = generic_div_clk_calc, + .parent = &ips_clk, + .div_shift = 11, +}; + +static struct clk nfc_clk = { + .name = "nfc_clk", + .flags = CLK_HAS_CTRL, + .reg = 0, + .bit = 29, + .calc = generic_div_clk_calc, + .parent = &ips_clk, + .div_shift = 8, +}; + +static struct clk pata_clk = { + .name = "pata_clk", + .flags = CLK_HAS_CTRL, + .reg = 0, + .bit = 28, + .calc = unity_clk_calc, + .parent = &ips_clk, +}; + +/* + * PSC clocks (bits 27 - 16) + * are setup elsewhere + */ + +static struct clk sata_clk = { + .name = "sata_clk", + .flags = CLK_HAS_CTRL, + .reg = 0, + .bit = 14, + .calc = unity_clk_calc, + .parent = &ips_clk, +}; + +static struct clk fec_clk = { + .name = "fec_clk", + .flags = CLK_HAS_CTRL, + .reg = 0, + .bit = 13, + .calc = unity_clk_calc, + .parent = &ips_clk, +}; + +static struct clk pci_clk = { + .name = "pci_clk", + .flags = CLK_HAS_CTRL, + .reg = 0, + .bit = 11, + .calc = generic_div_clk_calc, + .parent = &csb_clk, + .div_shift = 20, +}; + +/* + * Clocks controlled by SCCR2 (.reg = 1) + */ +static struct clk diu_clk = { + .name = "diu_clk", + .flags = CLK_HAS_CTRL, + .reg = 1, + .bit = 31, + .calc = diu_clk_calc, +}; + +static struct clk axe_clk = { + .name = "axe_clk", + .flags = CLK_HAS_CTRL, + .reg = 1, + .bit = 30, + .calc = unity_clk_calc, + .parent = &csb_clk, +}; + +static struct clk usb1_clk = { + .name = "usb1_clk", + .flags = CLK_HAS_CTRL, + .reg = 1, + .bit = 28, + .calc = unity_clk_calc, + .parent = &csb_clk, +}; + +static struct clk usb2_clk = { + .name = "usb2_clk", + .flags = CLK_HAS_CTRL, + .reg = 1, + .bit = 27, + .calc = unity_clk_calc, + .parent = &csb_clk, +}; + +static struct clk i2c_clk = { + .name = "i2c_clk", + .flags = CLK_HAS_CTRL, + .reg = 1, + .bit = 26, + .calc = unity_clk_calc, + .parent = &ips_clk, +}; + +static struct clk mscan_clk = { + .name = "mscan_clk", + .flags = CLK_HAS_CTRL, + .reg = 1, + .bit = 25, + .calc = unity_clk_calc, + .parent = &ips_clk, +}; + +static struct clk sdhc_clk = { + .name = "sdhc_clk", + .flags = CLK_HAS_CTRL, + .reg = 1, + .bit = 24, + .calc = unity_clk_calc, + .parent = &ips_clk, +}; + +static struct clk mbx_bus_clk = { + .name = "mbx_bus_clk", + .flags = CLK_HAS_CTRL, + .reg = 1, + .bit = 22, + .calc = half_clk_calc, + .parent = &csb_clk, +}; + +static struct clk mbx_clk = { + .name = "mbx_clk", + .flags = CLK_HAS_CTRL, + .reg = 1, + .bit = 21, + .calc = unity_clk_calc, + .parent = &csb_clk, +}; + +static struct clk mbx_3d_clk = { + .name = "mbx_3d_clk", + .flags = CLK_HAS_CTRL, + .reg = 1, + .bit = 20, + .calc = generic_div_clk_calc, + .parent = &mbx_bus_clk, + .div_shift = 14, +}; + +static void psc_mclk_in_calc(struct clk *clk) +{ + clk->rate = devtree_getfreq("psc_mclk_in"); + if (!clk->rate) + clk->rate = 25000000; +} + +static struct clk psc_mclk_in = { + .name = "psc_mclk_in", + .calc = psc_mclk_in_calc, +}; + +static struct clk spdif_txclk = { + .name = "spdif_txclk", + .flags = CLK_HAS_CTRL, + .reg = 1, + .bit = 23, +}; + +static struct clk spdif_rxclk = { + .name = "spdif_rxclk", + .flags = CLK_HAS_CTRL, + .reg = 1, + .bit = 23, +}; + +static void ac97_clk_calc(struct clk *clk) +{ + /* ac97 bit clock is always 24.567 MHz */ + clk->rate = 24567000; +} + +static struct clk ac97_clk = { + .name = "ac97_clk_in", + .calc = ac97_clk_calc, +}; + +struct clk *rate_clks[] = { + &ref_clk, + &sys_clk, + &diu_clk, + &csb_clk, + &e300_clk, + &ips_clk, + &fec_clk, + &sata_clk, + &pata_clk, + &nfc_clk, + &lpc_clk, + &mbx_bus_clk, + &mbx_clk, + &mbx_3d_clk, + &axe_clk, + &usb1_clk, + &usb2_clk, + &i2c_clk, + &mscan_clk, + &sdhc_clk, + &pci_clk, + &psc_mclk_in, + &spdif_txclk, + &spdif_rxclk, + &ac97_clk, + NULL +}; + +static void rate_clk_init(struct clk *clk) +{ + if (clk->calc) { + clk->calc(clk); + clk->flags |= CLK_HAS_RATE; + clk_register(clk); + } else { + printk(KERN_WARNING + "Could not initialize clk %s without a calc routine\n", + clk->name); + } +} + +static void rate_clks_init(void) +{ + struct clk **cpp, *clk; + + cpp = rate_clks; + while ((clk = *cpp++)) + rate_clk_init(clk); +} + +/* + * There are two clk enable registers with 32 enable bits each + * psc clocks and device clocks are all stored in dev_clks + */ +struct clk dev_clks[2][32]; + +/* + * Given a psc number return the dev_clk + * associated with it + */ +static struct clk *psc_dev_clk(int pscnum) +{ + int reg, bit; + struct clk *clk; + + reg = 0; + bit = 27 - pscnum; + + clk = &dev_clks[reg][bit]; + clk->reg = 0; + clk->bit = bit; + return clk; +} + +/* + * PSC clock rate calculation + */ +static void psc_calc_rate(struct clk *clk, int pscnum, struct device_node *np) +{ + unsigned long mclk_src = sys_clk.rate; + unsigned long mclk_div; + + /* + * Can only change value of mclk divider + * when the divider is disabled. + * + * Zero is not a valid divider so minimum + * divider is 1 + * + * disable/set divider/enable + */ + out_be32(&clockctl->pccr[pscnum], 0); + out_be32(&clockctl->pccr[pscnum], 0x00020000); + out_be32(&clockctl->pccr[pscnum], 0x00030000); + + if (clockctl->pccr[pscnum] & 0x80) { + clk->rate = spdif_rxclk.rate; + return; + } + + switch ((clockctl->pccr[pscnum] >> 14) & 0x3) { + case 0: + mclk_src = sys_clk.rate; + break; + case 1: + mclk_src = ref_clk.rate; + break; + case 2: + mclk_src = psc_mclk_in.rate; + break; + case 3: + mclk_src = spdif_txclk.rate; + break; + } + + mclk_div = ((clockctl->pccr[pscnum] >> 17) & 0x7fff) + 1; + clk->rate = mclk_src / mclk_div; +} + +/* + * Find all psc nodes in device tree and assign a clock + * with name "psc%d_mclk" and dev pointing at the device + * returned from of_find_device_by_node + */ +static void psc_clks_init(void) +{ + struct device_node *np; + const u32 *cell_index; + struct of_device *ofdev; + + for_each_compatible_node(np, NULL, "fsl,mpc5121-psc") { + cell_index = of_get_property(np, "cell-index", NULL); + if (cell_index) { + int pscnum = *cell_index; + struct clk *clk = psc_dev_clk(pscnum); + + clk->flags = CLK_HAS_RATE | CLK_HAS_CTRL; + ofdev = of_find_device_by_node(np); + clk->dev = &ofdev->dev; + /* + * AC97 is special rate clock does + * not go through normal path + */ + if (strcmp("ac97", np->name) == 0) + clk->rate = ac97_clk.rate; + else + psc_calc_rate(clk, pscnum, np); + sprintf(clk->name, "psc%d_mclk", pscnum); + clk_register(clk); + clk_enable(clk); + } + } +} + +static struct clk_interface mpc5121_clk_functions = { + .clk_get = mpc5121_clk_get, + .clk_enable = mpc5121_clk_enable, + .clk_disable = mpc5121_clk_disable, + .clk_get_rate = mpc5121_clk_get_rate, + .clk_put = mpc5121_clk_put, + .clk_round_rate = mpc5121_clk_round_rate, + .clk_set_rate = mpc5121_clk_set_rate, + .clk_set_parent = NULL, + .clk_get_parent = NULL, +}; + +static int +mpc5121_clk_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock"); + if (np) { + clockctl = of_iomap(np, 0); + of_node_put(np); + } + + if (!clockctl) { + printk(KERN_ERR "Could not map clock control registers\n"); + return 0; + } + + rate_clks_init(); + psc_clks_init(); + + /* leave clockctl mapped forever */ + /*iounmap(clockctl); */ + DEBUG_CLK_DUMP(); + clocks_initialized++; + clk_functions = mpc5121_clk_functions; + return 0; +} + + +arch_initcall(mpc5121_clk_init); diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c index 50bd3a31902..5ebf6939a69 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (C) 2007, 2008 Freescale Semiconductor, Inc. All rights reserved. * * Author: John Rigby, <jrigby@freescale.com>, Thur Mar 29 2007 * @@ -15,7 +15,6 @@ #include <linux/kernel.h> #include <linux/io.h> -#include <linux/irq.h> #include <linux/of_platform.h> #include <asm/machdep.h> @@ -23,65 +22,22 @@ #include <asm/prom.h> #include <asm/time.h> -/** - * mpc512x_find_ips_freq - Find the IPS bus frequency for a device - * @node: device node - * - * Returns IPS bus frequency, or 0 if the bus frequency cannot be found. - */ -unsigned long -mpc512x_find_ips_freq(struct device_node *node) -{ - struct device_node *np; - const unsigned int *p_ips_freq = NULL; - - of_node_get(node); - while (node) { - p_ips_freq = of_get_property(node, "bus-frequency", NULL); - if (p_ips_freq) - break; - - np = of_get_parent(node); - of_node_put(node); - node = np; - } - if (node) - of_node_put(node); - - return p_ips_freq ? *p_ips_freq : 0; -} -EXPORT_SYMBOL(mpc512x_find_ips_freq); - -static struct of_device_id __initdata of_bus_ids[] = { - { .name = "soc", }, - { .name = "localbus", }, - {}, -}; +#include "mpc512x.h" +#include "mpc5121_ads.h" -static void __init mpc5121_ads_declare_of_platform_devices(void) +static void __init mpc5121_ads_setup_arch(void) { - /* Find every child of the SOC node and add it to of_platform */ - if (of_platform_bus_probe(NULL, of_bus_ids, NULL)) - printk(KERN_ERR __FILE__ ": " - "Error while probing of_platform bus\n"); + printk(KERN_INFO "MPC5121 ADS board from Freescale Semiconductor\n"); + /* + * cpld regs are needed early + */ + mpc5121_ads_cpld_map(); } static void __init mpc5121_ads_init_IRQ(void) { - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, "fsl,ipic"); - if (!np) - return; - - ipic_init(np, 0); - of_node_put(np); - - /* - * Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - ipic_set_default_priority(); + mpc512x_init_IRQ(); + mpc5121_ads_cpld_pic_init(); } /* @@ -97,7 +53,8 @@ static int __init mpc5121_ads_probe(void) define_machine(mpc5121_ads) { .name = "MPC5121 ADS", .probe = mpc5121_ads_probe, - .init = mpc5121_ads_declare_of_platform_devices, + .setup_arch = mpc5121_ads_setup_arch, + .init = mpc512x_declare_of_platform_devices, .init_IRQ = mpc5121_ads_init_IRQ, .get_irq = ipic_get_irq, .calibrate_decr = generic_calibrate_decr, diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.h b/arch/powerpc/platforms/512x/mpc5121_ads.h new file mode 100644 index 00000000000..662076cfee2 --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc5121_ads.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. + * + * 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. + * + * Prototypes for ADS5121 specific code + */ + +#ifndef __MPC512ADS_H__ +#define __MPC512ADS_H__ +extern void __init mpc5121_ads_cpld_map(void); +extern void __init mpc5121_ads_cpld_pic_init(void); +#endif /* __MPC512ADS_H__ */ diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c new file mode 100644 index 00000000000..a6ce8056662 --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: John Rigby, <jrigby@freescale.com> + * + * Description: + * MPC5121ADS CPLD irq handling + * + * This 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. + */ + +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <asm/prom.h> + +static struct device_node *cpld_pic_node; +static struct irq_host *cpld_pic_host; + +/* + * Bits to ignore in the misc_status register + * 0x10 touch screen pendown is hard routed to irq1 + * 0x02 pci status is read from pci status register + */ +#define MISC_IGNORE 0x12 + +/* + * Nothing to ignore in pci status register + */ +#define PCI_IGNORE 0x00 + +struct cpld_pic { + u8 pci_mask; + u8 pci_status; + u8 route; + u8 misc_mask; + u8 misc_status; + u8 misc_control; +}; + +static struct cpld_pic __iomem *cpld_regs; + +static void __iomem * +irq_to_pic_mask(unsigned int irq) +{ + return irq <= 7 ? &cpld_regs->pci_mask : &cpld_regs->misc_mask; +} + +static unsigned int +irq_to_pic_bit(unsigned int irq) +{ + return 1 << (irq & 0x7); +} + +static void +cpld_mask_irq(unsigned int irq) +{ + unsigned int cpld_irq = (unsigned int)irq_map[irq].hwirq; + void __iomem *pic_mask = irq_to_pic_mask(cpld_irq); + + out_8(pic_mask, + in_8(pic_mask) | irq_to_pic_bit(cpld_irq)); +} + +static void +cpld_unmask_irq(unsigned int irq) +{ + unsigned int cpld_irq = (unsigned int)irq_map[irq].hwirq; + void __iomem *pic_mask = irq_to_pic_mask(cpld_irq); + + out_8(pic_mask, + in_8(pic_mask) & ~irq_to_pic_bit(cpld_irq)); +} + +static struct irq_chip cpld_pic = { + .typename = " CPLD PIC ", + .mask = cpld_mask_irq, + .ack = cpld_mask_irq, + .unmask = cpld_unmask_irq, +}; + +static int +cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp, + u8 __iomem *maskp) +{ + int cpld_irq; + u8 status = in_8(statusp); + u8 mask = in_8(maskp); + + /* ignore don't cares and masked irqs */ + status |= (ignore | mask); + + if (status == 0xff) + return NO_IRQ_IGNORE; + + cpld_irq = ffz(status) + offset; + + return irq_linear_revmap(cpld_pic_host, cpld_irq); +} + +static void +cpld_pic_cascade(unsigned int irq, struct irq_desc *desc) +{ + irq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status, + &cpld_regs->pci_mask); + if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { + generic_handle_irq(irq); + return; + } + + irq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status, + &cpld_regs->misc_mask); + if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { + generic_handle_irq(irq); + return; + } +} + +static int +cpld_pic_host_match(struct irq_host *h, struct device_node *node) +{ + return cpld_pic_node == node; +} + +static int +cpld_pic_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + get_irq_desc(virq)->status |= IRQ_LEVEL; + set_irq_chip_and_handler(virq, &cpld_pic, handle_level_irq); + return 0; +} + +static struct +irq_host_ops cpld_pic_host_ops = { + .match = cpld_pic_host_match, + .map = cpld_pic_host_map, +}; + +void __init +mpc5121_ads_cpld_map(void) +{ + struct device_node *np = NULL; + + np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic"); + if (!np) { + printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n"); + return; + } + + cpld_regs = of_iomap(np, 0); + of_node_put(np); +} + +void __init +mpc5121_ads_cpld_pic_init(void) +{ + unsigned int cascade_irq; + struct device_node *np = NULL; + + pr_debug("cpld_ic_init\n"); + + np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic"); + if (!np) { + printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n"); + return; + } + + if (!cpld_regs) + goto end; + + cascade_irq = irq_of_parse_and_map(np, 0); + if (cascade_irq == NO_IRQ) + goto end; + + /* + * statically route touch screen pendown through 1 + * and ignore it here + * route all others through our cascade irq + */ + out_8(&cpld_regs->route, 0xfd); + out_8(&cpld_regs->pci_mask, 0xff); + /* unmask pci ints in misc mask */ + out_8(&cpld_regs->misc_mask, ~(MISC_IGNORE)); + + cpld_pic_node = of_node_get(np); + + cpld_pic_host = + irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 16, &cpld_pic_host_ops, 16); + if (!cpld_pic_host) { + printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n"); + goto end; + } + + set_irq_chained_handler(cascade_irq, cpld_pic_cascade); +end: + of_node_put(np); +} diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c new file mode 100644 index 00000000000..2479de9e2d1 --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc5121_generic.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: John Rigby, <jrigby@freescale.com> + * + * Description: + * MPC5121 SoC setup + * + * This 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. + * + */ + +#include <linux/kernel.h> +#include <linux/of_platform.h> + +#include <asm/machdep.h> +#include <asm/ipic.h> +#include <asm/prom.h> +#include <asm/time.h> + +#include "mpc512x.h" + +/* + * list of supported boards + */ +static char *board[] __initdata = { + "prt,prtlvt", + NULL +}; + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init mpc5121_generic_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(mpc5121_generic) { + .name = "MPC5121 generic", + .probe = mpc5121_generic_probe, + .init = mpc512x_declare_of_platform_devices, + .init_IRQ = mpc512x_init_IRQ, + .get_irq = ipic_get_irq, + .calibrate_decr = generic_calibrate_decr, +}; diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h new file mode 100644 index 00000000000..9c03693cb00 --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc512x.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. + * + * 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. + * + * Prototypes for MPC512x shared code + */ + +#ifndef __MPC512X_H__ +#define __MPC512X_H__ +extern unsigned long mpc512x_find_ips_freq(struct device_node *node); +extern void __init mpc512x_init_IRQ(void); +void __init mpc512x_declare_of_platform_devices(void); +#endif /* __MPC512X_H__ */ diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c new file mode 100644 index 00000000000..d8cd579f319 --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: John Rigby <jrigby@freescale.com> + * + * Description: + * MPC512x Shared code + * + * This 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. + */ + +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/of_platform.h> + +#include <asm/machdep.h> +#include <asm/ipic.h> +#include <asm/prom.h> +#include <asm/time.h> + +#include "mpc512x.h" + +unsigned long +mpc512x_find_ips_freq(struct device_node *node) +{ + struct device_node *np; + const unsigned int *p_ips_freq = NULL; + + of_node_get(node); + while (node) { + p_ips_freq = of_get_property(node, "bus-frequency", NULL); + if (p_ips_freq) + break; + + np = of_get_parent(node); + of_node_put(node); + node = np; + } + if (node) + of_node_put(node); + + return p_ips_freq ? *p_ips_freq : 0; +} +EXPORT_SYMBOL(mpc512x_find_ips_freq); + +void __init mpc512x_init_IRQ(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-ipic"); + if (!np) + return; + + ipic_init(np, 0); + of_node_put(np); + + /* + * Initialize the default interrupt mapping priorities, + * in case the boot rom changed something on us. + */ + ipic_set_default_priority(); +} + +/* + * Nodes to do bus probe on, soc and localbus + */ +static struct of_device_id __initdata of_bus_ids[] = { + { .compatible = "fsl,mpc5121-immr", }, + { .compatible = "fsl,mpc5121-localbus", }, + {}, +}; + +void __init mpc512x_declare_of_platform_devices(void) +{ + if (of_platform_bus_probe(NULL, of_bus_ids, NULL)) + printk(KERN_ERR __FILE__ ": " + "Error while probing of_platform bus\n"); +} + diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c index 41c7fd91e99..fe92e65103e 100644 --- a/arch/powerpc/platforms/52xx/lite5200_pm.c +++ b/arch/powerpc/platforms/52xx/lite5200_pm.c @@ -14,6 +14,7 @@ static struct mpc52xx_sdma __iomem *bes; static struct mpc52xx_xlb __iomem *xlb; static struct mpc52xx_gpio __iomem *gps; static struct mpc52xx_gpio_wkup __iomem *gpw; +static void __iomem *pci; static void __iomem *sram; static const int sram_size = 0x4000; /* 16 kBytes */ static void __iomem *mbar; @@ -50,6 +51,8 @@ static int lite5200_pm_prepare(void) { .type = "builtin", .compatible = "mpc5200", }, /* efika */ {} }; + u64 regaddr64 = 0; + const u32 *regaddr_p; /* deep sleep? let mpc52xx code handle that */ if (lite5200_pm_target_state == PM_SUSPEND_STANDBY) @@ -60,8 +63,12 @@ static int lite5200_pm_prepare(void) /* map registers */ np = of_find_matching_node(NULL, immr_ids); - mbar = of_iomap(np, 0); + regaddr_p = of_get_address(np, 0, NULL, NULL); + if (regaddr_p) + regaddr64 = of_translate_address(np, regaddr_p); of_node_put(np); + + mbar = ioremap((u32) regaddr64, 0xC000); if (!mbar) { printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__); return -ENOSYS; @@ -71,6 +78,7 @@ static int lite5200_pm_prepare(void) pic = mbar + 0x500; gps = mbar + 0xb00; gpw = mbar + 0xc00; + pci = mbar + 0xd00; bes = mbar + 0x1200; xlb = mbar + 0x1f00; sram = mbar + 0x8000; @@ -85,6 +93,7 @@ static struct mpc52xx_sdma sbes; static struct mpc52xx_xlb sxlb; static struct mpc52xx_gpio sgps; static struct mpc52xx_gpio_wkup sgpw; +static char spci[0x200]; static void lite5200_save_regs(void) { @@ -94,6 +103,7 @@ static void lite5200_save_regs(void) _memcpy_fromio(&sxlb, xlb, sizeof(*xlb)); _memcpy_fromio(&sgps, gps, sizeof(*gps)); _memcpy_fromio(&sgpw, gpw, sizeof(*gpw)); + _memcpy_fromio(spci, pci, 0x200); _memcpy_fromio(saved_sram, sram, sram_size); } @@ -103,6 +113,8 @@ static void lite5200_restore_regs(void) int i; _memcpy_toio(sram, saved_sram, sram_size); + /* PCI Configuration */ + _memcpy_toio(pci, spci, 0x200); /* * GPIOs. Interrupt Master Enable has higher address then other diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c index 48da5dfe485..8a455ebce98 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c @@ -100,7 +100,7 @@ static int mpc52xx_wkup_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct mpc52xx_gpiochip *chip = container_of(mm_gc, struct mpc52xx_gpiochip, mmchip); - struct mpc52xx_gpio_wkup *regs = mm_gc->regs; + struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs; unsigned long flags; spin_lock_irqsave(&gpio_lock, flags); @@ -122,7 +122,7 @@ static int mpc52xx_wkup_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct mpc52xx_gpio_wkup *regs = mm_gc->regs; + struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs; struct mpc52xx_gpiochip *chip = container_of(mm_gc, struct mpc52xx_gpiochip, mmchip); unsigned long flags; @@ -150,7 +150,7 @@ static int __devinit mpc52xx_wkup_gpiochip_probe(struct of_device *ofdev, const struct of_device_id *match) { struct mpc52xx_gpiochip *chip; - struct mpc52xx_gpio_wkup *regs; + struct mpc52xx_gpio_wkup __iomem *regs; struct of_gpio_chip *ofchip; int ret; @@ -260,7 +260,7 @@ static int mpc52xx_simple_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct mpc52xx_gpiochip *chip = container_of(mm_gc, struct mpc52xx_gpiochip, mmchip); - struct mpc52xx_gpio *regs = mm_gc->regs; + struct mpc52xx_gpio __iomem *regs = mm_gc->regs; unsigned long flags; spin_lock_irqsave(&gpio_lock, flags); @@ -284,7 +284,7 @@ mpc52xx_simple_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct mpc52xx_gpiochip *chip = container_of(mm_gc, struct mpc52xx_gpiochip, mmchip); - struct mpc52xx_gpio *regs = mm_gc->regs; + struct mpc52xx_gpio __iomem *regs = mm_gc->regs; unsigned long flags; spin_lock_irqsave(&gpio_lock, flags); @@ -312,7 +312,7 @@ static int __devinit mpc52xx_simple_gpiochip_probe(struct of_device *ofdev, { struct mpc52xx_gpiochip *chip; struct of_gpio_chip *ofchip; - struct mpc52xx_gpio *regs; + struct mpc52xx_gpio __iomem *regs; int ret; chip = kzalloc(sizeof(*chip), GFP_KERNEL); @@ -387,7 +387,7 @@ mpc52xx_gpt_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) static int mpc52xx_gpt_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct mpc52xx_gpt *regs = mm_gc->regs; + struct mpc52xx_gpt __iomem *regs = mm_gc->regs; out_be32(®s->mode, 0x04); diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index e3428ddd904..5a382bb15f6 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -63,6 +63,7 @@ #define MPC52xx_PCI_TCR_P 0x01000000 #define MPC52xx_PCI_TCR_LD 0x00010000 +#define MPC52xx_PCI_TCR_WCT8 0x00000008 #define MPC52xx_PCI_TBATR_DISABLE 0x0 #define MPC52xx_PCI_TBATR_ENABLE 0x1 @@ -313,7 +314,7 @@ mpc52xx_pci_setup(struct pci_controller *hose, out_be32(&pci_regs->tbatr1, MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM ); - out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD); + out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD | MPC52xx_PCI_TCR_WCT8); tmp = in_be32(&pci_regs->gscr); #if 0 diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig index 917ac889155..1c8034bfa79 100644 --- a/arch/powerpc/platforms/82xx/Kconfig +++ b/arch/powerpc/platforms/82xx/Kconfig @@ -1,7 +1,8 @@ -choice - prompt "82xx Board Type" - depends on PPC_82xx - default MPC8272_ADS +menuconfig PPC_82xx + bool "82xx-based boards (PQ II)" + depends on 6xx && PPC_MULTIPLATFORM + +if PPC_82xx config MPC8272_ADS bool "Freescale MPC8272 ADS" @@ -36,7 +37,7 @@ config EP8248E This board is also resold by Freescale as the QUICCStart MPC8248 Evaluation System and/or the CWH-PPC-8248N-VE. -endchoice +endif config PQ2ADS bool diff --git a/arch/powerpc/platforms/82xx/ep8248e.c b/arch/powerpc/platforms/82xx/ep8248e.c index d5770fdf7f0..373e993a5ed 100644 --- a/arch/powerpc/platforms/82xx/ep8248e.c +++ b/arch/powerpc/platforms/82xx/ep8248e.c @@ -59,6 +59,7 @@ static void __init ep8248e_pic_init(void) of_node_put(np); } +#ifdef CONFIG_FS_ENET_MDIO_FCC static void ep8248e_set_mdc(struct mdiobb_ctrl *ctrl, int level) { if (level) @@ -164,6 +165,7 @@ static struct of_platform_driver ep8248e_mdio_driver = { .probe = ep8248e_mdio_probe, .remove = ep8248e_mdio_remove, }; +#endif struct cpm_pin { int port, pin, flags; @@ -296,7 +298,9 @@ static __initdata struct of_device_id of_bus_ids[] = { static int __init declare_of_platform_devices(void) { of_platform_bus_probe(NULL, of_bus_ids, NULL); +#ifdef CONFIG_FS_ENET_MDIO_FCC of_register_platform_driver(&ep8248e_mdio_driver); +#endif return 0; } diff --git a/arch/powerpc/platforms/82xx/mpc8272_ads.c b/arch/powerpc/platforms/82xx/mpc8272_ads.c index 7d301875198..8054c685d32 100644 --- a/arch/powerpc/platforms/82xx/mpc8272_ads.c +++ b/arch/powerpc/platforms/82xx/mpc8272_ads.c @@ -96,6 +96,10 @@ static struct cpm_pin mpc8272_ads_pins[] = { {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, {2, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, {2, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* I2C */ + {3, 14, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN}, + {3, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN}, }; static void __init init_ioports(void) diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index a8013816125..9876d7e072f 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -109,7 +109,7 @@ static int pci_pic_host_map(struct irq_host *h, unsigned int virq, { get_irq_desc(virq)->status |= IRQ_LEVEL; set_irq_chip_data(virq, h->host_data); - set_irq_chip(virq, &pq2ads_pci_ic); + set_irq_chip_and_handler(virq, &pq2ads_pci_ic, handle_level_irq); return 0; } diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index 13587e2e868..27d9bf86de0 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig @@ -1,10 +1,12 @@ -menuconfig MPC83xx - bool "83xx Board Type" - depends on PPC_83xx +menuconfig PPC_83xx + bool "83xx-based boards" + depends on 6xx && PPC_MULTIPLATFORM select PPC_UDBG_16550 select PPC_INDIRECT_PCI + select FSL_SOC + select IPIC -if MPC83xx +if PPC_83xx config MPC831x_RDB bool "Freescale MPC831x RDB" @@ -58,6 +60,17 @@ config MPC836x_MDS help This option enables support for the MPC836x MDS Processor Board. +config MPC836x_RDK + bool "Freescale/Logic MPC836x RDK" + select DEFAULT_UIMAGE + select QUICC_ENGINE + select QE_GPIO + select FSL_GTM + select FSL_LBC + help + This option enables support for the MPC836x RDK Processor Board, + also known as ZOOM PowerQUICC Kit. + config MPC837x_MDS bool "Freescale MPC837x MDS" select DEFAULT_UIMAGE @@ -79,6 +92,15 @@ config SBC834x help This option enables support for the Wind River SBC834x board. +config ASP834x + bool "Analogue & Micro ASP 834x" + select PPC_MPC834x + select REDBOOT + help + This enables support for the Analogue & Micro ASP 83xx + board. + + endif # used for usb diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile index 7e6dd3e259d..f331fd7dd83 100644 --- a/arch/powerpc/platforms/83xx/Makefile +++ b/arch/powerpc/platforms/83xx/Makefile @@ -8,7 +8,9 @@ obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o obj-$(CONFIG_MPC834x_MDS) += mpc834x_mds.o obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o obj-$(CONFIG_MPC836x_MDS) += mpc836x_mds.o +obj-$(CONFIG_MPC836x_RDK) += mpc836x_rdk.o obj-$(CONFIG_MPC832x_MDS) += mpc832x_mds.o obj-$(CONFIG_MPC837x_MDS) += mpc837x_mds.o obj-$(CONFIG_SBC834x) += sbc834x.o obj-$(CONFIG_MPC837x_RDB) += mpc837x_rdb.o +obj-$(CONFIG_ASP834x) += asp834x.o diff --git a/arch/powerpc/platforms/83xx/asp834x.c b/arch/powerpc/platforms/83xx/asp834x.c new file mode 100644 index 00000000000..bb30d67ad0a --- /dev/null +++ b/arch/powerpc/platforms/83xx/asp834x.c @@ -0,0 +1,90 @@ +/* + * arch/powerpc/platforms/83xx/asp834x.c + * + * Analogue & Micro ASP8347 board specific routines + * clone of mpc834x_itx + * + * Copyright 2008 Codehermit + * + * Maintainer: Bryan O'Donoghue <bodonoghue@codhermit.ie> + * + * 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. + */ + +#include <linux/pci.h> +#include <linux/of_platform.h> + +#include <asm/time.h> +#include <asm/ipic.h> +#include <asm/udbg.h> + +#include "mpc83xx.h" + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init asp834x_setup_arch(void) +{ + if (ppc_md.progress) + ppc_md.progress("asp834x_setup_arch()", 0); + + mpc834x_usb_cfg(); +} + +static void __init asp834x_init_IRQ(void) +{ + struct device_node *np; + + np = of_find_node_by_type(NULL, "ipic"); + if (!np) + return; + + ipic_init(np, 0); + + of_node_put(np); + + /* Initialize the default interrupt mapping priorities, + * in case the boot rom changed something on us. + */ + ipic_set_default_priority(); +} + +static struct __initdata of_device_id asp8347_ids[] = { + { .type = "soc", }, + { .compatible = "soc", }, + { .compatible = "simple-bus", }, + {}, +}; + +static int __init asp8347_declare_of_platform_devices(void) +{ + of_platform_bus_probe(NULL, asp8347_ids, NULL); + return 0; +} +machine_device_initcall(asp834x, asp8347_declare_of_platform_devices); + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init asp834x_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + return of_flat_dt_is_compatible(root, "analogue-and-micro,asp8347e"); +} + +define_machine(asp834x) { + .name = "ASP8347E", + .probe = asp834x_probe, + .setup_arch = asp834x_setup_arch, + .init_IRQ = asp834x_init_IRQ, + .get_irq = ipic_get_irq, + .restart = mpc83xx_restart, + .time_init = mpc83xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/83xx/mpc836x_rdk.c b/arch/powerpc/platforms/83xx/mpc836x_rdk.c new file mode 100644 index 00000000000..c10dec4bf17 --- /dev/null +++ b/arch/powerpc/platforms/83xx/mpc836x_rdk.c @@ -0,0 +1,102 @@ +/* + * MPC8360E-RDK board file. + * + * Copyright (c) 2006 Freescale Semicondutor, Inc. + * Copyright (c) 2007-2008 MontaVista Software, Inc. + * + * Author: Anton Vorontsov <avorontsov@ru.mvista.com> + * + * 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. + */ + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/of_platform.h> +#include <linux/io.h> +#include <asm/prom.h> +#include <asm/time.h> +#include <asm/ipic.h> +#include <asm/udbg.h> +#include <asm/qe.h> +#include <asm/qe_ic.h> +#include <sysdev/fsl_soc.h> + +#include "mpc83xx.h" + +static struct of_device_id __initdata mpc836x_rdk_ids[] = { + { .compatible = "simple-bus", }, + {}, +}; + +static int __init mpc836x_rdk_declare_of_platform_devices(void) +{ + return of_platform_bus_probe(NULL, mpc836x_rdk_ids, NULL); +} +machine_device_initcall(mpc836x_rdk, mpc836x_rdk_declare_of_platform_devices); + +static void __init mpc836x_rdk_setup_arch(void) +{ +#ifdef CONFIG_PCI + struct device_node *np; +#endif + + if (ppc_md.progress) + ppc_md.progress("mpc836x_rdk_setup_arch()", 0); + +#ifdef CONFIG_PCI + for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") + mpc83xx_add_bridge(np); +#endif + + qe_reset(); +} + +static void __init mpc836x_rdk_init_IRQ(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,ipic"); + if (!np) + return; + + ipic_init(np, 0); + + /* + * Initialize the default interrupt mapping priorities, + * in case the boot rom changed something on us. + */ + ipic_set_default_priority(); + of_node_put(np); + + np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); + if (!np) + return; + + qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); + of_node_put(np); +} + +/* + * Called very early, MMU is off, device-tree isn't unflattened. + */ +static int __init mpc836x_rdk_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "fsl,mpc8360rdk"); +} + +define_machine(mpc836x_rdk) { + .name = "MPC836x RDK", + .probe = mpc836x_rdk_probe, + .setup_arch = mpc836x_rdk_setup_arch, + .init_IRQ = mpc836x_rdk_init_IRQ, + .get_irq = ipic_get_irq, + .restart = mpc83xx_restart, + .time_init = mpc83xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index 7ff29d53dc2..cebea5cadbc 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -34,9 +34,16 @@ config MPC85xx_MDS bool "Freescale MPC85xx MDS" select DEFAULT_UIMAGE select QUICC_ENGINE + select PHYLIB help This option enables support for the MPC85xx MDS board +config MPC8536_DS + bool "Freescale MPC8536 DS" + select DEFAULT_UIMAGE + help + This option enables support for the MPC8536 DS board + config MPC85xx_DS bool "Freescale MPC85xx DS" select PPC_I8259 @@ -74,6 +81,14 @@ config TQM8541 select TQM85xx select CPM2 +config TQM8548 + bool "TQ Components TQM8548" + help + This option enables support for the TQ Components TQM8548 board. + select DEFAULT_UIMAGE + select PPC_CPM_NEW_BINDING + select TQM85xx + config TQM8555 bool "TQ Components TQM8555" help diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 6cea185f62b..cb3054e1001 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o +obj-$(CONFIG_MPC8536_DS) += mpc8536_ds.o obj-$(CONFIG_MPC85xx_DS) += mpc85xx_ds.o obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o obj-$(CONFIG_STX_GP3) += stx_gp3.o diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c new file mode 100644 index 00000000000..6b846aa1ced --- /dev/null +++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c @@ -0,0 +1,125 @@ +/* + * MPC8536 DS Board Setup + * + * Copyright 2008 Freescale Semiconductor, Inc. + * + * 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. + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/interrupt.h> +#include <linux/of_platform.h> + +#include <asm/system.h> +#include <asm/time.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <mm/mmu_decl.h> +#include <asm/prom.h> +#include <asm/udbg.h> +#include <asm/mpic.h> + +#include <sysdev/fsl_soc.h> +#include <sysdev/fsl_pci.h> + +void __init mpc8536_ds_pic_init(void) +{ + struct mpic *mpic; + struct resource r; + struct device_node *np; + + np = of_find_node_by_type(NULL, "open-pic"); + if (np == NULL) { + printk(KERN_ERR "Could not find open-pic node\n"); + return; + } + + if (of_address_to_resource(np, 0, &r)) { + printk(KERN_ERR "Failed to map mpic register space\n"); + of_node_put(np); + return; + } + + mpic = mpic_alloc(np, r.start, + MPIC_PRIMARY | MPIC_WANTS_RESET | + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, + 0, 256, " OpenPIC "); + BUG_ON(mpic == NULL); + of_node_put(np); + + mpic_init(mpic); +} + +/* + * Setup the architecture + */ +static void __init mpc8536_ds_setup_arch(void) +{ +#ifdef CONFIG_PCI + struct device_node *np; +#endif + + if (ppc_md.progress) + ppc_md.progress("mpc8536_ds_setup_arch()", 0); + +#ifdef CONFIG_PCI + for_each_node_by_type(np, "pci") { + if (of_device_is_compatible(np, "fsl,mpc8540-pci") || + of_device_is_compatible(np, "fsl,mpc8548-pcie")) { + struct resource rsrc; + of_address_to_resource(np, 0, &rsrc); + if ((rsrc.start & 0xfffff) == 0x8000) + fsl_add_bridge(np, 1); + else + fsl_add_bridge(np, 0); + } + } + +#endif + + printk("MPC8536 DS board from Freescale Semiconductor\n"); +} + +static struct of_device_id __initdata mpc8536_ds_ids[] = { + { .type = "soc", }, + { .compatible = "soc", }, + {}, +}; + +static int __init mpc8536_ds_publish_devices(void) +{ + return of_platform_bus_probe(NULL, mpc8536_ds_ids, NULL); +} +machine_device_initcall(mpc8536_ds, mpc8536_ds_publish_devices); + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mpc8536_ds_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "fsl,mpc8536ds"); +} + +define_machine(mpc8536_ds) { + .name = "MPC8536 DS", + .probe = mpc8536_ds_probe, + .setup_arch = mpc8536_ds_setup_arch, + .init_IRQ = mpc8536_ds_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 3582c841844..ba498d6f2d0 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -119,6 +119,8 @@ static const struct cpm_pin mpc8560_ads_pins[] = { {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* SCC2 */ + {2, 12, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {2, 13, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, {3, 26, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, {3, 27, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, {3, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, @@ -145,7 +147,6 @@ static const struct cpm_pin mpc8560_ads_pins[] = { {1, 4, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, {1, 5, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, {1, 6, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, - {1, 7, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, {1, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, {1, 9, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, {1, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, @@ -156,8 +157,9 @@ static const struct cpm_pin mpc8560_ads_pins[] = { {1, 15, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, {1, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, {1, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, - {2, 16, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* CLK16 */ - {2, 17, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* CLK15 */ + {2, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* CLK16 */ + {2, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* CLK15 */ + {2, 27, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, }; static void __init init_ioports(void) diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 8b1de7884be..50d7ea8f922 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/interrupt.h> #include <linux/fsl_devices.h> +#include <linux/of_platform.h> #include <asm/system.h> #include <asm/pgtable.h> @@ -335,6 +336,19 @@ static int __init mpc85xx_cds_probe(void) return of_flat_dt_is_compatible(root, "MPC85xxCDS"); } +static struct of_device_id __initdata of_bus_ids[] = { + { .type = "soc", }, + { .compatible = "soc", }, + { .compatible = "simple-bus", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + return of_platform_bus_probe(NULL, of_bus_ids, NULL); +} +machine_device_initcall(mpc85xx_cds, declare_of_platform_devices); + define_machine(mpc85xx_cds) { .name = "MPC85xx CDS", .probe = mpc85xx_cds_probe, diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index dfd8b4ad9b2..25f41cd2d33 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -58,14 +58,13 @@ void __init mpc85xx_ds_pic_init(void) { struct mpic *mpic; struct resource r; - struct device_node *np = NULL; + struct device_node *np; #ifdef CONFIG_PPC_I8259 struct device_node *cascade_node = NULL; int cascade_irq; #endif - np = of_find_node_by_type(np, "open-pic"); - + np = of_find_node_by_type(NULL, "open-pic"); if (np == NULL) { printk(KERN_ERR "Could not find open-pic node\n"); return; @@ -78,9 +77,11 @@ void __init mpc85xx_ds_pic_init(void) } mpic = mpic_alloc(np, r.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + MPIC_PRIMARY | MPIC_WANTS_RESET | + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); + of_node_put(np); mpic_init(mpic); @@ -184,7 +185,7 @@ static int __init mpc8544_ds_probe(void) } } -static struct of_device_id mpc85xxds_ids[] = { +static struct of_device_id __initdata mpc85xxds_ids[] = { { .type = "soc", }, { .compatible = "soc", }, {}, @@ -195,6 +196,7 @@ static int __init mpc85xxds_publish_devices(void) return of_platform_bus_probe(NULL, mpc85xxds_ids, NULL); } machine_device_initcall(mpc8544_ds, mpc85xxds_publish_devices); +machine_device_initcall(mpc8572_ds, mpc85xxds_publish_devices); /* * Called very early, device-tree isn't unflattened diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c index 77681acf1ba..d850880d696 100644 --- a/arch/powerpc/platforms/85xx/tqm85xx.c +++ b/arch/powerpc/platforms/85xx/tqm85xx.c @@ -120,8 +120,18 @@ static void __init tqm85xx_setup_arch(void) #endif #ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8540-pci") - fsl_add_bridge(np, 1); + for_each_node_by_type(np, "pci") { + if (of_device_is_compatible(np, "fsl,mpc8540-pci") || + of_device_is_compatible(np, "fsl,mpc8548-pcie")) { + struct resource rsrc; + if (!of_address_to_resource(np, 0, &rsrc)) { + if ((rsrc.start & 0xfffff) == 0x8000) + fsl_add_bridge(np, 1); + else + fsl_add_bridge(np, 0); + } + } + } #endif } @@ -165,10 +175,11 @@ static int __init tqm85xx_probe(void) { unsigned long root = of_get_flat_dt_root(); - if ((of_flat_dt_is_compatible(root, "tqm,8540")) || - (of_flat_dt_is_compatible(root, "tqm,8541")) || - (of_flat_dt_is_compatible(root, "tqm,8555")) || - (of_flat_dt_is_compatible(root, "tqm,8560"))) + if ((of_flat_dt_is_compatible(root, "tqc,tqm8540")) || + (of_flat_dt_is_compatible(root, "tqc,tqm8541")) || + (of_flat_dt_is_compatible(root, "tqc,tqm8548")) || + (of_flat_dt_is_compatible(root, "tqc,tqm8555")) || + (of_flat_dt_is_compatible(root, "tqc,tqm8560"))) return 1; return 0; diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 053f49a1dca..80a81e02bb5 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -1,7 +1,13 @@ -choice - prompt "86xx Board Type" - depends on PPC_86xx - default MPC8641_HPCN +config PPC_86xx +menuconfig PPC_86xx + bool "86xx-based boards" + depends on 6xx && PPC_MULTIPLATFORM + select FSL_SOC + select ALTIVEC + help + The Freescale E600 SoCs have 74xx cores. + +if PPC_86xx config MPC8641_HPCN bool "Freescale MPC8641 HPCN" @@ -24,7 +30,7 @@ config MPC8610_HPCD help This option enables support for the MPC8610 HPCD board. -endchoice +endif config MPC8641 bool diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile index 1b9b4a9b252..8fee37dec79 100644 --- a/arch/powerpc/platforms/86xx/Makefile +++ b/arch/powerpc/platforms/86xx/Makefile @@ -2,6 +2,7 @@ # Makefile for the PowerPC 86xx linux kernel. # +obj-y := pic.o obj-$(CONFIG_SMP) += mpc86xx_smp.o obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o obj-$(CONFIG_SBC8641D) += sbc8641d.o diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index dea13208bf6..30725302884 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -39,6 +39,8 @@ #include <sysdev/fsl_pci.h> #include <sysdev/fsl_soc.h> +#include "mpc86xx.h" + static unsigned char *pixis_bdcfg0, *pixis_arch; static struct of_device_id __initdata mpc8610_ids[] = { @@ -56,27 +58,6 @@ static int __init mpc8610_declare_of_platform_devices(void) } machine_device_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices); -static void __init mpc86xx_hpcd_init_irq(void) -{ - struct mpic *mpic1; - struct device_node *np; - struct resource res; - - /* Determine PIC address. */ - np = of_find_node_by_type(NULL, "open-pic"); - if (np == NULL) - return; - of_address_to_resource(np, 0, &res); - - /* Alloc mpic structure and per isu has 16 INT entries. */ - mpic1 = mpic_alloc(np, res.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, - 0, 256, " MPIC "); - BUG_ON(mpic1 == NULL); - - mpic_init(mpic1); -} - #ifdef CONFIG_PCI static void __devinit quirk_uli1575(struct pci_dev *dev) { @@ -404,7 +385,7 @@ define_machine(mpc86xx_hpcd) { .name = "MPC86xx HPCD", .probe = mpc86xx_hpcd_probe, .setup_arch = mpc86xx_hpcd_setup_arch, - .init_IRQ = mpc86xx_hpcd_init_irq, + .init_IRQ = mpc86xx_init_irq, .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, .time_init = mpc86xx_time_init, diff --git a/arch/powerpc/platforms/86xx/mpc86xx.h b/arch/powerpc/platforms/86xx/mpc86xx.h index 525ffa1904f..08efb57559d 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx.h +++ b/arch/powerpc/platforms/86xx/mpc86xx.h @@ -15,6 +15,7 @@ * mpc86xx_* files. Mostly for use by mpc86xx_setup(). */ -extern void __init mpc86xx_smp_init(void); +extern void mpc86xx_smp_init(void); +extern void mpc86xx_init_irq(void); #endif /* __MPC86XX_H__ */ diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index f13704aabbe..7916599c912 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -28,7 +28,6 @@ #include <asm/prom.h> #include <mm/mmu_decl.h> #include <asm/udbg.h> -#include <asm/i8259.h> #include <asm/mpic.h> @@ -46,67 +45,6 @@ #endif #ifdef CONFIG_PCI -static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc) -{ - unsigned int cascade_irq = i8259_irq(); - if (cascade_irq != NO_IRQ) - generic_handle_irq(cascade_irq); - desc->chip->eoi(irq); -} -#endif /* CONFIG_PCI */ - -static void __init -mpc86xx_hpcn_init_irq(void) -{ - struct mpic *mpic1; - struct device_node *np; - struct resource res; -#ifdef CONFIG_PCI - struct device_node *cascade_node = NULL; - int cascade_irq; -#endif - - /* Determine PIC address. */ - np = of_find_node_by_type(NULL, "open-pic"); - if (np == NULL) - return; - of_address_to_resource(np, 0, &res); - - /* Alloc mpic structure and per isu has 16 INT entries. */ - mpic1 = mpic_alloc(np, res.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, - 0, 256, " MPIC "); - BUG_ON(mpic1 == NULL); - - mpic_init(mpic1); - -#ifdef CONFIG_PCI - /* Initialize i8259 controller */ - for_each_node_by_type(np, "interrupt-controller") - if (of_device_is_compatible(np, "chrp,iic")) { - cascade_node = np; - break; - } - if (cascade_node == NULL) { - printk(KERN_DEBUG "mpc86xxhpcn: no ISA interrupt controller\n"); - return; - } - - cascade_irq = irq_of_parse_and_map(cascade_node, 0); - if (cascade_irq == NO_IRQ) { - printk(KERN_ERR "mpc86xxhpcn: failed to map cascade interrupt"); - return; - } - DBG("mpc86xxhpcn: cascade mapped to irq %d\n", cascade_irq); - - i8259_init(cascade_node, 0); - of_node_put(cascade_node); - - set_irq_chained_handler(cascade_irq, mpc86xx_8259_cascade); -#endif -} - -#ifdef CONFIG_PCI extern int uses_fsl_uli_m1575; extern int uli_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn); @@ -237,7 +175,7 @@ define_machine(mpc86xx_hpcn) { .name = "MPC86xx HPCN", .probe = mpc86xx_hpcn_probe, .setup_arch = mpc86xx_hpcn_setup_arch, - .init_IRQ = mpc86xx_hpcn_init_irq, + .init_IRQ = mpc86xx_init_irq, .show_cpuinfo = mpc86xx_hpcn_show_cpuinfo, .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c index ba55b0ff0f7..835f2dc24dc 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/delay.h> +#include <asm/code-patching.h> #include <asm/page.h> #include <asm/pgtable.h> #include <asm/pci-bridge.h> @@ -56,8 +57,7 @@ smp_86xx_kick_cpu(int nr) unsigned int save_vector; unsigned long target, flags; int n = 0; - volatile unsigned int *vector - = (volatile unsigned int *)(KERNELBASE + 0x100); + unsigned int *vector = (unsigned int *)(KERNELBASE + 0x100); if (nr < 0 || nr >= NR_CPUS) return; @@ -71,7 +71,7 @@ smp_86xx_kick_cpu(int nr) /* Setup fake reset vector to call __secondary_start_mpc86xx. */ target = (unsigned long) __secondary_start_mpc86xx; - create_branch((unsigned long)vector, target, BRANCH_SET_LINK); + patch_branch(vector, target, BRANCH_SET_LINK); /* Kick that CPU */ smp_86xx_release_core(nr); diff --git a/arch/powerpc/platforms/86xx/pic.c b/arch/powerpc/platforms/86xx/pic.c new file mode 100644 index 00000000000..8881c5de500 --- /dev/null +++ b/arch/powerpc/platforms/86xx/pic.c @@ -0,0 +1,78 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * 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. + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/of_platform.h> + +#include <asm/system.h> +#include <asm/mpic.h> +#include <asm/i8259.h> + +#ifdef CONFIG_PPC_I8259 +static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc) +{ + unsigned int cascade_irq = i8259_irq(); + if (cascade_irq != NO_IRQ) + generic_handle_irq(cascade_irq); + desc->chip->eoi(irq); +} +#endif /* CONFIG_PPC_I8259 */ + +void __init mpc86xx_init_irq(void) +{ + struct mpic *mpic; + struct device_node *np; + struct resource res; +#ifdef CONFIG_PPC_I8259 + struct device_node *cascade_node = NULL; + int cascade_irq; +#endif + + /* Determine PIC address. */ + np = of_find_node_by_type(NULL, "open-pic"); + if (np == NULL) + return; + of_address_to_resource(np, 0, &res); + + mpic = mpic_alloc(np, res.start, + MPIC_PRIMARY | MPIC_WANTS_RESET | + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, + 0, 256, " MPIC "); + of_node_put(np); + BUG_ON(mpic == NULL); + + mpic_init(mpic); + +#ifdef CONFIG_PPC_I8259 + /* Initialize i8259 controller */ + for_each_node_by_type(np, "interrupt-controller") + if (of_device_is_compatible(np, "chrp,iic")) { + cascade_node = np; + break; + } + + if (cascade_node == NULL) { + printk(KERN_DEBUG "Could not find i8259 PIC\n"); + return; + } + + cascade_irq = irq_of_parse_and_map(cascade_node, 0); + if (cascade_irq == NO_IRQ) { + printk(KERN_ERR "Failed to map cascade interrupt\n"); + return; + } + + i8259_init(cascade_node, 0); + of_node_put(cascade_node); + + set_irq_chained_handler(cascade_irq, mpc86xx_8259_cascade); +#endif +} diff --git a/arch/powerpc/platforms/86xx/sbc8641d.c b/arch/powerpc/platforms/86xx/sbc8641d.c index 510a06ef0b5..00e6fad3b3c 100644 --- a/arch/powerpc/platforms/86xx/sbc8641d.c +++ b/arch/powerpc/platforms/86xx/sbc8641d.c @@ -38,29 +38,6 @@ #include "mpc86xx.h" static void __init -sbc8641_init_irq(void) -{ - struct mpic *mpic1; - struct device_node *np; - struct resource res; - - /* Determine PIC address. */ - np = of_find_node_by_type(NULL, "open-pic"); - if (np == NULL) - return; - of_address_to_resource(np, 0, &res); - - /* Alloc mpic structure and per isu has 16 INT entries. */ - mpic1 = mpic_alloc(np, res.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, - 0, 256, " MPIC "); - of_node_put(np); - BUG_ON(mpic1 == NULL); - - mpic_init(mpic1); -} - -static void __init sbc8641_setup_arch(void) { #ifdef CONFIG_PCI @@ -151,7 +128,7 @@ define_machine(sbc8641) { .name = "SBC8641D", .probe = sbc8641_probe, .setup_arch = sbc8641_setup_arch, - .init_IRQ = sbc8641_init_irq, + .init_IRQ = mpc86xx_init_irq, .show_cpuinfo = sbc8641_show_cpuinfo, .get_irq = mpic_get_irq, .restart = fsl_rstcr_restart, diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c index c028a5b71bb..caaec29796b 100644 --- a/arch/powerpc/platforms/8xx/mpc86xads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c @@ -65,6 +65,10 @@ static struct cpm_pin mpc866ads_pins[] = { {CPM_PORTD, 13, CPM_PIN_OUTPUT}, {CPM_PORTD, 14, CPM_PIN_OUTPUT}, {CPM_PORTD, 15, CPM_PIN_OUTPUT}, + + /* I2C */ + {CPM_PORTB, 26, CPM_PIN_INPUT | CPM_PIN_OPENDRAIN}, + {CPM_PORTB, 27, CPM_PIN_INPUT | CPM_PIN_OPENDRAIN}, }; static void __init init_ioports(void) diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c index 6e7ded0233f..45ed6cdc131 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c @@ -158,6 +158,9 @@ static struct cpm_pin mpc885ads_pins[] = { {CPM_PORTE, 28, CPM_PIN_OUTPUT}, {CPM_PORTE, 29, CPM_PIN_OUTPUT}, #endif + /* I2C */ + {CPM_PORTB, 26, CPM_PIN_INPUT | CPM_PIN_OPENDRAIN}, + {CPM_PORTB, 27, CPM_PIN_INPUT | CPM_PIN_OPENDRAIN}, }; static void __init init_ioports(void) diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 87454c52697..690c1f46e69 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -1,36 +1,9 @@ menu "Platform support" -choice - prompt "Machine type" - depends on PPC64 || 6xx - default PPC_MULTIPLATFORM - config PPC_MULTIPLATFORM - bool "Generic desktop/server/laptop" - help - Select this option if configuring for an IBM pSeries or - RS/6000 machine, an Apple machine, or a PReP, CHRP, - Maple or Cell-based machine. - -config PPC_82xx - bool "Freescale 82xx" - depends on 6xx - -config PPC_83xx - bool "Freescale 83xx" - depends on 6xx - select FSL_SOC - select MPC83xx - select IPIC - -config PPC_86xx - bool "Freescale 86xx" - depends on 6xx - select FSL_SOC - select ALTIVEC - help - The Freescale E600 SoCs have 74xx cores. -endchoice + bool + depends on PPC64 || 6xx + default y config CLASSIC32 def_bool y diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index f7efaa925a1..5bc4b611ff8 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -95,6 +95,11 @@ config E500 select FSL_EMB_PERFMON bool +config PPC_E500MC + bool "e500mc Support" + select PPC_FPU + depends on E500 + config PPC_FPU bool default y if PPC64 @@ -155,9 +160,25 @@ config ALTIVEC If in doubt, say Y here. +config VSX + bool "VSX Support" + depends on POWER4 && ALTIVEC && PPC_FPU + ---help--- + + This option enables kernel support for the Vector Scaler extensions + to the PowerPC processor. The kernel currently supports saving and + restoring VSX registers, and turning on the 'VSX enable' bit so user + processes can execute VSX instructions. + + This option is only useful if you have a processor that supports + VSX (P7 and above), but does not have any affect on a non-VSX + CPUs (it does, however add code to the kernel). + + If in doubt, say Y here. + config SPE bool "SPE Support" - depends on E200 || E500 + depends on E200 || (E500 && !PPC_E500MC) default y ---help--- This option enables kernel support for the Signal Processing @@ -182,7 +203,7 @@ config PPC_STD_MMU_32 config PPC_MM_SLICES bool - default y if HUGETLB_PAGE + default y if HUGETLB_PAGE || PPC_64K_PAGES default n config VIRT_CPU_ACCOUNTING diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index c39f5c225f2..896548ba1ca 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -14,6 +14,7 @@ #include <linux/pci.h> #include <linux/msi.h> #include <linux/of_platform.h> +#include <linux/debugfs.h> #include <asm/dcr.h> #include <asm/machdep.h> @@ -69,8 +70,19 @@ struct axon_msic { dma_addr_t fifo_phys; dcr_host_t dcr_host; u32 read_offset; +#ifdef DEBUG + u32 __iomem *trigger; +#endif }; +#ifdef DEBUG +void axon_msi_debug_setup(struct device_node *dn, struct axon_msic *msic); +#else +static inline void axon_msi_debug_setup(struct device_node *dn, + struct axon_msic *msic) { } +#endif + + static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val) { pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n); @@ -346,7 +358,14 @@ static int axon_msi_probe(struct of_device *device, goto out_free_msic; } - msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP, + virq = irq_of_parse_and_map(dn, 0); + if (virq == NO_IRQ) { + printk(KERN_ERR "axon_msi: irq parse and map failed for %s\n", + dn->full_name); + goto out_free_fifo; + } + + msic->irq_host = irq_alloc_host(dn, IRQ_HOST_MAP_NOMAP, NR_IRQS, &msic_host_ops, 0); if (!msic->irq_host) { printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n", @@ -356,13 +375,6 @@ static int axon_msi_probe(struct of_device *device, msic->irq_host->host_data = msic; - virq = irq_of_parse_and_map(dn, 0); - if (virq == NO_IRQ) { - printk(KERN_ERR "axon_msi: irq parse and map failed for %s\n", - dn->full_name); - goto out_free_host; - } - set_irq_data(virq, msic); set_irq_chained_handler(virq, axon_msi_cascade); pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq); @@ -381,12 +393,12 @@ static int axon_msi_probe(struct of_device *device, ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs; ppc_md.msi_check_device = axon_msi_check_device; + axon_msi_debug_setup(dn, msic); + printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name); return 0; -out_free_host: - kfree(msic->irq_host); out_free_fifo: dma_free_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES, msic->fifo_virt, msic->fifo_phys); @@ -418,3 +430,47 @@ static int __init axon_msi_init(void) return of_register_platform_driver(&axon_msi_driver); } subsys_initcall(axon_msi_init); + + +#ifdef DEBUG +static int msic_set(void *data, u64 val) +{ + struct axon_msic *msic = data; + out_le32(msic->trigger, val); + return 0; +} + +static int msic_get(void *data, u64 *val) +{ + *val = 0; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(fops_msic, msic_get, msic_set, "%llu\n"); + +void axon_msi_debug_setup(struct device_node *dn, struct axon_msic *msic) +{ + char name[8]; + u64 addr; + + addr = of_translate_address(dn, of_get_property(dn, "reg", NULL)); + if (addr == OF_BAD_ADDR) { + pr_debug("axon_msi: couldn't translate reg property\n"); + return; + } + + msic->trigger = ioremap(addr, 0x4); + if (!msic->trigger) { + pr_debug("axon_msi: ioremap failed\n"); + return; + } + + snprintf(name, sizeof(name), "msic_%d", of_node_to_nid(dn)); + + if (!debugfs_create_file(name, 0600, powerpc_debugfs_root, + msic, &fops_msic)) { + pr_debug("axon_msi: debugfs_create_file failed!\n"); + return; + } +} +#endif /* DEBUG */ diff --git a/arch/powerpc/platforms/cell/beat_htab.c b/arch/powerpc/platforms/cell/beat_htab.c index 81467ff055c..2e67bd840e0 100644 --- a/arch/powerpc/platforms/cell/beat_htab.c +++ b/arch/powerpc/platforms/cell/beat_htab.c @@ -112,7 +112,7 @@ static long beat_lpar_hpte_insert(unsigned long hpte_group, if (!(vflags & HPTE_V_BOLTED)) DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); - if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) + if (rflags & _PAGE_NO_CACHE) hpte_r &= ~_PAGE_COHERENT; spin_lock(&beat_htab_lock); @@ -334,7 +334,7 @@ static long beat_lpar_hpte_insert_v3(unsigned long hpte_group, if (!(vflags & HPTE_V_BOLTED)) DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); - if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) + if (rflags & _PAGE_NO_CACHE) hpte_r &= ~_PAGE_COHERENT; /* insert into not-volted entry */ diff --git a/arch/powerpc/platforms/cell/celleb_scc_pciex.c b/arch/powerpc/platforms/cell/celleb_scc_pciex.c index 31da84c458d..0e04f8fb152 100644 --- a/arch/powerpc/platforms/cell/celleb_scc_pciex.c +++ b/arch/powerpc/platforms/cell/celleb_scc_pciex.c @@ -217,7 +217,7 @@ static u##size scc_pciex_in##name(unsigned long port) \ static void scc_pciex_ins##name(unsigned long p, void *b, unsigned long c) \ { \ struct iowa_bus *bus = iowa_pio_find_bus(p); \ - u##size *dst = b; \ + __le##size *dst = b; \ for (; c != 0; c--, dst++) \ *dst = cpu_to_le##size(__scc_pciex_in##name(bus->phb, p)); \ scc_pciex_io_flush(bus); \ @@ -231,10 +231,11 @@ static void scc_pciex_outs##name(unsigned long p, const void *b, \ unsigned long c) \ { \ struct iowa_bus *bus = iowa_pio_find_bus(p); \ - const u##size *src = b; \ + const __le##size *src = b; \ for (; c != 0; c--, src++) \ __scc_pciex_out##name(bus->phb, le##size##_to_cpu(*src), p); \ } +#define __le8 u8 #define cpu_to_le8(x) (x) #define le8_to_cpu(x) (x) PCIEX_PIO_FUNC(8, b) diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 5bf7df14602..2d5bb22d6c0 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -218,6 +218,7 @@ void iic_request_IPIs(void) { iic_request_ipi(PPC_MSG_CALL_FUNCTION, "IPI-call"); iic_request_ipi(PPC_MSG_RESCHEDULE, "IPI-resched"); + iic_request_ipi(PPC_MSG_CALL_FUNC_SINGLE, "IPI-call-single"); #ifdef CONFIG_DEBUGGER iic_request_ipi(PPC_MSG_DEBUGGER_BREAK, "IPI-debug"); #endif /* CONFIG_DEBUGGER */ diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 45646b2b4af..eeacb3a52ca 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -540,7 +540,7 @@ static unsigned long cell_dma_direct_offset; static unsigned long dma_iommu_fixed_base; struct dma_mapping_ops dma_iommu_fixed_ops; -static void cell_dma_dev_setup_iommu(struct device *dev) +static struct iommu_table *cell_get_iommu_table(struct device *dev) { struct iommu_window *window; struct cbe_iommu *iommu; @@ -555,11 +555,11 @@ static void cell_dma_dev_setup_iommu(struct device *dev) printk(KERN_ERR "iommu: missing iommu for %s (node %d)\n", archdata->of_node ? archdata->of_node->full_name : "?", archdata->numa_node); - return; + return NULL; } window = list_entry(iommu->windows.next, struct iommu_window, list); - archdata->dma_data = &window->table; + return &window->table; } static void cell_dma_dev_setup_fixed(struct device *dev); @@ -572,7 +572,7 @@ static void cell_dma_dev_setup(struct device *dev) if (get_dma_ops(dev) == &dma_iommu_fixed_ops) cell_dma_dev_setup_fixed(dev); else if (get_pci_dma_ops() == &dma_iommu_ops) - cell_dma_dev_setup_iommu(dev); + archdata->dma_data = cell_get_iommu_table(dev); else if (get_pci_dma_ops() == &dma_direct_ops) archdata->dma_data = (void *)cell_dma_direct_offset; else diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c index 655704ad03c..505f9b9bdf0 100644 --- a/arch/powerpc/platforms/cell/ras.c +++ b/arch/powerpc/platforms/cell/ras.c @@ -17,6 +17,7 @@ #include <asm/reg.h> #include <asm/io.h> #include <asm/prom.h> +#include <asm/kexec.h> #include <asm/machdep.h> #include <asm/rtas.h> #include <asm/cell-regs.h> @@ -226,6 +227,11 @@ static int cbe_ptcal_notify_reboot(struct notifier_block *nb, return cbe_ptcal_disable(); } +static void cbe_ptcal_crash_shutdown(void) +{ + cbe_ptcal_disable(); +} + static struct notifier_block cbe_ptcal_reboot_notifier = { .notifier_call = cbe_ptcal_notify_reboot }; @@ -241,12 +247,20 @@ int __init cbe_ptcal_init(void) return -ENODEV; ret = register_reboot_notifier(&cbe_ptcal_reboot_notifier); - if (ret) { - printk(KERN_ERR "Can't disable PTCAL, so not enabling\n"); - return ret; - } + if (ret) + goto out1; + + ret = crash_shutdown_register(&cbe_ptcal_crash_shutdown); + if (ret) + goto out2; return cbe_ptcal_enable(); + +out2: + unregister_reboot_notifier(&cbe_ptcal_reboot_notifier); +out1: + printk(KERN_ERR "Can't disable PTCAL, so not enabling\n"); + return ret; } arch_initcall(cbe_ptcal_init); diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 3f4b4aef756..4e5655624ae 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -300,7 +300,7 @@ static void __init spider_init_one(struct device_node *of_node, int chip, panic("spider_pic: can't map registers !"); /* Allocate a host */ - pic->host = irq_alloc_host(of_node_get(of_node), IRQ_HOST_MAP_LINEAR, + pic->host = irq_alloc_host(of_node, IRQ_HOST_MAP_LINEAR, SPIDER_SRC_COUNT, &spider_host_ops, SPIDER_IRQ_INVALID); if (pic->host == NULL) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 70c660121ec..78f905bc6a4 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -219,15 +219,25 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) { + int ret; + pr_debug("%s, %lx, %lx\n", __func__, dsisr, ea); - /* Handle kernel space hash faults immediately. - User hash faults need to be deferred to process context. */ - if ((dsisr & MFC_DSISR_PTE_NOT_FOUND) - && REGION_ID(ea) != USER_REGION_ID - && hash_page(ea, _PAGE_PRESENT, 0x300) == 0) { - spu_restart_dma(spu); - return 0; + /* + * Handle kernel space hash faults immediately. User hash + * faults need to be deferred to process context. + */ + if ((dsisr & MFC_DSISR_PTE_NOT_FOUND) && + (REGION_ID(ea) != USER_REGION_ID)) { + + spin_unlock(&spu->register_lock); + ret = hash_page(ea, _PAGE_PRESENT, 0x300); + spin_lock(&spu->register_lock); + + if (!ret) { + spu_restart_dma(spu); + return 0; + } } spu->class_1_dar = ea; @@ -324,17 +334,13 @@ spu_irq_class_0(int irq, void *data) stat = spu_int_stat_get(spu, 0) & mask; spu->class_0_pending |= stat; - spu->class_0_dsisr = spu_mfc_dsisr_get(spu); spu->class_0_dar = spu_mfc_dar_get(spu); - spin_unlock(&spu->register_lock); - spu->stop_callback(spu, 0); - spu->class_0_pending = 0; - spu->class_0_dsisr = 0; spu->class_0_dar = 0; spu_int_stat_clear(spu, 0, stat); + spin_unlock(&spu->register_lock); return IRQ_HANDLED; } @@ -357,13 +363,12 @@ spu_irq_class_1(int irq, void *data) spu_mfc_dsisr_set(spu, 0ul); spu_int_stat_clear(spu, 1, stat); - if (stat & CLASS1_SEGMENT_FAULT_INTR) - __spu_trap_data_seg(spu, dar); - - spin_unlock(&spu->register_lock); pr_debug("%s: %lx %lx %lx %lx\n", __func__, mask, stat, dar, dsisr); + if (stat & CLASS1_SEGMENT_FAULT_INTR) + __spu_trap_data_seg(spu, dar); + if (stat & CLASS1_STORAGE_FAULT_INTR) __spu_trap_data_map(spu, dar, dsisr); @@ -376,6 +381,8 @@ spu_irq_class_1(int irq, void *data) spu->class_1_dsisr = 0; spu->class_1_dar = 0; + spin_unlock(&spu->register_lock); + return stat ? IRQ_HANDLED : IRQ_NONE; } @@ -394,14 +401,12 @@ spu_irq_class_2(int irq, void *data) mask = spu_int_mask_get(spu, 2); /* ignore interrupts we're not waiting for */ stat &= mask; - /* mailbox interrupts are level triggered. mask them now before * acknowledging */ if (stat & mailbox_intrs) spu_int_mask_and(spu, 2, ~(stat & mailbox_intrs)); /* acknowledge all interrupts before the callbacks */ spu_int_stat_clear(spu, 2, stat); - spin_unlock(&spu->register_lock); pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask); @@ -421,6 +426,9 @@ spu_irq_class_2(int irq, void *data) spu->wbox_callback(spu); spu->stats.class2_intr++; + + spin_unlock(&spu->register_lock); + return stat ? IRQ_HANDLED : IRQ_NONE; } diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 177735f7931..6653ddbed04 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -130,17 +130,17 @@ void spu_unmap_mappings(struct spu_context *ctx) if (ctx->local_store) unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); if (ctx->mfc) - unmap_mapping_range(ctx->mfc, 0, 0x1000, 1); + unmap_mapping_range(ctx->mfc, 0, SPUFS_MFC_MAP_SIZE, 1); if (ctx->cntl) - unmap_mapping_range(ctx->cntl, 0, 0x1000, 1); + unmap_mapping_range(ctx->cntl, 0, SPUFS_CNTL_MAP_SIZE, 1); if (ctx->signal1) - unmap_mapping_range(ctx->signal1, 0, PAGE_SIZE, 1); + unmap_mapping_range(ctx->signal1, 0, SPUFS_SIGNAL_MAP_SIZE, 1); if (ctx->signal2) - unmap_mapping_range(ctx->signal2, 0, PAGE_SIZE, 1); + unmap_mapping_range(ctx->signal2, 0, SPUFS_SIGNAL_MAP_SIZE, 1); if (ctx->mss) - unmap_mapping_range(ctx->mss, 0, 0x1000, 1); + unmap_mapping_range(ctx->mss, 0, SPUFS_MSS_MAP_SIZE, 1); if (ctx->psmap) - unmap_mapping_range(ctx->psmap, 0, 0x20000, 1); + unmap_mapping_range(ctx->psmap, 0, SPUFS_PS_MAP_SIZE, 1); mutex_unlock(&ctx->mapping_lock); } diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index c81341ff75b..99c73066b82 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -238,11 +238,13 @@ spufs_mem_write(struct file *file, const char __user *buffer, return size; } -static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma, - unsigned long address) +static int +spufs_mem_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct spu_context *ctx = vma->vm_file->private_data; - unsigned long pfn, offset, addr0 = address; + unsigned long address = (unsigned long)vmf->virtual_address; + unsigned long pfn, offset; + #ifdef CONFIG_SPU_FS_64K_LS struct spu_state *csa = &ctx->csa; int psize; @@ -260,15 +262,15 @@ static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma, } #endif /* CONFIG_SPU_FS_64K_LS */ - offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); + offset = vmf->pgoff << PAGE_SHIFT; if (offset >= LS_SIZE) - return NOPFN_SIGBUS; + return VM_FAULT_SIGBUS; - pr_debug("spufs_mem_mmap_nopfn address=0x%lx -> 0x%lx, offset=0x%lx\n", - addr0, address, offset); + pr_debug("spufs_mem_mmap_fault address=0x%lx, offset=0x%lx\n", + address, offset); if (spu_acquire(ctx)) - return NOPFN_REFAULT; + return VM_FAULT_NOPAGE; if (ctx->state == SPU_STATE_SAVED) { vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) @@ -283,12 +285,12 @@ static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma, spu_release(ctx); - return NOPFN_REFAULT; + return VM_FAULT_NOPAGE; } static struct vm_operations_struct spufs_mem_mmap_vmops = { - .nopfn = spufs_mem_mmap_nopfn, + .fault = spufs_mem_mmap_fault, }; static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) @@ -351,20 +353,19 @@ static const struct file_operations spufs_mem_fops = { #endif }; -static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, - unsigned long address, +static int spufs_ps_fault(struct vm_area_struct *vma, + struct vm_fault *vmf, unsigned long ps_offs, unsigned long ps_size) { struct spu_context *ctx = vma->vm_file->private_data; - unsigned long area, offset = address - vma->vm_start; + unsigned long area, offset = vmf->pgoff << PAGE_SHIFT; int ret = 0; - spu_context_nospu_trace(spufs_ps_nopfn__enter, ctx); + spu_context_nospu_trace(spufs_ps_fault__enter, ctx); - offset += vma->vm_pgoff << PAGE_SHIFT; if (offset >= ps_size) - return NOPFN_SIGBUS; + return VM_FAULT_SIGBUS; /* * Because we release the mmap_sem, the context may be destroyed while @@ -378,7 +379,7 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, * pages to hand out to the user, but we don't want to wait * with the mmap_sem held. * It is possible to drop the mmap_sem here, but then we need - * to return NOPFN_REFAULT because the mappings may have + * to return VM_FAULT_NOPAGE because the mappings may have * hanged. */ if (spu_acquire(ctx)) @@ -386,14 +387,15 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, if (ctx->state == SPU_STATE_SAVED) { up_read(¤t->mm->mmap_sem); - spu_context_nospu_trace(spufs_ps_nopfn__sleep, ctx); + spu_context_nospu_trace(spufs_ps_fault__sleep, ctx); ret = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); - spu_context_trace(spufs_ps_nopfn__wake, ctx, ctx->spu); + spu_context_trace(spufs_ps_fault__wake, ctx, ctx->spu); down_read(¤t->mm->mmap_sem); } else { area = ctx->spu->problem_phys + ps_offs; - vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT); - spu_context_trace(spufs_ps_nopfn__insert, ctx, ctx->spu); + vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, + (area + offset) >> PAGE_SHIFT); + spu_context_trace(spufs_ps_fault__insert, ctx, ctx->spu); } if (!ret) @@ -401,18 +403,18 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, refault: put_spu_context(ctx); - return NOPFN_REFAULT; + return VM_FAULT_NOPAGE; } #if SPUFS_MMAP_4K -static unsigned long spufs_cntl_mmap_nopfn(struct vm_area_struct *vma, - unsigned long address) +static int spufs_cntl_mmap_fault(struct vm_area_struct *vma, + struct vm_fault *vmf) { - return spufs_ps_nopfn(vma, address, 0x4000, 0x1000); + return spufs_ps_fault(vma, vmf, 0x4000, SPUFS_CNTL_MAP_SIZE); } static struct vm_operations_struct spufs_cntl_mmap_vmops = { - .nopfn = spufs_cntl_mmap_nopfn, + .fault = spufs_cntl_mmap_fault, }; /* @@ -1097,23 +1099,23 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, return 4; } -static unsigned long spufs_signal1_mmap_nopfn(struct vm_area_struct *vma, - unsigned long address) +static int +spufs_signal1_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { -#if PAGE_SIZE == 0x1000 - return spufs_ps_nopfn(vma, address, 0x14000, 0x1000); -#elif PAGE_SIZE == 0x10000 +#if SPUFS_SIGNAL_MAP_SIZE == 0x1000 + return spufs_ps_fault(vma, vmf, 0x14000, SPUFS_SIGNAL_MAP_SIZE); +#elif SPUFS_SIGNAL_MAP_SIZE == 0x10000 /* For 64k pages, both signal1 and signal2 can be used to mmap the whole * signal 1 and 2 area */ - return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); + return spufs_ps_fault(vma, vmf, 0x10000, SPUFS_SIGNAL_MAP_SIZE); #else #error unsupported page size #endif } static struct vm_operations_struct spufs_signal1_mmap_vmops = { - .nopfn = spufs_signal1_mmap_nopfn, + .fault = spufs_signal1_mmap_fault, }; static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) @@ -1234,23 +1236,23 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, } #if SPUFS_MMAP_4K -static unsigned long spufs_signal2_mmap_nopfn(struct vm_area_struct *vma, - unsigned long address) +static int +spufs_signal2_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { -#if PAGE_SIZE == 0x1000 - return spufs_ps_nopfn(vma, address, 0x1c000, 0x1000); -#elif PAGE_SIZE == 0x10000 +#if SPUFS_SIGNAL_MAP_SIZE == 0x1000 + return spufs_ps_fault(vma, vmf, 0x1c000, SPUFS_SIGNAL_MAP_SIZE); +#elif SPUFS_SIGNAL_MAP_SIZE == 0x10000 /* For 64k pages, both signal1 and signal2 can be used to mmap the whole * signal 1 and 2 area */ - return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); + return spufs_ps_fault(vma, vmf, 0x10000, SPUFS_SIGNAL_MAP_SIZE); #else #error unsupported page size #endif } static struct vm_operations_struct spufs_signal2_mmap_vmops = { - .nopfn = spufs_signal2_mmap_nopfn, + .fault = spufs_signal2_mmap_fault, }; static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) @@ -1362,14 +1364,14 @@ DEFINE_SPUFS_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, spufs_signal2_type_set, "%llu\n", SPU_ATTR_ACQUIRE); #if SPUFS_MMAP_4K -static unsigned long spufs_mss_mmap_nopfn(struct vm_area_struct *vma, - unsigned long address) +static int +spufs_mss_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { - return spufs_ps_nopfn(vma, address, 0x0000, 0x1000); + return spufs_ps_fault(vma, vmf, 0x0000, SPUFS_MSS_MAP_SIZE); } static struct vm_operations_struct spufs_mss_mmap_vmops = { - .nopfn = spufs_mss_mmap_nopfn, + .fault = spufs_mss_mmap_fault, }; /* @@ -1424,14 +1426,14 @@ static const struct file_operations spufs_mss_fops = { .mmap = spufs_mss_mmap, }; -static unsigned long spufs_psmap_mmap_nopfn(struct vm_area_struct *vma, - unsigned long address) +static int +spufs_psmap_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { - return spufs_ps_nopfn(vma, address, 0x0000, 0x20000); + return spufs_ps_fault(vma, vmf, 0x0000, SPUFS_PS_MAP_SIZE); } static struct vm_operations_struct spufs_psmap_mmap_vmops = { - .nopfn = spufs_psmap_mmap_nopfn, + .fault = spufs_psmap_mmap_fault, }; /* @@ -1484,14 +1486,14 @@ static const struct file_operations spufs_psmap_fops = { #if SPUFS_MMAP_4K -static unsigned long spufs_mfc_mmap_nopfn(struct vm_area_struct *vma, - unsigned long address) +static int +spufs_mfc_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { - return spufs_ps_nopfn(vma, address, 0x3000, 0x1000); + return spufs_ps_fault(vma, vmf, 0x3000, SPUFS_MFC_MAP_SIZE); } static struct vm_operations_struct spufs_mfc_mmap_vmops = { - .nopfn = spufs_mfc_mmap_nopfn, + .fault = spufs_mfc_mmap_fault, }; /* @@ -2553,22 +2555,74 @@ void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx, wake_up(&ctx->switch_log->wait); } -struct tree_descr spufs_dir_contents[] = { +static int spufs_show_ctx(struct seq_file *s, void *private) +{ + struct spu_context *ctx = s->private; + u64 mfc_control_RW; + + mutex_lock(&ctx->state_mutex); + if (ctx->spu) { + struct spu *spu = ctx->spu; + struct spu_priv2 __iomem *priv2 = spu->priv2; + + spin_lock_irq(&spu->register_lock); + mfc_control_RW = in_be64(&priv2->mfc_control_RW); + spin_unlock_irq(&spu->register_lock); + } else { + struct spu_state *csa = &ctx->csa; + + mfc_control_RW = csa->priv2.mfc_control_RW; + } + + seq_printf(s, "%c flgs(%lx) sflgs(%lx) pri(%d) ts(%d) spu(%02d)" + " %c %lx %lx %lx %lx %x %x\n", + ctx->state == SPU_STATE_SAVED ? 'S' : 'R', + ctx->flags, + ctx->sched_flags, + ctx->prio, + ctx->time_slice, + ctx->spu ? ctx->spu->number : -1, + !list_empty(&ctx->rq) ? 'q' : ' ', + ctx->csa.class_0_pending, + ctx->csa.class_0_dar, + ctx->csa.class_1_dsisr, + mfc_control_RW, + ctx->ops->runcntl_read(ctx), + ctx->ops->status_read(ctx)); + + mutex_unlock(&ctx->state_mutex); + + return 0; +} + +static int spufs_ctx_open(struct inode *inode, struct file *file) +{ + return single_open(file, spufs_show_ctx, SPUFS_I(inode)->i_ctx); +} + +static const struct file_operations spufs_ctx_fops = { + .open = spufs_ctx_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +struct spufs_tree_descr spufs_dir_contents[] = { { "capabilities", &spufs_caps_fops, 0444, }, - { "mem", &spufs_mem_fops, 0666, }, - { "regs", &spufs_regs_fops, 0666, }, + { "mem", &spufs_mem_fops, 0666, LS_SIZE, }, + { "regs", &spufs_regs_fops, 0666, sizeof(struct spu_reg128[128]), }, { "mbox", &spufs_mbox_fops, 0444, }, { "ibox", &spufs_ibox_fops, 0444, }, { "wbox", &spufs_wbox_fops, 0222, }, - { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, - { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, - { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, + { "mbox_stat", &spufs_mbox_stat_fops, 0444, sizeof(u32), }, + { "ibox_stat", &spufs_ibox_stat_fops, 0444, sizeof(u32), }, + { "wbox_stat", &spufs_wbox_stat_fops, 0444, sizeof(u32), }, { "signal1", &spufs_signal1_fops, 0666, }, { "signal2", &spufs_signal2_fops, 0666, }, { "signal1_type", &spufs_signal1_type, 0666, }, { "signal2_type", &spufs_signal2_type, 0666, }, { "cntl", &spufs_cntl_fops, 0666, }, - { "fpcr", &spufs_fpcr_fops, 0666, }, + { "fpcr", &spufs_fpcr_fops, 0666, sizeof(struct spu_reg128), }, { "lslr", &spufs_lslr_ops, 0444, }, { "mfc", &spufs_mfc_fops, 0666, }, { "mss", &spufs_mss_fops, 0666, }, @@ -2578,29 +2632,31 @@ struct tree_descr spufs_dir_contents[] = { { "decr_status", &spufs_decr_status_ops, 0666, }, { "event_mask", &spufs_event_mask_ops, 0666, }, { "event_status", &spufs_event_status_ops, 0444, }, - { "psmap", &spufs_psmap_fops, 0666, }, + { "psmap", &spufs_psmap_fops, 0666, SPUFS_PS_MAP_SIZE, }, { "phys-id", &spufs_id_ops, 0666, }, { "object-id", &spufs_object_id_ops, 0666, }, - { "mbox_info", &spufs_mbox_info_fops, 0444, }, - { "ibox_info", &spufs_ibox_info_fops, 0444, }, - { "wbox_info", &spufs_wbox_info_fops, 0444, }, - { "dma_info", &spufs_dma_info_fops, 0444, }, - { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, + { "mbox_info", &spufs_mbox_info_fops, 0444, sizeof(u32), }, + { "ibox_info", &spufs_ibox_info_fops, 0444, sizeof(u32), }, + { "wbox_info", &spufs_wbox_info_fops, 0444, sizeof(u32), }, + { "dma_info", &spufs_dma_info_fops, 0444, + sizeof(struct spu_dma_info), }, + { "proxydma_info", &spufs_proxydma_info_fops, 0444, + sizeof(struct spu_proxydma_info)}, { "tid", &spufs_tid_fops, 0444, }, { "stat", &spufs_stat_fops, 0444, }, { "switch_log", &spufs_switch_log_fops, 0444 }, {}, }; -struct tree_descr spufs_dir_nosched_contents[] = { +struct spufs_tree_descr spufs_dir_nosched_contents[] = { { "capabilities", &spufs_caps_fops, 0444, }, - { "mem", &spufs_mem_fops, 0666, }, + { "mem", &spufs_mem_fops, 0666, LS_SIZE, }, { "mbox", &spufs_mbox_fops, 0444, }, { "ibox", &spufs_ibox_fops, 0444, }, { "wbox", &spufs_wbox_fops, 0222, }, - { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, - { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, - { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, + { "mbox_stat", &spufs_mbox_stat_fops, 0444, sizeof(u32), }, + { "ibox_stat", &spufs_ibox_stat_fops, 0444, sizeof(u32), }, + { "wbox_stat", &spufs_wbox_stat_fops, 0444, sizeof(u32), }, { "signal1", &spufs_signal1_nosched_fops, 0222, }, { "signal2", &spufs_signal2_nosched_fops, 0222, }, { "signal1_type", &spufs_signal1_type, 0666, }, @@ -2609,7 +2665,7 @@ struct tree_descr spufs_dir_nosched_contents[] = { { "mfc", &spufs_mfc_fops, 0666, }, { "cntl", &spufs_cntl_fops, 0666, }, { "npc", &spufs_npc_ops, 0666, }, - { "psmap", &spufs_psmap_fops, 0666, }, + { "psmap", &spufs_psmap_fops, 0666, SPUFS_PS_MAP_SIZE, }, { "phys-id", &spufs_id_ops, 0666, }, { "object-id", &spufs_object_id_ops, 0666, }, { "tid", &spufs_tid_fops, 0444, }, @@ -2617,6 +2673,11 @@ struct tree_descr spufs_dir_nosched_contents[] = { {}, }; +struct spufs_tree_descr spufs_dir_debug_contents[] = { + { ".ctx", &spufs_ctx_fops, 0444, }, + {}, +}; + struct spufs_coredump_reader spufs_coredump_read[] = { { "regs", __spufs_regs_read, NULL, sizeof(struct spu_reg128[128])}, { "fpcr", __spufs_fpcr_read, NULL, sizeof(struct spu_reg128) }, diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index f407b247185..7123472801d 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -42,10 +42,19 @@ #include "spufs.h" +struct spufs_sb_info { + int debug; +}; + static struct kmem_cache *spufs_inode_cache; char *isolated_loader; static int isolated_loader_size; +static struct spufs_sb_info *spufs_get_sb_info(struct super_block *sb) +{ + return sb->s_fs_info; +} + static struct inode * spufs_alloc_inode(struct super_block *sb) { @@ -109,7 +118,7 @@ spufs_setattr(struct dentry *dentry, struct iattr *attr) static int spufs_new_file(struct super_block *sb, struct dentry *dentry, const struct file_operations *fops, int mode, - struct spu_context *ctx) + size_t size, struct spu_context *ctx) { static struct inode_operations spufs_file_iops = { .setattr = spufs_setattr, @@ -125,6 +134,7 @@ spufs_new_file(struct super_block *sb, struct dentry *dentry, ret = 0; inode->i_op = &spufs_file_iops; inode->i_fop = fops; + inode->i_size = size; inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx); d_add(dentry, inode); out: @@ -177,7 +187,7 @@ static int spufs_rmdir(struct inode *parent, struct dentry *dir) return simple_rmdir(parent, dir); } -static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, +static int spufs_fill_dir(struct dentry *dir, struct spufs_tree_descr *files, int mode, struct spu_context *ctx) { struct dentry *dentry, *tmp; @@ -189,7 +199,7 @@ static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, if (!dentry) goto out; ret = spufs_new_file(dir->d_sb, dentry, files->ops, - files->mode & mode, ctx); + files->mode & mode, files->size, ctx); if (ret) goto out; files++; @@ -279,6 +289,13 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, if (ret) goto out_free_ctx; + if (spufs_get_sb_info(dir->i_sb)->debug) + ret = spufs_fill_dir(dentry, spufs_dir_debug_contents, + mode, ctx); + + if (ret) + goto out_free_ctx; + d_instantiate(dentry, inode); dget(dentry); dir->i_nlink++; @@ -639,18 +656,19 @@ out: /* File system initialization */ enum { - Opt_uid, Opt_gid, Opt_mode, Opt_err, + Opt_uid, Opt_gid, Opt_mode, Opt_debug, Opt_err, }; static match_table_t spufs_tokens = { - { Opt_uid, "uid=%d" }, - { Opt_gid, "gid=%d" }, - { Opt_mode, "mode=%o" }, - { Opt_err, NULL }, + { Opt_uid, "uid=%d" }, + { Opt_gid, "gid=%d" }, + { Opt_mode, "mode=%o" }, + { Opt_debug, "debug" }, + { Opt_err, NULL }, }; static int -spufs_parse_options(char *options, struct inode *root) +spufs_parse_options(struct super_block *sb, char *options, struct inode *root) { char *p; substring_t args[MAX_OPT_ARGS]; @@ -678,6 +696,9 @@ spufs_parse_options(char *options, struct inode *root) return 0; root->i_mode = option | S_IFDIR; break; + case Opt_debug: + spufs_get_sb_info(sb)->debug = 1; + break; default: return 0; } @@ -736,7 +757,7 @@ spufs_create_root(struct super_block *sb, void *data) SPUFS_I(inode)->i_ctx = NULL; ret = -EINVAL; - if (!spufs_parse_options(data, inode)) + if (!spufs_parse_options(sb, data, inode)) goto out_iput; ret = -ENOMEM; @@ -754,6 +775,7 @@ out: static int spufs_fill_super(struct super_block *sb, void *data, int silent) { + struct spufs_sb_info *info; static struct super_operations s_ops = { .alloc_inode = spufs_alloc_inode, .destroy_inode = spufs_destroy_inode, @@ -765,11 +787,16 @@ spufs_fill_super(struct super_block *sb, void *data, int silent) save_mount_options(sb, data); + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = SPUFS_MAGIC; sb->s_op = &s_ops; + sb->s_fs_info = info; return spufs_create_root(sb, data); } diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index b7493b86581..f7edba6cb79 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -27,7 +27,6 @@ void spufs_stop_callback(struct spu *spu, int irq) switch(irq) { case 0 : ctx->csa.class_0_pending = spu->class_0_pending; - ctx->csa.class_0_dsisr = spu->class_0_dsisr; ctx->csa.class_0_dar = spu->class_0_dar; break; case 1 : @@ -51,18 +50,22 @@ int spu_stopped(struct spu_context *ctx, u32 *stat) u64 dsisr; u32 stopped; - *stat = ctx->ops->status_read(ctx); - - if (test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags)) - return 1; - stopped = SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP | SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP; - if (!(*stat & SPU_STATUS_RUNNING) && (*stat & stopped)) + +top: + *stat = ctx->ops->status_read(ctx); + if (*stat & stopped) { + /* + * If the spu hasn't finished stopping, we need to + * re-read the register to get the stopped value. + */ + if (*stat & SPU_STATUS_RUNNING) + goto top; return 1; + } - dsisr = ctx->csa.class_0_dsisr; - if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) + if (test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags)) return 1; dsisr = ctx->csa.class_1_dsisr; diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 745dd51ec37..34654743363 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -230,19 +230,23 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx) ctx->stats.slb_flt_base = spu->stats.slb_flt; ctx->stats.class2_intr_base = spu->stats.class2_intr; + spu_associate_mm(spu, ctx->owner); + + spin_lock_irq(&spu->register_lock); spu->ctx = ctx; spu->flags = 0; ctx->spu = spu; ctx->ops = &spu_hw_ops; spu->pid = current->pid; spu->tgid = current->tgid; - spu_associate_mm(spu, ctx->owner); spu->ibox_callback = spufs_ibox_callback; spu->wbox_callback = spufs_wbox_callback; spu->stop_callback = spufs_stop_callback; spu->mfc_callback = spufs_mfc_callback; - mb(); + spin_unlock_irq(&spu->register_lock); + spu_unmap_mappings(ctx); + spu_switch_log_notify(spu, ctx, SWITCH_LOG_START, 0); spu_restore(&ctx->csa, spu); spu->timestamp = jiffies; @@ -403,6 +407,8 @@ static int has_affinity(struct spu_context *ctx) */ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) { + u32 status; + spu_context_trace(spu_unbind_context__enter, ctx, spu); spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); @@ -423,18 +429,22 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) spu_unmap_mappings(ctx); spu_save(&ctx->csa, spu); spu_switch_log_notify(spu, ctx, SWITCH_LOG_STOP, 0); + + spin_lock_irq(&spu->register_lock); spu->timestamp = jiffies; ctx->state = SPU_STATE_SAVED; spu->ibox_callback = NULL; spu->wbox_callback = NULL; spu->stop_callback = NULL; spu->mfc_callback = NULL; - spu_associate_mm(spu, NULL); spu->pid = 0; spu->tgid = 0; ctx->ops = &spu_backing_ops; spu->flags = 0; spu->ctx = NULL; + spin_unlock_irq(&spu->register_lock); + + spu_associate_mm(spu, NULL); ctx->stats.slb_flt += (spu->stats.slb_flt - ctx->stats.slb_flt_base); @@ -444,6 +454,9 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) /* This maps the underlying spu state to idle */ spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED); ctx->spu = NULL; + + if (spu_stopped(ctx, &status)) + wake_up_all(&ctx->stop_wq); } /** @@ -886,7 +899,8 @@ static noinline void spusched_tick(struct spu_context *ctx) spu_add_to_rq(ctx); } else { spu_context_nospu_trace(spusched_tick__newslice, ctx); - ctx->time_slice++; + if (!ctx->time_slice) + ctx->time_slice++; } out: spu_release(ctx); @@ -980,6 +994,7 @@ void spuctx_switch_state(struct spu_context *ctx, struct timespec ts; struct spu *spu; enum spu_utilization_state old_state; + int node; ktime_get_ts(&ts); curtime = timespec_to_ns(&ts); @@ -1001,6 +1016,11 @@ void spuctx_switch_state(struct spu_context *ctx, spu->stats.times[old_state] += delta; spu->stats.util_state = new_state; spu->stats.tstamp = curtime; + node = spu->node; + if (old_state == SPU_UTIL_USER) + atomic_dec(&cbe_spu_info[node].busy_spus); + if (new_state == SPU_UTIL_USER); + atomic_inc(&cbe_spu_info[node].busy_spus); } } diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 454c277c145..8ae8ef9dfc2 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -32,6 +32,13 @@ #include <asm/spu_csa.h> #include <asm/spu_info.h> +#define SPUFS_PS_MAP_SIZE 0x20000 +#define SPUFS_MFC_MAP_SIZE 0x1000 +#define SPUFS_CNTL_MAP_SIZE 0x1000 +#define SPUFS_CNTL_MAP_SIZE 0x1000 +#define SPUFS_SIGNAL_MAP_SIZE PAGE_SIZE +#define SPUFS_MSS_MAP_SIZE 0x1000 + /* The magic number for our file system */ enum { SPUFS_MAGIC = 0x23c9b64e, @@ -228,8 +235,16 @@ struct spufs_inode_info { #define SPUFS_I(inode) \ container_of(inode, struct spufs_inode_info, vfs_inode) -extern struct tree_descr spufs_dir_contents[]; -extern struct tree_descr spufs_dir_nosched_contents[]; +struct spufs_tree_descr { + const char *name; + const struct file_operations *ops; + int mode; + size_t size; +}; + +extern struct spufs_tree_descr spufs_dir_contents[]; +extern struct spufs_tree_descr spufs_dir_nosched_contents[]; +extern struct spufs_tree_descr spufs_dir_debug_contents[]; /* system call implementation */ extern struct spufs_calls spufs_calls; diff --git a/arch/powerpc/platforms/cell/spufs/sputrace.c b/arch/powerpc/platforms/cell/spufs/sputrace.c index 53202422ba7..8c0e95766a6 100644 --- a/arch/powerpc/platforms/cell/spufs/sputrace.c +++ b/arch/powerpc/platforms/cell/spufs/sputrace.c @@ -182,10 +182,10 @@ struct spu_probe spu_probes[] = { { "spu_yield__enter", "ctx %p", spu_context_nospu_event }, { "spu_deactivate__enter", "ctx %p", spu_context_nospu_event }, { "__spu_deactivate__unload", "ctx %p spu %p", spu_context_event }, - { "spufs_ps_nopfn__enter", "ctx %p", spu_context_nospu_event }, - { "spufs_ps_nopfn__sleep", "ctx %p", spu_context_nospu_event }, - { "spufs_ps_nopfn__wake", "ctx %p spu %p", spu_context_event }, - { "spufs_ps_nopfn__insert", "ctx %p spu %p", spu_context_event }, + { "spufs_ps_fault__enter", "ctx %p", spu_context_nospu_event }, + { "spufs_ps_fault__sleep", "ctx %p", spu_context_nospu_event }, + { "spufs_ps_fault__wake", "ctx %p spu %p", spu_context_event }, + { "spufs_ps_fault__insert", "ctx %p spu %p", spu_context_event }, { "spu_acquire_saved__enter", "ctx %p", spu_context_nospu_event }, { "destroy_spu_context__enter", "ctx %p", spu_context_nospu_event }, { "spufs_stop_callback__enter", "ctx %p spu %p", spu_context_event }, diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 116babbaaf8..1ba7ce5aafa 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -63,13 +63,6 @@ static struct mpic *chrp_mpic; DEFINE_PER_CPU(struct timer_list, heartbeat_timer); unsigned long event_scan_interval; -/* - * XXX this should be in xmon.h, but putting it there means xmon.h - * has to include <linux/interrupt.h> (to get irqreturn_t), which - * causes all sorts of problems. -- paulus - */ -extern irqreturn_t xmon_irq(int, void *); - extern unsigned long loops_per_jiffy; /* To be replaced by RTAS when available */ diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index 42908896781..4f9f8184d16 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -59,6 +59,16 @@ config PPC_PRPMC2800 help This option enables support for the Motorola PrPMC2800 board +config PPC_C2K + bool "SBS/GEFanuc C2K board" + depends on EMBEDDED6xx + select MV64X60 + select NOT_COHERENT_CACHE + select MTD_CFI_I4 + help + This option enables support for the GE Fanuc C2K board (formerly + an SBS board). + config TSI108_BRIDGE bool select PCI diff --git a/arch/powerpc/platforms/embedded6xx/Makefile b/arch/powerpc/platforms/embedded6xx/Makefile index 06524d3ffd2..0773c08bd44 100644 --- a/arch/powerpc/platforms/embedded6xx/Makefile +++ b/arch/powerpc/platforms/embedded6xx/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_LINKSTATION) += linkstation.o ls_uart.o obj-$(CONFIG_STORCENTER) += storcenter.o obj-$(CONFIG_PPC_HOLLY) += holly.o obj-$(CONFIG_PPC_PRPMC2800) += prpmc2800.o +obj-$(CONFIG_PPC_C2K) += c2k.o diff --git a/arch/powerpc/platforms/embedded6xx/c2k.c b/arch/powerpc/platforms/embedded6xx/c2k.c new file mode 100644 index 00000000000..d0b25b8c39d --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/c2k.c @@ -0,0 +1,158 @@ +/* + * Board setup routines for the GEFanuc C2K board + * + * Author: Remi Machet <rmachet@slac.stanford.edu> + * + * Originated from prpmc2800.c + * + * 2008 (c) Stanford University + * 2007 (c) MontaVista, Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/seq_file.h> +#include <linux/time.h> +#include <linux/of.h> +#include <linux/kexec.h> + +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/system.h> +#include <asm/time.h> + +#include <mm/mmu_decl.h> + +#include <sysdev/mv64x60.h> + +#define MV64x60_MPP_CNTL_0 0x0000 +#define MV64x60_MPP_CNTL_2 0x0008 + +#define MV64x60_GPP_IO_CNTL 0x0000 +#define MV64x60_GPP_LEVEL_CNTL 0x0010 +#define MV64x60_GPP_VALUE_SET 0x0018 + +static void __iomem *mv64x60_mpp_reg_base; +static void __iomem *mv64x60_gpp_reg_base; + +static void __init c2k_setup_arch(void) +{ + struct device_node *np; + phys_addr_t paddr; + const unsigned int *reg; + + /* + * ioremap mpp and gpp registers in case they are later + * needed by c2k_reset_board(). + */ + np = of_find_compatible_node(NULL, NULL, "marvell,mv64360-mpp"); + reg = of_get_property(np, "reg", NULL); + paddr = of_translate_address(np, reg); + of_node_put(np); + mv64x60_mpp_reg_base = ioremap(paddr, reg[1]); + + np = of_find_compatible_node(NULL, NULL, "marvell,mv64360-gpp"); + reg = of_get_property(np, "reg", NULL); + paddr = of_translate_address(np, reg); + of_node_put(np); + mv64x60_gpp_reg_base = ioremap(paddr, reg[1]); + +#ifdef CONFIG_PCI + mv64x60_pci_init(); +#endif +} + +static void c2k_reset_board(void) +{ + u32 temp; + + local_irq_disable(); + + temp = in_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_0); + temp &= 0xFFFF0FFF; + out_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_0, temp); + + temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL); + temp |= 0x00000004; + out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL, temp); + + temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL); + temp |= 0x00000004; + out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL, temp); + + temp = in_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_2); + temp &= 0xFFFF0FFF; + out_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_2, temp); + + temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL); + temp |= 0x00080000; + out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL, temp); + + temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL); + temp |= 0x00080000; + out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL, temp); + + out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_VALUE_SET, 0x00080004); +} + +static void c2k_restart(char *cmd) +{ + c2k_reset_board(); + msleep(100); + panic("restart failed\n"); +} + +#ifdef CONFIG_NOT_COHERENT_CACHE +#define COHERENCY_SETTING "off" +#else +#define COHERENCY_SETTING "on" +#endif + +void c2k_show_cpuinfo(struct seq_file *m) +{ + uint memsize = total_memory; + + seq_printf(m, "Vendor\t\t: GEFanuc\n"); + seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); + seq_printf(m, "coherency\t: %s\n", COHERENCY_SETTING); +} + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init c2k_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "GEFanuc,C2K")) + return 0; + + printk(KERN_INFO "Detected a GEFanuc C2K board\n"); + + _set_L2CR(0); + _set_L2CR(L2CR_L2E | L2CR_L2PE | L2CR_L2I); + return 1; +} + +define_machine(c2k) { + .name = "C2K", + .probe = c2k_probe, + .setup_arch = c2k_setup_arch, + .init_early = mv64x60_init_early, + .show_cpuinfo = c2k_show_cpuinfo, + .init_IRQ = mv64x60_init_irq, + .get_irq = mv64x60_get_irq, + .restart = c2k_restart, + .calibrate_decr = generic_calibrate_decr, +#ifdef CONFIG_KEXEC + .machine_kexec = default_machine_kexec, + .machine_kexec_prepare = default_machine_kexec_prepare, + .machine_crash_shutdown = default_machine_crash_shutdown, +#endif +}; diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index 11fa3c772ed..ab5d8687c3c 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -214,13 +214,13 @@ dma_addr_t iseries_hv_map(void *vaddr, size_t size, enum dma_data_direction direction) { return iommu_map_single(NULL, &vio_iommu_table, vaddr, size, - DMA_32BIT_MASK, direction); + DMA_32BIT_MASK, direction, NULL); } void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) { - iommu_unmap_single(&vio_iommu_table, dma_handle, size, direction); + iommu_unmap_single(&vio_iommu_table, dma_handle, size, direction, NULL); } void __init iommu_vio_init(void) diff --git a/arch/powerpc/platforms/maple/time.c b/arch/powerpc/platforms/maple/time.c index 9f7579b38c7..53bca132fb4 100644 --- a/arch/powerpc/platforms/maple/time.c +++ b/arch/powerpc/platforms/maple/time.c @@ -41,8 +41,6 @@ #define DBG(x...) #endif -extern void GregorianDay(struct rtc_time * tm); - static int maple_rtc_addr; static int maple_clock_read(int addr) diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile index 4d72c8f7215..89774177b20 100644 --- a/arch/powerpc/platforms/powermac/Makefile +++ b/arch/powerpc/platforms/powermac/Makefile @@ -1,5 +1,10 @@ CFLAGS_bootx_init.o += -fPIC +ifdef CONFIG_FTRACE +# Do not trace early boot code +CFLAGS_REMOVE_bootx_init.o = -pg +endif + obj-y += pic.o setup.o time.o feature.o pci.o \ sleep.o low_i2c.o cache.o pfunc_core.o \ pfunc_base.o diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 829b8b02527..6d149ae8ffa 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -34,16 +34,10 @@ #include <asm/time.h> #include <asm/pmac_feature.h> #include <asm/mpic.h> +#include <asm/xmon.h> #include "pmac.h" -/* - * XXX this should be in xmon.h, but putting it there means xmon.h - * has to include <linux/interrupt.h> (to get irqreturn_t), which - * causes all sorts of problems. -- paulus - */ -extern irqreturn_t xmon_irq(int, void *); - #ifdef CONFIG_PPC32 struct pmac_irq_hw { unsigned int event; diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index cb2d894541c..4ae3d00e0bd 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -36,6 +36,7 @@ #include <asm/ptrace.h> #include <asm/atomic.h> +#include <asm/code-patching.h> #include <asm/irq.h> #include <asm/page.h> #include <asm/pgtable.h> @@ -786,8 +787,7 @@ static void __devinit smp_core99_kick_cpu(int nr) { unsigned int save_vector; unsigned long target, flags; - volatile unsigned int *vector - = ((volatile unsigned int *)(KERNELBASE+0x100)); + unsigned int *vector = (unsigned int *)(KERNELBASE+0x100); if (nr < 0 || nr > 3) return; @@ -804,7 +804,7 @@ static void __devinit smp_core99_kick_cpu(int nr) * b __secondary_start_pmac_0 + nr*8 - KERNELBASE */ target = (unsigned long) __secondary_start_pmac_0 + nr * 8; - create_branch((unsigned long)vector, target, BRANCH_SET_LINK); + patch_branch(vector, target, BRANCH_SET_LINK); /* Put some life in our friend */ pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0); diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index f0b12f21236..a0927a3bacb 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c @@ -105,9 +105,10 @@ static void __init ps3_smp_setup_cpu(int cpu) * to index needs to be setup. */ - BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION != 0); - BUILD_BUG_ON(PPC_MSG_RESCHEDULE != 1); - BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3); + BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION != 0); + BUILD_BUG_ON(PPC_MSG_RESCHEDULE != 1); + BUILD_BUG_ON(PPC_MSG_CALL_FUNC_SINGLE != 2); + BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3); for (i = 0; i < MSG_COUNT; i++) { result = ps3_event_receive_port_setup(cpu, &virqs[i]); diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 43c493fca2d..d66c3628a11 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -349,9 +349,14 @@ static int ps3_system_bus_match(struct device *_dev, result = dev->match_id == drv->match_id; - pr_info("%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__, __LINE__, - dev->match_id, dev->core.bus_id, drv->match_id, drv->core.name, - (result ? "match" : "miss")); + if (result) + pr_info("%s:%d: dev=%u(%s), drv=%u(%s): match\n", __func__, + __LINE__, dev->match_id, dev->core.bus_id, + drv->match_id, drv->core.name); + else + pr_debug("%s:%d: dev=%u(%s), drv=%u(%s): miss\n", __func__, + __LINE__, dev->match_id, dev->core.bus_id, + drv->match_id, drv->core.name); return result; } @@ -362,7 +367,7 @@ static int ps3_system_bus_probe(struct device *_dev) struct ps3_system_bus_driver *drv; BUG_ON(!dev); - pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id); + pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id); drv = ps3_system_bus_dev_to_system_bus_drv(dev); BUG_ON(!drv); @@ -370,10 +375,10 @@ static int ps3_system_bus_probe(struct device *_dev) if (drv->probe) result = drv->probe(dev); else - pr_info("%s:%d: %s no probe method\n", __func__, __LINE__, + pr_debug("%s:%d: %s no probe method\n", __func__, __LINE__, dev->core.bus_id); - pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id); + pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id); return result; } @@ -384,7 +389,7 @@ static int ps3_system_bus_remove(struct device *_dev) struct ps3_system_bus_driver *drv; BUG_ON(!dev); - pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id); + pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id); drv = ps3_system_bus_dev_to_system_bus_drv(dev); BUG_ON(!drv); @@ -395,7 +400,7 @@ static int ps3_system_bus_remove(struct device *_dev) dev_dbg(&dev->core, "%s:%d %s: no remove method\n", __func__, __LINE__, drv->core.name); - pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id); + pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id); return result; } @@ -550,7 +555,7 @@ static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, */ static dma_addr_t ps3_sb_map_single(struct device *_dev, void *ptr, size_t size, - enum dma_data_direction direction) + enum dma_data_direction direction, struct dma_attrs *attrs) { struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); int result; @@ -570,7 +575,8 @@ static dma_addr_t ps3_sb_map_single(struct device *_dev, void *ptr, size_t size, static dma_addr_t ps3_ioc0_map_single(struct device *_dev, void *ptr, size_t size, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); int result; @@ -603,7 +609,7 @@ static dma_addr_t ps3_ioc0_map_single(struct device *_dev, void *ptr, } static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction direction) + size_t size, enum dma_data_direction direction, struct dma_attrs *attrs) { struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); int result; @@ -617,7 +623,7 @@ static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, } static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sgl, - int nents, enum dma_data_direction direction) + int nents, enum dma_data_direction direction, struct dma_attrs *attrs) { #if defined(CONFIG_PS3_DYNAMIC_DMA) BUG_ON("do"); @@ -646,14 +652,15 @@ static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sgl, static int ps3_ioc0_map_sg(struct device *_dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) + enum dma_data_direction direction, + struct dma_attrs *attrs) { BUG(); return 0; } static void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) + int nents, enum dma_data_direction direction, struct dma_attrs *attrs) { #if defined(CONFIG_PS3_DYNAMIC_DMA) BUG_ON("do"); @@ -661,7 +668,8 @@ static void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg, } static void ps3_ioc0_unmap_sg(struct device *_dev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) + int nents, enum dma_data_direction direction, + struct dma_attrs *attrs) { BUG(); } diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 6f544ba4b37..c027f0a70a0 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -812,6 +812,7 @@ int rtas_set_slot_reset(struct pci_dn *pdn) static inline void __restore_bars (struct pci_dn *pdn) { int i; + u32 cmd; if (NULL==pdn->phb) return; for (i=4; i<10; i++) { @@ -832,6 +833,19 @@ static inline void __restore_bars (struct pci_dn *pdn) /* max latency, min grant, interrupt pin and line */ rtas_write_config(pdn, 15*4, 4, pdn->config_space[15]); + + /* Restore PERR & SERR bits, some devices require it, + don't touch the other command bits */ + rtas_read_config(pdn, PCI_COMMAND, 4, &cmd); + if (pdn->config_space[1] & PCI_COMMAND_PARITY) + cmd |= PCI_COMMAND_PARITY; + else + cmd &= ~PCI_COMMAND_PARITY; + if (pdn->config_space[1] & PCI_COMMAND_SERR) + cmd |= PCI_COMMAND_SERR; + else + cmd &= ~PCI_COMMAND_SERR; + rtas_write_config(pdn, PCI_COMMAND, 4, cmd); } /** diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index 68ea5eee39a..8c1ca477c52 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -42,17 +42,20 @@ static inline const char * pcid_name (struct pci_dev *pdev) } #ifdef DEBUG -static void print_device_node_tree (struct pci_dn *pdn, int dent) +static void print_device_node_tree(struct pci_dn *pdn, int dent) { int i; - if (!pdn) return; - for (i=0;i<dent; i++) + struct device_node *pc; + + if (!pdn) + return; + for (i = 0; i < dent; i++) printk(" "); printk("dn=%s mode=%x \tcfg_addr=%x pe_addr=%x \tfull=%s\n", pdn->node->name, pdn->eeh_mode, pdn->eeh_config_addr, pdn->eeh_pe_config_addr, pdn->node->full_name); dent += 3; - struct device_node *pc = pdn->node->child; + pc = pdn->node->child; while (pc) { print_device_node_tree(PCI_DN(pc), dent); pc = pc->sibling; diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c index 9d3a40f4597..5a707da3f5c 100644 --- a/arch/powerpc/platforms/pseries/firmware.c +++ b/arch/powerpc/platforms/pseries/firmware.c @@ -26,6 +26,7 @@ #include <asm/prom.h> #include <asm/udbg.h> +#include "pseries.h" typedef struct { unsigned long val; diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index 3c5727dd5aa..a1a368dd2d9 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -15,34 +15,13 @@ #include <asm/machdep.h> #include <asm/pSeries_reconfig.h> -static int pseries_remove_memory(struct device_node *np) +static int pseries_remove_lmb(unsigned long base, unsigned int lmb_size) { - const char *type; - const unsigned int *my_index; - const unsigned int *regs; - u64 start_pfn, start; + unsigned long start, start_pfn; struct zone *zone; - int ret = -EINVAL; - - /* - * Check to see if we are actually removing memory - */ - type = of_get_property(np, "device_type", NULL); - if (type == NULL || strcmp(type, "memory") != 0) - return 0; + int ret; - /* - * Find the memory index and size of the removing section - */ - my_index = of_get_property(np, "ibm,my-drc-index", NULL); - if (!my_index) - return ret; - - regs = of_get_property(np, "reg", NULL); - if (!regs) - return ret; - - start_pfn = section_nr_to_pfn(*my_index & 0xffff); + start_pfn = base >> PFN_SECTION_SHIFT; zone = page_zone(pfn_to_page(start_pfn)); /* @@ -54,56 +33,111 @@ static int pseries_remove_memory(struct device_node *np) * to sysfs "state" file and we can't remove sysfs entries * while writing to it. So we have to defer it to here. */ - ret = __remove_pages(zone, start_pfn, regs[3] >> PAGE_SHIFT); + ret = __remove_pages(zone, start_pfn, lmb_size >> PAGE_SHIFT); if (ret) return ret; /* * Update memory regions for memory remove */ - lmb_remove(start_pfn << PAGE_SHIFT, regs[3]); + lmb_remove(base, lmb_size); /* * Remove htab bolted mappings for this section of memory */ - start = (unsigned long)__va(start_pfn << PAGE_SHIFT); - ret = remove_section_mapping(start, start + regs[3]); + start = (unsigned long)__va(base); + ret = remove_section_mapping(start, start + lmb_size); return ret; } -static int pseries_add_memory(struct device_node *np) +static int pseries_remove_memory(struct device_node *np) { const char *type; - const unsigned int *my_index; const unsigned int *regs; - u64 start_pfn; + unsigned long base; + unsigned int lmb_size; int ret = -EINVAL; /* - * Check to see if we are actually adding memory + * Check to see if we are actually removing memory */ type = of_get_property(np, "device_type", NULL); if (type == NULL || strcmp(type, "memory") != 0) return 0; /* - * Find the memory index and size of the added section + * Find the bae address and size of the lmb */ - my_index = of_get_property(np, "ibm,my-drc-index", NULL); - if (!my_index) + regs = of_get_property(np, "reg", NULL); + if (!regs) return ret; + base = *(unsigned long *)regs; + lmb_size = regs[3]; + + ret = pseries_remove_lmb(base, lmb_size); + return ret; +} + +static int pseries_add_memory(struct device_node *np) +{ + const char *type; + const unsigned int *regs; + unsigned long base; + unsigned int lmb_size; + int ret = -EINVAL; + + /* + * Check to see if we are actually adding memory + */ + type = of_get_property(np, "device_type", NULL); + if (type == NULL || strcmp(type, "memory") != 0) + return 0; + + /* + * Find the base and size of the lmb + */ regs = of_get_property(np, "reg", NULL); if (!regs) return ret; - start_pfn = section_nr_to_pfn(*my_index & 0xffff); + base = *(unsigned long *)regs; + lmb_size = regs[3]; /* * Update memory region to represent the memory add */ - lmb_add(start_pfn << PAGE_SHIFT, regs[3]); - return 0; + ret = lmb_add(base, lmb_size); + return (ret < 0) ? -EINVAL : 0; +} + +static int pseries_drconf_memory(unsigned long *base, unsigned int action) +{ + struct device_node *np; + const unsigned long *lmb_size; + int rc; + + np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); + if (!np) + return -EINVAL; + + lmb_size = of_get_property(np, "ibm,lmb-size", NULL); + if (!lmb_size) { + of_node_put(np); + return -EINVAL; + } + + if (action == PSERIES_DRCONF_MEM_ADD) { + rc = lmb_add(*base, *lmb_size); + rc = (rc < 0) ? -EINVAL : 0; + } else if (action == PSERIES_DRCONF_MEM_REMOVE) { + rc = pseries_remove_lmb(*base, *lmb_size); + } else { + rc = -EINVAL; + } + + of_node_put(np); + return rc; } static int pseries_memory_notifier(struct notifier_block *nb, @@ -120,6 +154,11 @@ static int pseries_memory_notifier(struct notifier_block *nb, if (pseries_remove_memory(node)) err = NOTIFY_BAD; break; + case PSERIES_DRCONF_MEM_ADD: + case PSERIES_DRCONF_MEM_REMOVE: + if (pseries_drconf_memory(node, action)) + err = NOTIFY_BAD; + break; default: err = NOTIFY_DONE; break; diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 176f1f39d2d..9a12908510f 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -135,9 +135,10 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, u64 rpn; long l, limit; - if (npages == 1) - return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, - direction); + if (npages == 1) { + tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, direction); + return; + } tcep = __get_cpu_var(tce_page); @@ -147,9 +148,11 @@ static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, if (!tcep) { tcep = (u64 *)__get_free_page(GFP_ATOMIC); /* If allocation fails, fall back to the loop implementation */ - if (!tcep) - return tce_build_pSeriesLP(tbl, tcenum, npages, - uaddr, direction); + if (!tcep) { + tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, + direction); + return; + } __get_cpu_var(tce_page) = tcep; } diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c index e9dd5fe081c..53cbd53d874 100644 --- a/arch/powerpc/platforms/pseries/kexec.c +++ b/arch/powerpc/platforms/pseries/kexec.c @@ -70,4 +70,4 @@ static int __init pseries_kexec_setup(void) return 0; } -__initcall(pseries_kexec_setup); +machine_device_initcall(pseries, pseries_kexec_setup); diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 2cbaedb17f3..52a80e5840e 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -52,7 +52,7 @@ EXPORT_SYMBOL(plpar_hcall_norets); extern void pSeries_find_serial_port(void); -int vtermno; /* virtual terminal# for udbg */ +static int vtermno; /* virtual terminal# for udbg */ #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) static void udbg_hvsi_putc(char c) @@ -305,7 +305,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, flags = 0; /* Make pHyp happy */ - if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) + if ((rflags & _PAGE_NO_CACHE) & !(rflags & _PAGE_WRITETHRU)) hpte_r &= ~_PAGE_COHERENT; lpar_rc = plpar_pte_enter(flags, hpte_group, hpte_v, hpte_r, &slot); diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index f68903e15bd..42f7e384e6c 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -131,8 +131,10 @@ int __init pSeries_nvram_init(void) return -ENODEV; nbytes_p = of_get_property(nvram, "#bytes", &proplen); - if (nbytes_p == NULL || proplen != sizeof(unsigned int)) + if (nbytes_p == NULL || proplen != sizeof(unsigned int)) { + of_node_put(nvram); return -EIO; + } nvram_size = *nbytes_p; diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 2b548afd100..d20b96e22c2 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -55,7 +55,7 @@ static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX]; static DEFINE_SPINLOCK(ras_log_buf_lock); -char mce_data_buf[RTAS_ERROR_LOG_MAX]; +static char mce_data_buf[RTAS_ERROR_LOG_MAX]; static int ras_get_sensor_state_token; static int ras_check_exception_token; diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 75769aae41d..7637bd38c79 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -365,7 +365,7 @@ static char *parse_node(char *buf, size_t bufsize, struct device_node **npp) *buf = '\0'; buf++; - handle = simple_strtoul(handle_str, NULL, 10); + handle = simple_strtoul(handle_str, NULL, 0); *npp = of_find_node_by_phandle(handle); return buf; @@ -422,8 +422,8 @@ static int do_update_property(char *buf, size_t bufsize) { struct device_node *np; unsigned char *value; - char *name, *end; - int length; + char *name, *end, *next_prop; + int rc, length; struct property *newprop, *oldprop; buf = parse_node(buf, bufsize, &np); end = buf + bufsize; @@ -431,7 +431,8 @@ static int do_update_property(char *buf, size_t bufsize) if (!np) return -ENODEV; - if (parse_next_property(buf, end, &name, &length, &value) == NULL) + next_prop = parse_next_property(buf, end, &name, &length, &value); + if (!next_prop) return -EINVAL; newprop = new_property(name, length, value, NULL); @@ -442,7 +443,34 @@ static int do_update_property(char *buf, size_t bufsize) if (!oldprop) return -ENODEV; - return prom_update_property(np, newprop, oldprop); + rc = prom_update_property(np, newprop, oldprop); + if (rc) + return rc; + + /* For memory under the ibm,dynamic-reconfiguration-memory node + * of the device tree, adding and removing memory is just an update + * to the ibm,dynamic-memory property instead of adding/removing a + * memory node in the device tree. For these cases we still need to + * involve the notifier chain. + */ + if (!strcmp(name, "ibm,dynamic-memory")) { + int action; + + next_prop = parse_next_property(next_prop, end, &name, + &length, &value); + if (!next_prop) + return -EINVAL; + + if (!strcmp(name, "add")) + action = PSERIES_DRCONF_MEM_ADD; + else + action = PSERIES_DRCONF_MEM_REMOVE; + + blocking_notifier_call_chain(&pSeries_reconfig_chain, + action, value); + } + + return 0; } /** diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index 7d3e2b0bd4d..c9ffd8c225f 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c @@ -32,7 +32,7 @@ static DEFINE_SPINLOCK(rtasd_log_lock); -DECLARE_WAIT_QUEUE_HEAD(rtas_log_wait); +static DECLARE_WAIT_QUEUE_HEAD(rtas_log_wait); static char *rtas_log_buf; static unsigned long rtas_log_start; @@ -329,7 +329,7 @@ static unsigned int rtas_log_poll(struct file *file, poll_table * wait) return 0; } -const struct file_operations proc_rtas_log_operations = { +static const struct file_operations proc_rtas_log_operations = { .read = rtas_log_read, .poll = rtas_log_poll, .open = rtas_log_open, diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index f5d29f5b13c..90beb444e1d 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -109,7 +109,7 @@ static void __init fwnmi_init(void) fwnmi_active = 1; } -void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc) +static void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc) { unsigned int cascade_irq = i8259_irq(); if (cascade_irq != NO_IRQ) @@ -482,7 +482,7 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus) * possible with power button press. If ibm,power-off-ups token is used * it will allow auto poweron after power is restored. */ -void pSeries_power_off(void) +static void pSeries_power_off(void) { int rc; int rtas_poweroff_ups_token = rtas_token("ibm,power-off-ups"); diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index ebebc28fe89..0fc830f576f 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -383,13 +383,11 @@ static irqreturn_t xics_ipi_dispatch(int cpu) mb(); smp_message_recv(PPC_MSG_RESCHEDULE); } -#if 0 - if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK, + if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, &xics_ipi_message[cpu].value)) { mb(); - smp_message_recv(PPC_MSG_MIGRATE_TASK); + smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE); } -#endif #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, &xics_ipi_message[cpu].value)) { |