diff options
58 files changed, 1680 insertions, 1141 deletions
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 16f60b41c147..6e3e3e5c611f 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -61,8 +61,8 @@ RAMC SDRAM/DDR Controller required properties: - compatible: Should be "atmel,at91rm9200-sdramc", "atmel,at91sam9260-sdramc", "atmel,at91sam9g45-ddramc", + "atmel,sama5d3-ddramc", - reg: Should contain registers location and length - For at91sam9263 and at91sam9g45 you must specify 2 entries. Examples: @@ -71,12 +71,6 @@ Examples: reg = <0xffffe800 0x200>; }; - ramc0: ramc@ffffe400 { - compatible = "atmel,at91sam9g45-ddramc"; - reg = <0xffffe400 0x200 - 0xffffe600 0x200>; - }; - SHDWC Shutdown Controller required properties: diff --git a/MAINTAINERS b/MAINTAINERS index cf24bb56bab9..93e6a92a951d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1381,6 +1381,11 @@ M: Dinh Nguyen <dinguyen@altera.com> S: Maintained F: drivers/clk/socfpga/ +ARM/SOCFPGA EDAC SUPPORT +M: Thor Thayer <tthayer@opensource.altera.com> +S: Maintained +F: drivers/edac/altera_edac. + ARM/STI ARCHITECTURE M: Srinivas Kandagatla <srinivas.kandagatla@gmail.com> M: Maxime Coquelin <maxime.coquelin@st.com> diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi index bb23c2d33cf8..840958ba556c 100644 --- a/arch/arm/boot/dts/at91sam9263.dtsi +++ b/arch/arm/boot/dts/at91sam9263.dtsi @@ -345,10 +345,14 @@ }; }; - ramc: ramc@ffffe200 { + ramc0: ramc@ffffe200 { compatible = "atmel,at91sam9260-sdramc"; - reg = <0xffffe200 0x200 - 0xffffe800 0x200>; + reg = <0xffffe200 0x200>; + }; + + ramc1: ramc@ffffe800 { + compatible = "atmel,at91sam9260-sdramc"; + reg = <0xffffe800 0x200>; }; pit: timer@fffffd30 { diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index 932a669156af..857fd3e0b8a0 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -96,8 +96,14 @@ ramc0: ramc@ffffe400 { compatible = "atmel,at91sam9g45-ddramc"; - reg = <0xffffe400 0x200 - 0xffffe600 0x200>; + reg = <0xffffe400 0x200>; + clocks = <&ddrck>; + clock-names = "ddrck"; + }; + + ramc1: ramc@ffffe600 { + compatible = "atmel,at91sam9g45-ddramc"; + reg = <0xffffe600 0x200>; clocks = <&ddrck>; clock-names = "ddrck"; }; diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi index 2bfac310dbec..68eb9aded164 100644 --- a/arch/arm/boot/dts/at91sam9n12.dtsi +++ b/arch/arm/boot/dts/at91sam9n12.dtsi @@ -87,6 +87,8 @@ ramc0: ramc@ffffe800 { compatible = "atmel,at91sam9g45-ddramc"; reg = <0xffffe800 0x200>; + clocks = <&ddrck>; + clock-names = "ddrck"; }; pmc: pmc@fffffc00 { diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index e1a5c70b885c..765a1e39858e 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -95,6 +95,8 @@ ramc0: ramc@ffffe800 { compatible = "atmel,at91sam9g45-ddramc"; reg = <0xffffe800 0x200>; + clocks = <&ddrck>; + clock-names = "ddrck"; }; pmc: pmc@fffffc00 { diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 45013b867c8d..7702a0d120cb 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -402,8 +402,10 @@ }; ramc0: ramc@ffffea00 { - compatible = "atmel,at91sam9g45-ddramc"; + compatible = "atmel,sama5d3-ddramc"; reg = <0xffffea00 0x200>; + clocks = <&ddrck>, <&mpddr_clk>; + clock-names = "ddrck", "mpddr"; }; dbgu: serial@ffffee00 { @@ -1170,6 +1172,11 @@ #clock-cells = <0>; reg = <48>; }; + + mpddr_clk: mpddr_clk { + #clock-cells = <0>; + reg = <49>; + }; }; }; @@ -1178,6 +1185,11 @@ reg = <0xfffffe00 0x10>; }; + shutdown-controller@fffffe10 { + compatible = "atmel,at91sam9x5-shdwc"; + reg = <0xfffffe10 0x10>; + }; + pit: timer@fffffe30 { compatible = "atmel,at91sam9260-pit"; reg = <0xfffffe30 0xf>; diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 6cc6f7aebdae..474c855fa83c 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -28,36 +28,30 @@ config OLD_CLK_AT91 bool default AT91_PMC_UNIT && AT91_USE_OLD_CLK -config AT91_SAM9_ALT_RESET - bool - default !ARCH_AT91X40 - -config AT91_SAM9G45_RESET - bool - default !ARCH_AT91X40 - -config AT91_SAM9_TIME +config OLD_IRQ_AT91 bool + select MULTI_IRQ_HANDLER + select SPARSE_IRQ config HAVE_AT91_SMD bool config SOC_AT91SAM9 bool - select AT91_SAM9_TIME + select ATMEL_AIC_IRQ if !OLD_IRQ_AT91 select CPU_ARM926T select GENERIC_CLOCKEVENTS - select MULTI_IRQ_HANDLER - select SPARSE_IRQ + select MEMORY if USE_OF + select ATMEL_SDRAMC if USE_OF config SOC_SAMA5 bool - select AT91_SAM9_TIME + select ATMEL_AIC5_IRQ select CPU_V7 select GENERIC_CLOCKEVENTS - select MULTI_IRQ_HANDLER - select SPARSE_IRQ select USE_OF + select MEMORY + select ATMEL_SDRAMC menu "Atmel AT91 System-on-Chip" @@ -70,8 +64,7 @@ config ARCH_AT91X40 depends on !MMU select CPU_ARM7TDMI select ARCH_USES_GETTIMEOFFSET - select MULTI_IRQ_HANDLER - select SPARSE_IRQ + select OLD_IRQ_AT91 help Select this if you are using one of Atmel's AT91X40 SoC. @@ -108,11 +101,10 @@ endif if SOC_SAM_V4_V5 config SOC_AT91RM9200 bool "AT91RM9200" + select ATMEL_AIC_IRQ if !OLD_IRQ_AT91 select CPU_ARM920T select GENERIC_CLOCKEVENTS select HAVE_AT91_DBGU0 - select MULTI_IRQ_HANDLER - select SPARSE_IRQ select HAVE_AT91_USB_CLK config SOC_AT91SAM9260 diff --git a/arch/arm/mach-at91/Kconfig.non_dt b/arch/arm/mach-at91/Kconfig.non_dt index 44ace320d2e1..b774c3d3c632 100644 --- a/arch/arm/mach-at91/Kconfig.non_dt +++ b/arch/arm/mach-at91/Kconfig.non_dt @@ -14,31 +14,37 @@ config ARCH_AT91RM9200 bool "AT91RM9200" select SOC_AT91RM9200 select AT91_USE_OLD_CLK + select OLD_IRQ_AT91 config ARCH_AT91SAM9260 bool "AT91SAM9260 or AT91SAM9XE or AT91SAM9G20" select SOC_AT91SAM9260 select AT91_USE_OLD_CLK + select OLD_IRQ_AT91 config ARCH_AT91SAM9261 bool "AT91SAM9261 or AT91SAM9G10" select SOC_AT91SAM9261 select AT91_USE_OLD_CLK + select OLD_IRQ_AT91 config ARCH_AT91SAM9263 bool "AT91SAM9263" select SOC_AT91SAM9263 select AT91_USE_OLD_CLK + select OLD_IRQ_AT91 config ARCH_AT91SAM9RL bool "AT91SAM9RL" select SOC_AT91SAM9RL select AT91_USE_OLD_CLK + select OLD_IRQ_AT91 config ARCH_AT91SAM9G45 bool "AT91SAM9G45" select SOC_AT91SAM9G45 select AT91_USE_OLD_CLK + select OLD_IRQ_AT91 endchoice diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index 78e9cec282f4..61d04f9314e7 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -2,15 +2,13 @@ # Makefile for the linux kernel. # -obj-y := irq.o gpio.o setup.o sysirq_mask.o +obj-y := gpio.o setup.o sysirq_mask.o obj-m := obj-n := obj- := +obj-$(CONFIG_OLD_IRQ_AT91) += irq.o obj-$(CONFIG_OLD_CLK_AT91) += clock.o -obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o -obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o -obj-$(CONFIG_AT91_SAM9_TIME) += at91sam926x_time.o obj-$(CONFIG_SOC_AT91SAM9) += sam9_smc.o # CPU-specific support diff --git a/arch/arm/mach-at91/at91_rstc.h b/arch/arm/mach-at91/at91_rstc.h deleted file mode 100644 index a600e6992920..000000000000 --- a/arch/arm/mach-at91/at91_rstc.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * arch/arm/mach-at91/include/mach/at91_rstc.h - * - * Copyright (C) 2007 Andrew Victor - * Copyright (C) 2007 Atmel Corporation. - * - * Reset Controller (RSTC) - System peripherals regsters. - * Based on AT91SAM9261 datasheet revision D. - * - * 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. - */ - -#ifndef AT91_RSTC_H -#define AT91_RSTC_H - -#ifndef __ASSEMBLY__ -extern void __iomem *at91_rstc_base; - -#define at91_rstc_read(field) \ - __raw_readl(at91_rstc_base + field) - -#define at91_rstc_write(field, value) \ - __raw_writel(value, at91_rstc_base + field) -#else -.extern at91_rstc_base -#endif - -#define AT91_RSTC_CR 0x00 /* Reset Controller Control Register */ -#define AT91_RSTC_PROCRST (1 << 0) /* Processor Reset */ -#define AT91_RSTC_PERRST (1 << 2) /* Peripheral Reset */ -#define AT91_RSTC_EXTRST (1 << 3) /* External Reset */ -#define AT91_RSTC_KEY (0xa5 << 24) /* KEY Password */ - -#define AT91_RSTC_SR 0x04 /* Reset Controller Status Register */ -#define AT91_RSTC_URSTS (1 << 0) /* User Reset Status */ -#define AT91_RSTC_RSTTYP (7 << 8) /* Reset Type */ -#define AT91_RSTC_RSTTYP_GENERAL (0 << 8) -#define AT91_RSTC_RSTTYP_WAKEUP (1 << 8) -#define AT91_RSTC_RSTTYP_WATCHDOG (2 << 8) -#define AT91_RSTC_RSTTYP_SOFTWARE (3 << 8) -#define AT91_RSTC_RSTTYP_USER (4 << 8) -#define AT91_RSTC_NRSTL (1 << 16) /* NRST Pin Level */ -#define AT91_RSTC_SRCMP (1 << 17) /* Software Reset Command in Progress */ - -#define AT91_RSTC_MR 0x08 /* Reset Controller Mode Register */ -#define AT91_RSTC_URSTEN (1 << 0) /* User Reset Enable */ -#define AT91_RSTC_URSTIEN (1 << 4) /* User Reset Interrupt Enable */ -#define AT91_RSTC_ERSTL (0xf << 8) /* External Reset Length */ - -#endif diff --git a/arch/arm/mach-at91/at91_shdwc.h b/arch/arm/mach-at91/at91_shdwc.h deleted file mode 100644 index 9e29f31ec9a6..000000000000 --- a/arch/arm/mach-at91/at91_shdwc.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * arch/arm/mach-at91/include/mach/at91_shdwc.h - * - * Copyright (C) 2007 Andrew Victor - * Copyright (C) 2007 Atmel Corporation. - * - * Shutdown Controller (SHDWC) - System peripherals regsters. - * Based on AT91SAM9261 datasheet revision D. - * - * 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. - */ - -#ifndef AT91_SHDWC_H -#define AT91_SHDWC_H - -#ifndef __ASSEMBLY__ -extern void __iomem *at91_shdwc_base; - -#define at91_shdwc_read(field) \ - __raw_readl(at91_shdwc_base + field) - -#define at91_shdwc_write(field, value) \ - __raw_writel(value, at91_shdwc_base + field) -#endif - -#define AT91_SHDW_CR 0x00 /* Shut Down Control Register */ -#define AT91_SHDW_SHDW (1 << 0) /* Shut Down command */ -#define AT91_SHDW_KEY (0xa5 << 24) /* KEY Password */ - -#define AT91_SHDW_MR 0x04 /* Shut Down Mode Register */ -#define AT91_SHDW_WKMODE0 (3 << 0) /* Wake-up 0 Mode Selection */ -#define AT91_SHDW_WKMODE0_NONE 0 -#define AT91_SHDW_WKMODE0_HIGH 1 -#define AT91_SHDW_WKMODE0_LOW 2 -#define AT91_SHDW_WKMODE0_ANYLEVEL 3 -#define AT91_SHDW_CPTWK0_MAX 0xf /* Maximum Counter On Wake Up 0 */ -#define AT91_SHDW_CPTWK0 (AT91_SHDW_CPTWK0_MAX << 4) /* Counter On Wake Up 0 */ -#define AT91_SHDW_CPTWK0_(x) ((x) << 4) -#define AT91_SHDW_RTTWKEN (1 << 16) /* Real Time Timer Wake-up Enable */ -#define AT91_SHDW_RTCWKEN (1 << 17) /* Real Time Clock Wake-up Enable */ - -#define AT91_SHDW_SR 0x08 /* Shut Down Status Register */ -#define AT91_SHDW_WAKEUP0 (1 << 0) /* Wake-up 0 Status */ -#define AT91_SHDW_RTTWK (1 << 16) /* Real-time Timer Wake-up */ -#define AT91_SHDW_RTCWK (1 << 17) /* Real-time Clock Wake-up [SAM9RL] */ - -#endif diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index 3477ba94c4c5..aab1f969a7c3 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -11,6 +11,7 @@ */ #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/clk/at91_pmc.h> #include <asm/proc-fns.h> @@ -24,7 +25,6 @@ #include <mach/hardware.h> #include "at91_aic.h" -#include "at91_rstc.h" #include "soc.h" #include "generic.h" #include "sam9_smc.h" @@ -342,8 +342,6 @@ static void __init at91sam9260_map_io(void) static void __init at91sam9260_ioremap_registers(void) { - at91_ioremap_shdwc(AT91SAM9260_BASE_SHDWC); - at91_ioremap_rstc(AT91SAM9260_BASE_RSTC); at91_ioremap_ramc(0, AT91SAM9260_BASE_SDRAMC, 512); at91sam926x_ioremap_pit(AT91SAM9260_BASE_PIT); at91sam9_ioremap_smc(0, AT91SAM9260_BASE_SMC); @@ -354,7 +352,6 @@ static void __init at91sam9260_ioremap_registers(void) static void __init at91sam9260_initialize(void) { arm_pm_idle = at91sam9_idle; - arm_pm_restart = at91sam9_alt_restart; at91_sysirq_mask_rtt(AT91SAM9260_BASE_RTT); @@ -362,6 +359,45 @@ static void __init at91sam9260_initialize(void) at91_gpio_init(at91sam9260_gpio, 3); } +static struct resource rstc_resources[] = { + [0] = { + .start = AT91SAM9260_BASE_RSTC, + .end = AT91SAM9260_BASE_RSTC + SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9260_BASE_SDRAMC, + .end = AT91SAM9260_BASE_SDRAMC + SZ_512 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device rstc_device = { + .name = "at91-sam9260-reset", + .resource = rstc_resources, + .num_resources = ARRAY_SIZE(rstc_resources), +}; + +static struct resource shdwc_resources[] = { + [0] = { + .start = AT91SAM9260_BASE_SHDWC, + .end = AT91SAM9260_BASE_SHDWC + SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device shdwc_device = { + .name = "at91-poweroff", + .resource = shdwc_resources, + .num_resources = ARRAY_SIZE(shdwc_resources), +}; + +static void __init at91sam9260_register_devices(void) +{ + platform_device_register(&rstc_device); + platform_device_register(&shdwc_device); +} + /* -------------------------------------------------------------------- * Interrupt initialization * -------------------------------------------------------------------- */ @@ -404,6 +440,11 @@ static unsigned int at91sam9260_default_irq_priority[NR_AIC_IRQS] __initdata = { 0, /* Advanced Interrupt Controller */ }; +static void __init at91sam9260_init_time(void) +{ + at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS); +} + AT91_SOC_START(at91sam9260) .map_io = at91sam9260_map_io, .default_irq_priority = at91sam9260_default_irq_priority, @@ -411,5 +452,7 @@ AT91_SOC_START(at91sam9260) | (1 << AT91SAM9260_ID_IRQ2), .ioremap_registers = at91sam9260_ioremap_registers, .register_clocks = at91sam9260_register_clocks, + .register_devices = at91sam9260_register_devices, .init = at91sam9260_initialize, + .init_time = at91sam9260_init_time, AT91_SOC_END diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index fb164a5d04a9..a8bd35963332 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -11,6 +11,7 @@ */ #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/clk/at91_pmc.h> #include <asm/proc-fns.h> @@ -23,7 +24,6 @@ #include <mach/hardware.h> #include "at91_aic.h" -#include "at91_rstc.h" #include "soc.h" #include "generic.h" #include "sam9_smc.h" @@ -301,8 +301,6 @@ static void __init at91sam9261_map_io(void) static void __init at91sam9261_ioremap_registers(void) { - at91_ioremap_shdwc(AT91SAM9261_BASE_SHDWC); - at91_ioremap_rstc(AT91SAM9261_BASE_RSTC); at91_ioremap_ramc(0, AT91SAM9261_BASE_SDRAMC, 512); at91sam926x_ioremap_pit(AT91SAM9261_BASE_PIT); at91sam9_ioremap_smc(0, AT91SAM9261_BASE_SMC); @@ -313,7 +311,6 @@ static void __init at91sam9261_ioremap_registers(void) static void __init at91sam9261_initialize(void) { arm_pm_idle = at91sam9_idle; - arm_pm_restart = at91sam9_alt_restart; at91_sysirq_mask_rtt(AT91SAM9261_BASE_RTT); @@ -321,6 +318,45 @@ static void __init at91sam9261_initialize(void) at91_gpio_init(at91sam9261_gpio, 3); } +static struct resource rstc_resources[] = { + [0] = { + .start = AT91SAM9261_BASE_RSTC, + .end = AT91SAM9261_BASE_RSTC + SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9261_BASE_SDRAMC, + .end = AT91SAM9261_BASE_SDRAMC + SZ_512 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device rstc_device = { + .name = "at91-sam9260-reset", + .resource = rstc_resources, + .num_resources = ARRAY_SIZE(rstc_resources), +}; + +static struct resource shdwc_resources[] = { + [0] = { + .start = AT91SAM9261_BASE_SHDWC, + .end = AT91SAM9261_BASE_SHDWC + SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device shdwc_device = { + .name = "at91-poweroff", + .resource = shdwc_resources, + .num_resources = ARRAY_SIZE(shdwc_resources), +}; + +static void __init at91sam9261_register_devices(void) +{ + platform_device_register(&rstc_device); + platform_device_register(&shdwc_device); +} + /* -------------------------------------------------------------------- * Interrupt initialization * -------------------------------------------------------------------- */ @@ -363,6 +399,11 @@ static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = { 0, /* Advanced Interrupt Controller */ }; +static void __init at91sam9261_init_time(void) +{ + at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS); +} + AT91_SOC_START(at91sam9261) .map_io = at91sam9261_map_io, .default_irq_priority = at91sam9261_default_irq_priority, @@ -370,5 +411,7 @@ AT91_SOC_START(at91sam9261) | (1 << AT91SAM9261_ID_IRQ2), .ioremap_registers = at91sam9261_ioremap_registers, .register_clocks = at91sam9261_register_clocks, + .register_devices = at91sam9261_register_devices, .init = at91sam9261_initialize, + .init_time = at91sam9261_init_time, AT91_SOC_END diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 810fa5f15a51..fbff228cc63e 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -11,6 +11,7 @@ */ #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/clk/at91_pmc.h> #include <asm/proc-fns.h> @@ -22,7 +23,6 @@ #include <mach/hardware.h> #include "at91_aic.h" -#include "at91_rstc.h" #include "soc.h" #include "generic.h" #include "sam9_smc.h" @@ -321,8 +321,6 @@ static void __init at91sam9263_map_io(void) static void __init at91sam9263_ioremap_registers(void) { - at91_ioremap_shdwc(AT91SAM9263_BASE_SHDWC); - at91_ioremap_rstc(AT91SAM9263_BASE_RSTC); at91_ioremap_ramc(0, AT91SAM9263_BASE_SDRAMC0, 512); at91_ioremap_ramc(1, AT91SAM9263_BASE_SDRAMC1, 512); at91sam926x_ioremap_pit(AT91SAM9263_BASE_PIT); @@ -335,7 +333,6 @@ static void __init at91sam9263_ioremap_registers(void) static void __init at91sam9263_initialize(void) { arm_pm_idle = at91sam9_idle; - arm_pm_restart = at91sam9_alt_restart; at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT0); at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT1); @@ -344,6 +341,45 @@ static void __init at91sam9263_initialize(void) at91_gpio_init(at91sam9263_gpio, 5); } +static struct resource rstc_resources[] = { + [0] = { + .start = AT91SAM9263_BASE_RSTC, + .end = AT91SAM9263_BASE_RSTC + SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9263_BASE_SDRAMC0, + .end = AT91SAM9263_BASE_SDRAMC0 + SZ_512 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device rstc_device = { + .name = "at91-sam9260-reset", + .resource = rstc_resources, + .num_resources = ARRAY_SIZE(rstc_resources), +}; + +static struct resource shdwc_resources[] = { + [0] = { + .start = AT91SAM9263_BASE_SHDWC, + .end = AT91SAM9263_BASE_SHDWC + SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device shdwc_device = { + .name = "at91-poweroff", + .resource = shdwc_resources, + .num_resources = ARRAY_SIZE(shdwc_resources), +}; + +static void __init at91sam9263_register_devices(void) +{ + platform_device_register(&rstc_device); + platform_device_register(&shdwc_device); +} + /* -------------------------------------------------------------------- * Interrupt initialization * -------------------------------------------------------------------- */ @@ -386,11 +422,18 @@ static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = { 0, /* Advanced Interrupt Controller (IRQ1) */ }; +static void __init at91sam9263_init_time(void) +{ + at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS); +} + AT91_SOC_START(at91sam9263) .map_io = at91sam9263_map_io, .default_irq_priority = at91sam9263_default_irq_priority, .extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1), .ioremap_registers = at91sam9263_ioremap_registers, .register_clocks = at91sam9263_register_clocks, + .register_devices = at91sam9263_register_devices, .init = at91sam9263_initialize, + .init_time = at91sam9263_init_time, AT91_SOC_END diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c deleted file mode 100644 index 0a9e2fc8f796..000000000000 --- a/arch/arm/mach-at91/at91sam926x_time.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * at91sam926x_time.c - Periodic Interval Timer (PIT) for at91sam926x - * - * Copyright (C) 2005-2006 M. Amine SAYA, ATMEL Rousset, France - * Revision 2005 M. Nicolas Diremdjian, ATMEL Rousset, France - * Converted to ClockSource/ClockEvents by David Brownell. - * - * 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/interrupt.h> -#include <linux/irq.h> -#include <linux/kernel.h> -#include <linux/clk.h> -#include <linux/clockchips.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> - -#include <asm/mach/time.h> -#include <mach/hardware.h> - -#define AT91_PIT_MR 0x00 /* Mode Register */ -#define AT91_PIT_PITIEN (1 << 25) /* Timer Interrupt Enable */ -#define AT91_PIT_PITEN (1 << 24) /* Timer Enabled */ -#define AT91_PIT_PIV (0xfffff) /* Periodic Interval Value */ - -#define AT91_PIT_SR 0x04 /* Status Register */ -#define AT91_PIT_PITS (1 << 0) /* Timer Status */ - -#define AT91_PIT_PIVR 0x08 /* Periodic Interval Value Register */ -#define AT91_PIT_PIIR 0x0c /* Periodic Interval Image Register */ -#define AT91_PIT_PICNT (0xfff << 20) /* Interval Counter */ -#define AT91_PIT_CPIV (0xfffff) /* Inverval Value */ - -#define PIT_CPIV(x) ((x) & AT91_PIT_CPIV) -#define PIT_PICNT(x) (((x) & AT91_PIT_PICNT) >> 20) - -static u32 pit_cycle; /* write-once */ -static u32 pit_cnt; /* access only w/system irq blocked */ -static void __iomem *pit_base_addr __read_mostly; -static struct clk *mck; - -static inline unsigned int pit_read(unsigned int reg_offset) -{ - return __raw_readl(pit_base_addr + reg_offset); -} - -static inline void pit_write(unsigned int reg_offset, unsigned long value) -{ - __raw_writel(value, pit_base_addr + reg_offset); -} - -/* - * Clocksource: just a monotonic counter of MCK/16 cycles. - * We don't care whether or not PIT irqs are enabled. - */ -static cycle_t read_pit_clk(struct clocksource *cs) -{ - unsigned long flags; - u32 elapsed; - u32 t; - - raw_local_irq_save(flags); - elapsed = pit_cnt; - t = pit_read(AT91_PIT_PIIR); - raw_local_irq_restore(flags); - - elapsed += PIT_PICNT(t) * pit_cycle; - elapsed += PIT_CPIV(t); - return elapsed; -} - -static struct clocksource pit_clk = { - .name = "pit", - .rating = 175, - .read = read_pit_clk, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - - -/* - * Clockevent device: interrupts every 1/HZ (== pit_cycles * MCK/16) - */ -static void -pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) -{ - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* update clocksource counter */ - pit_cnt += pit_cycle * PIT_PICNT(pit_read(AT91_PIT_PIVR)); - pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN - | AT91_PIT_PITIEN); - break; - case CLOCK_EVT_MODE_ONESHOT: - BUG(); - /* FALLTHROUGH */ - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - /* disable irq, leaving the clocksource active */ - pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN); - break; - case CLOCK_EVT_MODE_RESUME: - break; - } -} - -static void at91sam926x_pit_suspend(struct clock_event_device *cedev) -{ - /* Disable timer */ - pit_write(AT91_PIT_MR, 0); -} - -static void at91sam926x_pit_reset(void) -{ - /* Disable timer and irqs */ - pit_write(AT91_PIT_MR, 0); - - /* Clear any pending interrupts, wait for PIT to stop counting */ - while (PIT_CPIV(pit_read(AT91_PIT_PIVR)) != 0) - cpu_relax(); - - /* Start PIT but don't enable IRQ */ - pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN); -} - -static void at91sam926x_pit_resume(struct clock_event_device *cedev) -{ - at91sam926x_pit_reset(); -} - -static struct clock_event_device pit_clkevt = { - .name = "pit", - .features = CLOCK_EVT_FEAT_PERIODIC, - .shift = 32, - .rating = 100, - .set_mode = pit_clkevt_mode, - .suspend = at91sam926x_pit_suspend, - .resume = at91sam926x_pit_resume, -}; - - -/* - * IRQ handler for the timer. - */ -static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id) -{ - /* - * irqs should be disabled here, but as the irq is shared they are only - * guaranteed to be off if the timer irq is registered first. - */ - WARN_ON_ONCE(!irqs_disabled()); - - /* The PIT interrupt may be disabled, and is shared */ - if ((pit_clkevt.mode == CLOCK_EVT_MODE_PERIODIC) - && (pit_read(AT91_PIT_SR) & AT91_PIT_PITS)) { - unsigned nr_ticks; - - /* Get number of ticks performed before irq, and ack it */ - nr_ticks = PIT_PICNT(pit_read(AT91_PIT_PIVR)); - do { - pit_cnt += pit_cycle; - pit_clkevt.event_handler(&pit_clkevt); - nr_ticks--; - } while (nr_ticks); - - return IRQ_HANDLED; - } - - return IRQ_NONE; -} - -static struct irqaction at91sam926x_pit_irq = { - .name = "at91_tick", - .flags = IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL, - .handler = at91sam926x_pit_interrupt, - .irq = NR_IRQS_LEGACY + AT91_ID_SYS, -}; - -#ifdef CONFIG_OF -static struct of_device_id pit_timer_ids[] = { - { .compatible = "atmel,at91sam9260-pit" }, - { /* sentinel */ } -}; - -static int __init of_at91sam926x_pit_init(void) -{ - struct device_node *np; - int ret; - - np = of_find_matching_node(NULL, pit_timer_ids); - if (!np) - goto err; - - pit_base_addr = of_iomap(np, 0); - if (!pit_base_addr) - goto node_err; - - mck = of_clk_get(np, 0); - - /* Get the interrupts property */ - ret = irq_of_parse_and_map(np, 0); - if (!ret) { - pr_crit("AT91: PIT: Unable to get IRQ from DT\n"); - if (!IS_ERR(mck)) - clk_put(mck); - goto ioremap_err; - } - at91sam926x_pit_irq.irq = ret; - - of_node_put(np); - - return 0; - -ioremap_err: - iounmap(pit_base_addr); -node_err: - of_node_put(np); -err: - return -EINVAL; -} -#else -static int __init of_at91sam926x_pit_init(void) -{ - return -EINVAL; -} -#endif - -/* - * Set up both clocksource and clockevent support. - */ -void __init at91sam926x_pit_init(void) -{ - unsigned long pit_rate; - unsigned bits; - int ret; - - mck = ERR_PTR(-ENOENT); - - /* For device tree enabled device: initialize here */ - of_at91sam926x_pit_init(); - - /* - * Use our actual MCK to figure out how many MCK/16 ticks per - * 1/HZ period (instead of a compile-time constant LATCH). - */ - if (IS_ERR(mck)) - mck = clk_get(NULL, "mck"); - - if (IS_ERR(mck)) - panic("AT91: PIT: Unable to get mck clk\n"); - pit_rate = clk_get_rate(mck) / 16; - pit_cycle = (pit_rate + HZ/2) / HZ; - WARN_ON(((pit_cycle - 1) & ~AT91_PIT_PIV) != 0); - - /* Initialize and enable the timer */ - at91sam926x_pit_reset(); - - /* - * Register clocksource. The high order bits of PIV are unused, - * so this isn't a 32-bit counter unless we get clockevent irqs. - */ - bits = 12 /* PICNT */ + ilog2(pit_cycle) /* PIV */; - pit_clk.mask = CLOCKSOURCE_MASK(bits); - clocksource_register_hz(&pit_clk, pit_rate); - - /* Set up irq handler */ - ret = setup_irq(at91sam926x_pit_irq.irq, &at91sam926x_pit_irq); - if (ret) - pr_crit("AT91: PIT: Unable to setup IRQ\n"); - - /* Set up and register clockevents */ - pit_clkevt.mult = div_sc(pit_rate, NSEC_PER_SEC, pit_clkevt.shift); - pit_clkevt.cpumask = cpumask_of(0); - clockevents_register_device(&pit_clkevt); -} - -void __init at91sam926x_ioremap_pit(u32 addr) -{ -#if defined(CONFIG_OF) - struct device_node *np = - of_find_matching_node(NULL, pit_timer_ids); - - if (np) { - of_node_put(np); - return; - } -#endif - pit_base_addr = ioremap(addr, 16); - - if (!pit_base_addr) - panic("Impossible to ioremap PIT\n"); -} diff --git a/arch/arm/mach-at91/at91sam9_alt_reset.S b/arch/arm/mach-at91/at91sam9_alt_reset.S deleted file mode 100644 index f039538d3bdb..000000000000 --- a/arch/arm/mach-at91/at91sam9_alt_reset.S +++ /dev/null @@ -1,40 +0,0 @@ -/* - * reset AT91SAM9G20 as per errata - * - * (C) BitBox Ltd 2010 - * - * unless the SDRAM is cleanly shutdown before we hit the - * reset register it can be left driving the data bus and - * killing the chance of a subsequent boot from NAND - * - * 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/linkage.h> -#include <mach/hardware.h> -#include <mach/at91_ramc.h> -#include "at91_rstc.h" - - .arm - - .globl at91sam9_alt_restart - -at91sam9_alt_restart: ldr r0, =at91_ramc_base @ preload constants - ldr r0, [r0] - ldr r4, =at91_rstc_base - ldr r1, [r4] - - mov r2, #1 - mov r3, #AT91_SDRAMC_LPCB_POWER_DOWN - ldr r4, =AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST - - .balign 32 @ align to cache line - - str r2, [r0, #AT91_SDRAMC_TR] @ disable SDRAM access - str r3, [r0, #AT91_SDRAMC_LPR] @ power down SDRAM - str r4, [r1, #AT91_RSTC_CR] @ reset processor - - b . diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 9d45496e4932..405427ec05f8 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/dma-mapping.h> #include <linux/clk/at91_pmc.h> +#include <linux/platform_device.h> #include <asm/irq.h> #include <asm/mach/arch.h> @@ -371,8 +372,6 @@ static void __init at91sam9g45_map_io(void) static void __init at91sam9g45_ioremap_registers(void) { - at91_ioremap_shdwc(AT91SAM9G45_BASE_SHDWC); - at91_ioremap_rstc(AT91SAM9G45_BASE_RSTC); at91_ioremap_ramc(0, AT91SAM9G45_BASE_DDRSDRC1, 512); at91_ioremap_ramc(1, AT91SAM9G45_BASE_DDRSDRC0, 512); at91sam926x_ioremap_pit(AT91SAM9G45_BASE_PIT); @@ -384,7 +383,6 @@ static void __init at91sam9g45_ioremap_registers(void) static void __init at91sam9g45_initialize(void) { arm_pm_idle = at91sam9_idle; - arm_pm_restart = at91sam9g45_restart; at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC); at91_sysirq_mask_rtt(AT91SAM9G45_BASE_RTT); @@ -393,6 +391,50 @@ static void __init at91sam9g45_initialize(void) at91_gpio_init(at91sam9g45_gpio, 5); } +static struct resource rstc_resources[] = { + [0] = { + .start = AT91SAM9G45_BASE_RSTC, + .end = AT91SAM9G45_BASE_RSTC + SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9G45_BASE_DDRSDRC1, + .end = AT91SAM9G45_BASE_DDRSDRC1 + SZ_512 - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = AT91SAM9G45_BASE_DDRSDRC0, + .end = AT91SAM9G45_BASE_DDRSDRC0 + SZ_512 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device rstc_device = { + .name = "at91-sam9g45-reset", + .resource = rstc_resources, + .num_resources = ARRAY_SIZE(rstc_resources), +}; + +static struct resource shdwc_resources[] = { + [0] = { + .start = AT91SAM9G45_BASE_SHDWC, + .end = AT91SAM9G45_BASE_SHDWC + SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device shdwc_device = { + .name = "at91-poweroff", + .resource = shdwc_resources, + .num_resources = ARRAY_SIZE(shdwc_resources), +}; + +static void __init at91sam9g45_register_devices(void) +{ + platform_device_register(&rstc_device); + platform_device_register(&shdwc_device); +} + /* -------------------------------------------------------------------- * Interrupt initialization * -------------------------------------------------------------------- */ @@ -435,11 +477,18 @@ static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = { 0, /* Advanced Interrupt Controller (IRQ0) */ }; +static void __init at91sam9g45_init_time(void) +{ + at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS); +} + AT91_SOC_START(at91sam9g45) .map_io = at91sam9g45_map_io, .default_irq_priority = at91sam9g45_default_irq_priority, .extern_irq = (1 << AT91SAM9G45_ID_IRQ0), .ioremap_registers = at91sam9g45_ioremap_registers, .register_clocks = at91sam9g45_register_clocks, + .register_devices = at91sam9g45_register_devices, .init = at91sam9g45_initialize, + .init_time = at91sam9g45_init_time, AT91_SOC_END diff --git a/arch/arm/mach-at91/at91sam9g45_reset.S b/arch/arm/mach-at91/at91sam9g45_reset.S deleted file mode 100644 index c40c1e2ef80f..000000000000 --- a/arch/arm/mach-at91/at91sam9g45_reset.S +++ /dev/null @@ -1,45 +0,0 @@ -/* - * reset AT91SAM9G45 as per errata - * - * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcosoft.com> - * - * unless the SDRAM is cleanly shutdown before we hit the - * reset register it can be left driving the data bus and - * killing the chance of a subsequent boot from NAND - * - * GPLv2 Only - */ - -#include <linux/linkage.h> -#include <mach/hardware.h> -#include <mach/at91_ramc.h> -#include "at91_rstc.h" - .arm - -/* - * at91_ramc_base is an array void* - * init at NULL if only one DDR controler is present in or DT - */ - .globl at91sam9g45_restart - -at91sam9g45_restart: - ldr r5, =at91_ramc_base @ preload constants - ldr r0, [r5] - ldr r5, [r5, #4] @ ddr1 - cmp r5, #0 - ldr r4, =at91_rstc_base - ldr r1, [r4] - - mov r2, #1 - mov r3, #AT91_DDRSDRC_LPCB_POWER_DOWN - ldr r4, =AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST - - .balign 32 @ align to cache line - - strne r2, [r5, #AT91_DDRSDRC_RTR] @ disable DDR1 access - strne r3, [r5, #AT91_DDRSDRC_LPR] @ power down DDR1 - str r2, [r0, #AT91_DDRSDRC_RTR] @ disable DDR0 access - str r3, [r0, #AT91_DDRSDRC_LPR] @ power down DDR0 - str r4, [r1, #AT91_RSTC_CR] @ reset processor - - b . diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index 878d5015daab..f553e4ea034b 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -10,6 +10,7 @@ */ #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/clk/at91_pmc.h> #include <asm/proc-fns.h> @@ -23,7 +24,6 @@ #include <mach/hardware.h> #include "at91_aic.h" -#include "at91_rstc.h" #include "soc.h" #include "generic.h" #include "sam9_smc.h" @@ -311,8 +311,6 @@ static void __init at91sam9rl_map_io(void) static void __init at91sam9rl_ioremap_registers(void) { - at91_ioremap_shdwc(AT91SAM9RL_BASE_SHDWC); - at91_ioremap_rstc(AT91SAM9RL_BASE_RSTC); at91_ioremap_ramc(0, AT91SAM9RL_BASE_SDRAMC, 512); at91sam926x_ioremap_pit(AT91SAM9RL_BASE_PIT); at91sam9_ioremap_smc(0, AT91SAM9RL_BASE_SMC); @@ -323,7 +321,6 @@ static void __init at91sam9rl_ioremap_registers(void) static void __init at91sam9rl_initialize(void) { arm_pm_idle = at91sam9_idle; - arm_pm_restart = at91sam9_alt_restart; at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC); at91_sysirq_mask_rtt(AT91SAM9RL_BASE_RTT); @@ -332,6 +329,45 @@ static void __init at91sam9rl_initialize(void) at91_gpio_init(at91sam9rl_gpio, 4); } +static struct resource rstc_resources[] = { + [0] = { + .start = AT91SAM9RL_BASE_RSTC, + .end = AT91SAM9RL_BASE_RSTC + SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9RL_BASE_SDRAMC, + .end = AT91SAM9RL_BASE_SDRAMC + SZ_512 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device rstc_device = { + .name = "at91-sam9260-reset", + .resource = rstc_resources, + .num_resources = ARRAY_SIZE(rstc_resources), +}; + +static struct resource shdwc_resources[] = { + [0] = { + .start = AT91SAM9RL_BASE_SHDWC, + .end = AT91SAM9RL_BASE_SHDWC + SZ_16 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device shdwc_device = { + .name = "at91-poweroff", + .resource = shdwc_resources, + .num_resources = ARRAY_SIZE(shdwc_resources), +}; + +static void __init at91sam9rl_register_devices(void) +{ + platform_device_register(&rstc_device); + platform_device_register(&shdwc_device); +} + /* -------------------------------------------------------------------- * Interrupt initialization * -------------------------------------------------------------------- */ @@ -374,6 +410,11 @@ static unsigned int at91sam9rl_default_irq_priority[NR_AIC_IRQS] __initdata = { 0, /* Advanced Interrupt Controller */ }; +static void __init at91sam9rl_init_time(void) +{ + at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS); +} + AT91_SOC_START(at91sam9rl) .map_io = at91sam9rl_map_io, .default_irq_priority = at91sam9rl_default_irq_priority, @@ -382,5 +423,7 @@ AT91_SOC_START(at91sam9rl) #if defined(CONFIG_OLD_CLK_AT91) .register_clocks = at91sam9rl_register_clocks, #endif + .register_devices = at91sam9rl_register_devices, .init = at91sam9rl_initialize, + .init_time = at91sam9rl_init_time, AT91_SOC_END diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c index 597c649170aa..e76e35ce81e7 100644 --- a/arch/arm/mach-at91/board-afeb-9260v1.c +++ b/arch/arm/mach-at91/board-afeb-9260v1.c @@ -167,6 +167,8 @@ static struct at91_cf_data afeb9260_cf_data = { static void __init afeb9260_board_init(void) { + at91_register_devices(); + /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -211,7 +213,7 @@ static void __init afeb9260_board_init(void) MACHINE_START(AFEB9260, "Custom afeb9260 board") /* Maintainer: Sergey Lapin <slapin@ossfans.org> */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = afeb9260_init_early, diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c index a30502c8d379..ae827dd2d0d2 100644 --- a/arch/arm/mach-at91/board-cam60.c +++ b/arch/arm/mach-at91/board-cam60.c @@ -170,6 +170,8 @@ static void __init cam60_add_device_nand(void) static void __init cam60_board_init(void) { + at91_register_devices(); + /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -188,7 +190,7 @@ static void __init cam60_board_init(void) MACHINE_START(CAM60, "KwikByte CAM60") /* Maintainer: KwikByte */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = cam60_init_early, diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c index 2037f78c84e7..731c8318f4f5 100644 --- a/arch/arm/mach-at91/board-cpu9krea.c +++ b/arch/arm/mach-at91/board-cpu9krea.c @@ -322,6 +322,8 @@ static struct mci_platform_data __initdata cpu9krea_mci0_data = { static void __init cpu9krea_board_init(void) { + at91_register_devices(); + /* NOR */ cpu9krea_add_device_nor(); /* Serial */ @@ -375,7 +377,7 @@ MACHINE_START(CPUAT9260, "Eukrea CPU9260") MACHINE_START(CPUAT9G20, "Eukrea CPU9G20") #endif /* Maintainer: Eric Benard - EUKREA Electromatique */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = cpu9krea_init_early, diff --git a/arch/arm/mach-at91/board-dt-rm9200.c b/arch/arm/mach-at91/board-dt-rm9200.c index 3a185faee795..61ea21445664 100644 --- a/arch/arm/mach-at91/board-dt-rm9200.c +++ b/arch/arm/mach-at91/board-dt-rm9200.c @@ -24,17 +24,6 @@ #include "at91_aic.h" #include "generic.h" - -static const struct of_device_id irq_of_match[] __initconst = { - { .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init }, - { /*sentinel*/ } -}; - -static void __init at91rm9200_dt_init_irq(void) -{ - of_irq_init(irq_of_match); -} - static const char *at91rm9200_dt_board_compat[] __initdata = { "atmel,at91rm9200", NULL @@ -43,8 +32,6 @@ static const char *at91rm9200_dt_board_compat[] __initdata = { DT_MACHINE_START(at91rm9200_dt, "Atmel AT91RM9200 (Device Tree)") .init_time = at91rm9200_timer_init, .map_io = at91_map_io, - .handle_irq = at91_aic_handle_irq, .init_early = at91rm9200_dt_initialize, - .init_irq = at91rm9200_dt_init_irq, .dt_compat = at91rm9200_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-at91/board-dt-sam9.c b/arch/arm/mach-at91/board-dt-sam9.c index 575b0be66ca8..d3048ccdc41f 100644 --- a/arch/arm/mach-at91/board-dt-sam9.c +++ b/arch/arm/mach-at91/board-dt-sam9.c @@ -25,26 +25,6 @@ #include "board.h" #include "generic.h" - -static void __init sam9_dt_timer_init(void) -{ -#if defined(CONFIG_COMMON_CLK) - of_clk_init(NULL); -#endif - at91sam926x_pit_init(); -} - -static const struct of_device_id irq_of_match[] __initconst = { - - { .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init }, - { /*sentinel*/ } -}; - -static void __init at91_dt_init_irq(void) -{ - of_irq_init(irq_of_match); -} - static const char *at91_dt_board_compat[] __initdata = { "atmel,at91sam9", NULL @@ -52,10 +32,7 @@ static const char *at91_dt_board_compat[] __initdata = { DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM (Device Tree)") /* Maintainer: Atmel */ - .init_time = sam9_dt_timer_init, .map_io = at91_map_io, - .handle_irq = at91_aic_handle_irq, .init_early = at91_dt_initialize, - .init_irq = at91_dt_init_irq, .dt_compat = at91_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-at91/board-dt-sama5.c b/arch/arm/mach-at91/board-dt-sama5.c index 075ec0576ada..be6aa2e2c343 100644 --- a/arch/arm/mach-at91/board-dt-sama5.c +++ b/arch/arm/mach-at91/board-dt-sama5.c @@ -27,25 +27,6 @@ #include "at91_aic.h" #include "generic.h" -static void __init sama5_dt_timer_init(void) -{ -#if defined(CONFIG_COMMON_CLK) - of_clk_init(NULL); -#endif - at91sam926x_pit_init(); -} - -static const struct of_device_id irq_of_match[] __initconst = { - - { .compatible = "atmel,sama5d3-aic", .data = at91_aic5_of_init }, - { /*sentinel*/ } -}; - -static void __init at91_dt_init_irq(void) -{ - of_irq_init(irq_of_match); -} - static int ksz9021rn_phy_fixup(struct phy_device *phy) { int value; @@ -80,11 +61,8 @@ static const char *sama5_dt_board_compat[] __initdata = { DT_MACHINE_START(sama5_dt, "Atmel SAMA5 (Device Tree)") /* Maintainer: Atmel */ - .init_time = sama5_dt_timer_init, .map_io = at91_map_io, - .handle_irq = at91_aic5_handle_irq, .init_early = at91_dt_initialize, - .init_irq = at91_dt_init_irq, .init_machine = sama5_dt_device_init, .dt_compat = sama5_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c index 68f1ab6bd08f..a6aa4a2432f2 100644 --- a/arch/arm/mach-at91/board-flexibity.c +++ b/arch/arm/mach-at91/board-flexibity.c @@ -138,6 +138,8 @@ static struct gpio_led flexibity_leds[] = { static void __init flexibity_board_init(void) { + at91_register_devices(); + /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -160,7 +162,7 @@ static void __init flexibity_board_init(void) MACHINE_START(FLEXIBITY, "Flexibity Connect") /* Maintainer: Maxim Osipov */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = flexibity_init_early, diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c index 8b22c60bb238..ec290b6ed9d8 100644 --- a/arch/arm/mach-at91/board-foxg20.c +++ b/arch/arm/mach-at91/board-foxg20.c @@ -263,7 +263,7 @@ static void __init foxg20_board_init(void) MACHINE_START(ACMENETUSFOXG20, "Acme Systems srl FOX Board G20") /* Maintainer: Sergio Tanzilli */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = foxg20_init_early, diff --git a/arch/arm/mach-at91/board-gsia18s.c b/arch/arm/mach-at91/board-gsia18s.c index b729dd1271bf..bf5cc55c7db6 100644 --- a/arch/arm/mach-at91/board-gsia18s.c +++ b/arch/arm/mach-at91/board-gsia18s.c @@ -576,7 +576,7 @@ static void __init gsia18s_board_init(void) } MACHINE_START(GSIA18S, "GS_IA18_S") - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = gsia18s_init_early, diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c index b48d95ec5152..9c26b94ce448 100644 --- a/arch/arm/mach-at91/board-pcontrol-g20.c +++ b/arch/arm/mach-at91/board-pcontrol-g20.c @@ -219,7 +219,7 @@ static void __init pcontrol_g20_board_init(void) MACHINE_START(PCONTROL_G20, "PControl G20") /* Maintainer: pgsellmann@portner-elektronik.at */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = pcontrol_g20_init_early, diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c index d24dda67e2d3..c2166e3a236c 100644 --- a/arch/arm/mach-at91/board-sam9-l9260.c +++ b/arch/arm/mach-at91/board-sam9-l9260.c @@ -187,6 +187,8 @@ static struct gpio_led ek_leds[] = { static void __init ek_board_init(void) { + at91_register_devices(); + /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -219,7 +221,7 @@ static void __init ek_board_init(void) MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260") /* Maintainer: Olimex */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = ek_init_early, diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c index 65dea12d685e..bf8a946b4cd0 100644 --- a/arch/arm/mach-at91/board-sam9260ek.c +++ b/arch/arm/mach-at91/board-sam9260ek.c @@ -45,7 +45,6 @@ #include <mach/system_rev.h> #include "at91_aic.h" -#include "at91_shdwc.h" #include "board.h" #include "sam9_smc.h" #include "generic.h" @@ -307,6 +306,8 @@ static void __init ek_add_device_buttons(void) {} static void __init ek_board_init(void) { + at91_register_devices(); + /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -344,7 +345,7 @@ static void __init ek_board_init(void) MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK") /* Maintainer: Atmel */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = ek_init_early, diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c index 4637432de08f..e85ada820bfb 100644 --- a/arch/arm/mach-at91/board-sam9261ek.c +++ b/arch/arm/mach-at91/board-sam9261ek.c @@ -49,7 +49,6 @@ #include <mach/system_rev.h> #include "at91_aic.h" -#include "at91_shdwc.h" #include "board.h" #include "sam9_smc.h" #include "generic.h" @@ -561,6 +560,8 @@ static struct gpio_led ek_leds[] = { static void __init ek_board_init(void) { + at91_register_devices(); + /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -603,7 +604,7 @@ static void __init ek_board_init(void) MACHINE_START(AT91SAM9261EK, "Atmel AT91SAM9261-EK") /* Maintainer: Atmel */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = ek_init_early, @@ -613,7 +614,7 @@ MACHINE_END MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK") /* Maintainer: Atmel */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = ek_init_early, diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c index fc446097f410..d76680f2a209 100644 --- a/arch/arm/mach-at91/board-sam9263ek.c +++ b/arch/arm/mach-at91/board-sam9263ek.c @@ -50,7 +50,6 @@ #include <mach/system_rev.h> #include "at91_aic.h" -#include "at91_shdwc.h" #include "board.h" #include "sam9_smc.h" #include "generic.h" @@ -439,6 +438,8 @@ static struct platform_device *devices[] __initdata = { static void __init ek_board_init(void) { + at91_register_devices(); + /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -483,7 +484,7 @@ static void __init ek_board_init(void) MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK") /* Maintainer: Atmel */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = ek_init_early, diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c index e1be6e25b380..49f075213451 100644 --- a/arch/arm/mach-at91/board-sam9g20ek.c +++ b/arch/arm/mach-at91/board-sam9g20ek.c @@ -410,7 +410,7 @@ static void __init ek_board_init(void) MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK") /* Maintainer: Atmel */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = ek_init_early, @@ -420,7 +420,7 @@ MACHINE_END MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod") /* Maintainer: Atmel */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = ek_init_early, diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c index b227732b0c83..a517c7f7af92 100644 --- a/arch/arm/mach-at91/board-sam9m10g45ek.c +++ b/arch/arm/mach-at91/board-sam9m10g45ek.c @@ -48,7 +48,6 @@ #include <mach/system_rev.h> #include "at91_aic.h" -#include "at91_shdwc.h" #include "board.h" #include "sam9_smc.h" #include "generic.h" @@ -471,6 +470,8 @@ static struct platform_device *devices[] __initdata = { static void __init ek_board_init(void) { + at91_register_devices(); + /* Serial */ /* DGBU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -517,7 +518,7 @@ static void __init ek_board_init(void) MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK") /* Maintainer: Atmel */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = ek_init_early, diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c index b64648b4a1fc..8bca329b0293 100644 --- a/arch/arm/mach-at91/board-sam9rlek.c +++ b/arch/arm/mach-at91/board-sam9rlek.c @@ -35,7 +35,6 @@ #include "at91_aic.h" -#include "at91_shdwc.h" #include "board.h" #include "sam9_smc.h" #include "generic.h" @@ -292,6 +291,8 @@ static void __init ek_add_device_buttons(void) {} static void __init ek_board_init(void) { + at91_register_devices(); + /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -323,7 +324,7 @@ static void __init ek_board_init(void) MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK") /* Maintainer: Atmel */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = ek_init_early, diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c index 1b870e6def0c..b4aff840a1a0 100644 --- a/arch/arm/mach-at91/board-snapper9260.c +++ b/arch/arm/mach-at91/board-snapper9260.c @@ -154,6 +154,8 @@ static void __init snapper9260_add_device_nand(void) static void __init snapper9260_board_init(void) { + at91_register_devices(); + at91_add_device_i2c(snapper9260_i2c_devices, ARRAY_SIZE(snapper9260_i2c_devices)); @@ -178,7 +180,7 @@ static void __init snapper9260_board_init(void) } MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module") - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = snapper9260_init_early, diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c index 3b575036ff96..e825641a1dee 100644 --- a/arch/arm/mach-at91/board-stamp9g20.c +++ b/arch/arm/mach-at91/board-stamp9g20.c @@ -275,7 +275,7 @@ static void __init stamp9g20evb_board_init(void) MACHINE_START(PORTUXG20, "taskit PortuxG20") /* Maintainer: taskit GmbH */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = stamp9g20_init_early, @@ -285,7 +285,7 @@ MACHINE_END MACHINE_START(STAMP9G20, "taskit Stamp9G20") /* Maintainer: taskit GmbH */ - .init_time = at91sam926x_pit_init, + .init_time = at91_init_time, .map_io = at91_map_io, .handle_irq = at91_aic_handle_irq, .init_early = stamp9g20_init_early, diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h index 631fa3b8c16d..189d7c7e7f60 100644 --- a/arch/arm/mach-at91/generic.h +++ b/arch/arm/mach-at91/generic.h @@ -8,6 +8,9 @@ * published by the Free Software Foundation. */ +#ifndef _AT91_GENERIC_H +#define _AT91_GENERIC_H + #include <linux/clkdev.h> #include <linux/of.h> #include <linux/reboot.h> @@ -37,12 +40,15 @@ extern int __init at91_aic5_of_init(struct device_node *node, extern void __init at91_sysirq_mask_rtc(u32 rtc_base); extern void __init at91_sysirq_mask_rtt(u32 rtt_base); + /* Devices */ +extern void __init at91_register_devices(void); /* Timer */ +extern void __init at91_init_time(void); extern void at91rm9200_ioremap_st(u32 addr); extern void at91rm9200_timer_init(void); extern void at91sam926x_ioremap_pit(u32 addr); -extern void at91sam926x_pit_init(void); +extern void at91sam926x_pit_init(int irq); extern void at91x40_timer_init(void); /* Clocks */ @@ -62,14 +68,6 @@ extern void at91_irq_resume(void); /* idle */ extern void at91sam9_idle(void); -/* reset */ -extern void at91_ioremap_rstc(u32 base_addr); -extern void at91sam9_alt_restart(enum reboot_mode, const char *); -extern void at91sam9g45_restart(enum reboot_mode, const char *); - -/* shutdown */ -extern void at91_ioremap_shdwc(u32 base_addr); - /* Matrix */ extern void at91_ioremap_matrix(u32 base_addr); @@ -90,3 +88,5 @@ extern int __init at91_gpio_of_irq_setup(struct device_node *node, struct device_node *parent); extern u32 at91_get_extern_irq(void); + +#endif /* _AT91_GENERIC_H */ diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c index 3d192c5aee66..cdb3ec9efd2b 100644 --- a/arch/arm/mach-at91/irq.c +++ b/arch/arm/mach-at91/irq.c @@ -48,11 +48,6 @@ void __iomem *at91_aic_base; static struct irq_domain *at91_aic_domain; static struct device_node *at91_aic_np; static unsigned int n_irqs = NR_AIC_IRQS; -static unsigned long at91_aic_caps = 0; - -/* AIC5 introduces a Source Select Register */ -#define AT91_AIC_CAP_AIC5 (1 << 0) -#define has_aic5() (at91_aic_caps & AT91_AIC_CAP_AIC5) #ifdef CONFIG_PM @@ -92,50 +87,14 @@ static int at91_aic_set_wake(struct irq_data *d, unsigned value) void at91_irq_suspend(void) { - int bit = -1; - - if (has_aic5()) { - /* disable enabled irqs */ - while ((bit = find_next_bit(backups, n_irqs, bit + 1)) < n_irqs) { - at91_aic_write(AT91_AIC5_SSR, - bit & AT91_AIC5_INTSEL_MSK); - at91_aic_write(AT91_AIC5_IDCR, 1); - } - /* enable wakeup irqs */ - bit = -1; - while ((bit = find_next_bit(wakeups, n_irqs, bit + 1)) < n_irqs) { - at91_aic_write(AT91_AIC5_SSR, - bit & AT91_AIC5_INTSEL_MSK); - at91_aic_write(AT91_AIC5_IECR, 1); - } - } else { - at91_aic_write(AT91_AIC_IDCR, *backups); - at91_aic_write(AT91_AIC_IECR, *wakeups); - } + at91_aic_write(AT91_AIC_IDCR, *backups); + at91_aic_write(AT91_AIC_IECR, *wakeups); } void at91_irq_resume(void) { - int bit = -1; - - if (has_aic5()) { - /* disable wakeup irqs */ - while ((bit = find_next_bit(wakeups, n_irqs, bit + 1)) < n_irqs) { - at91_aic_write(AT91_AIC5_SSR, - bit & AT91_AIC5_INTSEL_MSK); - at91_aic_write(AT91_AIC5_IDCR, 1); - } - /* enable irqs disabled for suspend */ - bit = -1; - while ((bit = find_next_bit(backups, n_irqs, bit + 1)) < n_irqs) { - at91_aic_write(AT91_AIC5_SSR, - bit & AT91_AIC5_INTSEL_MSK); - at91_aic_write(AT91_AIC5_IECR, 1); - } - } else { - at91_aic_write(AT91_AIC_IDCR, *wakeups); - at91_aic_write(AT91_AIC_IECR, *backups); - } + at91_aic_write(AT91_AIC_IDCR, *wakeups); + at91_aic_write(AT91_AIC_IECR, *backups); } #else @@ -169,21 +128,6 @@ at91_aic_handle_irq(struct pt_regs *regs) handle_IRQ(irqnr, regs); } -asmlinkage void __exception_irq_entry -at91_aic5_handle_irq(struct pt_regs *regs) -{ - u32 irqnr; - u32 irqstat; - - irqnr = at91_aic_read(AT91_AIC5_IVR); - irqstat = at91_aic_read(AT91_AIC5_ISR); - - if (!irqstat) - at91_aic_write(AT91_AIC5_EOICR, 0); - else - handle_IRQ(irqnr, regs); -} - static void at91_aic_mask_irq(struct irq_data *d) { /* Disable interrupt on AIC */ @@ -192,15 +136,6 @@ static void at91_aic_mask_irq(struct irq_data *d) clear_backup(d->hwirq); } -static void __maybe_unused at91_aic5_mask_irq(struct irq_data *d) -{ - /* Disable interrupt on AIC5 */ - at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK); - at91_aic_write(AT91_AIC5_IDCR, 1); - /* Update ISR cache */ - clear_backup(d->hwirq); -} - static void at91_aic_unmask_irq(struct irq_data *d) { /* Enable interrupt on AIC */ @@ -209,15 +144,6 @@ static void at91_aic_unmask_irq(struct irq_data *d) set_backup(d->hwirq); } -static void __maybe_unused at91_aic5_unmask_irq(struct irq_data *d) -{ - /* Enable interrupt on AIC5 */ - at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK); - at91_aic_write(AT91_AIC5_IECR, 1); - /* Update ISR cache */ - set_backup(d->hwirq); -} - static void at91_aic_eoi(struct irq_data *d) { /* @@ -227,11 +153,6 @@ static void at91_aic_eoi(struct irq_data *d) at91_aic_write(AT91_AIC_EOICR, 0); } -static void __maybe_unused at91_aic5_eoi(struct irq_data *d) -{ - at91_aic_write(AT91_AIC5_EOICR, 0); -} - static unsigned long *at91_extern_irq; u32 at91_get_extern_irq(void) @@ -282,16 +203,8 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type) if (srctype < 0) return srctype; - if (has_aic5()) { - at91_aic_write(AT91_AIC5_SSR, - d->hwirq & AT91_AIC5_INTSEL_MSK); - smr = at91_aic_read(AT91_AIC5_SMR) & ~AT91_AIC_SRCTYPE; - at91_aic_write(AT91_AIC5_SMR, smr | srctype); - } else { - smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) - & ~AT91_AIC_SRCTYPE; - at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype); - } + smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE; + at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype); return 0; } @@ -331,177 +244,6 @@ static void __init at91_aic_hw_init(unsigned int spu_vector) at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF); } -static void __init __maybe_unused at91_aic5_hw_init(unsigned int spu_vector) -{ - int i; - - /* - * Perform 8 End Of Interrupt Command to make sure AIC - * will not Lock out nIRQ - */ - for (i = 0; i < 8; i++) - at91_aic_write(AT91_AIC5_EOICR, 0); - - /* - * Spurious Interrupt ID in Spurious Vector Register. - * When there is no current interrupt, the IRQ Vector Register - * reads the value stored in AIC_SPU - */ - at91_aic_write(AT91_AIC5_SPU, spu_vector); - - /* No debugging in AIC: Debug (Protect) Control Register */ - at91_aic_write(AT91_AIC5_DCR, 0); - - /* Disable and clear all interrupts initially */ - for (i = 0; i < n_irqs; i++) { - at91_aic_write(AT91_AIC5_SSR, i & AT91_AIC5_INTSEL_MSK); - at91_aic_write(AT91_AIC5_IDCR, 1); - at91_aic_write(AT91_AIC5_ICCR, 1); - } -} - -#if defined(CONFIG_OF) -static unsigned int *at91_aic_irq_priorities; - -static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - /* Put virq number in Source Vector Register */ - at91_aic_write(AT91_AIC_SVR(hw), virq); - - /* Active Low interrupt, with priority */ - at91_aic_write(AT91_AIC_SMR(hw), - AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]); - - irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq); - set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); - - return 0; -} - -static int at91_aic5_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - at91_aic_write(AT91_AIC5_SSR, hw & AT91_AIC5_INTSEL_MSK); - - /* Put virq number in Source Vector Register */ - at91_aic_write(AT91_AIC5_SVR, virq); - - /* Active Low interrupt, with priority */ - at91_aic_write(AT91_AIC5_SMR, - AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]); - - irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq); - set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); - - return 0; -} - -static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type) -{ - if (WARN_ON(intsize < 3)) - return -EINVAL; - if (WARN_ON(intspec[0] >= n_irqs)) - return -EINVAL; - if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY) - || (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY))) - return -EINVAL; - - *out_hwirq = intspec[0]; - *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; - at91_aic_irq_priorities[*out_hwirq] = intspec[2]; - - return 0; -} - -static struct irq_domain_ops at91_aic_irq_ops = { - .map = at91_aic_irq_map, - .xlate = at91_aic_irq_domain_xlate, -}; - -int __init at91_aic_of_common_init(struct device_node *node, - struct device_node *parent) -{ - struct property *prop; - const __be32 *p; - u32 val; - - at91_extern_irq = kzalloc(BITS_TO_LONGS(n_irqs) - * sizeof(*at91_extern_irq), GFP_KERNEL); - if (!at91_extern_irq) - return -ENOMEM; - - if (at91_aic_pm_init()) { - kfree(at91_extern_irq); - return -ENOMEM; - } - - at91_aic_irq_priorities = kzalloc(n_irqs - * sizeof(*at91_aic_irq_priorities), - GFP_KERNEL); - if (!at91_aic_irq_priorities) - return -ENOMEM; - - at91_aic_base = of_iomap(node, 0); - at91_aic_np = node; - - at91_aic_domain = irq_domain_add_linear(at91_aic_np, n_irqs, - &at91_aic_irq_ops, NULL); - if (!at91_aic_domain) - panic("Unable to add AIC irq domain (DT)\n"); - - of_property_for_each_u32(node, "atmel,external-irqs", prop, p, val) { - if (val >= n_irqs) - pr_warn("AIC: external irq %d >= %d skip it\n", - val, n_irqs); - else - set_bit(val, at91_extern_irq); - } - - irq_set_default_host(at91_aic_domain); - - return 0; -} - -int __init at91_aic_of_init(struct device_node *node, - struct device_node *parent) -{ - int err; - - err = at91_aic_of_common_init(node, parent); - if (err) - return err; - - at91_aic_hw_init(n_irqs); - - return 0; -} - -int __init at91_aic5_of_init(struct device_node *node, - struct device_node *parent) -{ - int err; - - at91_aic_caps |= AT91_AIC_CAP_AIC5; - n_irqs = NR_AIC5_IRQS; - at91_aic_chip.irq_ack = at91_aic5_mask_irq; - at91_aic_chip.irq_mask = at91_aic5_mask_irq; - at91_aic_chip.irq_unmask = at91_aic5_unmask_irq; - at91_aic_chip.irq_eoi = at91_aic5_eoi; - at91_aic_irq_ops.map = at91_aic5_irq_map; - - err = at91_aic_of_common_init(node, parent); - if (err) - return err; - - at91_aic5_hw_init(n_irqs); - - return 0; -} -#endif - /* * Initialize the AIC interrupt controller. */ diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index e95554532987..4073ab7f38f3 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -34,79 +34,8 @@ #include "pm.h" #include "gpio.h" -/* - * Show the reason for the previous system reset. - */ - -#include "at91_rstc.h" -#include "at91_shdwc.h" - static void (*at91_pm_standby)(void); -static void __init show_reset_status(void) -{ - static char reset[] __initdata = "reset"; - - static char general[] __initdata = "general"; - static char wakeup[] __initdata = "wakeup"; - static char watchdog[] __initdata = "watchdog"; - static char software[] __initdata = "software"; - static char user[] __initdata = "user"; - static char unknown[] __initdata = "unknown"; - - static char signal[] __initdata = "signal"; - static char rtc[] __initdata = "rtc"; - static char rtt[] __initdata = "rtt"; - static char restore[] __initdata = "power-restored"; - - char *reason, *r2 = reset; - u32 reset_type, wake_type; - - if (!at91_shdwc_base || !at91_rstc_base) - return; - - reset_type = at91_rstc_read(AT91_RSTC_SR) & AT91_RSTC_RSTTYP; - wake_type = at91_shdwc_read(AT91_SHDW_SR); - - switch (reset_type) { - case AT91_RSTC_RSTTYP_GENERAL: - reason = general; - break; - case AT91_RSTC_RSTTYP_WAKEUP: - /* board-specific code enabled the wakeup sources */ - reason = wakeup; - - /* "wakeup signal" */ - if (wake_type & AT91_SHDW_WAKEUP0) - r2 = signal; - else { - r2 = reason; - if (wake_type & AT91_SHDW_RTTWK) /* rtt wakeup */ - reason = rtt; - else if (wake_type & AT91_SHDW_RTCWK) /* rtc wakeup */ - reason = rtc; - else if (wake_type == 0) /* power-restored wakeup */ - reason = restore; - else /* unknown wakeup */ - reason = unknown; - } - break; - case AT91_RSTC_RSTTYP_WATCHDOG: - reason = watchdog; - break; - case AT91_RSTC_RSTTYP_SOFTWARE: - reason = software; - break; - case AT91_RSTC_RSTTYP_USER: - reason = user; - break; - default: - reason = unknown; - break; - } - pr_info("AT91: Starting after %s %s\n", reason, r2); -} - static int at91_pm_valid_state(suspend_state_t state) { switch (state) { @@ -206,16 +135,19 @@ static int at91_pm_enter(suspend_state_t state) at91_pinctrl_gpio_suspend(); else at91_gpio_suspend(); - at91_irq_suspend(); - pr_debug("AT91: PM - wake mask %08x, pm state %d\n", - /* remember all the always-wake irqs */ - (at91_pmc_read(AT91_PMC_PCSR) - | (1 << AT91_ID_FIQ) - | (1 << AT91_ID_SYS) - | (at91_get_extern_irq())) - & at91_aic_read(AT91_AIC_IMR), - state); + if (IS_ENABLED(CONFIG_OLD_IRQ_AT91) && at91_aic_base) { + at91_irq_suspend(); + + pr_debug("AT91: PM - wake mask %08x, pm state %d\n", + /* remember all the always-wake irqs */ + (at91_pmc_read(AT91_PMC_PCSR) + | (1 << AT91_ID_FIQ) + | (1 << AT91_ID_SYS) + | (at91_get_extern_irq())) + & at91_aic_read(AT91_AIC_IMR), + state); + } switch (state) { /* @@ -280,12 +212,17 @@ static int at91_pm_enter(suspend_state_t state) goto error; } - pr_debug("AT91: PM - wakeup %08x\n", - at91_aic_read(AT91_AIC_IPR) & at91_aic_read(AT91_AIC_IMR)); + if (IS_ENABLED(CONFIG_OLD_IRQ_AT91) && at91_aic_base) + pr_debug("AT91: PM - wakeup %08x\n", + at91_aic_read(AT91_AIC_IPR) & + at91_aic_read(AT91_AIC_IMR)); error: target_state = PM_SUSPEND_ON; - at91_irq_resume(); + + if (IS_ENABLED(CONFIG_OLD_IRQ_AT91) && at91_aic_base) + at91_irq_resume(); + if (of_have_populated_dt()) at91_pinctrl_gpio_resume(); else @@ -338,7 +275,6 @@ static int __init at91_pm_init(void) suspend_set_ops(&at91_pm_ops); - show_reset_status(); return 0; } arch_initcall(at91_pm_init); diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c index f7a07a58ebb6..51c22a2fcea4 100644 --- a/arch/arm/mach-at91/setup.c +++ b/arch/arm/mach-at91/setup.c @@ -5,6 +5,8 @@ * Under GPLv2 */ +#define pr_fmt(fmt) "AT91: " fmt + #include <linux/module.h> #include <linux/io.h> #include <linux/mm.h> @@ -20,7 +22,6 @@ #include <mach/cpu.h> #include <mach/at91_dbgu.h> -#include "at91_shdwc.h" #include "soc.h" #include "generic.h" #include "pm.h" @@ -37,7 +38,7 @@ void __init at91rm9200_set_type(int type) else at91_soc_initdata.subtype = AT91_SOC_RM9200_BGA; - pr_info("AT91: filled in soc subtype: %s\n", + pr_info("filled in soc subtype: %s\n", at91_get_soc_subtype(&at91_soc_initdata)); } @@ -49,7 +50,8 @@ void __init at91_init_irq_default(void) void __init at91_init_interrupts(unsigned int *priority) { /* Initialize the AIC interrupt controller */ - at91_aic_init(priority, at91_boot_soc.extern_irq); + if (IS_ENABLED(CONFIG_OLD_IRQ_AT91)) + at91_aic_init(priority, at91_boot_soc.extern_irq); /* Enable GPIO interrupts */ at91_gpio_irq_setup(); @@ -66,7 +68,7 @@ void __init at91_ioremap_ramc(int id, u32 addr, u32 size) } at91_ramc_base[id] = ioremap(addr, size); if (!at91_ramc_base[id]) - panic("Impossible to ioremap ramc.%d 0x%x\n", id, addr); + panic(pr_fmt("Impossible to ioremap ramc.%d 0x%x\n"), id, addr); } static struct map_desc sram_desc[2] __initdata; @@ -83,7 +85,7 @@ void __init at91_init_sram(int bank, unsigned long base, unsigned int length) desc->length = length; desc->type = MT_MEMORY_RWX_NONCACHED; - pr_info("AT91: sram at 0x%lx of 0x%x mapped at 0x%lx\n", + pr_info("sram at 0x%lx of 0x%x mapped at 0x%lx\n", base, length, desc->virtual); iotable_init(desc, 1); @@ -302,45 +304,21 @@ void __init at91_map_io(void) soc_detect(AT91_BASE_DBGU1); if (!at91_soc_is_detected()) - panic("AT91: Impossible to detect the SOC type"); + panic(pr_fmt("Impossible to detect the SOC type")); - pr_info("AT91: Detected soc type: %s\n", + pr_info("Detected soc type: %s\n", at91_get_soc_type(&at91_soc_initdata)); if (at91_soc_initdata.subtype != AT91_SOC_SUBTYPE_NONE) - pr_info("AT91: Detected soc subtype: %s\n", + pr_info("Detected soc subtype: %s\n", at91_get_soc_subtype(&at91_soc_initdata)); if (!at91_soc_is_enabled()) - panic("AT91: Soc not enabled"); + panic(pr_fmt("Soc not enabled")); if (at91_boot_soc.map_io) at91_boot_soc.map_io(); } -void __iomem *at91_shdwc_base = NULL; - -static void at91sam9_poweroff(void) -{ - at91_shdwc_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW); -} - -void __init at91_ioremap_shdwc(u32 base_addr) -{ - at91_shdwc_base = ioremap(base_addr, 16); - if (!at91_shdwc_base) - panic("Impossible to ioremap at91_shdwc_base\n"); - pm_power_off = at91sam9_poweroff; -} - -void __iomem *at91_rstc_base; - -void __init at91_ioremap_rstc(u32 base_addr) -{ - at91_rstc_base = ioremap(base_addr, 16); - if (!at91_rstc_base) - panic("Impossible to ioremap at91_rstc_base\n"); -} - void __iomem *at91_matrix_base; EXPORT_SYMBOL_GPL(at91_matrix_base); @@ -348,42 +326,15 @@ void __init at91_ioremap_matrix(u32 base_addr) { at91_matrix_base = ioremap(base_addr, 512); if (!at91_matrix_base) - panic("Impossible to ioremap at91_matrix_base\n"); + panic(pr_fmt("Impossible to ioremap at91_matrix_base\n")); } #if defined(CONFIG_OF) && !defined(CONFIG_ARCH_AT91X40) -static struct of_device_id rstc_ids[] = { - { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9_alt_restart }, - { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart }, - { /*sentinel*/ } -}; - -static void at91_dt_rstc(void) -{ - struct device_node *np; - const struct of_device_id *of_id; - - np = of_find_matching_node(NULL, rstc_ids); - if (!np) - panic("unable to find compatible rstc node in dtb\n"); - - at91_rstc_base = of_iomap(np, 0); - if (!at91_rstc_base) - panic("unable to map rstc cpu registers\n"); - - of_id = of_match_node(rstc_ids, np); - if (!of_id) - panic("AT91: rtsc no restart function available\n"); - - arm_pm_restart = of_id->data; - - of_node_put(np); -} - static struct of_device_id ramc_ids[] = { { .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby }, { .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby }, { .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby }, + { .compatible = "atmel,sama5d3-ddramc", .data = at91_ddr_standby }, { /*sentinel*/ } }; @@ -391,100 +342,29 @@ static void at91_dt_ramc(void) { struct device_node *np; const struct of_device_id *of_id; + int idx = 0; + const void *standby = NULL; - np = of_find_matching_node(NULL, ramc_ids); - if (!np) - panic("unable to find compatible ram controller node in dtb\n"); - - at91_ramc_base[0] = of_iomap(np, 0); - if (!at91_ramc_base[0]) - panic("unable to map ramc[0] cpu registers\n"); - /* the controller may have 2 banks */ - at91_ramc_base[1] = of_iomap(np, 1); - - of_id = of_match_node(ramc_ids, np); - if (!of_id) - pr_warn("AT91: ramc no standby function available\n"); - else - at91_pm_set_standby(of_id->data); - - of_node_put(np); -} - -static struct of_device_id shdwc_ids[] = { - { .compatible = "atmel,at91sam9260-shdwc", }, - { .compatible = "atmel,at91sam9rl-shdwc", }, - { .compatible = "atmel,at91sam9x5-shdwc", }, - { /*sentinel*/ } -}; - -static const char *shdwc_wakeup_modes[] = { - [AT91_SHDW_WKMODE0_NONE] = "none", - [AT91_SHDW_WKMODE0_HIGH] = "high", - [AT91_SHDW_WKMODE0_LOW] = "low", - [AT91_SHDW_WKMODE0_ANYLEVEL] = "any", -}; - -const int at91_dtget_shdwc_wakeup_mode(struct device_node *np) -{ - const char *pm; - int err, i; + for_each_matching_node_and_match(np, ramc_ids, &of_id) { + at91_ramc_base[idx] = of_iomap(np, 0); + if (!at91_ramc_base[idx]) + panic(pr_fmt("unable to map ramc[%d] cpu registers\n"), idx); - err = of_property_read_string(np, "atmel,wakeup-mode", &pm); - if (err < 0) - return AT91_SHDW_WKMODE0_ANYLEVEL; + if (!standby) + standby = of_id->data; - for (i = 0; i < ARRAY_SIZE(shdwc_wakeup_modes); i++) - if (!strcasecmp(pm, shdwc_wakeup_modes[i])) - return i; - - return -ENODEV; -} - -static void at91_dt_shdwc(void) -{ - struct device_node *np; - int wakeup_mode; - u32 reg; - u32 mode = 0; - - np = of_find_matching_node(NULL, shdwc_ids); - if (!np) { - pr_debug("AT91: unable to find compatible shutdown (shdwc) controller node in dtb\n"); - return; + idx++; } - at91_shdwc_base = of_iomap(np, 0); - if (!at91_shdwc_base) - panic("AT91: unable to map shdwc cpu registers\n"); + if (!idx) + panic(pr_fmt("unable to find compatible ram controller node in dtb\n")); - wakeup_mode = at91_dtget_shdwc_wakeup_mode(np); - if (wakeup_mode < 0) { - pr_warn("AT91: shdwc unknown wakeup mode\n"); - goto end; - } - - if (!of_property_read_u32(np, "atmel,wakeup-counter", ®)) { - if (reg > AT91_SHDW_CPTWK0_MAX) { - pr_warn("AT91: shdwc wakeup counter 0x%x > 0x%x reduce it to 0x%x\n", - reg, AT91_SHDW_CPTWK0_MAX, AT91_SHDW_CPTWK0_MAX); - reg = AT91_SHDW_CPTWK0_MAX; - } - mode |= AT91_SHDW_CPTWK0_(reg); + if (!standby) { + pr_warn("ramc no standby function available\n"); + return; } - if (of_property_read_bool(np, "atmel,wakeup-rtc-timer")) - mode |= AT91_SHDW_RTCWKEN; - - if (of_property_read_bool(np, "atmel,wakeup-rtt-timer")) - mode |= AT91_SHDW_RTTWKEN; - - at91_shdwc_write(AT91_SHDW_MR, wakeup_mode | mode); - -end: - pm_power_off = at91sam9_poweroff; - - of_node_put(np); + at91_pm_set_standby(standby); } void __init at91rm9200_dt_initialize(void) @@ -503,9 +383,7 @@ void __init at91rm9200_dt_initialize(void) void __init at91_dt_initialize(void) { - at91_dt_rstc(); at91_dt_ramc(); - at91_dt_shdwc(); /* Init clock subsystem */ at91_dt_clock_init(); @@ -533,3 +411,13 @@ void __init at91_initialize(unsigned long main_clock) pinctrl_provide_dummies(); } + +void __init at91_register_devices(void) +{ + at91_boot_soc.register_devices(); +} + +void __init at91_init_time(void) +{ + at91_boot_soc.init_time(); +} diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h index a1e1482c6da8..2886b83dd0df 100644 --- a/arch/arm/mach-at91/soc.h +++ b/arch/arm/mach-at91/soc.h @@ -11,7 +11,9 @@ struct at91_init_soc { void (*map_io)(void); void (*ioremap_registers)(void); void (*register_clocks)(void); + void (*register_devices)(void); void (*init)(void); + void (*init_time)(void); }; extern struct at91_init_soc at91_boot_soc; diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c index 8c96307d7363..a76d03fd577b 100644 --- a/drivers/clk/at91/clk-system.c +++ b/drivers/clk/at91/clk-system.c @@ -119,13 +119,7 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name, init.ops = &system_ops; init.parent_names = &parent_name; init.num_parents = 1; - /* - * CLK_IGNORE_UNUSED is used to avoid ddrck switch off. - * TODO : we should implement a driver supporting at91 ddr controller - * (see drivers/memory) which would request and enable the ddrck clock. - * When this is done we will be able to remove CLK_IGNORE_UNUSED flag. - */ - init.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED; + init.flags = CLK_SET_RATE_PARENT; sys->id = id; sys->hw.init = &init; diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index cfd6519df661..82a2ebe41e27 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -120,6 +120,10 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK help Use ARM global timer clock source as sched_clock +config ATMEL_PIT + select CLKSRC_OF if OF + def_bool SOC_AT91SAM9 || SOC_SAMA5 + config CLKSRC_METAG_GENERIC def_bool y if METAG help diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 7fd9fd1dff42..e566f6c7ded4 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_CLKSRC_OF) += clksrc-of.o +obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c new file mode 100644 index 000000000000..d5289098b3df --- /dev/null +++ b/drivers/clocksource/timer-atmel-pit.c @@ -0,0 +1,296 @@ +/* + * at91sam926x_time.c - Periodic Interval Timer (PIT) for at91sam926x + * + * Copyright (C) 2005-2006 M. Amine SAYA, ATMEL Rousset, France + * Revision 2005 M. Nicolas Diremdjian, ATMEL Rousset, France + * Converted to ClockSource/ClockEvents by David Brownell. + * + * 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. + */ + +#define pr_fmt(fmt) "AT91: PIT: " fmt + +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/slab.h> + +#define AT91_PIT_MR 0x00 /* Mode Register */ +#define AT91_PIT_PITIEN BIT(25) /* Timer Interrupt Enable */ +#define AT91_PIT_PITEN BIT(24) /* Timer Enabled */ +#define AT91_PIT_PIV GENMASK(19, 0) /* Periodic Interval Value */ + +#define AT91_PIT_SR 0x04 /* Status Register */ +#define AT91_PIT_PITS BIT(0) /* Timer Status */ + +#define AT91_PIT_PIVR 0x08 /* Periodic Interval Value Register */ +#define AT91_PIT_PIIR 0x0c /* Periodic Interval Image Register */ +#define AT91_PIT_PICNT GENMASK(31, 20) /* Interval Counter */ +#define AT91_PIT_CPIV GENMASK(19, 0) /* Inverval Value */ + +#define PIT_CPIV(x) ((x) & AT91_PIT_CPIV) +#define PIT_PICNT(x) (((x) & AT91_PIT_PICNT) >> 20) + +struct pit_data { + struct clock_event_device clkevt; + struct clocksource clksrc; + + void __iomem *base; + u32 cycle; + u32 cnt; + unsigned int irq; + struct clk *mck; +}; + +static inline struct pit_data *clksrc_to_pit_data(struct clocksource *clksrc) +{ + return container_of(clksrc, struct pit_data, clksrc); +} + +static inline struct pit_data *clkevt_to_pit_data(struct clock_event_device *clkevt) +{ + return container_of(clkevt, struct pit_data, clkevt); +} + +static inline unsigned int pit_read(void __iomem *base, unsigned int reg_offset) +{ + return __raw_readl(base + reg_offset); +} + +static inline void pit_write(void __iomem *base, unsigned int reg_offset, unsigned long value) +{ + __raw_writel(value, base + reg_offset); +} + +/* + * Clocksource: just a monotonic counter of MCK/16 cycles. + * We don't care whether or not PIT irqs are enabled. + */ +static cycle_t read_pit_clk(struct clocksource *cs) +{ + struct pit_data *data = clksrc_to_pit_data(cs); + unsigned long flags; + u32 elapsed; + u32 t; + + raw_local_irq_save(flags); + elapsed = data->cnt; + t = pit_read(data->base, AT91_PIT_PIIR); + raw_local_irq_restore(flags); + + elapsed += PIT_PICNT(t) * data->cycle; + elapsed += PIT_CPIV(t); + return elapsed; +} + +/* + * Clockevent device: interrupts every 1/HZ (== pit_cycles * MCK/16) + */ +static void +pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) +{ + struct pit_data *data = clkevt_to_pit_data(dev); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* update clocksource counter */ + data->cnt += data->cycle * PIT_PICNT(pit_read(data->base, AT91_PIT_PIVR)); + pit_write(data->base, AT91_PIT_MR, + (data->cycle - 1) | AT91_PIT_PITEN | AT91_PIT_PITIEN); + break; + case CLOCK_EVT_MODE_ONESHOT: + BUG(); + /* FALLTHROUGH */ + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + /* disable irq, leaving the clocksource active */ + pit_write(data->base, AT91_PIT_MR, + (data->cycle - 1) | AT91_PIT_PITEN); + break; + case CLOCK_EVT_MODE_RESUME: + break; + } +} + +static void at91sam926x_pit_suspend(struct clock_event_device *cedev) +{ + struct pit_data *data = clkevt_to_pit_data(cedev); + + /* Disable timer */ + pit_write(data->base, AT91_PIT_MR, 0); +} + +static void at91sam926x_pit_reset(struct pit_data *data) +{ + /* Disable timer and irqs */ + pit_write(data->base, AT91_PIT_MR, 0); + + /* Clear any pending interrupts, wait for PIT to stop counting */ + while (PIT_CPIV(pit_read(data->base, AT91_PIT_PIVR)) != 0) + cpu_relax(); + + /* Start PIT but don't enable IRQ */ + pit_write(data->base, AT91_PIT_MR, + (data->cycle - 1) | AT91_PIT_PITEN); +} + +static void at91sam926x_pit_resume(struct clock_event_device *cedev) +{ + struct pit_data *data = clkevt_to_pit_data(cedev); + + at91sam926x_pit_reset(data); +} + +/* + * IRQ handler for the timer. + */ +static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id) +{ + struct pit_data *data = dev_id; + + /* + * irqs should be disabled here, but as the irq is shared they are only + * guaranteed to be off if the timer irq is registered first. + */ + WARN_ON_ONCE(!irqs_disabled()); + + /* The PIT interrupt may be disabled, and is shared */ + if ((data->clkevt.mode == CLOCK_EVT_MODE_PERIODIC) && + (pit_read(data->base, AT91_PIT_SR) & AT91_PIT_PITS)) { + unsigned nr_ticks; + + /* Get number of ticks performed before irq, and ack it */ + nr_ticks = PIT_PICNT(pit_read(data->base, AT91_PIT_PIVR)); + do { + data->cnt += data->cycle; + data->clkevt.event_handler(&data->clkevt); + nr_ticks--; + } while (nr_ticks); + + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +/* + * Set up both clocksource and clockevent support. + */ +static void __init at91sam926x_pit_common_init(struct pit_data *data) +{ + unsigned long pit_rate; + unsigned bits; + int ret; + + /* + * Use our actual MCK to figure out how many MCK/16 ticks per + * 1/HZ period (instead of a compile-time constant LATCH). + */ + pit_rate = clk_get_rate(data->mck) / 16; + data->cycle = DIV_ROUND_CLOSEST(pit_rate, HZ); + WARN_ON(((data->cycle - 1) & ~AT91_PIT_PIV) != 0); + + /* Initialize and enable the timer */ + at91sam926x_pit_reset(data); + + /* + * Register clocksource. The high order bits of PIV are unused, + * so this isn't a 32-bit counter unless we get clockevent irqs. + */ + bits = 12 /* PICNT */ + ilog2(data->cycle) /* PIV */; + data->clksrc.mask = CLOCKSOURCE_MASK(bits); + data->clksrc.name = "pit"; + data->clksrc.rating = 175; + data->clksrc.read = read_pit_clk, + data->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS, + clocksource_register_hz(&data->clksrc, pit_rate); + + /* Set up irq handler */ + ret = request_irq(data->irq, at91sam926x_pit_interrupt, + IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL, + "at91_tick", data); + if (ret) + panic(pr_fmt("Unable to setup IRQ\n")); + + /* Set up and register clockevents */ + data->clkevt.name = "pit"; + data->clkevt.features = CLOCK_EVT_FEAT_PERIODIC; + data->clkevt.shift = 32; + data->clkevt.mult = div_sc(pit_rate, NSEC_PER_SEC, data->clkevt.shift); + data->clkevt.rating = 100; + data->clkevt.cpumask = cpumask_of(0); + + data->clkevt.set_mode = pit_clkevt_mode; + data->clkevt.resume = at91sam926x_pit_resume; + data->clkevt.suspend = at91sam926x_pit_suspend; + clockevents_register_device(&data->clkevt); +} + +static void __init at91sam926x_pit_dt_init(struct device_node *node) +{ + struct pit_data *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + panic(pr_fmt("Unable to allocate memory\n")); + + data->base = of_iomap(node, 0); + if (!data->base) + panic(pr_fmt("Could not map PIT address\n")); + + data->mck = of_clk_get(node, 0); + if (IS_ERR(data->mck)) + /* Fallback on clkdev for !CCF-based boards */ + data->mck = clk_get(NULL, "mck"); + + if (IS_ERR(data->mck)) + panic(pr_fmt("Unable to get mck clk\n")); + + /* Get the interrupts property */ + data->irq = irq_of_parse_and_map(node, 0); + if (!data->irq) + panic(pr_fmt("Unable to get IRQ from DT\n")); + + at91sam926x_pit_common_init(data); +} +CLOCKSOURCE_OF_DECLARE(at91sam926x_pit, "atmel,at91sam9260-pit", + at91sam926x_pit_dt_init); + +static void __iomem *pit_base_addr; + +void __init at91sam926x_pit_init(int irq) +{ + struct pit_data *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + panic(pr_fmt("Unable to allocate memory\n")); + + data->base = pit_base_addr; + + data->mck = clk_get(NULL, "mck"); + if (IS_ERR(data->mck)) + panic(pr_fmt("Unable to get mck clk\n")); + + data->irq = irq; + + at91sam926x_pit_common_init(data); +} + +void __init at91sam926x_ioremap_pit(u32 addr) +{ + if (of_have_populated_dt()) + return; + + pit_base_addr = ioremap(addr, 16); + + if (!pit_base_addr) + panic(pr_fmt("Impossible to ioremap PIT\n")); +} diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index fd89ca982748..7072c2892d63 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -376,4 +376,13 @@ config EDAC_OCTEON_PCI Support for error detection and correction on the Cavium Octeon family of SOCs. +config EDAC_ALTERA_MC + tristate "Altera SDRAM Memory Controller EDAC" + depends on EDAC_MM_EDAC && ARCH_SOCFPGA + help + Support for error detection and correction on the + Altera SDRAM memory controller. Note that the + preloader must initialize the SDRAM before loading + the kernel. + endif # EDAC diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index c479a24d8f77..359aa499b200 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -65,3 +65,5 @@ obj-$(CONFIG_EDAC_OCTEON_PC) += octeon_edac-pc.o obj-$(CONFIG_EDAC_OCTEON_L2C) += octeon_edac-l2c.o obj-$(CONFIG_EDAC_OCTEON_LMC) += octeon_edac-lmc.o obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o + +obj-$(CONFIG_EDAC_ALTERA_MC) += altera_edac.o diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c new file mode 100644 index 000000000000..3c4929fda9d5 --- /dev/null +++ b/drivers/edac/altera_edac.c @@ -0,0 +1,410 @@ +/* + * Copyright Altera Corporation (C) 2014. All rights reserved. + * Copyright 2011-2012 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + * + * Adapted from the highbank_mc_edac driver. + */ + +#include <linux/ctype.h> +#include <linux/edac.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/types.h> +#include <linux/uaccess.h> + +#include "edac_core.h" +#include "edac_module.h" + +#define EDAC_MOD_STR "altera_edac" +#define EDAC_VERSION "1" + +/* SDRAM Controller CtrlCfg Register */ +#define CTLCFG_OFST 0x00 + +/* SDRAM Controller CtrlCfg Register Bit Masks */ +#define CTLCFG_ECC_EN 0x400 +#define CTLCFG_ECC_CORR_EN 0x800 +#define CTLCFG_GEN_SB_ERR 0x2000 +#define CTLCFG_GEN_DB_ERR 0x4000 + +#define CTLCFG_ECC_AUTO_EN (CTLCFG_ECC_EN | \ + CTLCFG_ECC_CORR_EN) + +/* SDRAM Controller Address Width Register */ +#define DRAMADDRW_OFST 0x2C + +/* SDRAM Controller Address Widths Field Register */ +#define DRAMADDRW_COLBIT_MASK 0x001F +#define DRAMADDRW_COLBIT_SHIFT 0 +#define DRAMADDRW_ROWBIT_MASK 0x03E0 +#define DRAMADDRW_ROWBIT_SHIFT 5 +#define DRAMADDRW_BANKBIT_MASK 0x1C00 +#define DRAMADDRW_BANKBIT_SHIFT 10 +#define DRAMADDRW_CSBIT_MASK 0xE000 +#define DRAMADDRW_CSBIT_SHIFT 13 + +/* SDRAM Controller Interface Data Width Register */ +#define DRAMIFWIDTH_OFST 0x30 + +/* SDRAM Controller Interface Data Width Defines */ +#define DRAMIFWIDTH_16B_ECC 24 +#define DRAMIFWIDTH_32B_ECC 40 + +/* SDRAM Controller DRAM Status Register */ +#define DRAMSTS_OFST 0x38 + +/* SDRAM Controller DRAM Status Register Bit Masks */ +#define DRAMSTS_SBEERR 0x04 +#define DRAMSTS_DBEERR 0x08 +#define DRAMSTS_CORR_DROP 0x10 + +/* SDRAM Controller DRAM IRQ Register */ +#define DRAMINTR_OFST 0x3C + +/* SDRAM Controller DRAM IRQ Register Bit Masks */ +#define DRAMINTR_INTREN 0x01 +#define DRAMINTR_SBEMASK 0x02 +#define DRAMINTR_DBEMASK 0x04 +#define DRAMINTR_CORRDROPMASK 0x08 +#define DRAMINTR_INTRCLR 0x10 + +/* SDRAM Controller Single Bit Error Count Register */ +#define SBECOUNT_OFST 0x40 + +/* SDRAM Controller Single Bit Error Count Register Bit Masks */ +#define SBECOUNT_MASK 0x0F + +/* SDRAM Controller Double Bit Error Count Register */ +#define DBECOUNT_OFST 0x44 + +/* SDRAM Controller Double Bit Error Count Register Bit Masks */ +#define DBECOUNT_MASK 0x0F + +/* SDRAM Controller ECC Error Address Register */ +#define ERRADDR_OFST 0x48 + +/* SDRAM Controller ECC Error Address Register Bit Masks */ +#define ERRADDR_MASK 0xFFFFFFFF + +/* Altera SDRAM Memory Controller data */ +struct altr_sdram_mc_data { + struct regmap *mc_vbase; +}; + +static irqreturn_t altr_sdram_mc_err_handler(int irq, void *dev_id) +{ + struct mem_ctl_info *mci = dev_id; + struct altr_sdram_mc_data *drvdata = mci->pvt_info; + u32 status, err_count, err_addr; + + /* Error Address is shared by both SBE & DBE */ + regmap_read(drvdata->mc_vbase, ERRADDR_OFST, &err_addr); + + regmap_read(drvdata->mc_vbase, DRAMSTS_OFST, &status); + + if (status & DRAMSTS_DBEERR) { + regmap_read(drvdata->mc_vbase, DBECOUNT_OFST, &err_count); + panic("\nEDAC: [%d Uncorrectable errors @ 0x%08X]\n", + err_count, err_addr); + } + if (status & DRAMSTS_SBEERR) { + regmap_read(drvdata->mc_vbase, SBECOUNT_OFST, &err_count); + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, err_count, + err_addr >> PAGE_SHIFT, + err_addr & ~PAGE_MASK, 0, + 0, 0, -1, mci->ctl_name, ""); + } + + regmap_write(drvdata->mc_vbase, DRAMINTR_OFST, + (DRAMINTR_INTRCLR | DRAMINTR_INTREN)); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_EDAC_DEBUG +static ssize_t altr_sdr_mc_err_inject_write(struct file *file, + const char __user *data, + size_t count, loff_t *ppos) +{ + struct mem_ctl_info *mci = file->private_data; + struct altr_sdram_mc_data *drvdata = mci->pvt_info; + u32 *ptemp; + dma_addr_t dma_handle; + u32 reg, read_reg; + + ptemp = dma_alloc_coherent(mci->pdev, 16, &dma_handle, GFP_KERNEL); + if (!ptemp) { + dma_free_coherent(mci->pdev, 16, ptemp, dma_handle); + edac_printk(KERN_ERR, EDAC_MC, + "Inject: Buffer Allocation error\n"); + return -ENOMEM; + } + + regmap_read(drvdata->mc_vbase, CTLCFG_OFST, &read_reg); + read_reg &= ~(CTLCFG_GEN_SB_ERR | CTLCFG_GEN_DB_ERR); + + /* Error are injected by writing a word while the SBE or DBE + * bit in the CTLCFG register is set. Reading the word will + * trigger the SBE or DBE error and the corresponding IRQ. + */ + if (count == 3) { + edac_printk(KERN_ALERT, EDAC_MC, + "Inject Double bit error\n"); + regmap_write(drvdata->mc_vbase, CTLCFG_OFST, + (read_reg | CTLCFG_GEN_DB_ERR)); + } else { + edac_printk(KERN_ALERT, EDAC_MC, + "Inject Single bit error\n"); + regmap_write(drvdata->mc_vbase, CTLCFG_OFST, + (read_reg | CTLCFG_GEN_SB_ERR)); + } + + ptemp[0] = 0x5A5A5A5A; + ptemp[1] = 0xA5A5A5A5; + + /* Clear the error injection bits */ + regmap_write(drvdata->mc_vbase, CTLCFG_OFST, read_reg); + /* Ensure it has been written out */ + wmb(); + + /* + * To trigger the error, we need to read the data back + * (the data was written with errors above). + * The ACCESS_ONCE macros and printk are used to prevent the + * the compiler optimizing these reads out. + */ + reg = ACCESS_ONCE(ptemp[0]); + read_reg = ACCESS_ONCE(ptemp[1]); + /* Force Read */ + rmb(); + + edac_printk(KERN_ALERT, EDAC_MC, "Read Data [0x%X, 0x%X]\n", + reg, read_reg); + + dma_free_coherent(mci->pdev, 16, ptemp, dma_handle); + + return count; +} + +static const struct file_operations altr_sdr_mc_debug_inject_fops = { + .open = simple_open, + .write = altr_sdr_mc_err_inject_write, + .llseek = generic_file_llseek, +}; + +static void altr_sdr_mc_create_debugfs_nodes(struct mem_ctl_info *mci) +{ + if (mci->debugfs) + debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci, + &altr_sdr_mc_debug_inject_fops); +} +#else +static void altr_sdr_mc_create_debugfs_nodes(struct mem_ctl_info *mci) +{} +#endif + +/* Get total memory size in bytes */ +static u32 altr_sdram_get_total_mem_size(struct regmap *mc_vbase) +{ + u32 size, read_reg, row, bank, col, cs, width; + + if (regmap_read(mc_vbase, DRAMADDRW_OFST, &read_reg) < 0) + return 0; + + if (regmap_read(mc_vbase, DRAMIFWIDTH_OFST, &width) < 0) + return 0; + + col = (read_reg & DRAMADDRW_COLBIT_MASK) >> + DRAMADDRW_COLBIT_SHIFT; + row = (read_reg & DRAMADDRW_ROWBIT_MASK) >> + DRAMADDRW_ROWBIT_SHIFT; + bank = (read_reg & DRAMADDRW_BANKBIT_MASK) >> + DRAMADDRW_BANKBIT_SHIFT; + cs = (read_reg & DRAMADDRW_CSBIT_MASK) >> + DRAMADDRW_CSBIT_SHIFT; + + /* Correct for ECC as its not addressible */ + if (width == DRAMIFWIDTH_32B_ECC) + width = 32; + if (width == DRAMIFWIDTH_16B_ECC) + width = 16; + + /* calculate the SDRAM size base on this info */ + size = 1 << (row + bank + col); + size = size * cs * (width / 8); + return size; +} + +static int altr_sdram_probe(struct platform_device *pdev) +{ + struct edac_mc_layer layers[2]; + struct mem_ctl_info *mci; + struct altr_sdram_mc_data *drvdata; + struct regmap *mc_vbase; + struct dimm_info *dimm; + u32 read_reg, mem_size; + int irq; + int res = 0; + + /* Validate the SDRAM controller has ECC enabled */ + /* Grab the register range from the sdr controller in device tree */ + mc_vbase = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "altr,sdr-syscon"); + if (IS_ERR(mc_vbase)) { + edac_printk(KERN_ERR, EDAC_MC, + "regmap for altr,sdr-syscon lookup failed.\n"); + return -ENODEV; + } + + if (regmap_read(mc_vbase, CTLCFG_OFST, &read_reg) || + ((read_reg & CTLCFG_ECC_AUTO_EN) != CTLCFG_ECC_AUTO_EN)) { + edac_printk(KERN_ERR, EDAC_MC, + "No ECC/ECC disabled [0x%08X]\n", read_reg); + return -ENODEV; + } + + /* Grab memory size from device tree. */ + mem_size = altr_sdram_get_total_mem_size(mc_vbase); + if (!mem_size) { + edac_printk(KERN_ERR, EDAC_MC, + "Unable to calculate memory size\n"); + return -ENODEV; + } + + /* Ensure the SDRAM Interrupt is disabled and cleared */ + if (regmap_write(mc_vbase, DRAMINTR_OFST, DRAMINTR_INTRCLR)) { + edac_printk(KERN_ERR, EDAC_MC, + "Error clearing SDRAM ECC IRQ\n"); + return -ENODEV; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + edac_printk(KERN_ERR, EDAC_MC, + "No irq %d in DT\n", irq); + return -ENODEV; + } + + layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; + layers[0].size = 1; + layers[0].is_virt_csrow = true; + layers[1].type = EDAC_MC_LAYER_CHANNEL; + layers[1].size = 1; + layers[1].is_virt_csrow = false; + mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, + sizeof(struct altr_sdram_mc_data)); + if (!mci) + return -ENOMEM; + + mci->pdev = &pdev->dev; + drvdata = mci->pvt_info; + drvdata->mc_vbase = mc_vbase; + platform_set_drvdata(pdev, mci); + + if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) { + res = -ENOMEM; + goto free; + } + + mci->mtype_cap = MEM_FLAG_DDR3; + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; + mci->edac_cap = EDAC_FLAG_SECDED; + mci->mod_name = EDAC_MOD_STR; + mci->mod_ver = EDAC_VERSION; + mci->ctl_name = dev_name(&pdev->dev); + mci->scrub_mode = SCRUB_SW_SRC; + mci->dev_name = dev_name(&pdev->dev); + + dimm = *mci->dimms; + dimm->nr_pages = ((mem_size - 1) >> PAGE_SHIFT) + 1; + dimm->grain = 8; + dimm->dtype = DEV_X8; + dimm->mtype = MEM_DDR3; + dimm->edac_mode = EDAC_SECDED; + + res = edac_mc_add_mc(mci); + if (res < 0) + goto err; + + res = devm_request_irq(&pdev->dev, irq, altr_sdram_mc_err_handler, + 0, dev_name(&pdev->dev), mci); + if (res < 0) { + edac_mc_printk(mci, KERN_ERR, + "Unable to request irq %d\n", irq); + res = -ENODEV; + goto err2; + } + + if (regmap_write(drvdata->mc_vbase, DRAMINTR_OFST, + (DRAMINTR_INTRCLR | DRAMINTR_INTREN))) { + edac_mc_printk(mci, KERN_ERR, + "Error enabling SDRAM ECC IRQ\n"); + res = -ENODEV; + goto err2; + } + + altr_sdr_mc_create_debugfs_nodes(mci); + + devres_close_group(&pdev->dev, NULL); + + return 0; + +err2: + edac_mc_del_mc(&pdev->dev); +err: + devres_release_group(&pdev->dev, NULL); +free: + edac_mc_free(mci); + edac_printk(KERN_ERR, EDAC_MC, + "EDAC Probe Failed; Error %d\n", res); + + return res; +} + +static int altr_sdram_remove(struct platform_device *pdev) +{ + struct mem_ctl_info *mci = platform_get_drvdata(pdev); + + edac_mc_del_mc(&pdev->dev); + edac_mc_free(mci); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static const struct of_device_id altr_sdram_ctrl_of_match[] = { + { .compatible = "altr,sdram-edac", }, + {}, +}; +MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match); + +static struct platform_driver altr_sdram_edac_driver = { + .probe = altr_sdram_probe, + .remove = altr_sdram_remove, + .driver = { + .name = "altr_sdram_edac", + .of_match_table = altr_sdram_ctrl_of_match, + }, +}; + +module_platform_driver(altr_sdram_edac_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Thor Thayer"); +MODULE_DESCRIPTION("EDAC Driver for Altera SDRAM Controller"); diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index fab81a143bd7..6d91c27fd4c8 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -7,6 +7,16 @@ menuconfig MEMORY if MEMORY +config ATMEL_SDRAMC + bool "Atmel (Multi-port DDR-)SDRAM Controller" + default y + depends on ARCH_AT91 && OF + help + This driver is for Atmel SDRAM Controller or Atmel Multi-port + DDR-SDRAM Controller available on Atmel AT91SAM9 and SAMA5 SoCs. + Starting with the at91sam9g45, this controller supports SDR, DDR and + LP-DDR memories. + config TI_AEMIF tristate "Texas Instruments AEMIF driver" depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index 4055c47f45ab..c32d31981be3 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -5,6 +5,7 @@ ifeq ($(CONFIG_DDR),y) obj-$(CONFIG_OF) += of_memory.o endif +obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o obj-$(CONFIG_TI_AEMIF) += ti-aemif.o obj-$(CONFIG_TI_EMIF) += emif.o obj-$(CONFIG_FSL_CORENET_CF) += fsl-corenet-cf.o diff --git a/drivers/memory/atmel-sdramc.c b/drivers/memory/atmel-sdramc.c new file mode 100644 index 000000000000..fed04e8efe75 --- /dev/null +++ b/drivers/memory/atmel-sdramc.c @@ -0,0 +1,98 @@ +/* + * Atmel (Multi-port DDR-)SDRAM Controller driver + * + * Copyright (C) 2014 Atmel + * + * 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 version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> + +struct at91_ramc_caps { + bool has_ddrck; + bool has_mpddr_clk; +}; + +static const struct at91_ramc_caps at91rm9200_caps = { }; + +static const struct at91_ramc_caps at91sam9g45_caps = { + .has_ddrck = 1, + .has_mpddr_clk = 0, +}; + +static const struct at91_ramc_caps sama5d3_caps = { + .has_ddrck = 1, + .has_mpddr_clk = 1, +}; + +static const struct of_device_id atmel_ramc_of_match[] = { + { .compatible = "atmel,at91rm9200-sdramc", .data = &at91rm9200_caps, }, + { .compatible = "atmel,at91sam9260-sdramc", .data = &at91rm9200_caps, }, + { .compatible = "atmel,at91sam9g45-ddramc", .data = &at91sam9g45_caps, }, + { .compatible = "atmel,sama5d3-ddramc", .data = &sama5d3_caps, }, + {}, +}; +MODULE_DEVICE_TABLE(of, atmel_ramc_of_match); + +static int atmel_ramc_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + const struct at91_ramc_caps *caps; + struct clk *clk; + + match = of_match_device(atmel_ramc_of_match, &pdev->dev); + caps = match->data; + + if (caps->has_ddrck) { + clk = devm_clk_get(&pdev->dev, "ddrck"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + clk_prepare_enable(clk); + } + + if (caps->has_mpddr_clk) { + clk = devm_clk_get(&pdev->dev, "mpddr"); + if (IS_ERR(clk)) { + pr_err("AT91 RAMC: couldn't get mpddr clock\n"); + return PTR_ERR(clk); + } + clk_prepare_enable(clk); + } + + return 0; +} + +static struct platform_driver atmel_ramc_driver = { + .probe = atmel_ramc_probe, + .driver = { + .name = "atmel-ramc", + .owner = THIS_MODULE, + .of_match_table = atmel_ramc_of_match, + }, +}; + +static int __init atmel_ramc_init(void) +{ + return platform_driver_register(&atmel_ramc_driver); +} +module_init(atmel_ramc_init); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>"); +MODULE_DESCRIPTION("Atmel (Multi-port DDR-)SDRAM Controller"); diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index ca41523bbebf..81b445122eea 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -6,15 +6,33 @@ menuconfig POWER_RESET Say Y here to enable board reset and power off +if POWER_RESET + config POWER_RESET_AS3722 bool "ams AS3722 power-off driver" - depends on MFD_AS3722 && POWER_RESET + depends on MFD_AS3722 help This driver supports turning off board via a ams AS3722 power-off. +config POWER_RESET_AT91_POWEROFF + bool "Atmel AT91 poweroff driver" + depends on ARCH_AT91 + default SOC_AT91SAM9 || SOC_SAMA5 + help + This driver supports poweroff for Atmel AT91SAM9 and SAMA5 + SoCs + +config POWER_RESET_AT91_RESET + bool "Atmel AT91 reset driver" + depends on ARCH_AT91 + default SOC_AT91SAM9 || SOC_SAMA5 + help + This driver supports restart for Atmel AT91SAM9 and SAMA5 + SoCs + config POWER_RESET_AXXIA bool "LSI Axxia reset driver" - depends on POWER_RESET && ARCH_AXXIA + depends on ARCH_AXXIA help This driver supports restart for Axxia SoC. @@ -33,7 +51,7 @@ config POWER_RESET_BRCMSTB config POWER_RESET_GPIO bool "GPIO power-off driver" - depends on OF_GPIO && POWER_RESET + depends on OF_GPIO help This driver supports turning off your board via a GPIO line. If your board needs a GPIO high/low to power down, say Y and @@ -47,13 +65,13 @@ config POWER_RESET_HISI config POWER_RESET_MSM bool "Qualcomm MSM power-off driver" - depends on POWER_RESET && ARCH_QCOM + depends on ARCH_QCOM help Power off and restart support for Qualcomm boards. config POWER_RESET_QNAP bool "QNAP power-off driver" - depends on OF_GPIO && POWER_RESET && PLAT_ORION + depends on OF_GPIO && PLAT_ORION help This driver supports turning off QNAP NAS devices by sending commands to the microcontroller which controls the main power. @@ -71,14 +89,13 @@ config POWER_RESET_RESTART config POWER_RESET_SUN6I bool "Allwinner A31 SoC reset driver" depends on ARCH_SUNXI - depends on POWER_RESET help Reboot support for the Allwinner A31 SoCs. config POWER_RESET_VEXPRESS bool "ARM Versatile Express power-off and reset driver" depends on ARM || ARM64 - depends on POWER_RESET && VEXPRESS_CONFIG + depends on VEXPRESS_CONFIG help Power off and reset support for the ARM Ltd. Versatile Express boards. @@ -86,7 +103,6 @@ config POWER_RESET_VEXPRESS config POWER_RESET_XGENE bool "APM SoC X-Gene reset driver" depends on ARM64 - depends on POWER_RESET help Reboot support for the APM SoC X-Gene Eval boards. @@ -97,3 +113,4 @@ config POWER_RESET_KEYSTONE help Reboot support for the KEYSTONE SoCs. +endif diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index a42e70edd037..4433a753fd93 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -1,4 +1,6 @@ obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o +obj-$(CONFIG_POWER_RESET_AT91_POWEROFF) += at91-poweroff.o +obj-$(CONFIG_POWER_RESET_AT91_RESET) += at91-reset.o obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o diff --git a/drivers/power/reset/at91-poweroff.c b/drivers/power/reset/at91-poweroff.c new file mode 100644 index 000000000000..c61000333bb9 --- /dev/null +++ b/drivers/power/reset/at91-poweroff.c @@ -0,0 +1,156 @@ +/* + * Atmel AT91 SAM9 SoCs reset code + * + * Copyright (C) 2007 Atmel Corporation. + * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + * Copyright (C) 2014 Free Electrons + * + * 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/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/printk.h> + +#define AT91_SHDW_CR 0x00 /* Shut Down Control Register */ +#define AT91_SHDW_SHDW BIT(0) /* Shut Down command */ +#define AT91_SHDW_KEY (0xa5 << 24) /* KEY Password */ + +#define AT91_SHDW_MR 0x04 /* Shut Down Mode Register */ +#define AT91_SHDW_WKMODE0 GENMASK(2, 0) /* Wake-up 0 Mode Selection */ +#define AT91_SHDW_CPTWK0_MAX 0xf /* Maximum Counter On Wake Up 0 */ +#define AT91_SHDW_CPTWK0 (AT91_SHDW_CPTWK0_MAX << 4) /* Counter On Wake Up 0 */ +#define AT91_SHDW_CPTWK0_(x) ((x) << 4) +#define AT91_SHDW_RTTWKEN BIT(16) /* Real Time Timer Wake-up Enable */ +#define AT91_SHDW_RTCWKEN BIT(17) /* Real Time Clock Wake-up Enable */ + +#define AT91_SHDW_SR 0x08 /* Shut Down Status Register */ +#define AT91_SHDW_WAKEUP0 BIT(0) /* Wake-up 0 Status */ +#define AT91_SHDW_RTTWK BIT(16) /* Real-time Timer Wake-up */ +#define AT91_SHDW_RTCWK BIT(17) /* Real-time Clock Wake-up [SAM9RL] */ + +enum wakeup_type { + AT91_SHDW_WKMODE0_NONE = 0, + AT91_SHDW_WKMODE0_HIGH = 1, + AT91_SHDW_WKMODE0_LOW = 2, + AT91_SHDW_WKMODE0_ANYLEVEL = 3, +}; + +static const char *shdwc_wakeup_modes[] = { + [AT91_SHDW_WKMODE0_NONE] = "none", + [AT91_SHDW_WKMODE0_HIGH] = "high", + [AT91_SHDW_WKMODE0_LOW] = "low", + [AT91_SHDW_WKMODE0_ANYLEVEL] = "any", +}; + +static void __iomem *at91_shdwc_base; + +static void __init at91_wakeup_status(void) +{ + u32 reg = readl(at91_shdwc_base + AT91_SHDW_SR); + char *reason = "unknown"; + + /* Simple power-on, just bail out */ + if (!reg) + return; + + if (reg & AT91_SHDW_RTTWK) + reason = "RTT"; + else if (reg & AT91_SHDW_RTCWK) + reason = "RTC"; + + pr_info("AT91: Wake-Up source: %s\n", reason); +} + +static void at91_poweroff(void) +{ + writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, at91_shdwc_base + AT91_SHDW_CR); +} + +const enum wakeup_type at91_poweroff_get_wakeup_mode(struct device_node *np) +{ + const char *pm; + int err, i; + + err = of_property_read_string(np, "atmel,wakeup-mode", &pm); + if (err < 0) + return AT91_SHDW_WKMODE0_ANYLEVEL; + + for (i = 0; i < ARRAY_SIZE(shdwc_wakeup_modes); i++) + if (!strcasecmp(pm, shdwc_wakeup_modes[i])) + return i; + + return -ENODEV; +} + +static void at91_poweroff_dt_set_wakeup_mode(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + enum wakeup_type wakeup_mode; + u32 mode = 0, tmp; + + wakeup_mode = at91_poweroff_get_wakeup_mode(np); + if (wakeup_mode < 0) { + dev_warn(&pdev->dev, "shdwc unknown wakeup mode\n"); + return; + } + + if (!of_property_read_u32(np, "atmel,wakeup-counter", &tmp)) { + if (tmp > AT91_SHDW_CPTWK0_MAX) { + dev_warn(&pdev->dev, + "shdwc wakeup counter 0x%x > 0x%x reduce it to 0x%x\n", + tmp, AT91_SHDW_CPTWK0_MAX, AT91_SHDW_CPTWK0_MAX); + tmp = AT91_SHDW_CPTWK0_MAX; + } + mode |= AT91_SHDW_CPTWK0_(tmp); + } + + if (of_property_read_bool(np, "atmel,wakeup-rtc-timer")) + mode |= AT91_SHDW_RTCWKEN; + + if (of_property_read_bool(np, "atmel,wakeup-rtt-timer")) + mode |= AT91_SHDW_RTTWKEN; + + writel(wakeup_mode | mode, at91_shdwc_base + AT91_SHDW_MR); +} + +static int at91_poweroff_probe(struct platform_device *pdev) +{ + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + at91_shdwc_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(at91_shdwc_base)) { + dev_err(&pdev->dev, "Could not map reset controller address\n"); + return PTR_ERR(at91_shdwc_base); + } + + at91_wakeup_status(); + + if (pdev->dev.of_node) + at91_poweroff_dt_set_wakeup_mode(pdev); + + pm_power_off = at91_poweroff; + + return 0; +} + +static struct of_device_id at91_poweroff_of_match[] = { + { .compatible = "atmel,at91sam9260-shdwc", }, + { .compatible = "atmel,at91sam9rl-shdwc", }, + { .compatible = "atmel,at91sam9x5-shdwc", }, + { /*sentinel*/ } +}; + +static struct platform_driver at91_poweroff_driver = { + .probe = at91_poweroff_probe, + .driver = { + .name = "at91-poweroff", + .of_match_table = at91_poweroff_of_match, + }, +}; +module_platform_driver(at91_poweroff_driver); diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c new file mode 100644 index 000000000000..3611806c9cfd --- /dev/null +++ b/drivers/power/reset/at91-reset.c @@ -0,0 +1,252 @@ +/* + * Atmel AT91 SAM9 SoCs reset code + * + * Copyright (C) 2007 Atmel Corporation. + * Copyright (C) BitBox Ltd 2010 + * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcosoft.com> + * Copyright (C) 2014 Free Electrons + * + * 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/io.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> + +#include <asm/system_misc.h> + +#include <mach/at91sam9_ddrsdr.h> +#include <mach/at91sam9_sdramc.h> + +#define AT91_RSTC_CR 0x00 /* Reset Controller Control Register */ +#define AT91_RSTC_PROCRST BIT(0) /* Processor Reset */ +#define AT91_RSTC_PERRST BIT(2) /* Peripheral Reset */ +#define AT91_RSTC_EXTRST BIT(3) /* External Reset */ +#define AT91_RSTC_KEY (0xa5 << 24) /* KEY Password */ + +#define AT91_RSTC_SR 0x04 /* Reset Controller Status Register */ +#define AT91_RSTC_URSTS BIT(0) /* User Reset Status */ +#define AT91_RSTC_RSTTYP GENMASK(10, 8) /* Reset Type */ +#define AT91_RSTC_NRSTL BIT(16) /* NRST Pin Level */ +#define AT91_RSTC_SRCMP BIT(17) /* Software Reset Command in Progress */ + +#define AT91_RSTC_MR 0x08 /* Reset Controller Mode Register */ +#define AT91_RSTC_URSTEN BIT(0) /* User Reset Enable */ +#define AT91_RSTC_URSTIEN BIT(4) /* User Reset Interrupt Enable */ +#define AT91_RSTC_ERSTL GENMASK(11, 8) /* External Reset Length */ + +enum reset_type { + RESET_TYPE_GENERAL = 0, + RESET_TYPE_WAKEUP = 1, + RESET_TYPE_WATCHDOG = 2, + RESET_TYPE_SOFTWARE = 3, + RESET_TYPE_USER = 4, +}; + +static void __iomem *at91_ramc_base[2], *at91_rstc_base; + +/* +* unless the SDRAM is cleanly shutdown before we hit the +* reset register it can be left driving the data bus and +* killing the chance of a subsequent boot from NAND +*/ +static void at91sam9260_restart(enum reboot_mode mode, const char *cmd) +{ + asm volatile( + /* Align to cache lines */ + ".balign 32\n\t" + + /* Disable SDRAM accesses */ + "str %2, [%0, #" __stringify(AT91_SDRAMC_TR) "]\n\t" + + /* Power down SDRAM */ + "str %3, [%0, #" __stringify(AT91_SDRAMC_LPR) "]\n\t" + + /* Reset CPU */ + "str %4, [%1, #" __stringify(AT91_RSTC_CR) "]\n\t" + + "b .\n\t" + : + : "r" (at91_ramc_base[0]), + "r" (at91_rstc_base), + "r" (1), + "r" (AT91_SDRAMC_LPCB_POWER_DOWN), + "r" (AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)); +} + +static void at91sam9g45_restart(enum reboot_mode mode, const char *cmd) +{ + asm volatile( + /* + * Test wether we have a second RAM controller to care + * about. + * + * First, test that we can dereference the virtual address. + */ + "cmp %1, #0\n\t" + "beq 1f\n\t" + + /* Then, test that the RAM controller is enabled */ + "ldr r0, [%1]\n\t" + "cmp r0, #0\n\t" + + /* Align to cache lines */ + ".balign 32\n\t" + + /* Disable SDRAM0 accesses */ + "1: str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" + /* Power down SDRAM0 */ + " str %4, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" + /* Disable SDRAM1 accesses */ + " strne %3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" + /* Power down SDRAM1 */ + " strne %4, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" + /* Reset CPU */ + " str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t" + + " b .\n\t" + : + : "r" (at91_ramc_base[0]), + "r" (at91_ramc_base[1]), + "r" (at91_rstc_base), + "r" (1), + "r" (AT91_DDRSDRC_LPCB_POWER_DOWN), + "r" (AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST) + : "r0"); +} + +static void __init at91_reset_status(struct platform_device *pdev) +{ + u32 reg = readl(at91_rstc_base + AT91_RSTC_SR); + char *reason; + + switch ((reg & AT91_RSTC_RSTTYP) >> 8) { + case RESET_TYPE_GENERAL: + reason = "general reset"; + break; + case RESET_TYPE_WAKEUP: + reason = "wakeup"; + break; + case RESET_TYPE_WATCHDOG: + reason = "watchdog reset"; + break; + case RESET_TYPE_SOFTWARE: + reason = "software reset"; + break; + case RESET_TYPE_USER: + reason = "user reset"; + break; + default: + reason = "unknown reset"; + break; + } + + pr_info("AT91: Starting after %s\n", reason); +} + +static struct of_device_id at91_ramc_of_match[] = { + { .compatible = "atmel,at91sam9260-sdramc", }, + { .compatible = "atmel,at91sam9g45-ddramc", }, + { .compatible = "atmel,sama5d3-ddramc", }, + { /* sentinel */ } +}; + +static struct of_device_id at91_reset_of_match[] = { + { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9260_restart }, + { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart }, + { /* sentinel */ } +}; + +static int at91_reset_of_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct device_node *np; + int idx = 0; + + at91_rstc_base = of_iomap(pdev->dev.of_node, 0); + if (!at91_rstc_base) { + dev_err(&pdev->dev, "Could not map reset controller address\n"); + return -ENODEV; + } + + for_each_matching_node(np, at91_ramc_of_match) { + at91_ramc_base[idx] = of_iomap(np, 0); + if (!at91_ramc_base[idx]) { + dev_err(&pdev->dev, "Could not map ram controller address\n"); + return -ENODEV; + } + idx++; + } + + match = of_match_node(at91_reset_of_match, pdev->dev.of_node); + arm_pm_restart = match->data; + + return 0; +} + +static int at91_reset_platform_probe(struct platform_device *pdev) +{ + const struct platform_device_id *match; + struct resource *res; + int idx = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + at91_rstc_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(at91_rstc_base)) { + dev_err(&pdev->dev, "Could not map reset controller address\n"); + return PTR_ERR(at91_rstc_base); + } + + for (idx = 0; idx < 2; idx++) { + res = platform_get_resource(pdev, IORESOURCE_MEM, idx + 1 ); + at91_ramc_base[idx] = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (IS_ERR(at91_ramc_base[idx])) { + dev_err(&pdev->dev, "Could not map ram controller address\n"); + return PTR_ERR(at91_ramc_base[idx]); + } + } + + match = platform_get_device_id(pdev); + arm_pm_restart = (void (*)(enum reboot_mode, const char*)) + match->driver_data; + + return 0; +} + +static int at91_reset_probe(struct platform_device *pdev) +{ + int ret; + + if (pdev->dev.of_node) + ret = at91_reset_of_probe(pdev); + else + ret = at91_reset_platform_probe(pdev); + + if (ret) + return ret; + + at91_reset_status(pdev); + + return 0; +} + +static struct platform_device_id at91_reset_plat_match[] = { + { "at91-sam9260-reset", (unsigned long)at91sam9260_restart }, + { "at91-sam9g45-reset", (unsigned long)at91sam9g45_restart }, + { /* sentinel */ } +}; + +static struct platform_driver at91_reset_driver = { + .probe = at91_reset_probe, + .driver = { + .name = "at91-reset", + .of_match_table = at91_reset_of_match, + }, + .id_table = at91_reset_plat_match, +}; +module_platform_driver(at91_reset_driver); |