diff options
32 files changed, 907 insertions, 752 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 2e9d78d21fd..ef514c42eb4 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -162,7 +162,8 @@ config ARCH_HAS_CPU_IDLE_WAIT def_bool y config NO_IOPORT - bool + def_bool !PCI + depends on !SH_CAYMAN && !SH_SH4202_MICRODEV config IO_TRAPPED bool @@ -275,6 +276,7 @@ config CPU_SUBTYPE_SH7203 select CPU_HAS_FPU select SYS_SUPPORTS_CMT select SYS_SUPPORTS_MTU2 + select ARCH_WANT_OPTIONAL_GPIOLIB config CPU_SUBTYPE_SH7206 bool "Support SH7206 processor" @@ -346,6 +348,7 @@ config CPU_SUBTYPE_SH7720 select CPU_SH3 select CPU_HAS_DSP select SYS_SUPPORTS_CMT + select ARCH_WANT_OPTIONAL_GPIOLIB help Select SH7720 if you have a SH3-DSP SH7720 CPU. @@ -408,6 +411,7 @@ config CPU_SUBTYPE_SH7723 select ARCH_SHMOBILE select ARCH_SPARSEMEM_ENABLE select SYS_SUPPORTS_CMT + select ARCH_WANT_OPTIONAL_GPIOLIB help Select SH7723 if you have an SH-MobileR2 CPU. @@ -418,6 +422,7 @@ config CPU_SUBTYPE_SH7724 select ARCH_SHMOBILE select ARCH_SPARSEMEM_ENABLE select SYS_SUPPORTS_CMT + select ARCH_WANT_OPTIONAL_GPIOLIB help Select SH7724 if you have an SH-MobileR2R CPU. @@ -425,6 +430,7 @@ config CPU_SUBTYPE_SH7757 bool "Support SH7757 processor" select CPU_SH4A select CPU_SHX2 + select ARCH_WANT_OPTIONAL_GPIOLIB help Select SH7757 if you have a SH4A SH7757 CPU. @@ -448,6 +454,7 @@ config CPU_SUBTYPE_SH7785 select CPU_SHX2 select ARCH_SPARSEMEM_ENABLE select SYS_SUPPORTS_NUMA + select ARCH_WANT_OPTIONAL_GPIOLIB config CPU_SUBTYPE_SH7786 bool "Support SH7786 processor" @@ -455,6 +462,7 @@ config CPU_SUBTYPE_SH7786 select CPU_SHX3 select CPU_HAS_PTEAEX select GENERIC_CLOCKEVENTS_BROADCAST if SMP + select ARCH_WANT_OPTIONAL_GPIOLIB config CPU_SUBTYPE_SHX3 bool "Support SH-X3 processor" @@ -479,6 +487,7 @@ config CPU_SUBTYPE_SH7722 select ARCH_SPARSEMEM_ENABLE select SYS_SUPPORTS_NUMA select SYS_SUPPORTS_CMT + select ARCH_WANT_OPTIONAL_GPIOLIB config CPU_SUBTYPE_SH7366 bool "Support SH7366 processor" @@ -568,15 +577,6 @@ config SH_CLK_CPG_LEGACY def_bool y if !CPU_SUBTYPE_SH7785 && !ARCH_SHMOBILE && \ !CPU_SHX3 && !CPU_SUBTYPE_SH7757 -config SH_CLK_MD - int "CPU Mode Pin Setting" - depends on CPU_SH2 - default 6 if CPU_SUBTYPE_SH7206 - default 5 if CPU_SUBTYPE_SH7619 - default 0 - help - MD2 - MD0 pin setting. - source "kernel/time/Kconfig" endmenu diff --git a/arch/sh/boards/board-secureedge5410.c b/arch/sh/boards/board-secureedge5410.c index 32f875e8493..f968f17891a 100644 --- a/arch/sh/boards/board-secureedge5410.c +++ b/arch/sh/boards/board-secureedge5410.c @@ -29,8 +29,6 @@ unsigned short secureedge5410_ioport; */ static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id) { - ctrl_delay(); /* dummy read */ - printk("SnapGear: erase switch interrupt!\n"); return IRQ_HANDLED; diff --git a/arch/sh/boards/mach-rsk/devices-rsk7203.c b/arch/sh/boards/mach-rsk/devices-rsk7203.c index 4fa08ba1025..a8089f79d05 100644 --- a/arch/sh/boards/mach-rsk/devices-rsk7203.c +++ b/arch/sh/boards/mach-rsk/devices-rsk7203.c @@ -1,7 +1,7 @@ /* * Renesas Technology Europe RSK+ 7203 Support. * - * Copyright (C) 2008 Paul Mundt + * Copyright (C) 2008 - 2010 Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -12,7 +12,9 @@ #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/smsc911x.h> +#include <linux/input.h> #include <linux/gpio.h> +#include <linux/gpio_keys.h> #include <linux/leds.h> #include <asm/machvec.h> #include <asm/io.h> @@ -84,9 +86,42 @@ static struct platform_device led_device = { }, }; +static struct gpio_keys_button rsk7203_gpio_keys_table[] = { + { + .code = BTN_0, + .gpio = GPIO_PB0, + .active_low = 1, + .desc = "SW1", + }, { + .code = BTN_1, + .gpio = GPIO_PB1, + .active_low = 1, + .desc = "SW2", + }, { + .code = BTN_2, + .gpio = GPIO_PB2, + .active_low = 1, + .desc = "SW3", + }, +}; + +static struct gpio_keys_platform_data rsk7203_gpio_keys_info = { + .buttons = rsk7203_gpio_keys_table, + .nbuttons = ARRAY_SIZE(rsk7203_gpio_keys_table), + .poll_interval = 50, /* default to 50ms */ +}; + +static struct platform_device keys_device = { + .name = "gpio-keys-polled", + .dev = { + .platform_data = &rsk7203_gpio_keys_info, + }, +}; + static struct platform_device *rsk7203_devices[] __initdata = { &smsc911x_device, &led_device, + &keys_device, }; static int __init rsk7203_devices_setup(void) diff --git a/arch/sh/boards/mach-sdk7786/Makefile b/arch/sh/boards/mach-sdk7786/Makefile index 23ff7d4ac49..8ae56e9560a 100644 --- a/arch/sh/boards/mach-sdk7786/Makefile +++ b/arch/sh/boards/mach-sdk7786/Makefile @@ -1,4 +1,4 @@ -obj-y := fpga.o irq.o setup.o +obj-y := fpga.o irq.o nmi.o setup.o obj-$(CONFIG_GENERIC_GPIO) += gpio.o obj-$(CONFIG_HAVE_SRAM_POOL) += sram.o diff --git a/arch/sh/boards/mach-sdk7786/nmi.c b/arch/sh/boards/mach-sdk7786/nmi.c new file mode 100644 index 00000000000..edcfa1f568b --- /dev/null +++ b/arch/sh/boards/mach-sdk7786/nmi.c @@ -0,0 +1,83 @@ +/* + * SDK7786 FPGA NMI Support. + * + * Copyright (C) 2010 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <mach/fpga.h> + +enum { + NMI_MODE_MANUAL, + NMI_MODE_AUX, + NMI_MODE_MASKED, + NMI_MODE_ANY, + NMI_MODE_UNKNOWN, +}; + +/* + * Default to the manual NMI switch. + */ +static unsigned int __initdata nmi_mode = NMI_MODE_ANY; + +static int __init nmi_mode_setup(char *str) +{ + if (!str) + return 0; + + if (strcmp(str, "manual") == 0) + nmi_mode = NMI_MODE_MANUAL; + else if (strcmp(str, "aux") == 0) + nmi_mode = NMI_MODE_AUX; + else if (strcmp(str, "masked") == 0) + nmi_mode = NMI_MODE_MASKED; + else if (strcmp(str, "any") == 0) + nmi_mode = NMI_MODE_ANY; + else { + nmi_mode = NMI_MODE_UNKNOWN; + pr_warning("Unknown NMI mode %s\n", str); + } + + printk("Set NMI mode to %d\n", nmi_mode); + return 0; +} +early_param("nmi_mode", nmi_mode_setup); + +void __init sdk7786_nmi_init(void) +{ + unsigned int source, mask, tmp; + + switch (nmi_mode) { + case NMI_MODE_MANUAL: + source = NMISR_MAN_NMI; + mask = NMIMR_MAN_NMIM; + break; + case NMI_MODE_AUX: + source = NMISR_AUX_NMI; + mask = NMIMR_AUX_NMIM; + break; + case NMI_MODE_ANY: + source = NMISR_MAN_NMI | NMISR_AUX_NMI; + mask = NMIMR_MAN_NMIM | NMIMR_AUX_NMIM; + break; + case NMI_MODE_MASKED: + case NMI_MODE_UNKNOWN: + default: + source = mask = 0; + break; + } + + /* Set the NMI source */ + tmp = fpga_read_reg(NMISR); + tmp &= ~NMISR_MASK; + tmp |= source; + fpga_write_reg(tmp, NMISR); + + /* And the IRQ masking */ + fpga_write_reg(NMIMR_MASK ^ mask, NMIMR); +} diff --git a/arch/sh/boards/mach-sdk7786/setup.c b/arch/sh/boards/mach-sdk7786/setup.c index 7e0c4e3878e..75e4ddbbec3 100644 --- a/arch/sh/boards/mach-sdk7786/setup.c +++ b/arch/sh/boards/mach-sdk7786/setup.c @@ -237,6 +237,7 @@ static void __init sdk7786_setup(char **cmdline_p) pr_info("Renesas Technology Europe SDK7786 support:\n"); sdk7786_fpga_init(); + sdk7786_nmi_init(); pr_info("\tPCB revision:\t%d\n", fpga_read_reg(PCBRR) & 0xf); diff --git a/arch/sh/boards/mach-se/7206/setup.c b/arch/sh/boards/mach-se/7206/setup.c index 7f4871c71a0..33039e0dc56 100644 --- a/arch/sh/boards/mach-se/7206/setup.c +++ b/arch/sh/boards/mach-se/7206/setup.c @@ -79,6 +79,11 @@ static int __init se7206_devices_setup(void) } __initcall(se7206_devices_setup); +static int se7206_mode_pins(void) +{ + return MODE_PIN1 | MODE_PIN2; +} + /* * The Machine Vector */ @@ -87,4 +92,5 @@ static struct sh_machine_vector mv_se __initmv = { .mv_name = "SolutionEngine", .mv_nr_irqs = 256, .mv_init_irq = init_se7206_IRQ, + .mv_mode_pins = se7206_mode_pins, }; diff --git a/arch/sh/boards/mach-se/board-se7619.c b/arch/sh/boards/mach-se/board-se7619.c index 1d0ef7faa10..82b6d4a5dc0 100644 --- a/arch/sh/boards/mach-se/board-se7619.c +++ b/arch/sh/boards/mach-se/board-se7619.c @@ -11,6 +11,11 @@ #include <asm/io.h> #include <asm/machvec.h> +static int se7619_mode_pins(void) +{ + return MODE_PIN2 | MODE_PIN0; +} + /* * The Machine Vector */ @@ -18,4 +23,5 @@ static struct sh_machine_vector mv_se __initmv = { .mv_name = "SolutionEngine", .mv_nr_irqs = 108, + .mv_mode_pins = se7619_mode_pins, }; diff --git a/arch/sh/configs/migor_defconfig b/arch/sh/configs/migor_defconfig index 9ad904a110d..cc61eda4492 100644 --- a/arch/sh/configs/migor_defconfig +++ b/arch/sh/configs/migor_defconfig @@ -54,6 +54,8 @@ CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set CONFIG_KEYBOARD_SH_KEYSC=y # CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_MIGOR=y # CONFIG_SERIO is not set CONFIG_VT_HW_CONSOLE_BINDING=y CONFIG_SERIAL_SH_SCI=y diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c index 60ee09a4e12..a09c77dd09d 100644 --- a/arch/sh/drivers/pci/pci.c +++ b/arch/sh/drivers/pci/pci.c @@ -382,14 +382,13 @@ static void __iomem *ioport_map_pci(struct pci_dev *dev, struct pci_channel *chan = dev->sysdata; if (unlikely(!chan->io_map_base)) { - chan->io_map_base = generic_io_base; + chan->io_map_base = sh_io_port_base; if (pci_domains_supported) panic("To avoid data corruption io_map_base MUST be " "set with multiple PCI domains."); } - return (void __iomem *)(chan->io_map_base + port); } diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index b237d525d59..89ab2c57a4c 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -1,5 +1,6 @@ #ifndef __ASM_SH_IO_H #define __ASM_SH_IO_H + /* * Convention: * read{b,w,l,q}/write{b,w,l,q} are for PCI, @@ -15,12 +16,6 @@ * SuperH specific I/O (raw I/O to on-chip CPU peripherals). In practice * these have the same semantics as the __raw variants, and as such, all * new code should be using the __raw versions. - * - * All ISA I/O routines are wrapped through the machine vector. If a - * board does not provide overrides, a generic set that are copied in - * from the default machine vector are used instead. These are largely - * for old compat code for I/O offseting to SuperIOs, all of which are - * better handled through the machvec ioport mapping routines these days. */ #include <linux/errno.h> #include <asm/cache.h> @@ -31,39 +26,10 @@ #include <asm-generic/iomap.h> #ifdef __KERNEL__ -/* - * Depending on which platform we are running on, we need different - * I/O functions. - */ -#define __IO_PREFIX generic +#define __IO_PREFIX generic #include <asm/io_generic.h> #include <asm/io_trapped.h> -#ifdef CONFIG_HAS_IOPORT - -#define inb(p) sh_mv.mv_inb((p)) -#define inw(p) sh_mv.mv_inw((p)) -#define inl(p) sh_mv.mv_inl((p)) -#define outb(x,p) sh_mv.mv_outb((x),(p)) -#define outw(x,p) sh_mv.mv_outw((x),(p)) -#define outl(x,p) sh_mv.mv_outl((x),(p)) - -#define inb_p(p) sh_mv.mv_inb_p((p)) -#define inw_p(p) sh_mv.mv_inw_p((p)) -#define inl_p(p) sh_mv.mv_inl_p((p)) -#define outb_p(x,p) sh_mv.mv_outb_p((x),(p)) -#define outw_p(x,p) sh_mv.mv_outw_p((x),(p)) -#define outl_p(x,p) sh_mv.mv_outl_p((x),(p)) - -#define insb(p,b,c) sh_mv.mv_insb((p), (b), (c)) -#define insw(p,b,c) sh_mv.mv_insw((p), (b), (c)) -#define insl(p,b,c) sh_mv.mv_insl((p), (b), (c)) -#define outsb(p,b,c) sh_mv.mv_outsb((p), (b), (c)) -#define outsw(p,b,c) sh_mv.mv_outsw((p), (b), (c)) -#define outsl(p,b,c) sh_mv.mv_outsl((p), (b), (c)) - -#endif - #define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile u8 __force *)(a) = (v)) #define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile u16 __force *)(a) = (v)) #define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile u32 __force *)(a) = (v)) @@ -74,68 +40,39 @@ #define __raw_readl(a) (__chk_io_ptr(a), *(volatile u32 __force *)(a)) #define __raw_readq(a) (__chk_io_ptr(a), *(volatile u64 __force *)(a)) -#define readb(a) ({ u8 r_ = __raw_readb(a); mb(); r_; }) -#define readw(a) ({ u16 r_ = __raw_readw(a); mb(); r_; }) -#define readl(a) ({ u32 r_ = __raw_readl(a); mb(); r_; }) -#define readq(a) ({ u64 r_ = __raw_readq(a); mb(); r_; }) - -#define writeb(v,a) ({ __raw_writeb((v),(a)); mb(); }) -#define writew(v,a) ({ __raw_writew((v),(a)); mb(); }) -#define writel(v,a) ({ __raw_writel((v),(a)); mb(); }) -#define writeq(v,a) ({ __raw_writeq((v),(a)); mb(); }) - -/* - * Legacy SuperH on-chip I/O functions - * - * These are all deprecated, all new (and especially cross-platform) code - * should be using the __raw_xxx() routines directly. - */ -static inline u8 __deprecated ctrl_inb(unsigned long addr) -{ - return __raw_readb(addr); -} - -static inline u16 __deprecated ctrl_inw(unsigned long addr) -{ - return __raw_readw(addr); -} - -static inline u32 __deprecated ctrl_inl(unsigned long addr) -{ - return __raw_readl(addr); -} - -static inline u64 __deprecated ctrl_inq(unsigned long addr) -{ - return __raw_readq(addr); -} - -static inline void __deprecated ctrl_outb(u8 v, unsigned long addr) -{ - __raw_writeb(v, addr); -} - -static inline void __deprecated ctrl_outw(u16 v, unsigned long addr) -{ - __raw_writew(v, addr); -} - -static inline void __deprecated ctrl_outl(u32 v, unsigned long addr) -{ - __raw_writel(v, addr); -} - -static inline void __deprecated ctrl_outq(u64 v, unsigned long addr) -{ - __raw_writeq(v, addr); -} - -extern unsigned long generic_io_base; - -static inline void ctrl_delay(void) -{ - __raw_readw(generic_io_base); -} +#define readb_relaxed(c) ({ u8 __v = __raw_readb(c); __v; }) +#define readw_relaxed(c) ({ u16 __v = le16_to_cpu((__force __le16) \ + __raw_readw(c)); __v; }) +#define readl_relaxed(c) ({ u32 __v = le32_to_cpu((__force __le32) \ + __raw_readl(c)); __v; }) +#define readq_relaxed(c) ({ u64 __v = le64_to_cpu((__force __le64) \ + __raw_readq(c)); __v; }) + +#define writeb_relaxed(v,c) ((void)__raw_writeb(v,c)) +#define writew_relaxed(v,c) ((void)__raw_writew((__force u16) \ + cpu_to_le16(v),c)) +#define writel_relaxed(v,c) ((void)__raw_writel((__force u32) \ + cpu_to_le32(v),c)) +#define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64) \ + cpu_to_le64(v),c)) + +#define readb(a) ({ u8 r_ = readb_relaxed(a); rmb(); r_; }) +#define readw(a) ({ u16 r_ = readw_relaxed(a); rmb(); r_; }) +#define readl(a) ({ u32 r_ = readl_relaxed(a); rmb(); r_; }) +#define readq(a) ({ u64 r_ = readq_relaxed(a); rmb(); r_; }) + +#define writeb(v,a) ({ wmb(); writeb_relaxed((v),(a)); }) +#define writew(v,a) ({ wmb(); writew_relaxed((v),(a)); }) +#define writel(v,a) ({ wmb(); writel_relaxed((v),(a)); }) +#define writeq(v,a) ({ wmb(); writeq_relaxed((v),(a)); }) + +#define readsb(p,d,l) __raw_readsb(p,d,l) +#define readsw(p,d,l) __raw_readsw(p,d,l) +#define readsl(p,d,l) __raw_readsl(p,d,l) + +#define writesb(p,d,l) __raw_writesb(p,d,l) +#define writesw(p,d,l) __raw_writesw(p,d,l) +#define writesl(p,d,l) __raw_writesl(p,d,l) #define __BUILD_UNCACHED_IO(bwlq, type) \ static inline type read##bwlq##_uncached(unsigned long addr) \ @@ -159,10 +96,11 @@ __BUILD_UNCACHED_IO(w, u16) __BUILD_UNCACHED_IO(l, u32) __BUILD_UNCACHED_IO(q, u64) -#define __BUILD_MEMORY_STRING(bwlq, type) \ +#define __BUILD_MEMORY_STRING(pfx, bwlq, type) \ \ -static inline void __raw_writes##bwlq(volatile void __iomem *mem, \ - const void *addr, unsigned int count) \ +static inline void \ +pfx##writes##bwlq(volatile void __iomem *mem, const void *addr, \ + unsigned int count) \ { \ const volatile type *__addr = addr; \ \ @@ -172,8 +110,8 @@ static inline void __raw_writes##bwlq(volatile void __iomem *mem, \ } \ } \ \ -static inline void __raw_reads##bwlq(volatile void __iomem *mem, \ - void *addr, unsigned int count) \ +static inline void pfx##reads##bwlq(volatile void __iomem *mem, \ + void *addr, unsigned int count) \ { \ volatile type *__addr = addr; \ \ @@ -183,85 +121,166 @@ static inline void __raw_reads##bwlq(volatile void __iomem *mem, \ } \ } -__BUILD_MEMORY_STRING(b, u8) -__BUILD_MEMORY_STRING(w, u16) +__BUILD_MEMORY_STRING(__raw_, b, u8) +__BUILD_MEMORY_STRING(__raw_, w, u16) #ifdef CONFIG_SUPERH32 void __raw_writesl(void __iomem *addr, const void *data, int longlen); void __raw_readsl(const void __iomem *addr, void *data, int longlen); #else -__BUILD_MEMORY_STRING(l, u32) +__BUILD_MEMORY_STRING(__raw_, l, u32) #endif -__BUILD_MEMORY_STRING(q, u64) - -#define writesb __raw_writesb -#define writesw __raw_writesw -#define writesl __raw_writesl - -#define readsb __raw_readsb -#define readsw __raw_readsw -#define readsl __raw_readsl - -#define readb_relaxed(a) readb(a) -#define readw_relaxed(a) readw(a) -#define readl_relaxed(a) readl(a) -#define readq_relaxed(a) readq(a) - -#ifndef CONFIG_GENERIC_IOMAP -/* Simple MMIO */ -#define ioread8(a) __raw_readb(a) -#define ioread16(a) __raw_readw(a) -#define ioread16be(a) be16_to_cpu(__raw_readw((a))) -#define ioread32(a) __raw_readl(a) -#define ioread32be(a) be32_to_cpu(__raw_readl((a))) - -#define iowrite8(v,a) __raw_writeb((v),(a)) -#define iowrite16(v,a) __raw_writew((v),(a)) -#define iowrite16be(v,a) __raw_writew(cpu_to_be16((v)),(a)) -#define iowrite32(v,a) __raw_writel((v),(a)) -#define iowrite32be(v,a) __raw_writel(cpu_to_be32((v)),(a)) - -#define ioread8_rep(a, d, c) __raw_readsb((a), (d), (c)) -#define ioread16_rep(a, d, c) __raw_readsw((a), (d), (c)) -#define ioread32_rep(a, d, c) __raw_readsl((a), (d), (c)) - -#define iowrite8_rep(a, s, c) __raw_writesb((a), (s), (c)) -#define iowrite16_rep(a, s, c) __raw_writesw((a), (s), (c)) -#define iowrite32_rep(a, s, c) __raw_writesl((a), (s), (c)) +__BUILD_MEMORY_STRING(__raw_, q, u64) + +#ifdef CONFIG_HAS_IOPORT + +/* + * Slowdown I/O port space accesses for antique hardware. + */ +#undef CONF_SLOWDOWN_IO + +/* + * On SuperH I/O ports are memory mapped, so we access them using normal + * load/store instructions. sh_io_port_base is the virtual address to + * which all ports are being mapped. + */ +extern const unsigned long sh_io_port_base; + +static inline void __set_io_port_base(unsigned long pbase) +{ + *(unsigned long *)&sh_io_port_base = pbase; + barrier(); +} + +#ifdef CONFIG_GENERIC_IOMAP +#define __ioport_map ioport_map +#else +extern void __iomem *__ioport_map(unsigned long addr, unsigned int size); #endif -#define mmio_insb(p,d,c) __raw_readsb(p,d,c) -#define mmio_insw(p,d,c) __raw_readsw(p,d,c) -#define mmio_insl(p,d,c) __raw_readsl(p,d,c) +#ifdef CONF_SLOWDOWN_IO +#define SLOW_DOWN_IO __raw_readw(sh_io_port_base) +#else +#define SLOW_DOWN_IO +#endif -#define mmio_outsb(p,s,c) __raw_writesb(p,s,c) -#define mmio_outsw(p,s,c) __raw_writesw(p,s,c) -#define mmio_outsl(p,s,c) __raw_writesl(p,s,c) +#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, p, slow) \ + \ +static inline void pfx##out##bwlq##p(type val, unsigned long port) \ +{ \ + volatile type *__addr; \ + \ + __addr = __ioport_map(port, sizeof(type)); \ + *__addr = val; \ + slow; \ +} \ + \ +static inline type pfx##in##bwlq##p(unsigned long port) \ +{ \ + volatile type *__addr; \ + type __val; \ + \ + __addr = __ioport_map(port, sizeof(type)); \ + __val = *__addr; \ + slow; \ + \ + return __val; \ +} -/* synco on SH-4A, otherwise a nop */ -#define mmiowb() wmb() +#define __BUILD_IOPORT_PFX(bus, bwlq, type) \ + __BUILD_IOPORT_SINGLE(bus, bwlq, type, ,) \ + __BUILD_IOPORT_SINGLE(bus, bwlq, type, _p, SLOW_DOWN_IO) -#define IO_SPACE_LIMIT 0xffffffff +#define BUILDIO_IOPORT(bwlq, type) \ + __BUILD_IOPORT_PFX(, bwlq, type) -#ifdef CONFIG_HAS_IOPORT +BUILDIO_IOPORT(b, u8) +BUILDIO_IOPORT(w, u16) +BUILDIO_IOPORT(l, u32) +BUILDIO_IOPORT(q, u64) + +#define __BUILD_IOPORT_STRING(bwlq, type) \ + \ +static inline void outs##bwlq(unsigned long port, const void *addr, \ + unsigned int count) \ +{ \ + const volatile type *__addr = addr; \ + \ + while (count--) { \ + out##bwlq(*__addr, port); \ + __addr++; \ + } \ +} \ + \ +static inline void ins##bwlq(unsigned long port, void *addr, \ + unsigned int count) \ +{ \ + volatile type *__addr = addr; \ + \ + while (count--) { \ + *__addr = in##bwlq(port); \ + __addr++; \ + } \ +} + +__BUILD_IOPORT_STRING(b, u8) +__BUILD_IOPORT_STRING(w, u16) +__BUILD_IOPORT_STRING(l, u32) +__BUILD_IOPORT_STRING(q, u64) + +#endif /* - * This function provides a method for the generic case where a - * board-specific ioport_map simply needs to return the port + some - * arbitrary port base. + * Legacy SuperH on-chip I/O functions * - * We use this at board setup time to implicitly set the port base, and - * as a result, we can use the generic ioport_map. + * These are all deprecated, all new (and especially cross-platform) code + * should be using the __raw_xxx() routines directly. */ -static inline void __set_io_port_base(unsigned long pbase) +static inline u8 __deprecated ctrl_inb(unsigned long addr) { - generic_io_base = pbase; + return __raw_readb(addr); } -#define __ioport_map(p, n) sh_mv.mv_ioport_map((p), (n)) +static inline u16 __deprecated ctrl_inw(unsigned long addr) +{ + return __raw_readw(addr); +} -#endif +static inline u32 __deprecated ctrl_inl(unsigned long addr) +{ + return __raw_readl(addr); +} + +static inline u64 __deprecated ctrl_inq(unsigned long addr) +{ + return __raw_readq(addr); +} + +static inline void __deprecated ctrl_outb(u8 v, unsigned long addr) +{ + __raw_writeb(v, addr); +} + +static inline void __deprecated ctrl_outw(u16 v, unsigned long addr) +{ + __raw_writew(v, addr); +} + +static inline void __deprecated ctrl_outl(u32 v, unsigned long addr) +{ + __raw_writel(v, addr); +} + +static inline void __deprecated ctrl_outq(u64 v, unsigned long addr) +{ + __raw_writeq(v, addr); +} + +#define IO_SPACE_LIMIT 0xffffffff + +/* synco on SH-4A, otherwise a nop */ +#define mmiowb() wmb() /* We really want to try and get these to memcpy etc */ void memcpy_fromio(void *, const volatile void __iomem *, unsigned long); @@ -395,10 +414,6 @@ static inline int iounmap_fixed(void __iomem *addr) { return -EINVAL; } #define ioremap_nocache ioremap #define iounmap __iounmap -#define maybebadio(port) \ - printk(KERN_ERR "bad PC-like io %s:%u for port 0x%lx at 0x%08x\n", \ - __func__, __LINE__, (port), (u32)__builtin_return_address(0)) - /* * Convert a physical pointer to a virtual kernel pointer for /dev/mem * access diff --git a/arch/sh/include/asm/io_generic.h b/arch/sh/include/asm/io_generic.h index 491df93cbf8..b5f6956f19c 100644 --- a/arch/sh/include/asm/io_generic.h +++ b/arch/sh/include/asm/io_generic.h @@ -11,31 +11,6 @@ #error "Don't include this header without a valid system prefix" #endif -u8 IO_CONCAT(__IO_PREFIX,inb)(unsigned long); -u16 IO_CONCAT(__IO_PREFIX,inw)(unsigned long); -u32 IO_CONCAT(__IO_PREFIX,inl)(unsigned long); - -void IO_CONCAT(__IO_PREFIX,outb)(u8, unsigned long); -void IO_CONCAT(__IO_PREFIX,outw)(u16, unsigned long); -void IO_CONCAT(__IO_PREFIX,outl)(u32, unsigned long); - -u8 IO_CONCAT(__IO_PREFIX,inb_p)(unsigned long); -u16 IO_CONCAT(__IO_PREFIX,inw_p)(unsigned long); -u32 IO_CONCAT(__IO_PREFIX,inl_p)(unsigned long); -void IO_CONCAT(__IO_PREFIX,outb_p)(u8, unsigned long); -void IO_CONCAT(__IO_PREFIX,outw_p)(u16, unsigned long); -void IO_CONCAT(__IO_PREFIX,outl_p)(u32, unsigned long); - -void IO_CONCAT(__IO_PREFIX,insb)(unsigned long, void *dst, unsigned long count); -void IO_CONCAT(__IO_PREFIX,insw)(unsigned long, void *dst, unsigned long count); -void IO_CONCAT(__IO_PREFIX,insl)(unsigned long, void *dst, unsigned long count); -void IO_CONCAT(__IO_PREFIX,outsb)(unsigned long, const void *src, unsigned long count); -void IO_CONCAT(__IO_PREFIX,outsw)(unsigned long, const void *src, unsigned long count); -void IO_CONCAT(__IO_PREFIX,outsl)(unsigned long, const void *src, unsigned long count); - -void *IO_CONCAT(__IO_PREFIX,ioremap)(unsigned long offset, unsigned long size); -void IO_CONCAT(__IO_PREFIX,iounmap)(void *addr); - void __iomem *IO_CONCAT(__IO_PREFIX,ioport_map)(unsigned long addr, unsigned int size); void IO_CONCAT(__IO_PREFIX,ioport_unmap)(void __iomem *addr); void IO_CONCAT(__IO_PREFIX,mem_init)(void); diff --git a/arch/sh/include/asm/machvec.h b/arch/sh/include/asm/machvec.h index a0b0cf79cf8..dd5d6e5bf20 100644 --- a/arch/sh/include/asm/machvec.h +++ b/arch/sh/include/asm/machvec.h @@ -23,27 +23,6 @@ struct sh_machine_vector { void (*mv_init_irq)(void); #ifdef CONFIG_HAS_IOPORT - u8 (*mv_inb)(unsigned long); - u16 (*mv_inw)(unsigned long); - u32 (*mv_inl)(unsigned long); - void (*mv_outb)(u8, unsigned long); - void (*mv_outw)(u16, unsigned long); - void (*mv_outl)(u32, unsigned long); - - u8 (*mv_inb_p)(unsigned long); - u16 (*mv_inw_p)(unsigned long); - u32 (*mv_inl_p)(unsigned long); - void (*mv_outb_p)(u8, unsigned long); - void (*mv_outw_p)(u16, unsigned long); - void (*mv_outl_p)(u32, unsigned long); - - void (*mv_insb)(unsigned long, void *dst, unsigned long count); - void (*mv_insw)(unsigned long, void *dst, unsigned long count); - void (*mv_insl)(unsigned long, void *dst, unsigned long count); - void (*mv_outsb)(unsigned long, const void *src, unsigned long count); - void (*mv_outsw)(unsigned long, const void *src, unsigned long count); - void (*mv_outsl)(unsigned long, const void *src, unsigned long count); - void __iomem *(*mv_ioport_map)(unsigned long port, unsigned int size); void (*mv_ioport_unmap)(void __iomem *); #endif diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h index f6edc10aa0d..de167d3a1a8 100644 --- a/arch/sh/include/asm/ptrace.h +++ b/arch/sh/include/asm/ptrace.h @@ -40,8 +40,8 @@ #include <asm/system.h> #define user_mode(regs) (((regs)->sr & 0x40000000)==0) -#define user_stack_pointer(regs) ((unsigned long)(regs)->regs[15]) -#define kernel_stack_pointer(regs) ((unsigned long)(regs)->regs[15]) +#define user_stack_pointer(_regs) ((unsigned long)(_regs)->regs[15]) +#define kernel_stack_pointer(_regs) ((unsigned long)(_regs)->regs[15]) #define instruction_pointer(regs) ((unsigned long)(regs)->pc) extern void show_regs(struct pt_regs *); diff --git a/arch/sh/include/asm/ptrace_32.h b/arch/sh/include/asm/ptrace_32.h index 35d9e257558..6c2239cca1a 100644 --- a/arch/sh/include/asm/ptrace_32.h +++ b/arch/sh/include/asm/ptrace_32.h @@ -76,7 +76,7 @@ struct pt_dspregs { #ifdef __KERNEL__ #define MAX_REG_OFFSET offsetof(struct pt_regs, tra) -#define regs_return_value(regs) ((regs)->regs[0]) +#define regs_return_value(_regs) ((_regs)->regs[0]) #endif /* __KERNEL__ */ diff --git a/arch/sh/include/asm/ptrace_64.h b/arch/sh/include/asm/ptrace_64.h index d43c1cb0bbe..bf9be7764d6 100644 --- a/arch/sh/include/asm/ptrace_64.h +++ b/arch/sh/include/asm/ptrace_64.h @@ -13,7 +13,7 @@ struct pt_regs { #ifdef __KERNEL__ #define MAX_REG_OFFSET offsetof(struct pt_regs, tregs[7]) -#define regs_return_value(regs) ((regs)->regs[3]) +#define regs_return_value(_regs) ((_regs)->regs[3]) #endif /* __KERNEL__ */ diff --git a/arch/sh/include/asm/unaligned-sh4a.h b/arch/sh/include/asm/unaligned-sh4a.h index 9f4dd252c98..c48a9c3420d 100644 --- a/arch/sh/include/asm/unaligned-sh4a.h +++ b/arch/sh/include/asm/unaligned-sh4a.h @@ -18,10 +18,20 @@ * of spill registers and blowing up when building at low optimization * levels. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34777. */ +#include <linux/unaligned/packed_struct.h> #include <linux/types.h> #include <asm/byteorder.h> -static __always_inline u32 __get_unaligned_cpu32(const u8 *p) +static inline u16 sh4a_get_unaligned_cpu16(const u8 *p) +{ +#ifdef __LITTLE_ENDIAN + return p[0] | p[1] << 8; +#else + return p[0] << 8 | p[1]; +#endif +} + +static __always_inline u32 sh4a_get_unaligned_cpu32(const u8 *p) { unsigned long unaligned; @@ -34,218 +44,148 @@ static __always_inline u32 __get_unaligned_cpu32(const u8 *p) return unaligned; } -struct __una_u16 { u16 x __attribute__((packed)); }; -struct __una_u32 { u32 x __attribute__((packed)); }; -struct __una_u64 { u64 x __attribute__((packed)); }; - -static inline u16 __get_unaligned_cpu16(const u8 *p) -{ -#ifdef __LITTLE_ENDIAN - return p[0] | p[1] << 8; -#else - return p[0] << 8 | p[1]; -#endif -} - /* * Even though movua.l supports auto-increment on the read side, it can * only store to r0 due to instruction encoding constraints, so just let * the compiler sort it out on its own. */ -static inline u64 __get_unaligned_cpu64(const u8 *p) +static inline u64 sh4a_get_unaligned_cpu64(const u8 *p) { #ifdef __LITTLE_ENDIAN - return (u64)__get_unaligned_cpu32(p + 4) << 32 | - __get_unaligned_cpu32(p); + return (u64)sh4a_get_unaligned_cpu32(p + 4) << 32 | + sh4a_get_unaligned_cpu32(p); #else - return (u64)__get_unaligned_cpu32(p) << 32 | - __get_unaligned_cpu32(p + 4); + return (u64)sh4a_get_unaligned_cpu32(p) << 32 | + sh4a_get_unaligned_cpu32(p + 4); #endif } static inline u16 get_unaligned_le16(const void *p) { - return le16_to_cpu(__get_unaligned_cpu16(p)); + return le16_to_cpu(sh4a_get_unaligned_cpu16(p)); } static inline u32 get_unaligned_le32(const void *p) { - return le32_to_cpu(__get_unaligned_cpu32(p)); + return le32_to_cpu(sh4a_get_unaligned_cpu32(p)); } static inline u64 get_unaligned_le64(const void *p) { - return le64_to_cpu(__get_unaligned_cpu64(p)); + return le64_to_cpu(sh4a_get_unaligned_cpu64(p)); } static inline u16 get_unaligned_be16(const void *p) { - return be16_to_cpu(__get_unaligned_cpu16(p)); + return be16_to_cpu(sh4a_get_unaligned_cpu16(p)); } static inline u32 get_unaligned_be32(const void *p) { - return be32_to_cpu(__get_unaligned_cpu32(p)); + return be32_to_cpu(sh4a_get_unaligned_cpu32(p)); } static inline u64 get_unaligned_be64(const void *p) { - return be64_to_cpu(__get_unaligned_cpu64(p)); + return be64_to_cpu(sh4a_get_unaligned_cpu64(p)); } -static inline void __put_le16_noalign(u8 *p, u16 val) +static inline void nonnative_put_le16(u16 val, u8 *p) { *p++ = val; *p++ = val >> 8; } -static inline void __put_le32_noalign(u8 *p, u32 val) +static inline void nonnative_put_le32(u32 val, u8 *p) { - __put_le16_noalign(p, val); - __put_le16_noalign(p + 2, val >> 16); + nonnative_put_le16(val, p); + nonnative_put_le16(val >> 16, p + 2); } -static inline void __put_le64_noalign(u8 *p, u64 val) +static inline void nonnative_put_le64(u64 val, u8 *p) { - __put_le32_noalign(p, val); - __put_le32_noalign(p + 4, val >> 32); + nonnative_put_le32(val, p); + nonnative_put_le32(val >> 32, p + 4); } -static inline void __put_be16_noalign(u8 *p, u16 val) +static inline void nonnative_put_be16(u16 val, u8 *p) { *p++ = val >> 8; *p++ = val; } -static inline void __put_be32_noalign(u8 *p, u32 val) +static inline void nonnative_put_be32(u32 val, u8 *p) { - __put_be16_noalign(p, val >> 16); - __put_be16_noalign(p + 2, val); + nonnative_put_be16(val >> 16, p); + nonnative_put_be16(val, p + 2); } -static inline void __put_be64_noalign(u8 *p, u64 val) +static inline void nonnative_put_be64(u64 val, u8 *p) { - __put_be32_noalign(p, val >> 32); - __put_be32_noalign(p + 4, val); + nonnative_put_be32(val >> 32, p); + nonnative_put_be32(val, p + 4); } static inline void put_unaligned_le16(u16 val, void *p) { #ifdef __LITTLE_ENDIAN - ((struct __una_u16 *)p)->x = val; + __put_unaligned_cpu16(val, p); #else - __put_le16_noalign(p, val); + nonnative_put_le16(val, p); #endif } static inline void put_unaligned_le32(u32 val, void *p) { #ifdef __LITTLE_ENDIAN - ((struct __una_u32 *)p)->x = val; + __put_unaligned_cpu32(val, p); #else - __put_le32_noalign(p, val); + nonnative_put_le32(val, p); #endif } static inline void put_unaligned_le64(u64 val, void *p) { #ifdef __LITTLE_ENDIAN - ((struct __una_u64 *)p)->x = val; + __put_unaligned_cpu64(val, p); #else - __put_le64_noalign(p, val); + nonnative_put_le64(val, p); #endif } static inline void put_unaligned_be16(u16 val, void *p) { #ifdef __BIG_ENDIAN - ((struct __una_u16 *)p)->x = val; + __put_unaligned_cpu16(val, p); #else - __put_be16_noalign(p, val); + nonnative_put_be16(val, p); #endif } static inline void put_unaligned_be32(u32 val, void *p) { #ifdef __BIG_ENDIAN - ((struct __una_u32 *)p)->x = val; + __put_unaligned_cpu32(val, p); #else - __put_be32_noalign(p, val); + nonnative_put_be32(val, p); #endif } static inline void put_unaligned_be64(u64 val, void *p) { #ifdef __BIG_ENDIAN - ((struct __una_u64 *)p)->x = val; + __put_unaligned_cpu64(val, p); #else - __put_be64_noalign(p, val); + nonnative_put_be64(val, p); #endif } /* - * Cause a link-time error if we try an unaligned access other than - * 1,2,4 or 8 bytes long + * While it's a bit non-obvious, even though the generic le/be wrappers + * use the __get/put_xxx prefixing, they actually wrap in to the + * non-prefixed get/put_xxx variants as provided above. */ -extern void __bad_unaligned_access_size(void); - -#define __get_unaligned_le(ptr) ((__force typeof(*(ptr)))({ \ - __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \ - __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)), \ - __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)), \ - __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)), \ - __bad_unaligned_access_size())))); \ - })) - -#define __get_unaligned_be(ptr) ((__force typeof(*(ptr)))({ \ - __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \ - __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)), \ - __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)), \ - __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)), \ - __bad_unaligned_access_size())))); \ - })) - -#define __put_unaligned_le(val, ptr) ({ \ - void *__gu_p = (ptr); \ - switch (sizeof(*(ptr))) { \ - case 1: \ - *(u8 *)__gu_p = (__force u8)(val); \ - break; \ - case 2: \ - put_unaligned_le16((__force u16)(val), __gu_p); \ - break; \ - case 4: \ - put_unaligned_le32((__force u32)(val), __gu_p); \ - break; \ - case 8: \ - put_unaligned_le64((__force u64)(val), __gu_p); \ - break; \ - default: \ - __bad_unaligned_access_size(); \ - break; \ - } \ - (void)0; }) - -#define __put_unaligned_be(val, ptr) ({ \ - void *__gu_p = (ptr); \ - switch (sizeof(*(ptr))) { \ - case 1: \ - *(u8 *)__gu_p = (__force u8)(val); \ - break; \ - case 2: \ - put_unaligned_be16((__force u16)(val), __gu_p); \ - break; \ - case 4: \ - put_unaligned_be32((__force u32)(val), __gu_p); \ - break; \ - case 8: \ - put_unaligned_be64((__force u64)(val), __gu_p); \ - break; \ - default: \ - __bad_unaligned_access_size(); \ - break; \ - } \ - (void)0; }) +#include <linux/unaligned/generic.h> #ifdef __LITTLE_ENDIAN # define get_unaligned __get_unaligned_le diff --git a/arch/sh/include/mach-sdk7786/mach/fpga.h b/arch/sh/include/mach-sdk7786/mach/fpga.h index 40f0c2d3690..a9cdac46992 100644 --- a/arch/sh/include/mach-sdk7786/mach/fpga.h +++ b/arch/sh/include/mach-sdk7786/mach/fpga.h @@ -14,11 +14,16 @@ #define INTTESTR 0x040 #define SYSSR 0x050 #define NRGPR 0x060 + #define NMISR 0x070 +#define NMISR_MAN_NMI BIT(0) +#define NMISR_AUX_NMI BIT(1) +#define NMISR_MASK (NMISR_MAN_NMI | NMISR_AUX_NMI) #define NMIMR 0x080 #define NMIMR_MAN_NMIM BIT(0) /* Manual NMI mask */ #define NMIMR_AUX_NMIM BIT(1) /* Auxiliary NMI mask */ +#define NMIMR_MASK (NMIMR_MAN_NMIM | NMIMR_AUX_NMIM) #define INTBSR 0x090 #define INTBMR 0x0a0 @@ -126,6 +131,9 @@ extern void __iomem *sdk7786_fpga_base; extern void sdk7786_fpga_init(void); +/* arch/sh/boards/mach-sdk7786/nmi.c */ +extern void sdk7786_nmi_init(void); + #define SDK7786_FPGA_REGADDR(reg) (sdk7786_fpga_base + (reg)) /* diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 8eed6a48544..ff80227b02d 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -20,6 +20,11 @@ obj-y := clkdev.o debugtraps.o dma-nommu.o dumpstack.o \ syscalls_$(BITS).o time.o topology.o traps.o \ traps_$(BITS).o unwinder.o +ifndef CONFIG_GENERIC_IOMAP +obj-y += iomap.o +obj-$(CONFIG_HAS_IOPORT) += ioport.o +endif + obj-y += cpu/ obj-$(CONFIG_VSYSCALL) += vsyscall/ obj-$(CONFIG_SMP) += smp.o @@ -39,7 +44,6 @@ obj-$(CONFIG_DUMP_CODE) += disassemble.o obj-$(CONFIG_HIBERNATION) += swsusp.o obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_callchain.o -obj-$(CONFIG_HAS_IOPORT) += io_generic.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile index 4edcb60a135..d49c2135fd4 100644 --- a/arch/sh/kernel/cpu/Makefile +++ b/arch/sh/kernel/cpu/Makefile @@ -20,4 +20,4 @@ obj-$(CONFIG_SH_CLK_CPG_LEGACY) += clock-cpg.o obj-$(CONFIG_SH_FPU) += fpu.o obj-$(CONFIG_SH_FPU_EMU) += fpu.o -obj-y += irq/ init.o clock.o hwblk.o +obj-y += irq/ init.o clock.o hwblk.o proc.o diff --git a/arch/sh/kernel/cpu/proc.c b/arch/sh/kernel/cpu/proc.c new file mode 100644 index 00000000000..e80a936f409 --- /dev/null +++ b/arch/sh/kernel/cpu/proc.c @@ -0,0 +1,148 @@ +#include <linux/seq_file.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <asm/machvec.h> +#include <asm/processor.h> + +static const char *cpu_name[] = { + [CPU_SH7201] = "SH7201", + [CPU_SH7203] = "SH7203", [CPU_SH7263] = "SH7263", + [CPU_SH7206] = "SH7206", [CPU_SH7619] = "SH7619", + [CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706", + [CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708", + [CPU_SH7709] = "SH7709", [CPU_SH7710] = "SH7710", + [CPU_SH7712] = "SH7712", [CPU_SH7720] = "SH7720", + [CPU_SH7721] = "SH7721", [CPU_SH7729] = "SH7729", + [CPU_SH7750] = "SH7750", [CPU_SH7750S] = "SH7750S", + [CPU_SH7750R] = "SH7750R", [CPU_SH7751] = "SH7751", + [CPU_SH7751R] = "SH7751R", [CPU_SH7760] = "SH7760", + [CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501", + [CPU_SH7763] = "SH7763", [CPU_SH7770] = "SH7770", + [CPU_SH7780] = "SH7780", [CPU_SH7781] = "SH7781", + [CPU_SH7343] = "SH7343", [CPU_SH7785] = "SH7785", + [CPU_SH7786] = "SH7786", [CPU_SH7757] = "SH7757", + [CPU_SH7722] = "SH7722", [CPU_SHX3] = "SH-X3", + [CPU_SH5_101] = "SH5-101", [CPU_SH5_103] = "SH5-103", + [CPU_MXG] = "MX-G", [CPU_SH7723] = "SH7723", + [CPU_SH7366] = "SH7366", [CPU_SH7724] = "SH7724", + [CPU_SH_NONE] = "Unknown" +}; + +const char *get_cpu_subtype(struct sh_cpuinfo *c) +{ + return cpu_name[c->type]; +} +EXPORT_SYMBOL(get_cpu_subtype); + +#ifdef CONFIG_PROC_FS +/* Symbolic CPU flags, keep in sync with asm/cpu-features.h */ +static const char *cpu_flags[] = { + "none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr", + "ptea", "llsc", "l2", "op32", "pteaex", NULL +}; + +static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c) +{ + unsigned long i; + + seq_printf(m, "cpu flags\t:"); + + if (!c->flags) { + seq_printf(m, " %s\n", cpu_flags[0]); + return; + } + + for (i = 0; cpu_flags[i]; i++) + if ((c->flags & (1 << i))) + seq_printf(m, " %s", cpu_flags[i+1]); + + seq_printf(m, "\n"); +} + +static void show_cacheinfo(struct seq_file *m, const char *type, + struct cache_info info) +{ + unsigned int cache_size; + + cache_size = info.ways * info.sets * info.linesz; + + seq_printf(m, "%s size\t: %2dKiB (%d-way)\n", + type, cache_size >> 10, info.ways); +} + +/* + * Get CPU information for use by the procfs. + */ +static int show_cpuinfo(struct seq_file *m, void *v) +{ + struct sh_cpuinfo *c = v; + unsigned int cpu = c - cpu_data; + + if (!cpu_online(cpu)) + return 0; + + if (cpu == 0) + seq_printf(m, "machine\t\t: %s\n", get_system_type()); + else + seq_printf(m, "\n"); + + seq_printf(m, "processor\t: %d\n", cpu); + seq_printf(m, "cpu family\t: %s\n", init_utsname()->machine); + seq_printf(m, "cpu type\t: %s\n", get_cpu_subtype(c)); + if (c->cut_major == -1) + seq_printf(m, "cut\t\t: unknown\n"); + else if (c->cut_minor == -1) + seq_printf(m, "cut\t\t: %d.x\n", c->cut_major); + else + seq_printf(m, "cut\t\t: %d.%d\n", c->cut_major, c->cut_minor); + + show_cpuflags(m, c); + + seq_printf(m, "cache type\t: "); + + /* + * Check for what type of cache we have, we support both the + * unified cache on the SH-2 and SH-3, as well as the harvard + * style cache on the SH-4. + */ + if (c->icache.flags & SH_CACHE_COMBINED) { + seq_printf(m, "unified\n"); + show_cacheinfo(m, "cache", c->icache); + } else { + seq_printf(m, "split (harvard)\n"); + show_cacheinfo(m, "icache", c->icache); + show_cacheinfo(m, "dcache", c->dcache); + } + + /* Optional secondary cache */ + if (c->flags & CPU_HAS_L2_CACHE) + show_cacheinfo(m, "scache", c->scache); + + seq_printf(m, "address sizes\t: %u bits physical\n", c->phys_bits); + + seq_printf(m, "bogomips\t: %lu.%02lu\n", + c->loops_per_jiffy/(500000/HZ), + (c->loops_per_jiffy/(5000/HZ)) % 100); + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < NR_CPUS ? cpu_data + *pos : NULL; +} +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} +static void c_stop(struct seq_file *m, void *v) +{ +} +const struct seq_operations cpuinfo_op = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, +}; +#endif /* CONFIG_PROC_FS */ diff --git a/arch/sh/kernel/cpu/sh2/clock-sh7619.c b/arch/sh/kernel/cpu/sh2/clock-sh7619.c index 0c9f24d7a02..5b7f12e58a8 100644 --- a/arch/sh/kernel/cpu/sh2/clock-sh7619.c +++ b/arch/sh/kernel/cpu/sh2/clock-sh7619.c @@ -14,24 +14,18 @@ */ #include <linux/init.h> #include <linux/kernel.h> +#include <linux/io.h> #include <asm/clock.h> #include <asm/freq.h> -#include <asm/io.h> +#include <asm/processor.h> static const int pll1rate[] = {1,2}; static const int pfc_divisors[] = {1,2,0,4}; - -#if (CONFIG_SH_CLK_MD == 1) || (CONFIG_SH_CLK_MD == 2) -#define PLL2 (4) -#elif (CONFIG_SH_CLK_MD == 5) || (CONFIG_SH_CLK_MD == 6) -#define PLL2 (2) -#else -#error "Illigal Clock Mode!" -#endif +static unsigned int pll2_mult; static void master_clk_init(struct clk *clk) { - clk->rate *= PLL2 * pll1rate[(__raw_readw(FREQCR) >> 8) & 7]; + clk->rate *= pll2_mult * pll1rate[(__raw_readw(FREQCR) >> 8) & 7]; } static struct clk_ops sh7619_master_clk_ops = { @@ -70,6 +64,14 @@ static struct clk_ops *sh7619_clk_ops[] = { void __init arch_init_clk_ops(struct clk_ops **ops, int idx) { + if (test_mode_pin(MODE_PIN2 | MODE_PIN0) || + test_mode_pin(MODE_PIN2 | MODE_PIN1)) + pll2_mult = 2; + else if (test_mode_pin(MODE_PIN0) || test_mode_pin(MODE_PIN1)) + pll2_mult = 4; + + BUG_ON(!pll2_mult); + if (idx < ARRAY_SIZE(sh7619_clk_ops)) *ops = sh7619_clk_ops[idx]; } diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7201.c b/arch/sh/kernel/cpu/sh2a/clock-sh7201.c index c509c40cba4..1174e2d96c0 100644 --- a/arch/sh/kernel/cpu/sh2a/clock-sh7201.c +++ b/arch/sh/kernel/cpu/sh2a/clock-sh7201.c @@ -22,19 +22,12 @@ static const int pll1rate[]={1,2,3,4,6,8}; static const int pfc_divisors[]={1,2,3,4,6,8,12}; #define ifc_divisors pfc_divisors -#if (CONFIG_SH_CLK_MD == 0) -#define PLL2 (4) -#elif (CONFIG_SH_CLK_MD == 2) -#define PLL2 (2) -#elif (CONFIG_SH_CLK_MD == 3) -#define PLL2 (1) -#else -#error "Illegal Clock Mode!" -#endif +static unsigned int pll2_mult; static void master_clk_init(struct clk *clk) { - clk->rate = 10000000 * PLL2 * pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007]; + clk->rate = 10000000 * pll2_mult * + pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007]; } static struct clk_ops sh7201_master_clk_ops = { @@ -80,6 +73,13 @@ static struct clk_ops *sh7201_clk_ops[] = { void __init arch_init_clk_ops(struct clk_ops **ops, int idx) { + if (test_mode_pin(MODE_PIN1 | MODE_PIN0)) + pll2_mult = 1; + else if (test_mode_pin(MODE_PIN1)) + pll2_mult = 2; + else + pll2_mult = 4; + if (idx < ARRAY_SIZE(sh7201_clk_ops)) *ops = sh7201_clk_ops[idx]; } diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7203.c b/arch/sh/kernel/cpu/sh2a/clock-sh7203.c index 7e75d8f7950..95a008e8b73 100644 --- a/arch/sh/kernel/cpu/sh2a/clock-sh7203.c +++ b/arch/sh/kernel/cpu/sh2a/clock-sh7203.c @@ -25,21 +25,11 @@ static const int pll1rate[]={8,12,16,0}; static const int pfc_divisors[]={1,2,3,4,6,8,12}; #define ifc_divisors pfc_divisors -#if (CONFIG_SH_CLK_MD == 0) -#define PLL2 (1) -#elif (CONFIG_SH_CLK_MD == 1) -#define PLL2 (2) -#elif (CONFIG_SH_CLK_MD == 2) -#define PLL2 (4) -#elif (CONFIG_SH_CLK_MD == 3) -#define PLL2 (4) -#else -#error "Illegal Clock Mode!" -#endif +static unsigned int pll2_mult; static void master_clk_init(struct clk *clk) { - clk->rate *= pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0003] * PLL2 ; + clk->rate *= pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0003] * pll2_mult; } static struct clk_ops sh7203_master_clk_ops = { @@ -79,6 +69,13 @@ static struct clk_ops *sh7203_clk_ops[] = { void __init arch_init_clk_ops(struct clk_ops **ops, int idx) { + if (test_mode_pin(MODE_PIN1)) + pll2_mult = 4; + else if (test_mode_pin(MODE_PIN0)) + pll2_mult = 2; + else + pll2_mult = 1; + if (idx < ARRAY_SIZE(sh7203_clk_ops)) *ops = sh7203_clk_ops[idx]; } diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7206.c b/arch/sh/kernel/cpu/sh2a/clock-sh7206.c index b27a5e2687a..3c314d7cd6e 100644 --- a/arch/sh/kernel/cpu/sh2a/clock-sh7206.c +++ b/arch/sh/kernel/cpu/sh2a/clock-sh7206.c @@ -22,19 +22,11 @@ static const int pll1rate[]={1,2,3,4,6,8}; static const int pfc_divisors[]={1,2,3,4,6,8,12}; #define ifc_divisors pfc_divisors -#if (CONFIG_SH_CLK_MD == 2) -#define PLL2 (4) -#elif (CONFIG_SH_CLK_MD == 6) -#define PLL2 (2) -#elif (CONFIG_SH_CLK_MD == 7) -#define PLL2 (1) -#else -#error "Illigal Clock Mode!" -#endif +static unsigned int pll2_mult; static void master_clk_init(struct clk *clk) { - clk->rate *= PLL2 * pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007]; + clk->rate *= pll2_mult * pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007]; } static struct clk_ops sh7206_master_clk_ops = { @@ -79,7 +71,13 @@ static struct clk_ops *sh7206_clk_ops[] = { void __init arch_init_clk_ops(struct clk_ops **ops, int idx) { + if (test_mode_pin(MODE_PIN2 | MODE_PIN1 | MODE_PIN0)) + pll2_mult = 1; + else if (test_mode_pin(MODE_PIN2 | MODE_PIN1)) + pll2_mult = 2; + else if (test_mode_pin(MODE_PIN1)) + pll2_mult = 4; + if (idx < ARRAY_SIZE(sh7206_clk_ops)) *ops = sh7206_clk_ops[idx]; } - diff --git a/arch/sh/kernel/io_generic.c b/arch/sh/kernel/io_generic.c deleted file mode 100644 index 447d78f666f..00000000000 --- a/arch/sh/kernel/io_generic.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * arch/sh/kernel/io_generic.c - * - * Copyright (C) 2000 Niibe Yutaka - * Copyright (C) 2005 - 2007 Paul Mundt - * - * Generic I/O routine. These can be used where a machine specific version - * is not required. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#include <linux/module.h> -#include <linux/io.h> -#include <asm/machvec.h> - -#ifdef CONFIG_CPU_SH3 -/* SH3 has a PCMCIA bug that needs a dummy read from area 6 for a - * workaround. */ -/* I'm not sure SH7709 has this kind of bug */ -#define dummy_read() __raw_readb(0xba000000) -#else -#define dummy_read() -#endif - -unsigned long generic_io_base = 0; - -u8 generic_inb(unsigned long port) -{ - return __raw_readb(__ioport_map(port, 1)); -} - -u16 generic_inw(unsigned long port) -{ - return __raw_readw(__ioport_map(port, 2)); -} - -u32 generic_inl(unsigned long port) -{ - return __raw_readl(__ioport_map(port, 4)); -} - -u8 generic_inb_p(unsigned long port) -{ - unsigned long v = generic_inb(port); - - ctrl_delay(); - return v; -} - -u16 generic_inw_p(unsigned long port) -{ - unsigned long v = generic_inw(port); - - ctrl_delay(); - return v; -} - -u32 generic_inl_p(unsigned long port) -{ - unsigned long v = generic_inl(port); - - ctrl_delay(); - return v; -} - -/* - * insb/w/l all read a series of bytes/words/longs from a fixed port - * address. However as the port address doesn't change we only need to - * convert the port address to real address once. - */ - -void generic_insb(unsigned long port, void *dst, unsigned long count) -{ - __raw_readsb(__ioport_map(port, 1), dst, count); - dummy_read(); -} - -void generic_insw(unsigned long port, void *dst, unsigned long count) -{ - __raw_readsw(__ioport_map(port, 2), dst, count); - dummy_read(); -} - -void generic_insl(unsigned long port, void *dst, unsigned long count) -{ - __raw_readsl(__ioport_map(port, 4), dst, count); - dummy_read(); -} - -void generic_outb(u8 b, unsigned long port) -{ - __raw_writeb(b, __ioport_map(port, 1)); -} - -void generic_outw(u16 b, unsigned long port) -{ - __raw_writew(b, __ioport_map(port, 2)); -} - -void generic_outl(u32 b, unsigned long port) -{ - __raw_writel(b, __ioport_map(port, 4)); -} - -void generic_outb_p(u8 b, unsigned long port) -{ - generic_outb(b, port); - ctrl_delay(); -} - -void generic_outw_p(u16 b, unsigned long port) -{ - generic_outw(b, port); - ctrl_delay(); -} - -void generic_outl_p(u32 b, unsigned long port) -{ - generic_outl(b, port); - ctrl_delay(); -} - -/* - * outsb/w/l all write a series of bytes/words/longs to a fixed port - * address. However as the port address doesn't change we only need to - * convert the port address to real address once. - */ -void generic_outsb(unsigned long port, const void *src, unsigned long count) -{ - __raw_writesb(__ioport_map(port, 1), src, count); - dummy_read(); -} - -void generic_outsw(unsigned long port, const void *src, unsigned long count) -{ - __raw_writesw(__ioport_map(port, 2), src, count); - dummy_read(); -} - -void generic_outsl(unsigned long port, const void *src, unsigned long count) -{ - __raw_writesl(__ioport_map(port, 4), src, count); - dummy_read(); -} - -void __iomem *generic_ioport_map(unsigned long addr, unsigned int size) -{ -#ifdef P1SEG - if (PXSEG(addr) >= P1SEG) - return (void __iomem *)addr; -#endif - - return (void __iomem *)(addr + generic_io_base); -} - -void generic_ioport_unmap(void __iomem *addr) -{ -} - -#ifndef CONFIG_GENERIC_IOMAP -void __iomem *ioport_map(unsigned long port, unsigned int nr) -{ - void __iomem *ret; - - ret = __ioport_map_trapped(port, nr); - if (ret) - return ret; - - return __ioport_map(port, nr); -} -EXPORT_SYMBOL(ioport_map); - -void ioport_unmap(void __iomem *addr) -{ - sh_mv.mv_ioport_unmap(addr); -} -EXPORT_SYMBOL(ioport_unmap); -#endif /* CONFIG_GENERIC_IOMAP */ diff --git a/arch/sh/kernel/iomap.c b/arch/sh/kernel/iomap.c new file mode 100644 index 00000000000..2e8e8b9b9ce --- /dev/null +++ b/arch/sh/kernel/iomap.c @@ -0,0 +1,165 @@ +/* + * arch/sh/kernel/iomap.c + * + * Copyright (C) 2000 Niibe Yutaka + * Copyright (C) 2005 - 2007 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/module.h> +#include <linux/io.h> + +unsigned int ioread8(void __iomem *addr) +{ + return readb(addr); +} +EXPORT_SYMBOL(ioread8); + +unsigned int ioread16(void __iomem *addr) +{ + return readw(addr); +} +EXPORT_SYMBOL(ioread16); + +unsigned int ioread16be(void __iomem *addr) +{ + return be16_to_cpu(__raw_readw(addr)); +} +EXPORT_SYMBOL(ioread16be); + +unsigned int ioread32(void __iomem *addr) +{ + return readl(addr); +} +EXPORT_SYMBOL(ioread32); + +unsigned int ioread32be(void __iomem *addr) +{ + return be32_to_cpu(__raw_readl(addr)); +} +EXPORT_SYMBOL(ioread32be); + +void iowrite8(u8 val, void __iomem *addr) +{ + writeb(val, addr); +} +EXPORT_SYMBOL(iowrite8); + +void iowrite16(u16 val, void __iomem *addr) +{ + writew(val, addr); +} +EXPORT_SYMBOL(iowrite16); + +void iowrite16be(u16 val, void __iomem *addr) +{ + __raw_writew(cpu_to_be16(val), addr); +} +EXPORT_SYMBOL(iowrite16be); + +void iowrite32(u32 val, void __iomem *addr) +{ + writel(val, addr); +} +EXPORT_SYMBOL(iowrite32); + +void iowrite32be(u32 val, void __iomem *addr) +{ + __raw_writel(cpu_to_be32(val), addr); +} +EXPORT_SYMBOL(iowrite32be); + +/* + * These are the "repeat MMIO read/write" functions. + * Note the "__raw" accesses, since we don't want to + * convert to CPU byte order. We write in "IO byte + * order" (we also don't have IO barriers). + */ +static inline void mmio_insb(void __iomem *addr, u8 *dst, int count) +{ + while (--count >= 0) { + u8 data = __raw_readb(addr); + *dst = data; + dst++; + } +} + +static inline void mmio_insw(void __iomem *addr, u16 *dst, int count) +{ + while (--count >= 0) { + u16 data = __raw_readw(addr); + *dst = data; + dst++; + } +} + +static inline void mmio_insl(void __iomem *addr, u32 *dst, int count) +{ + while (--count >= 0) { + u32 data = __raw_readl(addr); + *dst = data; + dst++; + } +} + +static inline void mmio_outsb(void __iomem *addr, const u8 *src, int count) +{ + while (--count >= 0) { + __raw_writeb(*src, addr); + src++; + } +} + +static inline void mmio_outsw(void __iomem *addr, const u16 *src, int count) +{ + while (--count >= 0) { + __raw_writew(*src, addr); + src++; + } +} + +static inline void mmio_outsl(void __iomem *addr, const u32 *src, int count) +{ + while (--count >= 0) { + __raw_writel(*src, addr); + src++; + } +} + +void ioread8_rep(void __iomem *addr, void *dst, unsigned long count) +{ + mmio_insb(addr, dst, count); +} +EXPORT_SYMBOL(ioread8_rep); + +void ioread16_rep(void __iomem *addr, void *dst, unsigned long count) +{ + mmio_insw(addr, dst, count); +} +EXPORT_SYMBOL(ioread16_rep); + +void ioread32_rep(void __iomem *addr, void *dst, unsigned long count) +{ + mmio_insl(addr, dst, count); +} +EXPORT_SYMBOL(ioread32_rep); + +void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count) +{ + mmio_outsb(addr, src, count); +} +EXPORT_SYMBOL(iowrite8_rep); + +void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count) +{ + mmio_outsw(addr, src, count); +} +EXPORT_SYMBOL(iowrite16_rep); + +void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count) +{ + mmio_outsl(addr, src, count); +} +EXPORT_SYMBOL(iowrite32_rep); diff --git a/arch/sh/kernel/ioport.c b/arch/sh/kernel/ioport.c new file mode 100644 index 00000000000..e3ad6103e7c --- /dev/null +++ b/arch/sh/kernel/ioport.c @@ -0,0 +1,43 @@ +/* + * arch/sh/kernel/ioport.c + * + * Copyright (C) 2000 Niibe Yutaka + * Copyright (C) 2005 - 2007 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/module.h> +#include <linux/io.h> + +const unsigned long sh_io_port_base __read_mostly = -1; +EXPORT_SYMBOL(sh_io_port_base); + +void __iomem *__ioport_map(unsigned long addr, unsigned int size) +{ + if (sh_mv.mv_ioport_map) + return sh_mv.mv_ioport_map(addr, size); + + return (void __iomem *)(addr + sh_io_port_base); +} +EXPORT_SYMBOL(__ioport_map); + +void __iomem *ioport_map(unsigned long port, unsigned int nr) +{ + void __iomem *ret; + + ret = __ioport_map_trapped(port, nr); + if (ret) + return ret; + + return __ioport_map(port, nr); +} +EXPORT_SYMBOL(ioport_map); + +void ioport_unmap(void __iomem *addr) +{ + if (sh_mv.mv_ioport_unmap) + sh_mv.mv_ioport_unmap(addr); +} +EXPORT_SYMBOL(ioport_unmap); diff --git a/arch/sh/kernel/machvec.c b/arch/sh/kernel/machvec.c index 9f9bb63616a..3d722e49db0 100644 --- a/arch/sh/kernel/machvec.c +++ b/arch/sh/kernel/machvec.c @@ -118,28 +118,6 @@ void __init sh_mv_setup(void) sh_mv.mv_##elem = generic_##elem; \ } while (0) -#ifdef CONFIG_HAS_IOPORT - -#ifdef P2SEG - __set_io_port_base(P2SEG); -#else - __set_io_port_base(0); -#endif - - mv_set(inb); mv_set(inw); mv_set(inl); - mv_set(outb); mv_set(outw); mv_set(outl); - - mv_set(inb_p); mv_set(inw_p); mv_set(inl_p); - mv_set(outb_p); mv_set(outw_p); mv_set(outl_p); - - mv_set(insb); mv_set(insw); mv_set(insl); - mv_set(outsb); mv_set(outsw); mv_set(outsl); - - mv_set(ioport_map); - mv_set(ioport_unmap); - -#endif - mv_set(irq_demux); mv_set(mode_pins); mv_set(mem_init); diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index d6b018c7ebd..4f267160c51 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -12,7 +12,6 @@ #include <linux/initrd.h> #include <linux/bootmem.h> #include <linux/console.h> -#include <linux/seq_file.h> #include <linux/root_dev.h> #include <linux/utsname.h> #include <linux/nodemask.h> @@ -319,146 +318,3 @@ int test_mode_pin(int pin) { return sh_mv.mv_mode_pins() & pin; } - -static const char *cpu_name[] = { - [CPU_SH7201] = "SH7201", - [CPU_SH7203] = "SH7203", [CPU_SH7263] = "SH7263", - [CPU_SH7206] = "SH7206", [CPU_SH7619] = "SH7619", - [CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706", - [CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708", - [CPU_SH7709] = "SH7709", [CPU_SH7710] = "SH7710", - [CPU_SH7712] = "SH7712", [CPU_SH7720] = "SH7720", - [CPU_SH7721] = "SH7721", [CPU_SH7729] = "SH7729", - [CPU_SH7750] = "SH7750", [CPU_SH7750S] = "SH7750S", - [CPU_SH7750R] = "SH7750R", [CPU_SH7751] = "SH7751", - [CPU_SH7751R] = "SH7751R", [CPU_SH7760] = "SH7760", - [CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501", - [CPU_SH7763] = "SH7763", [CPU_SH7770] = "SH7770", - [CPU_SH7780] = "SH7780", [CPU_SH7781] = "SH7781", - [CPU_SH7343] = "SH7343", [CPU_SH7785] = "SH7785", - [CPU_SH7786] = "SH7786", [CPU_SH7757] = "SH7757", - [CPU_SH7722] = "SH7722", [CPU_SHX3] = "SH-X3", - [CPU_SH5_101] = "SH5-101", [CPU_SH5_103] = "SH5-103", - [CPU_MXG] = "MX-G", [CPU_SH7723] = "SH7723", - [CPU_SH7366] = "SH7366", [CPU_SH7724] = "SH7724", - [CPU_SH_NONE] = "Unknown" -}; - -const char *get_cpu_subtype(struct sh_cpuinfo *c) -{ - return cpu_name[c->type]; -} -EXPORT_SYMBOL(get_cpu_subtype); - -#ifdef CONFIG_PROC_FS -/* Symbolic CPU flags, keep in sync with asm/cpu-features.h */ -static const char *cpu_flags[] = { - "none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr", - "ptea", "llsc", "l2", "op32", "pteaex", NULL -}; - -static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c) -{ - unsigned long i; - - seq_printf(m, "cpu flags\t:"); - - if (!c->flags) { - seq_printf(m, " %s\n", cpu_flags[0]); - return; - } - - for (i = 0; cpu_flags[i]; i++) - if ((c->flags & (1 << i))) - seq_printf(m, " %s", cpu_flags[i+1]); - - seq_printf(m, "\n"); -} - -static void show_cacheinfo(struct seq_file *m, const char *type, - struct cache_info info) -{ - unsigned int cache_size; - - cache_size = info.ways * info.sets * info.linesz; - - seq_printf(m, "%s size\t: %2dKiB (%d-way)\n", - type, cache_size >> 10, info.ways); -} - -/* - * Get CPU information for use by the procfs. - */ -static int show_cpuinfo(struct seq_file *m, void *v) -{ - struct sh_cpuinfo *c = v; - unsigned int cpu = c - cpu_data; - - if (!cpu_online(cpu)) - return 0; - - if (cpu == 0) - seq_printf(m, "machine\t\t: %s\n", get_system_type()); - else - seq_printf(m, "\n"); - - seq_printf(m, "processor\t: %d\n", cpu); - seq_printf(m, "cpu family\t: %s\n", init_utsname()->machine); - seq_printf(m, "cpu type\t: %s\n", get_cpu_subtype(c)); - if (c->cut_major == -1) - seq_printf(m, "cut\t\t: unknown\n"); - else if (c->cut_minor == -1) - seq_printf(m, "cut\t\t: %d.x\n", c->cut_major); - else - seq_printf(m, "cut\t\t: %d.%d\n", c->cut_major, c->cut_minor); - - show_cpuflags(m, c); - - seq_printf(m, "cache type\t: "); - - /* - * Check for what type of cache we have, we support both the - * unified cache on the SH-2 and SH-3, as well as the harvard - * style cache on the SH-4. - */ - if (c->icache.flags & SH_CACHE_COMBINED) { - seq_printf(m, "unified\n"); - show_cacheinfo(m, "cache", c->icache); - } else { - seq_printf(m, "split (harvard)\n"); - show_cacheinfo(m, "icache", c->icache); - show_cacheinfo(m, "dcache", c->dcache); - } - - /* Optional secondary cache */ - if (c->flags & CPU_HAS_L2_CACHE) - show_cacheinfo(m, "scache", c->scache); - - seq_printf(m, "address sizes\t: %u bits physical\n", c->phys_bits); - - seq_printf(m, "bogomips\t: %lu.%02lu\n", - c->loops_per_jiffy/(500000/HZ), - (c->loops_per_jiffy/(5000/HZ)) % 100); - - return 0; -} - -static void *c_start(struct seq_file *m, loff_t *pos) -{ - return *pos < NR_CPUS ? cpu_data + *pos : NULL; -} -static void *c_next(struct seq_file *m, void *v, loff_t *pos) -{ - ++*pos; - return c_start(m, pos); -} -static void c_stop(struct seq_file *m, void *v) -{ -} -const struct seq_operations cpuinfo_op = { - .start = c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, -}; -#endif /* CONFIG_PROC_FS */ diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 85ffd5e38c5..a0069c17151 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -27,7 +27,10 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/sh_dma.h> - +#include <linux/notifier.h> +#include <linux/kdebug.h> +#include <linux/spinlock.h> +#include <linux/rculist.h> #include "shdma.h" /* DMA descriptor control */ @@ -43,6 +46,13 @@ enum sh_dmae_desc_status { /* Default MEMCPY transfer size = 2^2 = 4 bytes */ #define LOG2_DEFAULT_XFER_SIZE 2 +/* + * Used for write-side mutual exclusion for the global device list, + * read-side synchronization by way of RCU. + */ +static DEFINE_SPINLOCK(sh_dmae_lock); +static LIST_HEAD(sh_dmae_devices); + /* A bitmask with bits enough for enum sh_dmae_slave_chan_id */ static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SH_DMA_SLAVE_NUMBER)]; @@ -817,10 +827,9 @@ static irqreturn_t sh_dmae_interrupt(int irq, void *data) return ret; } -#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) -static irqreturn_t sh_dmae_err(int irq, void *data) +static unsigned int sh_dmae_reset(struct sh_dmae_device *shdev) { - struct sh_dmae_device *shdev = (struct sh_dmae_device *)data; + unsigned int handled = 0; int i; /* halt the dma controller */ @@ -829,25 +838,35 @@ static irqreturn_t sh_dmae_err(int irq, void *data) /* We cannot detect, which channel caused the error, have to reset all */ for (i = 0; i < SH_DMAC_MAX_CHANNELS; i++) { struct sh_dmae_chan *sh_chan = shdev->chan[i]; - if (sh_chan) { - struct sh_desc *desc; - /* Stop the channel */ - dmae_halt(sh_chan); - /* Complete all */ - list_for_each_entry(desc, &sh_chan->ld_queue, node) { - struct dma_async_tx_descriptor *tx = &desc->async_tx; - desc->mark = DESC_IDLE; - if (tx->callback) - tx->callback(tx->callback_param); - } - list_splice_init(&sh_chan->ld_queue, &sh_chan->ld_free); + struct sh_desc *desc; + + if (!sh_chan) + continue; + + /* Stop the channel */ + dmae_halt(sh_chan); + + /* Complete all */ + list_for_each_entry(desc, &sh_chan->ld_queue, node) { + struct dma_async_tx_descriptor *tx = &desc->async_tx; + desc->mark = DESC_IDLE; + if (tx->callback) + tx->callback(tx->callback_param); } + + list_splice_init(&sh_chan->ld_queue, &sh_chan->ld_free); + handled++; } + sh_dmae_rst(shdev); - return IRQ_HANDLED; + return !!handled; +} + +static irqreturn_t sh_dmae_err(int irq, void *data) +{ + return IRQ_RETVAL(sh_dmae_reset(data)); } -#endif static void dmae_do_tasklet(unsigned long data) { @@ -876,6 +895,60 @@ static void dmae_do_tasklet(unsigned long data) sh_dmae_chan_ld_cleanup(sh_chan, false); } +static bool sh_dmae_nmi_notify(struct sh_dmae_device *shdev) +{ + unsigned int handled; + + /* Fast path out if NMIF is not asserted for this controller */ + if ((dmaor_read(shdev) & DMAOR_NMIF) == 0) + return false; + + handled = sh_dmae_reset(shdev); + if (handled) + return true; + + return false; +} + +static int sh_dmae_nmi_handler(struct notifier_block *self, + unsigned long cmd, void *data) +{ + struct sh_dmae_device *shdev; + int ret = NOTIFY_DONE; + bool triggered; + + /* + * Only concern ourselves with NMI events. + * + * Normally we would check the die chain value, but as this needs + * to be architecture independent, check for NMI context instead. + */ + if (!in_nmi()) + return NOTIFY_DONE; + + rcu_read_lock(); + list_for_each_entry_rcu(shdev, &sh_dmae_devices, node) { + /* + * Only stop if one of the controllers has NMIF asserted, + * we do not want to interfere with regular address error + * handling or NMI events that don't concern the DMACs. + */ + triggered = sh_dmae_nmi_notify(shdev); + if (triggered == true) + ret = NOTIFY_OK; + } + rcu_read_unlock(); + + return ret; +} + +static struct notifier_block sh_dmae_nmi_notifier __read_mostly = { + .notifier_call = sh_dmae_nmi_handler, + + /* Run before NMI debug handler and KGDB */ + .priority = 1, +}; + static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id, int irq, unsigned long flags) { @@ -967,6 +1040,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev) struct sh_dmae_pdata *pdata = pdev->dev.platform_data; unsigned long irqflags = IRQF_DISABLED, chan_flag[SH_DMAC_MAX_CHANNELS] = {}; + unsigned long flags; int errirq, chan_irq[SH_DMAC_MAX_CHANNELS]; int err, i, irq_cnt = 0, irqres = 0; struct sh_dmae_device *shdev; @@ -1032,6 +1106,15 @@ static int __init sh_dmae_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); + spin_lock_irqsave(&sh_dmae_lock, flags); + list_add_tail_rcu(&shdev->node, &sh_dmae_devices); + spin_unlock_irqrestore(&sh_dmae_lock, flags); + + /* Wire up NMI handling before bringing the controller online */ + err = register_die_notifier(&sh_dmae_nmi_notifier); + if (err) + goto notifier_err; + /* reset dma controller */ err = sh_dmae_rst(shdev); if (err) @@ -1135,6 +1218,12 @@ eirqres: eirq_err: #endif rst_err: + unregister_die_notifier(&sh_dmae_nmi_notifier); +notifier_err: + spin_lock_irqsave(&sh_dmae_lock, flags); + list_del_rcu(&shdev->node); + spin_unlock_irqrestore(&sh_dmae_lock, flags); + pm_runtime_put(&pdev->dev); if (dmars) iounmap(shdev->dmars); @@ -1155,6 +1244,7 @@ static int __exit sh_dmae_remove(struct platform_device *pdev) { struct sh_dmae_device *shdev = platform_get_drvdata(pdev); struct resource *res; + unsigned long flags; int errirq = platform_get_irq(pdev, 0); dma_async_device_unregister(&shdev->common); @@ -1162,6 +1252,12 @@ static int __exit sh_dmae_remove(struct platform_device *pdev) if (errirq > 0) free_irq(errirq, shdev); + unregister_die_notifier(&sh_dmae_nmi_notifier); + + spin_lock_irqsave(&sh_dmae_lock, flags); + list_del_rcu(&shdev->node); + spin_unlock_irqrestore(&sh_dmae_lock, flags); + /* channel data remove */ sh_dmae_chan_remove(shdev); diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h index 4021275a0a4..52e4fb17380 100644 --- a/drivers/dma/shdma.h +++ b/drivers/dma/shdma.h @@ -43,6 +43,7 @@ struct sh_dmae_device { struct dma_device common; struct sh_dmae_chan *chan[SH_DMAC_MAX_CHANNELS]; struct sh_dmae_pdata *pdata; + struct list_head node; u32 __iomem *chan_reg; u16 __iomem *dmars; }; |