diff options
137 files changed, 2962 insertions, 1851 deletions
diff --git a/Documentation/arm/firmware.txt b/Documentation/arm/firmware.txt index c2e468fe7b0b..da6713adac8a 100644 --- a/Documentation/arm/firmware.txt +++ b/Documentation/arm/firmware.txt @@ -7,32 +7,14 @@ world, which changes the way some things have to be initialized. This makes a need to provide an interface for such platforms to specify available firmware operations and call them when needed. -Firmware operations can be specified using struct firmware_ops - - struct firmware_ops { - /* - * Enters CPU idle mode - */ - int (*do_idle)(void); - /* - * Sets boot address of specified physical CPU - */ - int (*set_cpu_boot_addr)(int cpu, unsigned long boot_addr); - /* - * Boots specified physical CPU - */ - int (*cpu_boot)(int cpu); - /* - * Initializes L2 cache - */ - int (*l2x0_init)(void); - }; - -and then registered with register_firmware_ops function +Firmware operations can be specified by filling in a struct firmware_ops +with appropriate callbacks and then registering it with register_firmware_ops() +function. void register_firmware_ops(const struct firmware_ops *ops) -the ops pointer must be non-NULL. +The ops pointer must be non-NULL. More information about struct firmware_ops +and its members can be found in arch/arm/include/asm/firmware.h header. There is a default, empty set of operations provided, so there is no need to set anything if platform does not require firmware operations. diff --git a/Documentation/devicetree/bindings/arm/ux500/power_domain.txt b/Documentation/devicetree/bindings/arm/ux500/power_domain.txt new file mode 100644 index 000000000000..5679d1742d3e --- /dev/null +++ b/Documentation/devicetree/bindings/arm/ux500/power_domain.txt @@ -0,0 +1,35 @@ +* ST-Ericsson UX500 PM Domains + +UX500 supports multiple PM domains which are used to gate power to one or +more peripherals on the SOC. + +The implementation of PM domains for UX500 are based upon the generic PM domain +and use the corresponding DT bindings. + +==PM domain providers== + +Required properties: + - compatible: Must be "stericsson,ux500-pm-domains". + - #power-domain-cells : Number of cells in a power domain specifier, must be 1. + +Example: + pm_domains: pm_domains0 { + compatible = "stericsson,ux500-pm-domains"; + #power-domain-cells = <1>; + }; + +==PM domain consumers== + +Required properties: + - power-domains: A phandle and PM domain specifier. Below are the list of + valid specifiers: + + Index Specifier + ----- --------- + 0 DOMAIN_VAPE + +Example: + sdi0_per1@80126000 { + compatible = "arm,pl18x", "arm,primecell"; + power-domains = <&pm_domains DOMAIN_VAPE> + }; diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 89c4b5ccc68d..2075ebdccf5d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -320,24 +320,6 @@ config ARCH_MULTIPLATFORM select SPARSE_IRQ select USE_OF -config ARCH_INTEGRATOR - bool "ARM Ltd. Integrator family" - select ARM_AMBA - select ARM_PATCH_PHYS_VIRT if MMU - select AUTO_ZRELADDR - select COMMON_CLK - select COMMON_CLK_VERSATILE - select GENERIC_CLOCKEVENTS - select HAVE_TCM - select ICST - select MULTI_IRQ_HANDLER - select PLAT_VERSATILE - select SPARSE_IRQ - select USE_OF - select VERSATILE_FPGA_IRQ - help - Support for ARM's Integrator platform. - config ARCH_REALVIEW bool "ARM Ltd. RealView family" select ARCH_WANT_OPTIONAL_GPIOLIB diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 03dc4c1a8736..08707ef1ad84 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -139,6 +139,17 @@ choice Say Y here if you want kernel low-level debugging support on Marvell Berlin SoC based platforms. + config DEBUG_BRCMSTB_UART + bool "Use BRCMSTB UART for low-level debug" + depends on ARCH_BRCMSTB + select DEBUG_UART_8250 + help + Say Y here if you want the debug print routines to direct + their output to the first serial port on these devices. + + If you have a Broadcom STB chip and would like early print + messages to appear over the UART, select this option. + config DEBUG_CLPS711X_UART1 bool "Kernel low-level debugging messages via UART1" depends on ARCH_CLPS711X @@ -723,6 +734,14 @@ choice their output to UART 2. The port must have been initialised by the boot-loader before use. + config DEBUG_SA1100 + depends on ARCH_SA1100 + bool "Use SA1100 UARTs for low-level debug" + help + Say Y here if you want kernel low-level debugging support + on SA-11x0 UART ports. The kernel will check for the first + enabled UART in a sequence 3-1-2. + config DEBUG_SOCFPGA_UART depends on ARCH_SOCFPGA bool "Use SOCFPGA UART for low-level debug" @@ -866,6 +885,22 @@ choice Say Y here if you want kernel low-level debugging support for Mediatek mt6589 based platforms on UART0. + config DEBUG_MT8127_UART0 + bool "Mediatek mt8127 UART0" + depends on ARCH_MEDIATEK + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + for Mediatek mt8127 based platforms on UART0. + + config DEBUG_MT8135_UART3 + bool "Mediatek mt8135 UART3" + depends on ARCH_MEDIATEK + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + for Mediatek mt8135 based platforms on UART3. + config DEBUG_VEXPRESS_UART0_DETECT bool "Autodetect UART0 on Versatile Express Cortex-A core tiles" depends on ARCH_VEXPRESS && CPU_CP15_MMU @@ -1041,6 +1076,7 @@ config DEBUG_STI_UART config DEBUG_LL_INCLUDE string + default "debug/sa1100.S" if DEBUG_SA1100 default "debug/8250.S" if DEBUG_LL_UART_8250 || DEBUG_UART_8250 default "debug/clps711x.S" if DEBUG_CLPS711X_UART1 || DEBUG_CLPS711X_UART2 default "debug/meson.S" if DEBUG_MESON_UARTAO @@ -1113,7 +1149,9 @@ config DEBUG_UART_PHYS default 0x10126000 if DEBUG_RK3X_UART1 default 0x101f1000 if ARCH_VERSATILE default 0x101fb000 if DEBUG_NOMADIK_UART + default 0x11002000 if DEBUG_MT8127_UART0 default 0x11006000 if DEBUG_MT6589_UART0 + default 0x11009000 if DEBUG_MT8135_UART3 default 0x16000000 if ARCH_INTEGRATOR default 0x18000300 if DEBUG_BCM_5301X default 0x1c090000 if DEBUG_VEXPRESS_UART0_RS1 @@ -1153,6 +1191,7 @@ config DEBUG_UART_PHYS default 0xe0000000 if ARCH_SPEAR13XX default 0xe4007000 if DEBUG_HIP04_UART default 0xf0000be0 if ARCH_EBSA110 + default 0xf040ab00 if DEBUG_BRCMSTB_UART default 0xf1012000 if DEBUG_MVEBU_UART_ALTERNATE default 0xf1012000 if ARCH_DOVE || ARCH_MV78XX0 || \ ARCH_ORION5X @@ -1181,7 +1220,9 @@ config DEBUG_UART_VIRT default 0xf01fb000 if DEBUG_NOMADIK_UART default 0xf0201000 if DEBUG_BCM2835 default 0xf1000300 if DEBUG_BCM_5301X + default 0xf1002000 if DEBUG_MT8127_UART0 default 0xf1006000 if DEBUG_MT6589_UART0 + default 0xf1009000 if DEBUG_MT8135_UART3 default 0xf11f1000 if ARCH_VERSATILE default 0xf1600000 if ARCH_INTEGRATOR default 0xf1c28000 if DEBUG_SUNXI_UART0 @@ -1204,6 +1245,7 @@ config DEBUG_UART_VIRT default 0xfb002000 if DEBUG_CNS3XXX default 0xfb009000 if DEBUG_REALVIEW_STD_PORT default 0xfb10c000 if DEBUG_REALVIEW_PB1176_PORT + default 0xfc40ab00 if DEBUG_BRCMSTB_UART default 0xfcfe8600 if DEBUG_UART_BCM63XX default 0xfd000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX default 0xfd000000 if ARCH_SPEAR13XX @@ -1260,7 +1302,8 @@ config DEBUG_UART_8250_WORD ARCH_KEYSTONE || \ DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \ DEBUG_DAVINCI_DA8XX_UART2 || \ - DEBUG_BCM_KONA_UART || DEBUG_RK32_UART2 + DEBUG_BCM_KONA_UART || DEBUG_RK32_UART2 || \ + DEBUG_BRCMSTB_UART config DEBUG_UART_8250_FLOW_CONTROL bool "Enable flow control for 8250 UART" diff --git a/arch/arm/boot/dts/integrator.dtsi b/arch/arm/boot/dts/integrator.dtsi index 88e3d477bf16..28e38f8c6b0f 100644 --- a/arch/arm/boot/dts/integrator.dtsi +++ b/arch/arm/boot/dts/integrator.dtsi @@ -6,8 +6,18 @@ / { core-module@10000000 { - compatible = "arm,core-module-integrator"; + compatible = "arm,core-module-integrator", "syscon"; reg = <0x10000000 0x200>; + + /* Use core module LED to indicate CPU load */ + led@0c.0 { + compatible = "register-bit-led"; + offset = <0x0c>; + mask = <0x01>; + label = "integrator:core_module"; + linux,default-trigger = "cpu0"; + default-state = "on"; + }; }; ebi@12000000 { @@ -82,5 +92,41 @@ reg = <0x19000000 0x1000>; interrupts = <4>; }; + + syscon { + /* Debug registers mapped as syscon */ + compatible = "syscon"; + reg = <0x1a000000 0x10>; + + led@04.0 { + compatible = "register-bit-led"; + offset = <0x04>; + mask = <0x01>; + label = "integrator:green0"; + linux,default-trigger = "heartbeat"; + default-state = "on"; + }; + led@04.1 { + compatible = "register-bit-led"; + offset = <0x04>; + mask = <0x02>; + label = "integrator:yellow"; + default-state = "off"; + }; + led@04.2 { + compatible = "register-bit-led"; + offset = <0x04>; + mask = <0x04>; + label = "integrator:red"; + default-state = "off"; + }; + led@04.3 { + compatible = "register-bit-led"; + offset = <0x04>; + mask = <0x08>; + label = "integrator:green1"; + default-state = "off"; + }; + }; }; }; diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi index 9d2323020d34..bfd3f1c734b8 100644 --- a/arch/arm/boot/dts/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi @@ -11,6 +11,7 @@ #include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/mfd/dbx500-prcmu.h> +#include <dt-bindings/arm/ux500_pm_domains.h> #include "skeleton.dtsi" / { @@ -43,6 +44,10 @@ interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>; }; + pm_domains: pm_domains0 { + compatible = "stericsson,ux500-pm-domains"; + #power-domain-cells = <1>; + }; clocks { compatible = "stericsson,u8500-clks"; @@ -636,6 +641,7 @@ clock-frequency = <400000>; clocks = <&prcc_kclk 3 3>, <&prcc_pclk 3 3>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; i2c@80122000 { @@ -651,6 +657,7 @@ clocks = <&prcc_kclk 1 2>, <&prcc_pclk 1 2>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; i2c@80128000 { @@ -666,6 +673,7 @@ clocks = <&prcc_kclk 1 6>, <&prcc_pclk 1 6>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; i2c@80110000 { @@ -681,6 +689,7 @@ clocks = <&prcc_kclk 2 0>, <&prcc_pclk 2 0>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; i2c@8012a000 { @@ -696,6 +705,7 @@ clocks = <&prcc_kclk 1 9>, <&prcc_pclk 1 10>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; ssp@80002000 { @@ -709,6 +719,7 @@ dmas = <&dma 8 0 0x2>, /* Logical - DevToMem */ <&dma 8 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; ssp@80003000 { @@ -722,6 +733,7 @@ dmas = <&dma 9 0 0x2>, /* Logical - DevToMem */ <&dma 9 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; spi@8011a000 { @@ -736,6 +748,7 @@ dmas = <&dma 0 0 0x2>, /* Logical - DevToMem */ <&dma 0 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; spi@80112000 { @@ -750,6 +763,7 @@ dmas = <&dma 35 0 0x2>, /* Logical - DevToMem */ <&dma 35 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; spi@80111000 { @@ -764,6 +778,7 @@ dmas = <&dma 33 0 0x2>, /* Logical - DevToMem */ <&dma 33 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; spi@80129000 { @@ -778,6 +793,7 @@ dmas = <&dma 40 0 0x2>, /* Logical - DevToMem */ <&dma 40 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; uart@80120000 { @@ -836,6 +852,7 @@ clocks = <&prcc_kclk 1 5>, <&prcc_pclk 1 5>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -851,6 +868,7 @@ clocks = <&prcc_kclk 2 4>, <&prcc_pclk 2 6>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -866,6 +884,7 @@ clocks = <&prcc_kclk 3 4>, <&prcc_pclk 3 4>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -881,6 +900,7 @@ clocks = <&prcc_kclk 2 5>, <&prcc_pclk 2 7>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -896,6 +916,7 @@ clocks = <&prcc_kclk 2 2>, <&prcc_pclk 2 4>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -911,6 +932,7 @@ clocks = <&prcc_kclk 3 7>, <&prcc_pclk 3 7>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; diff --git a/arch/arm/configs/bcm_defconfig b/arch/arm/configs/bcm_defconfig index bc614f44b33d..83a87e48901c 100644 --- a/arch/arm/configs/bcm_defconfig +++ b/arch/arm/configs/bcm_defconfig @@ -25,7 +25,8 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_BCM=y -CONFIG_ARCH_BCM_MOBILE=y +CONFIG_ARCH_BCM_21664=y +CONFIG_ARCH_BCM_281XX=y CONFIG_ARM_THUMBEE=y CONFIG_SMP=y CONFIG_PREEMPT=y diff --git a/arch/arm/configs/integrator_defconfig b/arch/arm/configs/integrator_defconfig index c1f5adc5493e..71f14675d009 100644 --- a/arch/arm/configs/integrator_defconfig +++ b/arch/arm/configs/integrator_defconfig @@ -8,6 +8,9 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_MULTI_V4T=y +CONFIG_ARCH_MULTI_V5=y +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_INTEGRATOR=y CONFIG_ARCH_INTEGRATOR_AP=y CONFIG_ARCH_INTEGRATOR_CP=y diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h index 2c9f10df7568..89aefe10d66b 100644 --- a/arch/arm/include/asm/firmware.h +++ b/arch/arm/include/asm/firmware.h @@ -28,7 +28,7 @@ struct firmware_ops { /* * Enters CPU idle mode */ - int (*do_idle)(void); + int (*do_idle)(unsigned long mode); /* * Sets boot address of specified physical CPU */ @@ -41,6 +41,14 @@ struct firmware_ops { * Initializes L2 cache */ int (*l2x0_init)(void); + /* + * Enter system-wide suspend. + */ + int (*suspend)(void); + /* + * Restore state of privileged hardware after system-wide suspend. + */ + int (*resume)(void); }; /* Global pointer for current firmware_ops structure, can't be NULL. */ diff --git a/arch/arm/mach-sa1100/include/mach/debug-macro.S b/arch/arm/include/debug/sa1100.S index 530772d937ad..a0ae4f4cd924 100644 --- a/arch/arm/mach-sa1100/include/mach/debug-macro.S +++ b/arch/arm/include/debug/sa1100.S @@ -1,4 +1,4 @@ -/* arch/arm/mach-sa1100/include/mach/debug-macro.S +/* arch/arm/include/debug/sa1100.S * * Debugging macro include header * @@ -10,7 +10,13 @@ * published by the Free Software Foundation. * */ -#include <mach/hardware.h> + +#define UTCR3 0x0c +#define UTDR 0x14 +#define UTSR1 0x20 +#define UTCR3_TXE 0x00000002 /* Transmit Enable */ +#define UTSR1_TBY 0x00000001 /* Transmitter BusY (read) */ +#define UTSR1_TNF 0x00000004 /* Transmit FIFO Not Full (read) */ .macro addruart, rp, rv, tmp mrc p15, 0, \rp, c1, c0 diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 2abad742516d..1bd39b45d08b 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -5,8 +5,56 @@ menuconfig ARCH_BCM if ARCH_BCM +comment "IPROC architected SoCs" + +config ARCH_BCM_IPROC + bool + select ARM_GIC + select CACHE_L2X0 + select HAVE_ARM_SCU if SMP + select HAVE_ARM_TWD if SMP + select ARM_GLOBAL_TIMER + + select CLKSRC_MMIO + select ARCH_REQUIRE_GPIOLIB + select ARM_AMBA + select PINCTRL + help + This enables support for systems based on Broadcom IPROC architected SoCs. + The IPROC complex contains one or more ARM CPUs along with common + core periperals. Application specific SoCs are created by adding a + uArchitecture containing peripherals outside of the IPROC complex. + Currently supported SoCs are Cygnus. + +config ARCH_BCM_CYGNUS + bool "Broadcom Cygnus Support" if ARCH_MULTI_V7 + select ARCH_BCM_IPROC + help + Enable support for the Cygnus family, + which includes the following variants: + BCM11300, BCM11320, BCM11350, BCM11360, + BCM58300, BCM58302, BCM58303, BCM58305. + +config ARCH_BCM_5301X + bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7 + select ARCH_BCM_IPROC + help + Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. + + This is a network SoC line mostly used in home routers and + wifi access points, it's internal name is Northstar. + This inclused the following SoC: BCM53010, BCM53011, BCM53012, + BCM53014, BCM53015, BCM53016, BCM53017, BCM53018, BCM4707, + BCM4708 and BCM4709. + + Do not confuse this with the BCM4760 which is a totally + different SoC or with the older BCM47XX and BCM53XX based + network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx + +comment "KONA architected SoCs" + config ARCH_BCM_MOBILE - bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7 + bool select ARCH_REQUIRE_GPIOLIB select ARM_ERRATA_754322 select ARM_ERRATA_775420 @@ -15,16 +63,13 @@ config ARCH_BCM_MOBILE select TICK_ONESHOT select HAVE_ARM_ARCH_TIMER select PINCTRL + select ARCH_BCM_MOBILE_SMP if SMP help This enables support for systems based on Broadcom mobile SoCs. -if ARCH_BCM_MOBILE - -menu "Broadcom Mobile SoC Selection" - config ARCH_BCM_281XX bool "Broadcom BCM281XX SoC family" - default y + select ARCH_BCM_MOBILE select HAVE_SMP help Enable support for the BCM281XX family, which includes @@ -33,7 +78,7 @@ config ARCH_BCM_281XX config ARCH_BCM_21664 bool "Broadcom BCM21664 SoC family" - default y + select ARCH_BCM_MOBILE select HAVE_SMP help Enable support for the BCM21664 family, which includes @@ -41,19 +86,18 @@ config ARCH_BCM_21664 config ARCH_BCM_MOBILE_L2_CACHE bool "Broadcom mobile SoC level 2 cache support" - depends on (ARCH_BCM_281XX || ARCH_BCM_21664) + depends on ARCH_BCM_MOBILE default y select CACHE_L2X0 select ARCH_BCM_MOBILE_SMC config ARCH_BCM_MOBILE_SMC bool - depends on ARCH_BCM_281XX || ARCH_BCM_21664 + depends on ARCH_BCM_MOBILE config ARCH_BCM_MOBILE_SMP - bool "Broadcom mobile SoC SMP support" - depends on (ARCH_BCM_281XX || ARCH_BCM_21664) && SMP - default y + bool + depends on ARCH_BCM_MOBILE select HAVE_ARM_SCU select ARM_ERRATA_764369 help @@ -61,9 +105,7 @@ config ARCH_BCM_MOBILE_SMP Provided as an option so SMP support for SoCs of this type can be disabled for an SMP-enabled kernel. -endmenu - -endif +comment "Other Architectures" config ARCH_BCM2835 bool "Broadcom BCM2835 family" if ARCH_MULTI_V6 @@ -78,27 +120,6 @@ config ARCH_BCM2835 This enables support for the Broadcom BCM2835 SoC. This SoC is used in the Raspberry Pi and Roku 2 devices. -config ARCH_BCM_5301X - bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7 - select ARM_GIC - select CACHE_L2X0 - select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if SMP - select ARM_GLOBAL_TIMER - select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK - help - Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. - - This is a network SoC line mostly used in home routers and - wifi access points, it's internal name is Northstar. - This inclused the following SoC: BCM53010, BCM53011, BCM53012, - BCM53014, BCM53015, BCM53016, BCM53017, BCM53018, BCM4707, - BCM4708 and BCM4709. - - Do not confuse this with the BCM4760 which is a totally - different SoC or with the older BCM47XX and BCM53XX based - network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx - config ARCH_BCM_63XX bool "Broadcom BCM63xx DSL SoC" if ARCH_MULTI_V7 depends on MMU @@ -118,10 +139,7 @@ config ARCH_BCM_63XX config ARCH_BRCMSTB bool "Broadcom BCM7XXX based boards" if ARCH_MULTI_V7 - depends on MMU select ARM_GIC - select MIGHT_HAVE_PCI - select HAVE_SMP select HAVE_ARM_ARCH_TIMER select BRCMSTB_GISB_ARB select BRCMSTB_L2_IRQ diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile index 300ae4b79ae6..4c38674c73ec 100644 --- a/arch/arm/mach-bcm/Makefile +++ b/arch/arm/mach-bcm/Makefile @@ -10,6 +10,9 @@ # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. +# Cygnus +obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o + # BCM281XX obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o @@ -38,5 +41,7 @@ obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o obj-$(CONFIG_ARCH_BCM_63XX) := bcm63xx.o ifeq ($(CONFIG_ARCH_BRCMSTB),y) +CFLAGS_platsmp-brcmstb.o += -march=armv7-a obj-y += brcmstb.o +obj-$(CONFIG_SMP) += headsmp-brcmstb.o platsmp-brcmstb.o endif diff --git a/arch/arm/mach-bcm/bcm_cygnus.c b/arch/arm/mach-bcm/bcm_cygnus.c new file mode 100644 index 000000000000..30dc58be51b8 --- /dev/null +++ b/arch/arm/mach-bcm/bcm_cygnus.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014 Broadcom Corporation + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <asm/mach/arch.h> + +static const char const *bcm_cygnus_dt_compat[] = { + "brcm,cygnus", + NULL, +}; + +DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC") + .l2c_aux_val = 0, + .l2c_aux_mask = ~0, + .dt_compat = bcm_cygnus_dt_compat, +MACHINE_END diff --git a/arch/arm/mach-bcm/brcmstb.h b/arch/arm/mach-bcm/brcmstb.h new file mode 100644 index 000000000000..ec0c3d112b36 --- /dev/null +++ b/arch/arm/mach-bcm/brcmstb.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2013-2014 Broadcom Corporation + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __BRCMSTB_H__ +#define __BRCMSTB_H__ + +void brcmstb_secondary_startup(void); + +#endif /* __BRCMSTB_H__ */ diff --git a/arch/arm/mach-bcm/headsmp-brcmstb.S b/arch/arm/mach-bcm/headsmp-brcmstb.S new file mode 100644 index 000000000000..199c1ea58248 --- /dev/null +++ b/arch/arm/mach-bcm/headsmp-brcmstb.S @@ -0,0 +1,33 @@ +/* + * SMP boot code for secondary CPUs + * Based on arch/arm/mach-tegra/headsmp.S + * + * Copyright (C) 2010 NVIDIA, Inc. + * Copyright (C) 2013-2014 Broadcom Corporation + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <asm/assembler.h> +#include <linux/linkage.h> +#include <linux/init.h> + + .section ".text.head", "ax" + +ENTRY(brcmstb_secondary_startup) + /* + * Ensure CPU is in a sane state by disabling all IRQs and switching + * into SVC mode. + */ + setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r0 + + bl v7_invalidate_l1 + b secondary_startup +ENDPROC(brcmstb_secondary_startup) diff --git a/arch/arm/mach-bcm/platsmp-brcmstb.c b/arch/arm/mach-bcm/platsmp-brcmstb.c new file mode 100644 index 000000000000..31c87a284a34 --- /dev/null +++ b/arch/arm/mach-bcm/platsmp-brcmstb.c @@ -0,0 +1,329 @@ +/* + * Broadcom STB CPU SMP and hotplug support for ARM + * + * Copyright (C) 2013-2014 Broadcom Corporation + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/printk.h> +#include <linux/regmap.h> +#include <linux/smp.h> +#include <linux/mfd/syscon.h> + +#include <asm/cacheflush.h> +#include <asm/cp15.h> +#include <asm/mach-types.h> +#include <asm/smp_plat.h> + +#include "brcmstb.h" + +enum { + ZONE_MAN_CLKEN_MASK = BIT(0), + ZONE_MAN_RESET_CNTL_MASK = BIT(1), + ZONE_MAN_MEM_PWR_MASK = BIT(4), + ZONE_RESERVED_1_MASK = BIT(5), + ZONE_MAN_ISO_CNTL_MASK = BIT(6), + ZONE_MANUAL_CONTROL_MASK = BIT(7), + ZONE_PWR_DN_REQ_MASK = BIT(9), + ZONE_PWR_UP_REQ_MASK = BIT(10), + ZONE_BLK_RST_ASSERT_MASK = BIT(12), + ZONE_PWR_OFF_STATE_MASK = BIT(25), + ZONE_PWR_ON_STATE_MASK = BIT(26), + ZONE_DPG_PWR_STATE_MASK = BIT(28), + ZONE_MEM_PWR_STATE_MASK = BIT(29), + ZONE_RESET_STATE_MASK = BIT(31), + CPU0_PWR_ZONE_CTRL_REG = 1, + CPU_RESET_CONFIG_REG = 2, +}; + +static void __iomem *cpubiuctrl_block; +static void __iomem *hif_cont_block; +static u32 cpu0_pwr_zone_ctrl_reg; +static u32 cpu_rst_cfg_reg; +static u32 hif_cont_reg; + +#ifdef CONFIG_HOTPLUG_CPU +/* + * We must quiesce a dying CPU before it can be killed by the boot CPU. Because + * one or more cache may be disabled, we must flush to ensure coherency. We + * cannot use traditionl completion structures or spinlocks as they rely on + * coherency. + */ +static DEFINE_PER_CPU_ALIGNED(int, per_cpu_sw_state); + +static int per_cpu_sw_state_rd(u32 cpu) +{ + sync_cache_r(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu))); + return per_cpu(per_cpu_sw_state, cpu); +} + +static void per_cpu_sw_state_wr(u32 cpu, int val) +{ + dmb(); + per_cpu(per_cpu_sw_state, cpu) = val; + sync_cache_w(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu))); +} +#else +static inline void per_cpu_sw_state_wr(u32 cpu, int val) { } +#endif + +static void __iomem *pwr_ctrl_get_base(u32 cpu) +{ + void __iomem *base = cpubiuctrl_block + cpu0_pwr_zone_ctrl_reg; + base += (cpu_logical_map(cpu) * 4); + return base; +} + +static u32 pwr_ctrl_rd(u32 cpu) +{ + void __iomem *base = pwr_ctrl_get_base(cpu); + return readl_relaxed(base); +} + +static void pwr_ctrl_wr(u32 cpu, u32 val) +{ + void __iomem *base = pwr_ctrl_get_base(cpu); + writel(val, base); +} + +static void cpu_rst_cfg_set(u32 cpu, int set) +{ + u32 val; + val = readl_relaxed(cpubiuctrl_block + cpu_rst_cfg_reg); + if (set) + val |= BIT(cpu_logical_map(cpu)); + else + val &= ~BIT(cpu_logical_map(cpu)); + writel_relaxed(val, cpubiuctrl_block + cpu_rst_cfg_reg); +} + +static void cpu_set_boot_addr(u32 cpu, unsigned long boot_addr) +{ + const int reg_ofs = cpu_logical_map(cpu) * 8; + writel_relaxed(0, hif_cont_block + hif_cont_reg + reg_ofs); + writel_relaxed(boot_addr, hif_cont_block + hif_cont_reg + 4 + reg_ofs); +} + +static void brcmstb_cpu_boot(u32 cpu) +{ + /* Mark this CPU as "up" */ + per_cpu_sw_state_wr(cpu, 1); + + /* + * Set the reset vector to point to the secondary_startup + * routine + */ + cpu_set_boot_addr(cpu, virt_to_phys(brcmstb_secondary_startup)); + + /* Unhalt the cpu */ + cpu_rst_cfg_set(cpu, 0); +} + +static void brcmstb_cpu_power_on(u32 cpu) +{ + /* + * The secondary cores power was cut, so we must go through + * power-on initialization. + */ + u32 tmp; + + /* Request zone power up */ + pwr_ctrl_wr(cpu, ZONE_PWR_UP_REQ_MASK); + + /* Wait for the power up FSM to complete */ + do { + tmp = pwr_ctrl_rd(cpu); + } while (!(tmp & ZONE_PWR_ON_STATE_MASK)); +} + +static int brcmstb_cpu_get_power_state(u32 cpu) +{ + int tmp = pwr_ctrl_rd(cpu); + return (tmp & ZONE_RESET_STATE_MASK) ? 0 : 1; +} + +#ifdef CONFIG_HOTPLUG_CPU + +static void brcmstb_cpu_die(u32 cpu) +{ + v7_exit_coherency_flush(all); + + per_cpu_sw_state_wr(cpu, 0); + + /* Sit and wait to die */ + wfi(); + + /* We should never get here... */ + while (1) + ; +} + +static int brcmstb_cpu_kill(u32 cpu) +{ + u32 tmp; + + while (per_cpu_sw_state_rd(cpu)) + ; + + /* Program zone reset */ + pwr_ctrl_wr(cpu, ZONE_RESET_STATE_MASK | ZONE_BLK_RST_ASSERT_MASK | + ZONE_PWR_DN_REQ_MASK); + + /* Verify zone reset */ + tmp = pwr_ctrl_rd(cpu); + if (!(tmp & ZONE_RESET_STATE_MASK)) + pr_err("%s: Zone reset bit for CPU %d not asserted!\n", + __func__, cpu); + + /* Wait for power down */ + do { + tmp = pwr_ctrl_rd(cpu); + } while (!(tmp & ZONE_PWR_OFF_STATE_MASK)); + + /* Flush pipeline before resetting CPU */ + mb(); + + /* Assert reset on the CPU */ + cpu_rst_cfg_set(cpu, 1); + + return 1; +} + +#endif /* CONFIG_HOTPLUG_CPU */ + +static int __init setup_hifcpubiuctrl_regs(struct device_node *np) +{ + int rc = 0; + char *name; + struct device_node *syscon_np = NULL; + + name = "syscon-cpu"; + + syscon_np = of_parse_phandle(np, name, 0); + if (!syscon_np) { + pr_err("can't find phandle %s\n", name); + rc = -EINVAL; + goto cleanup; + } + + cpubiuctrl_block = of_iomap(syscon_np, 0); + if (!cpubiuctrl_block) { + pr_err("iomap failed for cpubiuctrl_block\n"); + rc = -EINVAL; + goto cleanup; + } + + rc = of_property_read_u32_index(np, name, CPU0_PWR_ZONE_CTRL_REG, + &cpu0_pwr_zone_ctrl_reg); + if (rc) { + pr_err("failed to read 1st entry from %s property (%d)\n", name, + rc); + rc = -EINVAL; + goto cleanup; + } + + rc = of_property_read_u32_index(np, name, CPU_RESET_CONFIG_REG, + &cpu_rst_cfg_reg); + if (rc) { + pr_err("failed to read 2nd entry from %s property (%d)\n", name, + rc); + rc = -EINVAL; + goto cleanup; + } + +cleanup: + of_node_put(syscon_np); + return rc; +} + +static int __init setup_hifcont_regs(struct device_node *np) +{ + int rc = 0; + char *name; + struct device_node *syscon_np = NULL; + + name = "syscon-cont"; + + syscon_np = of_parse_phandle(np, name, 0); + if (!syscon_np) { + pr_err("can't find phandle %s\n", name); + rc = -EINVAL; + goto cleanup; + } + + hif_cont_block = of_iomap(syscon_np, 0); + if (!hif_cont_block) { + pr_err("iomap failed for hif_cont_block\n"); + rc = -EINVAL; + goto cleanup; + } + + /* Offset is at top of hif_cont_block */ + hif_cont_reg = 0; + +cleanup: + of_node_put(syscon_np); + return rc; +} + +static void __init brcmstb_cpu_ctrl_setup(unsigned int max_cpus) +{ + int rc; + struct device_node *np; + char *name; + + name = "brcm,brcmstb-smpboot"; + np = of_find_compatible_node(NULL, NULL, name); + if (!np) { + pr_err("can't find compatible node %s\n", name); + return; + } + + rc = setup_hifcpubiuctrl_regs(np); + if (rc) + return; + + rc = setup_hifcont_regs(np); + if (rc) + return; +} + +static int brcmstb_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + /* Missing the brcm,brcmstb-smpboot DT node? */ + if (!cpubiuctrl_block || !hif_cont_block) + return -ENODEV; + + /* Bring up power to the core if necessary */ + if (brcmstb_cpu_get_power_state(cpu) == 0) + brcmstb_cpu_power_on(cpu); + + brcmstb_cpu_boot(cpu); + + return 0; +} + +static struct smp_operations brcmstb_smp_ops __initdata = { + .smp_prepare_cpus = brcmstb_cpu_ctrl_setup, + .smp_boot_secondary = brcmstb_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_kill = brcmstb_cpu_kill, + .cpu_die = brcmstb_cpu_die, +#endif +}; + +CPU_METHOD_OF_DECLARE(brcmstb_smp, "brcm,brahma-b15", &brcmstb_smp_ops); diff --git a/arch/arm/mach-berlin/Kconfig b/arch/arm/mach-berlin/Kconfig index 24f85be71671..84d34e07209c 100644 --- a/arch/arm/mach-berlin/Kconfig +++ b/arch/arm/mach-berlin/Kconfig @@ -1,11 +1,13 @@ menuconfig ARCH_BERLIN bool "Marvell Berlin SoCs" if ARCH_MULTI_V7 + select ARCH_HAS_RESET_CONTROLLER select ARCH_REQUIRE_GPIOLIB select ARM_GIC - select GENERIC_IRQ_CHIP select DW_APB_ICTL select DW_APB_TIMER_OF + select GENERIC_IRQ_CHIP select PINCTRL + select RESET_CONTROLLER if ARCH_BERLIN diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 2d0240f241b8..46f3c0d0d01f 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -123,4 +123,9 @@ config EXYNOS5420_MCPM This is needed to provide CPU and cluster power management on Exynos5420 implementing big.LITTLE. +config EXYNOS_CPU_SUSPEND + bool + select ARM_CPU_SUSPEND + default PM_SLEEP || ARM_EXYNOS_CPUIDLE + endif diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 27ae6144679c..775ee35cb277 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -11,7 +11,8 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) += -I$(srctree)/$(src)/include -I$(srctree) obj-$(CONFIG_ARCH_EXYNOS) += exynos.o pmu.o exynos-smc.o firmware.o -obj-$(CONFIG_PM_SLEEP) += pm.o sleep.o +obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm.o sleep.o +obj-$(CONFIG_PM_SLEEP) += suspend.o obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o @@ -21,6 +22,7 @@ CFLAGS_hotplug.o += -march=armv7-a plus_sec := $(call as-instr,.arch_extension sec,+sec) AFLAGS_exynos-smc.o :=-Wa,-march=armv7-a$(plus_sec) +AFLAGS_sleep.o :=-Wa,-march=armv7-a$(plus_sec) obj-$(CONFIG_EXYNOS5420_MCPM) += mcpm-exynos.o CFLAGS_mcpm-exynos.o += -march=armv7-a diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 47b904b3b973..ef95cb1cc00a 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -111,11 +111,19 @@ IS_SAMSUNG_CPU(exynos5800, EXYNOS5800_SOC_ID, EXYNOS5_SOC_MASK) #define soc_is_exynos5() (soc_is_exynos5250() || soc_is_exynos5410() || \ soc_is_exynos5420() || soc_is_exynos5800()) +extern u32 cp15_save_diag; +extern u32 cp15_save_power; + extern void __iomem *sysram_ns_base_addr; extern void __iomem *sysram_base_addr; extern void __iomem *pmu_base_addr; void exynos_sysram_init(void); +enum { + FW_DO_IDLE_SLEEP, + FW_DO_IDLE_AFTR, +}; + void exynos_firmware_init(void); extern u32 exynos_get_eint_wake_mask(void); @@ -127,6 +135,7 @@ static inline void exynos_pm_init(void) {} #endif extern void exynos_cpu_resume(void); +extern void exynos_cpu_resume_ns(void); extern struct smp_operations exynos_smp_ops; @@ -155,6 +164,10 @@ extern int exynos_cpu_power_state(int cpu); extern void exynos_cluster_power_down(int cluster); extern void exynos_cluster_power_up(int cluster); extern int exynos_cluster_power_state(int cluster); +extern void exynos_cpu_save_register(void); +extern void exynos_cpu_restore_register(void); +extern void exynos_pm_central_suspend(void); +extern int exynos_pm_central_resume(void); extern void exynos_enter_aftr(void); extern void s5p_init_cpu(void __iomem *cpuid_addr); diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 6b283eb3202e..a487e59555da 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -318,7 +318,10 @@ static void __init exynos_dt_machine_init(void) exynos_sysram_init(); if (of_machine_is_compatible("samsung,exynos4210") || - of_machine_is_compatible("samsung,exynos5250")) + of_machine_is_compatible("samsung,exynos4212") || + (of_machine_is_compatible("samsung,exynos4412") && + of_machine_is_compatible("samsung,trats2")) || + of_machine_is_compatible("samsung,exynos5250")) platform_device_register(&exynos_cpuidle); platform_device_register_simple("exynos-cpufreq", -1, NULL, 0); diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index e8797bb78871..766f57d2f029 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -14,16 +14,44 @@ #include <linux/of.h> #include <linux/of_address.h> +#include <asm/cacheflush.h> +#include <asm/cputype.h> #include <asm/firmware.h> +#include <asm/suspend.h> #include <mach/map.h> #include "common.h" #include "smc.h" -static int exynos_do_idle(void) +#define EXYNOS_SLEEP_MAGIC 0x00000bad +#define EXYNOS_AFTR_MAGIC 0xfcba0d10 +#define EXYNOS_BOOT_ADDR 0x8 +#define EXYNOS_BOOT_FLAG 0xc + +static void exynos_save_cp15(void) { - exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); + /* Save Power control and Diagnostic registers */ + asm ("mrc p15, 0, %0, c15, c0, 0\n" + "mrc p15, 0, %1, c15, c0, 1\n" + : "=r" (cp15_save_power), "=r" (cp15_save_diag) + : : "cc"); +} + +static int exynos_do_idle(unsigned long mode) +{ + switch (mode) { + case FW_DO_IDLE_AFTR: + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_save_cp15(); + __raw_writel(virt_to_phys(exynos_cpu_resume_ns), + sysram_ns_base_addr + 0x24); + __raw_writel(EXYNOS_AFTR_MAGIC, sysram_ns_base_addr + 0x20); + exynos_smc(SMC_CMD_CPU0AFTR, 0, 0, 0); + break; + case FW_DO_IDLE_SLEEP: + exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); + } return 0; } @@ -69,10 +97,43 @@ static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr) return 0; } +static int exynos_cpu_suspend(unsigned long arg) +{ + flush_cache_all(); + outer_flush_all(); + + exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); + + pr_info("Failed to suspend the system\n"); + writel(0, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); + return 1; +} + +static int exynos_suspend(void) +{ + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_save_cp15(); + + writel(EXYNOS_SLEEP_MAGIC, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); + writel(virt_to_phys(exynos_cpu_resume_ns), + sysram_ns_base_addr + EXYNOS_BOOT_ADDR); + + return cpu_suspend(0, exynos_cpu_suspend); +} + +static int exynos_resume(void) +{ + writel(0, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); + + return 0; +} + static const struct firmware_ops exynos_firmware_ops = { - .do_idle = exynos_do_idle, + .do_idle = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_do_idle : NULL, .set_cpu_boot_addr = exynos_set_cpu_boot_addr, .cpu_boot = exynos_cpu_boot, + .suspend = IS_ENABLED(CONFIG_PM_SLEEP) ? exynos_suspend : NULL, + .resume = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_resume : NULL, }; void __init exynos_firmware_init(void) diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index 41ae28d69e6f..8543064dc445 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -121,6 +121,26 @@ static inline void __iomem *cpu_boot_reg(int cpu) } /* + * Set wake up by local power mode and execute software reset for given core. + * + * Currently this is needed only when booting secondary CPU on Exynos3250. + */ +static void exynos_core_restart(u32 core_id) +{ + u32 val; + + if (!of_machine_is_compatible("samsung,exynos3250")) + return; + + val = pmu_raw_readl(EXYNOS_ARM_CORE_STATUS(core_id)); + val |= S5P_CORE_WAKEUP_FROM_LOCAL_CFG; + pmu_raw_writel(val, EXYNOS_ARM_CORE_STATUS(core_id)); + + pr_info("CPU%u: Software reset\n", core_id); + pmu_raw_writel(EXYNOS_CORE_PO_RESET(core_id), EXYNOS_SWRESET); +} + +/* * Write pen_release in a way that is guaranteed to be visible to all * observers, irrespective of whether they're taking part in coherency * or not. This is necessary for the hotplug code to work reliably. @@ -196,6 +216,9 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle) return -ETIMEDOUT; } } + + exynos_core_restart(core_id); + /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index abefacb45976..4f10fa6bfe10 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. + * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * * EXYNOS - Power Management support @@ -15,109 +15,44 @@ #include <linux/init.h> #include <linux/suspend.h> -#include <linux/syscore_ops.h> #include <linux/cpu_pm.h> #include <linux/io.h> -#include <linux/irqchip/arm-gic.h> #include <linux/err.h> -#include <linux/clk.h> -#include <asm/cacheflush.h> -#include <asm/hardware/cache-l2x0.h> +#include <asm/firmware.h> #include <asm/smp_scu.h> #include <asm/suspend.h> #include <plat/pm-common.h> -#include <plat/regs-srom.h> - -#include <mach/map.h> #include "common.h" #include "regs-pmu.h" #include "regs-sys.h" -/** - * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping - * @hwirq: Hardware IRQ signal of the GIC - * @mask: Mask in PMU wake-up mask register - */ -struct exynos_wkup_irq { - unsigned int hwirq; - u32 mask; -}; - -static struct sleep_save exynos5_sys_save[] = { - SAVE_ITEM(EXYNOS5_SYS_I2C_CFG), -}; - -static struct sleep_save exynos_core_save[] = { - /* SROM side */ - SAVE_ITEM(S5P_SROM_BW), - SAVE_ITEM(S5P_SROM_BC0), - SAVE_ITEM(S5P_SROM_BC1), - SAVE_ITEM(S5P_SROM_BC2), - SAVE_ITEM(S5P_SROM_BC3), -}; - -/* - * GIC wake-up support - */ - -static u32 exynos_irqwake_intmask = 0xffffffff; - -static const struct exynos_wkup_irq exynos4_wkup_irq[] = { - { 76, BIT(1) }, /* RTC alarm */ - { 77, BIT(2) }, /* RTC tick */ - { /* sentinel */ }, -}; - -static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { - { 75, BIT(1) }, /* RTC alarm */ - { 76, BIT(2) }, /* RTC tick */ - { /* sentinel */ }, -}; - -static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) +static inline void __iomem *exynos_boot_vector_addr(void) { - const struct exynos_wkup_irq *wkup_irq; - - if (soc_is_exynos5250()) - wkup_irq = exynos5250_wkup_irq; - else - wkup_irq = exynos4_wkup_irq; - - while (wkup_irq->mask) { - if (wkup_irq->hwirq == data->hwirq) { - if (!state) - exynos_irqwake_intmask |= wkup_irq->mask; - else - exynos_irqwake_intmask &= ~wkup_irq->mask; - return 0; - } - ++wkup_irq; - } - - return -ENOENT; + if (samsung_rev() == EXYNOS4210_REV_1_1) + return pmu_base_addr + S5P_INFORM7; + else if (samsung_rev() == EXYNOS4210_REV_1_0) + return sysram_base_addr + 0x24; + return pmu_base_addr + S5P_INFORM0; } -#define EXYNOS_BOOT_VECTOR_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \ - pmu_base_addr + S5P_INFORM7 : \ - (samsung_rev() == EXYNOS4210_REV_1_0 ? \ - (sysram_base_addr + 0x24) : \ - pmu_base_addr + S5P_INFORM0)) -#define EXYNOS_BOOT_VECTOR_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ - pmu_base_addr + S5P_INFORM6 : \ - (samsung_rev() == EXYNOS4210_REV_1_0 ? \ - (sysram_base_addr + 0x20) : \ - pmu_base_addr + S5P_INFORM1)) +static inline void __iomem *exynos_boot_vector_flag(void) +{ + if (samsung_rev() == EXYNOS4210_REV_1_1) + return pmu_base_addr + S5P_INFORM6; + else if (samsung_rev() == EXYNOS4210_REV_1_0) + return sysram_base_addr + 0x20; + return pmu_base_addr + S5P_INFORM1; +} #define S5P_CHECK_AFTR 0xFCBA0D10 -#define S5P_CHECK_SLEEP 0x00000BAD /* For Cortex-A9 Diagnostic and Power control register */ static unsigned int save_arm_register[2]; -static void exynos_cpu_save_register(void) +void exynos_cpu_save_register(void) { unsigned long tmp; @@ -134,7 +69,7 @@ static void exynos_cpu_save_register(void) save_arm_register[1] = tmp; } -static void exynos_cpu_restore_register(void) +void exynos_cpu_restore_register(void) { unsigned long tmp; @@ -153,7 +88,7 @@ static void exynos_cpu_restore_register(void) : "cc"); } -static void exynos_pm_central_suspend(void) +void exynos_pm_central_suspend(void) { unsigned long tmp; @@ -161,9 +96,13 @@ static void exynos_pm_central_suspend(void) tmp = pmu_raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); tmp &= ~S5P_CENTRAL_LOWPWR_CFG; pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); + + /* Setting SEQ_OPTION register */ + pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0, + S5P_CENTRAL_SEQ_OPTION); } -static int exynos_pm_central_resume(void) +int exynos_pm_central_resume(void) { unsigned long tmp; @@ -194,17 +133,26 @@ static void exynos_set_wakeupmask(long mask) static void exynos_cpu_set_boot_vector(long flags) { - __raw_writel(virt_to_phys(exynos_cpu_resume), EXYNOS_BOOT_VECTOR_ADDR); - __raw_writel(flags, EXYNOS_BOOT_VECTOR_FLAG); + __raw_writel(virt_to_phys(exynos_cpu_resume), + exynos_boot_vector_addr()); + __raw_writel(flags, exynos_boot_vector_flag()); } static int exynos_aftr_finisher(unsigned long flags) { + int ret; + exynos_set_wakeupmask(0x0000ff3e); - exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); /* Set value of power down register for aftr mode */ exynos_sys_powerdown_conf(SYS_AFTR); - cpu_do_idle(); + + ret = call_firmware_op(do_idle, FW_DO_IDLE_AFTR); + if (ret == -ENOSYS) { + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_cpu_save_register(); + exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); + cpu_do_idle(); + } return 1; } @@ -214,196 +162,16 @@ void exynos_enter_aftr(void) cpu_pm_enter(); exynos_pm_central_suspend(); - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) - exynos_cpu_save_register(); cpu_suspend(0, exynos_aftr_finisher); if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { scu_enable(S5P_VA_SCU); - exynos_cpu_restore_register(); + if (call_firmware_op(resume) == -ENOSYS) + exynos_cpu_restore_register(); } exynos_pm_central_resume(); cpu_pm_exit(); } - -static int exynos_cpu_suspend(unsigned long arg) -{ -#ifdef CONFIG_CACHE_L2X0 - outer_flush_all(); -#endif - - if (soc_is_exynos5250()) - flush_cache_all(); - - /* issue the standby signal into the pm unit. */ - cpu_do_idle(); - - pr_info("Failed to suspend the system\n"); - return 1; /* Aborting suspend */ -} - -static void exynos_pm_prepare(void) -{ - unsigned int tmp; - - /* Set wake-up mask registers */ - pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK); - pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK); - - s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); - - if (soc_is_exynos5250()) { - s3c_pm_do_save(exynos5_sys_save, ARRAY_SIZE(exynos5_sys_save)); - /* Disable USE_RETENTION of JPEG_MEM_OPTION */ - tmp = pmu_raw_readl(EXYNOS5_JPEG_MEM_OPTION); - tmp &= ~EXYNOS5_OPTION_USE_RETENTION; - pmu_raw_writel(tmp, EXYNOS5_JPEG_MEM_OPTION); - } - - /* Set value of power down register for sleep mode */ - - exynos_sys_powerdown_conf(SYS_SLEEP); - pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); - - /* ensure at least INFORM0 has the resume address */ - - pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); -} - -static int exynos_pm_suspend(void) -{ - unsigned long tmp; - - exynos_pm_central_suspend(); - - /* Setting SEQ_OPTION register */ - - tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0); - pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION); - - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) - exynos_cpu_save_register(); - - return 0; -} - -static void exynos_pm_resume(void) -{ - if (exynos_pm_central_resume()) - goto early_wakeup; - - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) - exynos_cpu_restore_register(); - - /* For release retention */ - - pmu_raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION); - - if (soc_is_exynos5250()) - s3c_pm_do_restore(exynos5_sys_save, - ARRAY_SIZE(exynos5_sys_save)); - - s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); - - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) - scu_enable(S5P_VA_SCU); - -early_wakeup: - - /* Clear SLEEP mode set in INFORM1 */ - pmu_raw_writel(0x0, S5P_INFORM1); - - return; -} - -static struct syscore_ops exynos_pm_syscore_ops = { - .suspend = exynos_pm_suspend, - .resume = exynos_pm_resume, -}; - -/* - * Suspend Ops - */ - -static int exynos_suspend_enter(suspend_state_t state) -{ - int ret; - - s3c_pm_debug_init(); - - S3C_PMDBG("%s: suspending the system...\n", __func__); - - S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__, - exynos_irqwake_intmask, exynos_get_eint_wake_mask()); - - if (exynos_irqwake_intmask == -1U - && exynos_get_eint_wake_mask() == -1U) { - pr_err("%s: No wake-up sources!\n", __func__); - pr_err("%s: Aborting sleep\n", __func__); - return -EINVAL; - } - - s3c_pm_save_uarts(); - exynos_pm_prepare(); - flush_cache_all(); - s3c_pm_check_store(); - - ret = cpu_suspend(0, exynos_cpu_suspend); - if (ret) - return ret; - - s3c_pm_restore_uarts(); - - S3C_PMDBG("%s: wakeup stat: %08x\n", __func__, - pmu_raw_readl(S5P_WAKEUP_STAT)); - - s3c_pm_check_restore(); - - S3C_PMDBG("%s: resuming the system...\n", __func__); - - return 0; -} - -static int exynos_suspend_prepare(void) -{ - s3c_pm_check_prepare(); - - return 0; -} - -static void exynos_suspend_finish(void) -{ - s3c_pm_check_cleanup(); -} - -static const struct platform_suspend_ops exynos_suspend_ops = { - .enter = exynos_suspend_enter, - .prepare = exynos_suspend_prepare, - .finish = exynos_suspend_finish, - .valid = suspend_valid_only_mem, -}; - -void __init exynos_pm_init(void) -{ - u32 tmp; - - /* Platform-specific GIC callback */ - gic_arch_extn.irq_set_wake = exynos_irq_set_wake; - - /* All wakeup disable */ - tmp = pmu_raw_readl(S5P_WAKEUP_MASK); - tmp |= ((0xFF << 8) | (0x1F << 1)); - pmu_raw_writel(tmp, S5P_WAKEUP_MASK); - - register_syscore_ops(&exynos_pm_syscore_ops); - suspend_set_ops(&exynos_suspend_ops); -} diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c index ff9d23f0a7d9..cfc62e86cdee 100644 --- a/arch/arm/mach-exynos/pmu.c +++ b/arch/arm/mach-exynos/pmu.c @@ -264,6 +264,7 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = { { EXYNOS5_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, { EXYNOS5_INTROM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, { EXYNOS5_JPEG_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, + { EXYNOS5_JPEG_MEM_OPTION, { 0x10, 0x10, 0x0} }, { EXYNOS5_HSI_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, { EXYNOS5_MCUIOP_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, { EXYNOS5_SATA_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h index 96a1569262b5..4ea5e320c6d1 100644 --- a/arch/arm/mach-exynos/regs-pmu.h +++ b/arch/arm/mach-exynos/regs-pmu.h @@ -21,6 +21,8 @@ #define S5P_USE_STANDBY_WFI0 (1 << 16) #define S5P_USE_STANDBY_WFE0 (1 << 24) +#define EXYNOS_CORE_PO_RESET(n) ((1 << 4) << n) +#define EXYNOS_WAKEUP_FROM_LOWPWR (1 << 28) #define EXYNOS_SWRESET 0x0400 #define EXYNOS5440_SWRESET 0x00C4 @@ -124,6 +126,7 @@ #define S5P_PAD_RET_EBIB_OPTION 0x31A8 #define S5P_CORE_LOCAL_PWR_EN 0x3 +#define S5P_CORE_WAKEUP_FROM_LOCAL_CFG (0x3 << 8) /* Only for EXYNOS4210 */ #define S5P_CMU_CLKSTOP_LCD1_LOWPWR 0x1154 diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S index 108a45f4bb62..e3c373082bbe 100644 --- a/arch/arm/mach-exynos/sleep.S +++ b/arch/arm/mach-exynos/sleep.S @@ -16,6 +16,7 @@ */ #include <linux/linkage.h> +#include "smc.h" #define CPU_MASK 0xff0ffff0 #define CPU_CORTEX_A9 0x410fc090 @@ -55,3 +56,30 @@ ENTRY(exynos_cpu_resume) #endif b cpu_resume ENDPROC(exynos_cpu_resume) + + .align + +ENTRY(exynos_cpu_resume_ns) + mrc p15, 0, r0, c0, c0, 0 + ldr r1, =CPU_MASK + and r0, r0, r1 + ldr r1, =CPU_CORTEX_A9 + cmp r0, r1 + bne skip_cp15 + + adr r0, cp15_save_power + ldr r1, [r0] + adr r0, cp15_save_diag + ldr r2, [r0] + mov r0, #SMC_CMD_C15RESUME + dsb + smc #0 +skip_cp15: + b cpu_resume +ENDPROC(exynos_cpu_resume_ns) + .globl cp15_save_diag +cp15_save_diag: + .long 0 @ cp15 diagnostic + .globl cp15_save_power +cp15_save_power: + .long 0 @ cp15 power control diff --git a/arch/arm/mach-exynos/smc.h b/arch/arm/mach-exynos/smc.h index 13a1dc8ecbf2..f7b82f9c1e21 100644 --- a/arch/arm/mach-exynos/smc.h +++ b/arch/arm/mach-exynos/smc.h @@ -26,6 +26,10 @@ #define SMC_CMD_L2X0INVALL (-24) #define SMC_CMD_L2X0DEBUG (-25) +#ifndef __ASSEMBLY__ + extern void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3); +#endif /* __ASSEMBLY__ */ + #endif diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c new file mode 100644 index 000000000000..f5d9773066eb --- /dev/null +++ b/arch/arm/mach-exynos/suspend.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * EXYNOS - Suspend support + * + * Based on arch/arm/mach-s3c2410/pm.c + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * 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/init.h> +#include <linux/suspend.h> +#include <linux/syscore_ops.h> +#include <linux/cpu_pm.h> +#include <linux/io.h> +#include <linux/irqchip/arm-gic.h> +#include <linux/err.h> + +#include <asm/cacheflush.h> +#include <asm/hardware/cache-l2x0.h> +#include <asm/firmware.h> +#include <asm/smp_scu.h> +#include <asm/suspend.h> + +#include <plat/pm-common.h> +#include <plat/regs-srom.h> + +#include "common.h" +#include "regs-pmu.h" +#include "regs-sys.h" + +#define S5P_CHECK_SLEEP 0x00000BAD + +#define REG_TABLE_END (-1U) + +/** + * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping + * @hwirq: Hardware IRQ signal of the GIC + * @mask: Mask in PMU wake-up mask register + */ +struct exynos_wkup_irq { + unsigned int hwirq; + u32 mask; +}; + +static struct sleep_save exynos5_sys_save[] = { + SAVE_ITEM(EXYNOS5_SYS_I2C_CFG), +}; + +static struct sleep_save exynos_core_save[] = { + /* SROM side */ + SAVE_ITEM(S5P_SROM_BW), + SAVE_ITEM(S5P_SROM_BC0), + SAVE_ITEM(S5P_SROM_BC1), + SAVE_ITEM(S5P_SROM_BC2), + SAVE_ITEM(S5P_SROM_BC3), +}; + +struct exynos_pm_data { + const struct exynos_wkup_irq *wkup_irq; + struct sleep_save *extra_save; + int num_extra_save; + unsigned int wake_disable_mask; + unsigned int *release_ret_regs; + + void (*pm_prepare)(void); + void (*pm_resume)(void); + int (*pm_suspend)(void); + int (*cpu_suspend)(unsigned long); +}; + +struct exynos_pm_data *pm_data; + +/* + * GIC wake-up support + */ + +static u32 exynos_irqwake_intmask = 0xffffffff; + +static const struct exynos_wkup_irq exynos4_wkup_irq[] = { + { 76, BIT(1) }, /* RTC alarm */ + { 77, BIT(2) }, /* RTC tick */ + { /* sentinel */ }, +}; + +static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { + { 75, BIT(1) }, /* RTC alarm */ + { 76, BIT(2) }, /* RTC tick */ + { /* sentinel */ }, +}; + +unsigned int exynos_release_ret_regs[] = { + S5P_PAD_RET_MAUDIO_OPTION, + S5P_PAD_RET_GPIO_OPTION, + S5P_PAD_RET_UART_OPTION, + S5P_PAD_RET_MMCA_OPTION, + S5P_PAD_RET_MMCB_OPTION, + S5P_PAD_RET_EBIA_OPTION, + S5P_PAD_RET_EBIB_OPTION, + REG_TABLE_END, +}; + +static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) +{ + const struct exynos_wkup_irq *wkup_irq; + + if (!pm_data->wkup_irq) + return -ENOENT; + wkup_irq = pm_data->wkup_irq; + + while (wkup_irq->mask) { + if (wkup_irq->hwirq == data->hwirq) { + if (!state) + exynos_irqwake_intmask |= wkup_irq->mask; + else + exynos_irqwake_intmask &= ~wkup_irq->mask; + return 0; + } + ++wkup_irq; + } + + return -ENOENT; +} + +static int exynos_cpu_do_idle(void) +{ + /* issue the standby signal into the pm unit. */ + cpu_do_idle(); + + pr_info("Failed to suspend the system\n"); + return 1; /* Aborting suspend */ +} + +static int exynos_cpu_suspend(unsigned long arg) +{ + flush_cache_all(); + outer_flush_all(); + return exynos_cpu_do_idle(); +} + +static void exynos_pm_set_wakeup_mask(void) +{ + /* Set wake-up mask registers */ + pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK); + pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK); +} + +static void exynos_pm_enter_sleep_mode(void) +{ + /* Set value of power down register for sleep mode */ + exynos_sys_powerdown_conf(SYS_SLEEP); + pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); + + /* ensure at least INFORM0 has the resume address */ + pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); +} + +static void exynos_pm_prepare(void) +{ + /* Set wake-up mask registers */ + exynos_pm_set_wakeup_mask(); + + s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + + if (pm_data->extra_save) + s3c_pm_do_save(pm_data->extra_save, + pm_data->num_extra_save); + + exynos_pm_enter_sleep_mode(); +} + +static int exynos_pm_suspend(void) +{ + exynos_pm_central_suspend(); + + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_cpu_save_register(); + + return 0; +} + +static void exynos_pm_release_retention(void) +{ + unsigned int i; + + for (i = 0; (pm_data->release_ret_regs[i] != REG_TABLE_END); i++) + pmu_raw_writel(EXYNOS_WAKEUP_FROM_LOWPWR, + pm_data->release_ret_regs[i]); +} + +static void exynos_pm_resume(void) +{ + u32 cpuid = read_cpuid_part(); + + if (exynos_pm_central_resume()) + goto early_wakeup; + + /* For release retention */ + exynos_pm_release_retention(); + + if (pm_data->extra_save) + s3c_pm_do_restore_core(pm_data->extra_save, + pm_data->num_extra_save); + + s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + + if (cpuid == ARM_CPU_PART_CORTEX_A9) + scu_enable(S5P_VA_SCU); + + if (call_firmware_op(resume) == -ENOSYS + && cpuid == ARM_CPU_PART_CORTEX_A9) + exynos_cpu_restore_register(); + +early_wakeup: + + /* Clear SLEEP mode set in INFORM1 */ + pmu_raw_writel(0x0, S5P_INFORM1); +} + +/* + * Suspend Ops + */ + +static int exynos_suspend_enter(suspend_state_t state) +{ + int ret; + + s3c_pm_debug_init(); + + S3C_PMDBG("%s: suspending the system...\n", __func__); + + S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__, + exynos_irqwake_intmask, exynos_get_eint_wake_mask()); + + if (exynos_irqwake_intmask == -1U + && exynos_get_eint_wake_mask() == -1U) { + pr_err("%s: No wake-up sources!\n", __func__); + pr_err("%s: Aborting sleep\n", __func__); + return -EINVAL; + } + + s3c_pm_save_uarts(); + if (pm_data->pm_prepare) + pm_data->pm_prepare(); + flush_cache_all(); + s3c_pm_check_store(); + + ret = call_firmware_op(suspend); + if (ret == -ENOSYS) + ret = cpu_suspend(0, pm_data->cpu_suspend); + if (ret) + return ret; + + s3c_pm_restore_uarts(); + + S3C_PMDBG("%s: wakeup stat: %08x\n", __func__, + pmu_raw_readl(S5P_WAKEUP_STAT)); + + s3c_pm_check_restore(); + + S3C_PMDBG("%s: resuming the system...\n", __func__); + + return 0; +} + +static int exynos_suspend_prepare(void) +{ + s3c_pm_check_prepare(); + + return 0; +} + +static void exynos_suspend_finish(void) +{ + s3c_pm_check_cleanup(); +} + +static const struct platform_suspend_ops exynos_suspend_ops = { + .enter = exynos_suspend_enter, + .prepare = exynos_suspend_prepare, + .finish = exynos_suspend_finish, + .valid = suspend_valid_only_mem, +}; + +static const struct exynos_pm_data exynos4_pm_data = { + .wkup_irq = exynos4_wkup_irq, + .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), + .release_ret_regs = exynos_release_ret_regs, + .pm_suspend = exynos_pm_suspend, + .pm_resume = exynos_pm_resume, + .pm_prepare = exynos_pm_prepare, + .cpu_suspend = exynos_cpu_suspend, +}; + +static const struct exynos_pm_data exynos5250_pm_data = { + .wkup_irq = exynos5250_wkup_irq, + .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), + .release_ret_regs = exynos_release_ret_regs, + .extra_save = exynos5_sys_save, + .num_extra_save = ARRAY_SIZE(exynos5_sys_save), + .pm_suspend = exynos_pm_suspend, + .pm_resume = exynos_pm_resume, + .pm_prepare = exynos_pm_prepare, + .cpu_suspend = exynos_cpu_suspend, +}; + +static struct of_device_id exynos_pmu_of_device_ids[] = { + { + .compatible = "samsung,exynos4210-pmu", + .data = &exynos4_pm_data, + }, { + .compatible = "samsung,exynos4212-pmu", + .data = &exynos4_pm_data, + }, { + .compatible = "samsung,exynos4412-pmu", + .data = &exynos4_pm_data, + }, { + .compatible = "samsung,exynos5250-pmu", + .data = &exynos5250_pm_data, + }, + { /*sentinel*/ }, +}; + +static struct syscore_ops exynos_pm_syscore_ops; + +void __init exynos_pm_init(void) +{ + const struct of_device_id *match; + u32 tmp; + + of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); + if (!match) { + pr_err("Failed to find PMU node\n"); + return; + } + pm_data = (struct exynos_pm_data *) match->data; + + /* Platform-specific GIC callback */ + gic_arch_extn.irq_set_wake = exynos_irq_set_wake; + + /* All wakeup disable */ + tmp = pmu_raw_readl(S5P_WAKEUP_MASK); + tmp |= pm_data->wake_disable_mask; + pmu_raw_writel(tmp, S5P_WAKEUP_MASK); + + exynos_pm_syscore_ops.suspend = pm_data->pm_suspend; + exynos_pm_syscore_ops.resume = pm_data->pm_resume; + + register_syscore_ops(&exynos_pm_syscore_ops); + suspend_set_ops(&exynos_suspend_ops); +} diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig index c455e974bbfe..02d083489a26 100644 --- a/arch/arm/mach-integrator/Kconfig +++ b/arch/arm/mach-integrator/Kconfig @@ -1,3 +1,26 @@ +config ARCH_INTEGRATOR + bool "ARM Ltd. Integrator family" if (ARCH_MULTI_V4T || ARCH_MULTI_V5 || ARCH_MULTI_V6) + select ARM_AMBA + select ARM_PATCH_PHYS_VIRT if MMU + select AUTO_ZRELADDR + select COMMON_CLK + select COMMON_CLK_VERSATILE + select GENERIC_CLOCKEVENTS + select HAVE_TCM + select ICST + select MFD_SYSCON + select MULTI_IRQ_HANDLER + select PLAT_VERSATILE + select POWER_RESET + select POWER_RESET_VERSATILE + select POWER_SUPPLY + select SOC_INTEGRATOR_CM + select SPARSE_IRQ + select USE_OF + select VERSATILE_FPGA_IRQ + help + Support for ARM's Integrator platform. + if ARCH_INTEGRATOR menu "Integrator Options" diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile index ec759ded7b60..1ebe45356b09 100644 --- a/arch/arm/mach-integrator/Makefile +++ b/arch/arm/mach-integrator/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-y := core.o lm.o leds.o +obj-y := core.o lm.o obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o diff --git a/arch/arm/mach-integrator/cm.h b/arch/arm/mach-integrator/cm.h index 4ecff7bff482..5b8ba8247f45 100644 --- a/arch/arm/mach-integrator/cm.h +++ b/arch/arm/mach-integrator/cm.h @@ -11,7 +11,6 @@ void cm_clear_irqs(void); #define CM_CTRL_LED (1 << 0) #define CM_CTRL_nMBDET (1 << 1) #define CM_CTRL_REMAP (1 << 2) -#define CM_CTRL_RESET (1 << 3) /* * Integrator/AP,PP2 specific diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h index ad0ac5547b2c..96c9dc56cabf 100644 --- a/arch/arm/mach-integrator/common.h +++ b/arch/arm/mach-integrator/common.h @@ -4,5 +4,3 @@ extern struct amba_pl010_data ap_uart_data; void integrator_init_early(void); int integrator_init(bool is_cp); void integrator_reserve(void); -void integrator_restart(enum reboot_mode, const char *); -void integrator_init_sysfs(struct device *parent, u32 id); diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index e3f3aca43efb..948872a419c1 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -60,40 +60,6 @@ void cm_control(u32 mask, u32 set) raw_spin_unlock_irqrestore(&cm_lock, flags); } -static const char *integrator_arch_str(u32 id) -{ - switch ((id >> 16) & 0xff) { - case 0x00: - return "ASB little-endian"; - case 0x01: - return "AHB little-endian"; - case 0x03: - return "AHB-Lite system bus, bi-endian"; - case 0x04: - return "AHB"; - case 0x08: - return "AHB system bus, ASB processor bus"; - default: - return "Unknown"; - } -} - -static const char *integrator_fpga_str(u32 id) -{ - switch ((id >> 12) & 0xf) { - case 0x01: - return "XC4062"; - case 0x02: - return "XC4085"; - case 0x03: - return "XVC600"; - case 0x04: - return "EPM7256AE (Altera PLD)"; - default: - return "Unknown"; - } -} - void cm_clear_irqs(void) { /* disable core module IRQs */ @@ -109,7 +75,6 @@ static const struct of_device_id cm_match[] = { void cm_init(void) { struct device_node *cm = of_find_matching_node(NULL, cm_match); - u32 val; if (!cm) { pr_crit("no core module node found in device tree\n"); @@ -121,13 +86,6 @@ void cm_init(void) return; } cm_clear_irqs(); - val = readl(cm_base + INTEGRATOR_HDR_ID_OFFSET); - pr_info("Detected ARM core module:\n"); - pr_info(" Manufacturer: %02x\n", (val >> 24)); - pr_info(" Architecture: %s\n", integrator_arch_str(val)); - pr_info(" FPGA: %s\n", integrator_fpga_str(val)); - pr_info(" Build: %02x\n", (val >> 4) & 0xFF); - pr_info(" Rev: %c\n", ('A' + (val & 0x03))); } /* @@ -139,64 +97,3 @@ void __init integrator_reserve(void) { memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET); } - -/* - * To reset, we hit the on-board reset register in the system FPGA - */ -void integrator_restart(enum reboot_mode mode, const char *cmd) -{ - cm_control(CM_CTRL_RESET, CM_CTRL_RESET); -} - -static u32 integrator_id; - -static ssize_t intcp_get_manf(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%02x\n", integrator_id >> 24); -} - -static struct device_attribute intcp_manf_attr = - __ATTR(manufacturer, S_IRUGO, intcp_get_manf, NULL); - -static ssize_t intcp_get_arch(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%s\n", integrator_arch_str(integrator_id)); -} - -static struct device_attribute intcp_arch_attr = - __ATTR(architecture, S_IRUGO, intcp_get_arch, NULL); - -static ssize_t intcp_get_fpga(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%s\n", integrator_fpga_str(integrator_id)); -} - -static struct device_attribute intcp_fpga_attr = - __ATTR(fpga, S_IRUGO, intcp_get_fpga, NULL); - -static ssize_t intcp_get_build(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%02x\n", (integrator_id >> 4) & 0xFF); -} - -static struct device_attribute intcp_build_attr = - __ATTR(build, S_IRUGO, intcp_get_build, NULL); - - - -void integrator_init_sysfs(struct device *parent, u32 id) -{ - integrator_id = id; - device_create_file(parent, &intcp_manf_attr); - device_create_file(parent, &intcp_arch_attr); - device_create_file(parent, &intcp_fpga_attr); - device_create_file(parent, &intcp_build_attr); -} diff --git a/arch/arm/mach-integrator/include/mach/uncompress.h b/arch/arm/mach-integrator/include/mach/uncompress.h deleted file mode 100644 index 8f3cc9954c16..000000000000 --- a/arch/arm/mach-integrator/include/mach/uncompress.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * arch/arm/mach-integrator/include/mach/uncompress.h - * - * Copyright (C) 1999 ARM Limited - * - * 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. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define AMBA_UART_DR (*(volatile unsigned char *)0x16000000) -#define AMBA_UART_LCRH (*(volatile unsigned char *)0x16000008) -#define AMBA_UART_LCRM (*(volatile unsigned char *)0x1600000c) -#define AMBA_UART_LCRL (*(volatile unsigned char *)0x16000010) -#define AMBA_UART_CR (*(volatile unsigned char *)0x16000014) -#define AMBA_UART_FR (*(volatile unsigned char *)0x16000018) - -/* - * This does not append a newline - */ -static void putc(int c) -{ - while (AMBA_UART_FR & (1 << 5)) - barrier(); - - AMBA_UART_DR = c; -} - -static inline void flush(void) -{ - while (AMBA_UART_FR & (1 << 3)) - barrier(); -} - -/* - * nothing to do - */ -#define arch_decomp_setup() diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 8ca290b479b1..30003ba447a5 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -27,22 +27,15 @@ #include <linux/syscore_ops.h> #include <linux/amba/bus.h> #include <linux/amba/kmi.h> -#include <linux/clocksource.h> -#include <linux/clockchips.h> -#include <linux/interrupt.h> #include <linux/io.h> #include <linux/irqchip.h> #include <linux/mtd/physmap.h> -#include <linux/clk.h> #include <linux/platform_data/clk-integrator.h> #include <linux/of_irq.h> #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/stat.h> -#include <linux/sys_soc.h> #include <linux/termios.h> -#include <linux/sched_clock.h> -#include <linux/clk-provider.h> #include <asm/hardware/arm_timer.h> #include <asm/setup.h> @@ -89,11 +82,6 @@ static void __iomem *ebi_base; static struct map_desc ap_io_desc[] __initdata __maybe_unused = { { - .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE), .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), .length = SZ_4K, @@ -257,188 +245,10 @@ struct amba_pl010_data ap_uart_data = { .set_mctrl = integrator_uart_set_mctrl, }; -/* - * Where is the timer (VA)? - */ -#define TIMER0_VA_BASE __io_address(INTEGRATOR_TIMER0_BASE) -#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE) -#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE) - -static unsigned long timer_reload; - -static u64 notrace integrator_read_sched_clock(void) -{ - return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE); -} - -static void integrator_clocksource_init(unsigned long inrate, - void __iomem *base) -{ - u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; - unsigned long rate = inrate; - - if (rate >= 1500000) { - rate /= 16; - ctrl |= TIMER_CTRL_DIV16; - } - - writel(0xffff, base + TIMER_LOAD); - writel(ctrl, base + TIMER_CTRL); - - clocksource_mmio_init(base + TIMER_VALUE, "timer2", - rate, 200, 16, clocksource_mmio_readl_down); - sched_clock_register(integrator_read_sched_clock, 16, rate); -} - -static void __iomem * clkevt_base; - -/* - * IRQ handler for the timer - */ -static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = dev_id; - - /* clear the interrupt */ - writel(1, clkevt_base + TIMER_INTCLR); - - evt->event_handler(evt); - - return IRQ_HANDLED; -} - -static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) -{ - u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; - - /* Disable timer */ - writel(ctrl, clkevt_base + TIMER_CTRL); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* Enable the timer and start the periodic tick */ - writel(timer_reload, clkevt_base + TIMER_LOAD); - ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; - writel(ctrl, clkevt_base + TIMER_CTRL); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* Leave the timer disabled, .set_next_event will enable it */ - ctrl &= ~TIMER_CTRL_PERIODIC; - writel(ctrl, clkevt_base + TIMER_CTRL); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - default: - /* Just leave in disabled state */ - break; - } - -} - -static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) -{ - unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); - - writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); - writel(next, clkevt_base + TIMER_LOAD); - writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); - - return 0; -} - -static struct clock_event_device integrator_clockevent = { - .name = "timer1", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = clkevt_set_mode, - .set_next_event = clkevt_set_next_event, - .rating = 300, -}; - -static struct irqaction integrator_timer_irq = { - .name = "timer", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = integrator_timer_interrupt, - .dev_id = &integrator_clockevent, -}; - -static void integrator_clockevent_init(unsigned long inrate, - void __iomem *base, int irq) -{ - unsigned long rate = inrate; - unsigned int ctrl = 0; - - clkevt_base = base; - /* Calculate and program a divisor */ - if (rate > 0x100000 * HZ) { - rate /= 256; - ctrl |= TIMER_CTRL_DIV256; - } else if (rate > 0x10000 * HZ) { - rate /= 16; - ctrl |= TIMER_CTRL_DIV16; - } - timer_reload = rate / HZ; - writel(ctrl, clkevt_base + TIMER_CTRL); - - setup_irq(irq, &integrator_timer_irq); - clockevents_config_and_register(&integrator_clockevent, - rate, - 1, - 0xffffU); -} - void __init ap_init_early(void) { } -static void __init ap_of_timer_init(void) -{ - struct device_node *node; - const char *path; - void __iomem *base; - int err; - int irq; - struct clk *clk; - unsigned long rate; - - of_clk_init(NULL); - - err = of_property_read_string(of_aliases, - "arm,timer-primary", &path); - if (WARN_ON(err)) - return; - node = of_find_node_by_path(path); - base = of_iomap(node, 0); - if (WARN_ON(!base)) - return; - - clk = of_clk_get(node, 0); - BUG_ON(IS_ERR(clk)); - clk_prepare_enable(clk); - rate = clk_get_rate(clk); - - writel(0, base + TIMER_CTRL); - integrator_clocksource_init(rate, base); - - err = of_property_read_string(of_aliases, - "arm,timer-secondary", &path); - if (WARN_ON(err)) - return; - node = of_find_node_by_path(path); - base = of_iomap(node, 0); - if (WARN_ON(!base)) - return; - irq = irq_of_parse_and_map(node, 0); - - clk = of_clk_get(node, 0); - BUG_ON(IS_ERR(clk)); - clk_prepare_enable(clk); - rate = clk_get_rate(clk); - - writel(0, base + TIMER_CTRL); - integrator_clockevent_init(rate, base, irq); -} - static void __init ap_init_irq_of(void) { cm_init(); @@ -477,10 +287,6 @@ static void __init ap_init_of(void) unsigned long sc_dec; struct device_node *syscon; struct device_node *ebi; - struct device *parent; - struct soc_device *soc_dev; - struct soc_device_attribute *soc_dev_attr; - u32 ap_sc_id; int i; syscon = of_find_matching_node(NULL, ap_syscon_match); @@ -500,28 +306,6 @@ static void __init ap_init_of(void) of_platform_populate(NULL, of_default_bus_match_table, ap_auxdata_lookup, NULL); - ap_sc_id = readl(ap_syscon_base); - - soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); - if (!soc_dev_attr) - return; - - soc_dev_attr->soc_id = "XVC"; - soc_dev_attr->machine = "Integrator/AP"; - soc_dev_attr->family = "Integrator"; - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c", - 'A' + (ap_sc_id & 0x0f)); - - soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR(soc_dev)) { - kfree(soc_dev_attr->revision); - kfree(soc_dev_attr); - return; - } - - parent = soc_device_to_device(soc_dev); - integrator_init_sysfs(parent, ap_sc_id); - sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET); for (i = 0; i < 4; i++) { struct lm_device *lmdev; @@ -553,8 +337,6 @@ DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)") .map_io = ap_map_io, .init_early = ap_init_early, .init_irq = ap_init_irq_of, - .init_time = ap_of_timer_init, .init_machine = ap_init_of, - .restart = integrator_restart, .dt_compat = ap_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index cca02eb75eb5..b5fb71a36ee6 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -27,7 +27,6 @@ #include <linux/of_irq.h> #include <linux/of_address.h> #include <linux/of_platform.h> -#include <linux/sys_soc.h> #include <linux/sched_clock.h> #include <asm/setup.h> @@ -274,10 +273,6 @@ static const struct of_device_id intcp_syscon_match[] = { static void __init intcp_init_of(void) { struct device_node *cpcon; - struct device *parent; - struct soc_device *soc_dev; - struct soc_device_attribute *soc_dev_attr; - u32 intcp_sc_id; cpcon = of_find_matching_node(NULL, intcp_syscon_match); if (!cpcon) @@ -289,28 +284,6 @@ static void __init intcp_init_of(void) of_platform_populate(NULL, of_default_bus_match_table, intcp_auxdata_lookup, NULL); - - intcp_sc_id = readl(intcp_con_base); - - soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); - if (!soc_dev_attr) - return; - - soc_dev_attr->soc_id = "XCV"; - soc_dev_attr->machine = "Integrator/CP"; - soc_dev_attr->family = "Integrator"; - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c", - 'A' + (intcp_sc_id & 0x0f)); - - soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR(soc_dev)) { - kfree(soc_dev_attr->revision); - kfree(soc_dev_attr); - return; - } - - parent = soc_device_to_device(soc_dev); - integrator_init_sysfs(parent, intcp_sc_id); } static const char * intcp_dt_board_compat[] = { @@ -324,6 +297,5 @@ DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)") .init_early = intcp_init_early, .init_irq = intcp_init_irq_of, .init_machine = intcp_init_of, - .restart = integrator_restart, .dt_compat = intcp_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c deleted file mode 100644 index f1dcb57a59e2..000000000000 --- a/arch/arm/mach-integrator/leds.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard - * Based on Versatile and RealView machine LED code - * - * License terms: GNU General Public License (GPL) version 2 - * Author: Bryan Wu <bryan.wu@canonical.com> - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/leds.h> - -#include "hardware.h" -#include "cm.h" - -#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) - -#define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE) -#define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET) - -struct integrator_led { - struct led_classdev cdev; - u8 mask; -}; - -/* - * The triggers lines up below will only be used if the - * LED triggers are compiled in. - */ -static const struct { - const char *name; - const char *trigger; -} integrator_leds[] = { - { "integrator:green0", "heartbeat", }, - { "integrator:yellow", }, - { "integrator:red", }, - { "integrator:green1", }, - { "integrator:core_module", "cpu0", }, -}; - -static void integrator_led_set(struct led_classdev *cdev, - enum led_brightness b) -{ - struct integrator_led *led = container_of(cdev, - struct integrator_led, cdev); - u32 reg = __raw_readl(LEDREG); - - if (b != LED_OFF) - reg |= led->mask; - else - reg &= ~led->mask; - - while (__raw_readl(ALPHA_REG) & 1) - cpu_relax(); - - __raw_writel(reg, LEDREG); -} - -static enum led_brightness integrator_led_get(struct led_classdev *cdev) -{ - struct integrator_led *led = container_of(cdev, - struct integrator_led, cdev); - u32 reg = __raw_readl(LEDREG); - - return (reg & led->mask) ? LED_FULL : LED_OFF; -} - -static void cm_led_set(struct led_classdev *cdev, - enum led_brightness b) -{ - if (b != LED_OFF) - cm_control(CM_CTRL_LED, CM_CTRL_LED); - else - cm_control(CM_CTRL_LED, 0); -} - -static enum led_brightness cm_led_get(struct led_classdev *cdev) -{ - u32 reg = cm_get(); - - return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF; -} - -static int __init integrator_leds_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) { - struct integrator_led *led; - - led = kzalloc(sizeof(*led), GFP_KERNEL); - if (!led) - break; - - - led->cdev.name = integrator_leds[i].name; - - if (i == 4) { /* Setting for LED in core module */ - led->cdev.brightness_set = cm_led_set; - led->cdev.brightness_get = cm_led_get; - } else { - led->cdev.brightness_set = integrator_led_set; - led->cdev.brightness_get = integrator_led_get; - } - - led->cdev.default_trigger = integrator_leds[i].trigger; - led->mask = BIT(i); - - if (led_classdev_register(NULL, &led->cdev) < 0) { - kfree(led); - break; - } - } - - return 0; -} - -/* - * Since we may have triggers on any subsystem, defer registration - * until after subsystem_init. - */ -fs_initcall(integrator_leds_init); -#endif diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig index 2c043a210db0..f73f588f649c 100644 --- a/arch/arm/mach-mediatek/Kconfig +++ b/arch/arm/mach-mediatek/Kconfig @@ -1,6 +1,6 @@ config ARCH_MEDIATEK - bool "Mediatek MT6589 SoC" if ARCH_MULTI_V7 + bool "Mediatek MT65xx & MT81xx SoC" if ARCH_MULTI_V7 select ARM_GIC select MTK_TIMER help - Support for Mediatek Cortex-A7 Quad-Core-SoC MT6589. + Support for Mediatek MT65xx & MT81xx SoCs diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index d9e94122073e..3b653b3ac268 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -113,7 +113,7 @@ obj-y += prm_common.o cm_common.o obj-$(CONFIG_ARCH_OMAP2) += prm2xxx_3xxx.o prm2xxx.o cm2xxx.o obj-$(CONFIG_ARCH_OMAP3) += prm2xxx_3xxx.o prm3xxx.o cm3xxx.o obj-$(CONFIG_ARCH_OMAP3) += vc3xxx_data.o vp3xxx_data.o -omap-prcm-4-5-common = cminst44xx.o cm44xx.o prm44xx.o \ +omap-prcm-4-5-common = cminst44xx.o prm44xx.o \ prcm_mpu44xx.o prminst44xx.o \ vc44xx_data.o vp44xx_data.o obj-$(CONFIG_ARCH_OMAP4) += $(omap-prcm-4-5-common) diff --git a/arch/arm/mach-omap2/am33xx-restart.c b/arch/arm/mach-omap2/am33xx-restart.c index c88d8df753c2..5bace6a45ffb 100644 --- a/arch/arm/mach-omap2/am33xx-restart.c +++ b/arch/arm/mach-omap2/am33xx-restart.c @@ -9,8 +9,7 @@ #include <linux/reboot.h> #include "common.h" -#include "prm-regbits-33xx.h" -#include "prm33xx.h" +#include "prm.h" /** * am3xx_restart - trigger a software restart of the SoC @@ -24,12 +23,5 @@ void am33xx_restart(enum reboot_mode mode, const char *cmd) { /* TODO: Handle mode and cmd if necessary */ - am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK, - AM33XX_RST_GLOBAL_WARM_SW_MASK, - AM33XX_PRM_DEVICE_MOD, - AM33XX_PRM_RSTCTRL_OFFSET); - - /* OCP barrier */ - (void)am33xx_prm_read_reg(AM33XX_PRM_DEVICE_MOD, - AM33XX_PRM_RSTCTRL_OFFSET); + omap_prm_reset_system(); } diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c index eb8c75ec3b1a..5c5ebb4db5f7 100644 --- a/arch/arm/mach-omap2/cclock3xxx_data.c +++ b/arch/arm/mach-omap2/cclock3xxx_data.c @@ -257,6 +257,9 @@ static const struct clk_ops dpll1_ck_ops = { .get_parent = &omap2_init_dpll_parent, .recalc_rate = &omap3_dpll_recalc, .set_rate = &omap3_noncore_dpll_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, + .determine_rate = &omap3_noncore_dpll_determine_rate, .round_rate = &omap2_dpll_round_rate, }; @@ -367,6 +370,9 @@ static const struct clk_ops dpll4_ck_ops = { .get_parent = &omap2_init_dpll_parent, .recalc_rate = &omap3_dpll_recalc, .set_rate = &omap3_dpll4_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_dpll4_set_rate_and_parent, + .determine_rate = &omap3_noncore_dpll_determine_rate, .round_rate = &omap2_dpll_round_rate, }; diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 500530d1364a..6ad5b4dbd33e 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -171,7 +171,8 @@ static void _omap2_module_wait_ready(struct clk_hw_omap *clk) _wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit), idlest_val, __clk_get_name(clk->hw.clk)); } else { - cm_wait_module_ready(prcm_mod, idlest_reg_id, idlest_bit); + omap_cm_wait_module_ready(0, prcm_mod, idlest_reg_id, + idlest_bit); }; } @@ -771,4 +772,8 @@ void __init ti_clk_init_features(void) ti_clk_features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL; else if (cpu_is_omap34xx()) ti_clk_features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL; + + /* On OMAP3430 ES1.0, DPLL4 can't be re-programmed */ + if (omap_rev() == OMAP3430_REV_ES1_0) + ti_clk_features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM; } diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 4592a2762592..641337c6cde9 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -234,6 +234,7 @@ struct ti_clk_features { }; #define TI_CLK_DPLL_HAS_FREQSEL (1 << 0) +#define TI_CLK_DPLL4_DENY_REPROGRAM (1 << 1) extern struct ti_clk_features ti_clk_features; diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c index 0b02b4161d71..a9e86db5daf9 100644 --- a/arch/arm/mach-omap2/clock3xxx.c +++ b/arch/arm/mach-omap2/clock3xxx.c @@ -38,6 +38,18 @@ /* needed by omap3_core_dpll_m2_set_rate() */ struct clk *sdrc_ick_p, *arm_fck_p; + +/** + * omap3_dpll4_set_rate - set rate for omap3 per-dpll + * @hw: clock to change + * @rate: target rate for clock + * @parent_rate: rate of the parent clock + * + * Check if the current SoC supports the per-dpll reprogram operation + * or not, and then do the rate change if supported. Returns -EINVAL + * if not supported, 0 for success, and potential error codes from the + * clock rate change. + */ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { @@ -46,7 +58,7 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, * on 3430ES1 prevents us from changing DPLL multipliers or dividers * on DPLL4. */ - if (omap_rev() == OMAP3430_REV_ES1_0) { + if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) { pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); return -EINVAL; } @@ -54,6 +66,30 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, return omap3_noncore_dpll_set_rate(hw, rate, parent_rate); } +/** + * omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll + * @hw: clock to change + * @rate: target rate for clock + * @parent_rate: rate of the parent clock + * @index: parent index, 0 - reference clock, 1 - bypass clock + * + * Check if the current SoC support the per-dpll reprogram operation + * or not, and then do the rate + parent change if supported. Returns + * -EINVAL if not supported, 0 for success, and potential error codes + * from the clock rate change. + */ +int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate, u8 index) +{ + if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) { + pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); + return -EINVAL; + } + + return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate, + index); +} + void __init omap3_clk_lock_dpll5(void) { struct clk *dpll5_clk; diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h index 93473f9a551c..6222e87a79b6 100644 --- a/arch/arm/mach-omap2/cm.h +++ b/arch/arm/mach-omap2/cm.h @@ -45,17 +45,29 @@ extern void omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2); * struct cm_ll_data - fn ptrs to per-SoC CM function implementations * @split_idlest_reg: ptr to the SoC CM-specific split_idlest_reg impl * @wait_module_ready: ptr to the SoC CM-specific wait_module_ready impl + * @wait_module_idle: ptr to the SoC CM-specific wait_module_idle impl + * @module_enable: ptr to the SoC CM-specific module_enable impl + * @module_disable: ptr to the SoC CM-specific module_disable impl */ struct cm_ll_data { int (*split_idlest_reg)(void __iomem *idlest_reg, s16 *prcm_inst, u8 *idlest_reg_id); - int (*wait_module_ready)(s16 prcm_mod, u8 idlest_id, u8 idlest_shift); + int (*wait_module_ready)(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift); + int (*wait_module_idle)(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift); + void (*module_enable)(u8 mode, u8 part, u16 inst, u16 clkctrl_offs); + void (*module_disable)(u8 part, u16 inst, u16 clkctrl_offs); }; extern int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, u8 *idlest_reg_id); -extern int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift); - +int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift); +int omap_cm_wait_module_idle(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift); +int omap_cm_module_enable(u8 mode, u8 part, u16 inst, u16 clkctrl_offs); +int omap_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs); extern int cm_register(struct cm_ll_data *cld); extern int cm_unregister(struct cm_ll_data *cld); diff --git a/arch/arm/mach-omap2/cm1_44xx.h b/arch/arm/mach-omap2/cm1_44xx.h index 5ae8fe39d6ee..a5949927b661 100644 --- a/arch/arm/mach-omap2/cm1_44xx.h +++ b/arch/arm/mach-omap2/cm1_44xx.h @@ -25,8 +25,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM1_44XX_H #define __ARCH_ARM_MACH_OMAP2_CM1_44XX_H -#include "cm_44xx_54xx.h" - /* CM1 base address */ #define OMAP4430_CM1_BASE 0x4a004000 diff --git a/arch/arm/mach-omap2/cm1_54xx.h b/arch/arm/mach-omap2/cm1_54xx.h index 90b3348e6672..fd245dfa7391 100644 --- a/arch/arm/mach-omap2/cm1_54xx.h +++ b/arch/arm/mach-omap2/cm1_54xx.h @@ -22,8 +22,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM1_54XX_H #define __ARCH_ARM_MACH_OMAP2_CM1_54XX_H -#include "cm_44xx_54xx.h" - /* CM1 base address */ #define OMAP54XX_CM_CORE_AON_BASE 0x4a004000 diff --git a/arch/arm/mach-omap2/cm1_7xx.h b/arch/arm/mach-omap2/cm1_7xx.h index ca6fa1febaac..2f1c09eea021 100644 --- a/arch/arm/mach-omap2/cm1_7xx.h +++ b/arch/arm/mach-omap2/cm1_7xx.h @@ -23,8 +23,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM1_7XX_H #define __ARCH_ARM_MACH_OMAP2_CM1_7XX_H -#include "cm_44xx_54xx.h" - /* CM1 base address */ #define DRA7XX_CM_CORE_AON_BASE 0x4a005000 diff --git a/arch/arm/mach-omap2/cm2_44xx.h b/arch/arm/mach-omap2/cm2_44xx.h index ee5136d7cdda..7521abf3d830 100644 --- a/arch/arm/mach-omap2/cm2_44xx.h +++ b/arch/arm/mach-omap2/cm2_44xx.h @@ -25,8 +25,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM2_44XX_H #define __ARCH_ARM_MACH_OMAP2_CM2_44XX_H -#include "cm_44xx_54xx.h" - /* CM2 base address */ #define OMAP4430_CM2_BASE 0x4a008000 diff --git a/arch/arm/mach-omap2/cm2_54xx.h b/arch/arm/mach-omap2/cm2_54xx.h index 2683231b299b..ff4040c196d8 100644 --- a/arch/arm/mach-omap2/cm2_54xx.h +++ b/arch/arm/mach-omap2/cm2_54xx.h @@ -21,8 +21,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM2_54XX_H #define __ARCH_ARM_MACH_OMAP2_CM2_54XX_H -#include "cm_44xx_54xx.h" - /* CM2 base address */ #define OMAP54XX_CM_CORE_BASE 0x4a008000 diff --git a/arch/arm/mach-omap2/cm2_7xx.h b/arch/arm/mach-omap2/cm2_7xx.h index e966e3a3c931..ce63fdb68056 100644 --- a/arch/arm/mach-omap2/cm2_7xx.h +++ b/arch/arm/mach-omap2/cm2_7xx.h @@ -22,8 +22,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM2_7XX_H #define __ARCH_ARM_MACH_OMAP2_CM2_7XX_H -#include "cm_44xx_54xx.h" - /* CM2 base address */ #define DRA7XX_CM_CORE_BASE 0x4a008000 diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c index 8be6ea50c092..a96d901b1d5d 100644 --- a/arch/arm/mach-omap2/cm2xxx.c +++ b/arch/arm/mach-omap2/cm2xxx.c @@ -53,7 +53,7 @@ static void _write_clktrctrl(u8 c, s16 module, u32 mask) omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL); } -bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) +static bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) { u32 v; @@ -64,12 +64,12 @@ bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) return (v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0; } -void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) +static void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) { _write_clktrctrl(OMAP24XX_CLKSTCTRL_ENABLE_AUTO, module, mask); } -void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) +static void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) { _write_clktrctrl(OMAP24XX_CLKSTCTRL_DISABLE_AUTO, module, mask); } @@ -150,7 +150,7 @@ static int _omap2xxx_apll_enable(u8 enable_bit, u8 status_bit) v |= m; omap2_cm_write_mod_reg(v, PLL_MOD, CM_CLKEN); - omap2xxx_cm_wait_module_ready(PLL_MOD, 1, status_bit); + omap2xxx_cm_wait_module_ready(0, PLL_MOD, 1, status_bit); /* * REVISIT: Should we return an error code if @@ -204,8 +204,9 @@ void omap2xxx_cm_apll96_disable(void) * XXX This function is only needed until absolute register addresses are * removed from the OMAP struct clk records. */ -int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, - u8 *idlest_reg_id) +static int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, + s16 *prcm_inst, + u8 *idlest_reg_id) { unsigned long offs; u8 idlest_offs; @@ -238,6 +239,7 @@ int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, /** * omap2xxx_cm_wait_module_ready - wait for a module to leave idle or standby + * @part: PRCM partition, ignored for OMAP2 * @prcm_mod: PRCM module offset * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) * @idlest_shift: shift of the bit in the CM_IDLEST* register to check @@ -246,7 +248,8 @@ int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, * (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon * success or -EBUSY if the module doesn't enable in time. */ -int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) +int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, + u8 idlest_shift) { int ena = 0, i = 0; u8 cm_idlest_reg; diff --git a/arch/arm/mach-omap2/cm2xxx.h b/arch/arm/mach-omap2/cm2xxx.h index 891d81c3c8f4..c89502b168ae 100644 --- a/arch/arm/mach-omap2/cm2xxx.h +++ b/arch/arm/mach-omap2/cm2xxx.h @@ -46,9 +46,6 @@ #ifndef __ASSEMBLER__ -extern void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask); -extern void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask); - extern void omap2xxx_cm_set_dpll_disable_autoidle(void); extern void omap2xxx_cm_set_dpll_auto_low_power_stop(void); @@ -57,11 +54,8 @@ extern void omap2xxx_cm_set_apll54_auto_low_power_stop(void); extern void omap2xxx_cm_set_apll96_disable_autoidle(void); extern void omap2xxx_cm_set_apll96_auto_low_power_stop(void); -extern bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask); -extern int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, - u8 idlest_shift); -extern int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, - s16 *prcm_inst, u8 *idlest_reg_id); +int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, + u8 idlest_shift); extern int omap2xxx_cm_fclks_active(void); extern int omap2xxx_cm_mpu_retention_allowed(void); extern u32 omap2xxx_cm_get_core_clk_src(void); diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c index b3f99e93def0..b9ad463a368a 100644 --- a/arch/arm/mach-omap2/cm33xx.c +++ b/arch/arm/mach-omap2/cm33xx.c @@ -96,13 +96,12 @@ static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask) /** * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to * bit 0. */ -static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs) +static u32 _clkctrl_idlest(u16 inst, u16 clkctrl_offs) { u32 v = am33xx_cm_read_reg(inst, clkctrl_offs); v &= AM33XX_IDLEST_MASK; @@ -113,17 +112,16 @@ static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs) /** * _is_module_ready - can module registers be accessed without causing an abort? * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise. */ -static bool _is_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) +static bool _is_module_ready(u16 inst, u16 clkctrl_offs) { u32 v; - v = _clkctrl_idlest(inst, cdoffs, clkctrl_offs); + v = _clkctrl_idlest(inst, clkctrl_offs); return (v == CLKCTRL_IDLEST_FUNCTIONAL || v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false; @@ -158,7 +156,7 @@ static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs) * Returns true if the clockdomain referred to by (@inst, @cdoffs) * is in hardware-supervised idle mode, or 0 otherwise. */ -bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs) +static bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs) { u32 v; @@ -177,7 +175,7 @@ bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs) * Put a clockdomain referred to by (@inst, @cdoffs) into * hardware-supervised idle mode. No return value. */ -void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs) +static void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs); } @@ -191,7 +189,7 @@ void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs) * software-supervised idle mode, i.e., controlled manually by the * Linux OMAP clockdomain code. No return value. */ -void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs) +static void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs); } @@ -204,7 +202,7 @@ void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs) * Put a clockdomain referred to by (@inst, @cdoffs) into idle * No return value. */ -void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs) +static void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs); } @@ -217,7 +215,7 @@ void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs) * Take a clockdomain referred to by (@inst, @cdoffs) out of idle, * waking it up. No return value. */ -void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) +static void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs); } @@ -228,20 +226,22 @@ void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) /** * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state + * @part: PRCM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) + * @bit_shift: bit shift for the register, ignored for AM33xx * * Wait for the module IDLEST to be functional. If the idle state is in any * the non functional state (trans, idle or disabled), module and thus the * sysconfig cannot be accessed and will probably lead to an "imprecise * external abort" */ -int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) +static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs, + u8 bit_shift) { int i = 0; - omap_test_timeout(_is_module_ready(inst, cdoffs, clkctrl_offs), + omap_test_timeout(_is_module_ready(inst, clkctrl_offs), MAX_MODULE_READY_TIME, i); return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; @@ -250,22 +250,24 @@ int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) /** * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled' * state + * @part: CM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) + * @bit_shift: bit shift for the register, ignored for AM33xx * * Wait for the module IDLEST to be disabled. Some PRCM transition, * like reset assertion or parent clock de-activation must wait the * module to be fully disabled. */ -int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, u16 clkctrl_offs) +static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs, + u8 bit_shift) { int i = 0; if (!clkctrl_offs) return 0; - omap_test_timeout((_clkctrl_idlest(inst, cdoffs, clkctrl_offs) == + omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) == CLKCTRL_IDLEST_DISABLED), MAX_MODULE_READY_TIME, i); @@ -275,13 +277,14 @@ int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, u16 clkctrl_offs) /** * am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL * @mode: Module mode (SW or HW) + * @part: CM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * No return value. */ -void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs) +static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst, + u16 clkctrl_offs) { u32 v; @@ -293,13 +296,13 @@ void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs) /** * am33xx_cm_module_disable - Disable the module inside CLKCTRL + * @part: CM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * No return value. */ -void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs) +static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs) { u32 v; @@ -362,3 +365,21 @@ struct clkdm_ops am33xx_clkdm_operations = { .clkdm_clk_enable = am33xx_clkdm_clk_enable, .clkdm_clk_disable = am33xx_clkdm_clk_disable, }; + +static struct cm_ll_data am33xx_cm_ll_data = { + .wait_module_ready = &am33xx_cm_wait_module_ready, + .wait_module_idle = &am33xx_cm_wait_module_idle, + .module_enable = &am33xx_cm_module_enable, + .module_disable = &am33xx_cm_module_disable, +}; + +int __init am33xx_cm_init(void) +{ + return cm_register(&am33xx_cm_ll_data); +} + +static void __exit am33xx_cm_exit(void) +{ + cm_unregister(&am33xx_cm_ll_data); +} +__exitcall(am33xx_cm_exit); diff --git a/arch/arm/mach-omap2/cm33xx.h b/arch/arm/mach-omap2/cm33xx.h index bd2441790779..046b4b2bc9d9 100644 --- a/arch/arm/mach-omap2/cm33xx.h +++ b/arch/arm/mach-omap2/cm33xx.h @@ -374,41 +374,6 @@ #ifndef __ASSEMBLER__ -bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs); -void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs); -void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs); -void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs); -void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs); - -#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX) -extern int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, - u16 clkctrl_offs); -extern void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, - u16 clkctrl_offs); -extern void am33xx_cm_module_disable(u16 inst, s16 cdoffs, - u16 clkctrl_offs); -extern int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, - u16 clkctrl_offs); -#else -static inline int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, - u16 clkctrl_offs) -{ - return 0; -} -static inline void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, - u16 clkctrl_offs) -{ -} -static inline void am33xx_cm_module_disable(u16 inst, s16 cdoffs, - u16 clkctrl_offs) -{ -} -static inline int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, - u16 clkctrl_offs) -{ - return 0; -} -#endif - +int am33xx_cm_init(void); #endif /* ASSEMBLER */ #endif diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c index 129a4e7f6ef5..ebead8f035f9 100644 --- a/arch/arm/mach-omap2/cm3xxx.c +++ b/arch/arm/mach-omap2/cm3xxx.c @@ -42,7 +42,7 @@ static void _write_clktrctrl(u8 c, s16 module, u32 mask) omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL); } -bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) +static bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) { u32 v; @@ -53,22 +53,22 @@ bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0; } -void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) +static void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) { _write_clktrctrl(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, module, mask); } -void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) +static void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) { _write_clktrctrl(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, module, mask); } -void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask) +static void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask) { _write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, module, mask); } -void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) +static void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) { _write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, module, mask); } @@ -79,6 +79,7 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) /** * omap3xxx_cm_wait_module_ready - wait for a module to leave idle or standby + * @part: PRCM partition, ignored for OMAP3 * @prcm_mod: PRCM module offset * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) * @idlest_shift: shift of the bit in the CM_IDLEST* register to check @@ -87,7 +88,8 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) * (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon * success or -EBUSY if the module doesn't enable in time. */ -int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) +static int omap3xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, + u8 idlest_shift) { int ena = 0, i = 0; u8 cm_idlest_reg; @@ -116,8 +118,9 @@ int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) * XXX This function is only needed until absolute register addresses are * removed from the OMAP struct clk records. */ -int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, - u8 *idlest_reg_id) +static int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, + s16 *prcm_inst, + u8 *idlest_reg_id) { unsigned long offs; u8 idlest_offs; diff --git a/arch/arm/mach-omap2/cm3xxx.h b/arch/arm/mach-omap2/cm3xxx.h index 7a16b5598127..734a8581c0c4 100644 --- a/arch/arm/mach-omap2/cm3xxx.h +++ b/arch/arm/mach-omap2/cm3xxx.h @@ -68,18 +68,6 @@ #ifndef __ASSEMBLER__ -extern void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask); -extern void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask); -extern void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask); -extern void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask); - -extern bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask); -extern int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, - u8 idlest_shift); - -extern int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, - s16 *prcm_inst, u8 *idlest_reg_id); - extern void omap3_cm_save_context(void); extern void omap3_cm_restore_context(void); extern void omap3_cm_save_scratchpad_contents(u32 *ptr); diff --git a/arch/arm/mach-omap2/cm44xx.c b/arch/arm/mach-omap2/cm44xx.c deleted file mode 100644 index fe5cc7bae489..000000000000 --- a/arch/arm/mach-omap2/cm44xx.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * OMAP4 CM1, CM2 module low-level functions - * - * Copyright (C) 2010 Nokia Corporation - * Paul Walmsley - * - * 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. - * - * These functions are intended to be used only by the cminst44xx.c file. - * XXX Perhaps we should just move them there and make them static. - */ - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/err.h> -#include <linux/io.h> - -#include "cm.h" -#include "cm1_44xx.h" -#include "cm2_44xx.h" - -/* CM1 hardware module low-level functions */ - -/* Read a register in CM1 */ -u32 omap4_cm1_read_inst_reg(s16 inst, u16 reg) -{ - return readl_relaxed(cm_base + inst + reg); -} - -/* Write into a register in CM1 */ -void omap4_cm1_write_inst_reg(u32 val, s16 inst, u16 reg) -{ - writel_relaxed(val, cm_base + inst + reg); -} - -/* Read a register in CM2 */ -u32 omap4_cm2_read_inst_reg(s16 inst, u16 reg) -{ - return readl_relaxed(cm2_base + inst + reg); -} - -/* Write into a register in CM2 */ -void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 reg) -{ - writel_relaxed(val, cm2_base + inst + reg); -} diff --git a/arch/arm/mach-omap2/cm44xx.h b/arch/arm/mach-omap2/cm44xx.h index 3380beeace6e..728d06a4af19 100644 --- a/arch/arm/mach-omap2/cm44xx.h +++ b/arch/arm/mach-omap2/cm44xx.h @@ -23,4 +23,7 @@ #define OMAP4_CM_CLKSTCTRL 0x0000 #define OMAP4_CM_STATICDEP 0x0004 +void omap_cm_base_init(void); +int omap4_cm_init(void); + #endif diff --git a/arch/arm/mach-omap2/cm_44xx_54xx.h b/arch/arm/mach-omap2/cm_44xx_54xx.h deleted file mode 100644 index cbb211690321..000000000000 --- a/arch/arm/mach-omap2/cm_44xx_54xx.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * OMAP44xx and OMAP54xx CM1/CM2 function prototypes - * - * Copyright (C) 2009-2013 Texas Instruments, Inc. - * Copyright (C) 2009-2010 Nokia Corporation - * - * Paul Walmsley (paul@pwsan.com) - * Rajendra Nayak (rnayak@ti.com) - * Benoit Cousson (b-cousson@ti.com) - * - * This file is automatically generated from the OMAP hardware databases. - * We respectfully ask that any modifications to this file be coordinated - * with the public linux-omap@vger.kernel.org mailing list and the - * authors above to ensure that the autogeneration scripts are kept - * up-to-date with the file contents. - * - * 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. - * - */ - -#ifndef __ARCH_ARM_MACH_OMAP2_CM_44XX_54XX_H -#define __ARCH_ARM_MACH_OMAP2_CM_44XX_55XX_H - -/* CM1 Function prototypes */ -extern u32 omap4_cm1_read_inst_reg(s16 inst, u16 idx); -extern void omap4_cm1_write_inst_reg(u32 val, s16 inst, u16 idx); -extern u32 omap4_cm1_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); - -/* CM2 Function prototypes */ -extern u32 omap4_cm2_read_inst_reg(s16 inst, u16 idx); -extern void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 idx); -extern u32 omap4_cm2_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); - -#endif diff --git a/arch/arm/mach-omap2/cm_common.c b/arch/arm/mach-omap2/cm_common.c index 8f6c4710877e..8fe02fcedc48 100644 --- a/arch/arm/mach-omap2/cm_common.c +++ b/arch/arm/mach-omap2/cm_common.c @@ -72,9 +72,10 @@ int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, } /** - * cm_wait_module_ready - wait for a module to leave idle or standby + * omap_cm_wait_module_ready - wait for a module to leave idle or standby + * @part: PRCM partition * @prcm_mod: PRCM module offset - * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) + * @idlest_reg: CM_IDLESTx register * @idlest_shift: shift of the bit in the CM_IDLEST* register to check * * Wait for the PRCM to indicate that the module identified by @@ -83,7 +84,8 @@ int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, * no per-SoC wait_module_ready() function pointer has been registered * or if the idlest register is unknown on the SoC. */ -int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) +int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift) { if (!cm_ll_data->wait_module_ready) { WARN_ONCE(1, "cm: %s: no low-level function defined\n", @@ -91,7 +93,79 @@ int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) return -EINVAL; } - return cm_ll_data->wait_module_ready(prcm_mod, idlest_id, idlest_shift); + return cm_ll_data->wait_module_ready(part, prcm_mod, idlest_reg, + idlest_shift); +} + +/** + * omap_cm_wait_module_idle - wait for a module to enter idle or standby + * @part: PRCM partition + * @prcm_mod: PRCM module offset + * @idlest_reg: CM_IDLESTx register + * @idlest_shift: shift of the bit in the CM_IDLEST* register to check + * + * Wait for the PRCM to indicate that the module identified by + * (@prcm_mod, @idlest_id, @idlest_shift) is no longer clocked. Return + * 0 upon success, -EBUSY if the module doesn't enable in time, or + * -EINVAL if no per-SoC wait_module_idle() function pointer has been + * registered or if the idlest register is unknown on the SoC. + */ +int omap_cm_wait_module_idle(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift) +{ + if (!cm_ll_data->wait_module_idle) { + WARN_ONCE(1, "cm: %s: no low-level function defined\n", + __func__); + return -EINVAL; + } + + return cm_ll_data->wait_module_idle(part, prcm_mod, idlest_reg, + idlest_shift); +} + +/** + * omap_cm_module_enable - enable a module + * @mode: target mode for the module + * @part: PRCM partition + * @inst: PRCM instance + * @clkctrl_offs: CM_CLKCTRL register offset for the module + * + * Enables clocks for a module identified by (@part, @inst, @clkctrl_offs) + * making its IO space accessible. Return 0 upon success, -EINVAL if no + * per-SoC module_enable() function pointer has been registered. + */ +int omap_cm_module_enable(u8 mode, u8 part, u16 inst, u16 clkctrl_offs) +{ + if (!cm_ll_data->module_enable) { + WARN_ONCE(1, "cm: %s: no low-level function defined\n", + __func__); + return -EINVAL; + } + + cm_ll_data->module_enable(mode, part, inst, clkctrl_offs); + return 0; +} + +/** + * omap_cm_module_disable - disable a module + * @part: PRCM partition + * @inst: PRCM instance + * @clkctrl_offs: CM_CLKCTRL register offset for the module + * + * Disables clocks for a module identified by (@part, @inst, @clkctrl_offs) + * makings its IO space inaccessible. Return 0 upon success, -EINVAL if + * no per-SoC module_disable() function pointer has been registered. + */ +int omap_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs) +{ + if (!cm_ll_data->module_disable) { + WARN_ONCE(1, "cm: %s: no low-level function defined\n", + __func__); + return -EINVAL; + } + + cm_ll_data->module_disable(part, inst, clkctrl_offs); + return 0; } /** diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c index 12aca56942c0..95a8cff66aff 100644 --- a/arch/arm/mach-omap2/cminst44xx.c +++ b/arch/arm/mach-omap2/cminst44xx.c @@ -26,7 +26,6 @@ #include "cm1_44xx.h" #include "cm2_44xx.h" #include "cm44xx.h" -#include "cminst44xx.h" #include "cm-regbits-34xx.h" #include "prcm44xx.h" #include "prm44xx.h" @@ -74,17 +73,18 @@ void omap_cm_base_init(void) /* Private functions */ +static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx); + /** * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to * bit 0. */ -static u32 _clkctrl_idlest(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) +static u32 _clkctrl_idlest(u8 part, u16 inst, u16 clkctrl_offs) { u32 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs); v &= OMAP4430_IDLEST_MASK; @@ -96,26 +96,23 @@ static u32 _clkctrl_idlest(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) * _is_module_ready - can module registers be accessed without causing an abort? * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise. */ -static bool _is_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) +static bool _is_module_ready(u8 part, u16 inst, u16 clkctrl_offs) { u32 v; - v = _clkctrl_idlest(part, inst, cdoffs, clkctrl_offs); + v = _clkctrl_idlest(part, inst, clkctrl_offs); return (v == CLKCTRL_IDLEST_FUNCTIONAL || v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false; } -/* Public functions */ - /* Read a register in a CM instance */ -u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx) +static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx) { BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS || part == OMAP4430_INVALID_PRCM_PARTITION || @@ -124,7 +121,7 @@ u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx) } /* Write into a register in a CM instance */ -void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx) +static void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx) { BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS || part == OMAP4430_INVALID_PRCM_PARTITION || @@ -133,8 +130,8 @@ void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx) } /* Read-modify-write a register in CM1. Caller must lock */ -u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst, - s16 idx) +static u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst, + s16 idx) { u32 v; @@ -146,17 +143,18 @@ u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst, return v; } -u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx) +static u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx) { return omap4_cminst_rmw_inst_reg_bits(bits, bits, part, inst, idx); } -u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx) +static u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst, + s16 idx) { return omap4_cminst_rmw_inst_reg_bits(bits, 0x0, part, inst, idx); } -u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask) +static u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask) { u32 v; @@ -200,7 +198,7 @@ static void _clktrctrl_write(u8 c, u8 part, u16 inst, u16 cdoffs) * Returns true if the clockdomain referred to by (@part, @inst, @cdoffs) * is in hardware-supervised idle mode, or 0 otherwise. */ -bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs) +static bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs) { u32 v; @@ -220,7 +218,7 @@ bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs) * Put a clockdomain referred to by (@part, @inst, @cdoffs) into * hardware-supervised idle mode. No return value. */ -void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs) +static void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, part, inst, cdoffs); } @@ -235,7 +233,7 @@ void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs) * software-supervised idle mode, i.e., controlled manually by the * Linux OMAP clockdomain code. No return value. */ -void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs) +static void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, part, inst, cdoffs); } @@ -249,7 +247,7 @@ void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs) * Take a clockdomain referred to by (@part, @inst, @cdoffs) out of idle, * waking it up. No return value. */ -void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs) +static void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, part, inst, cdoffs); } @@ -258,7 +256,7 @@ void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs) * */ -void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs) +static void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, part, inst, cdoffs); } @@ -267,23 +265,23 @@ void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs) * omap4_cminst_wait_module_ready - wait for a module to be in 'func' state * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) + * @bit_shift: bit shift for the register, ignored for OMAP4+ * * Wait for the module IDLEST to be functional. If the idle state is in any * the non functional state (trans, idle or disabled), module and thus the * sysconfig cannot be accessed and will probably lead to an "imprecise * external abort" */ -int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs) +static int omap4_cminst_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs, + u8 bit_shift) { int i = 0; if (!clkctrl_offs) return 0; - omap_test_timeout(_is_module_ready(part, inst, cdoffs, clkctrl_offs), + omap_test_timeout(_is_module_ready(part, inst, clkctrl_offs), MAX_MODULE_READY_TIME, i); return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; @@ -294,21 +292,22 @@ int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, * state * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) + * @bit_shift: Bit shift for the register, ignored for OMAP4+ * * Wait for the module IDLEST to be disabled. Some PRCM transition, * like reset assertion or parent clock de-activation must wait the * module to be fully disabled. */ -int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) +static int omap4_cminst_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs, + u8 bit_shift) { int i = 0; if (!clkctrl_offs) return 0; - omap_test_timeout((_clkctrl_idlest(part, inst, cdoffs, clkctrl_offs) == + omap_test_timeout((_clkctrl_idlest(part, inst, clkctrl_offs) == CLKCTRL_IDLEST_DISABLED), MAX_MODULE_DISABLE_TIME, i); @@ -320,13 +319,12 @@ int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_off * @mode: Module mode (SW or HW) * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * No return value. */ -void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs) +static void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, + u16 clkctrl_offs) { u32 v; @@ -340,13 +338,11 @@ void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, * omap4_cminst_module_disable - Disable the module inside CLKCTRL * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * No return value. */ -void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs) +static void omap4_cminst_module_disable(u8 part, u16 inst, u16 clkctrl_offs) { u32 v; @@ -510,3 +506,21 @@ struct clkdm_ops am43xx_clkdm_operations = { .clkdm_clk_enable = omap4_clkdm_clk_enable, .clkdm_clk_disable = omap4_clkdm_clk_disable, }; + +static struct cm_ll_data omap4xxx_cm_ll_data = { + .wait_module_ready = &omap4_cminst_wait_module_ready, + .wait_module_idle = &omap4_cminst_wait_module_idle, + .module_enable = &omap4_cminst_module_enable, + .module_disable = &omap4_cminst_module_disable, +}; + +int __init omap4_cm_init(void) +{ + return cm_register(&omap4xxx_cm_ll_data); +} + +static void __exit omap4_cm_exit(void) +{ + cm_unregister(&omap4xxx_cm_ll_data); +} +__exitcall(omap4_cm_exit); diff --git a/arch/arm/mach-omap2/cminst44xx.h b/arch/arm/mach-omap2/cminst44xx.h deleted file mode 100644 index 7f56ea444bc4..000000000000 --- a/arch/arm/mach-omap2/cminst44xx.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * OMAP4 Clock Management (CM) function prototypes - * - * Copyright (C) 2010 Nokia Corporation - * Paul Walmsley - * - * 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. - */ -#ifndef __ARCH_ASM_MACH_OMAP2_CMINST44XX_H -#define __ARCH_ASM_MACH_OMAP2_CMINST44XX_H - -bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs); -void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs); -void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs); -void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs); -void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs); -extern int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs); -extern int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs); -extern void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs); -extern void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs); -/* - * In an ideal world, we would not export these low-level functions, - * but this will probably take some time to fix properly - */ -u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx); -void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx); -u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, - u16 inst, s16 idx); -u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, - s16 idx); -u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst, - s16 idx); -extern u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, - u32 mask); - -extern void omap_cm_base_init(void); - -#endif diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index ac3d789ac3cd..20e120d071dd 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -460,25 +460,24 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw) /* Non-CORE DPLL rate set code */ /** - * omap3_noncore_dpll_set_rate - set non-core DPLL rate - * @clk: struct clk * of DPLL to set - * @rate: rounded target rate + * omap3_noncore_dpll_determine_rate - determine rate for a DPLL + * @hw: pointer to the clock to determine rate for + * @rate: target rate for the DPLL + * @best_parent_rate: pointer for returning best parent rate + * @best_parent_clk: pointer for returning best parent clock * - * Set the DPLL CLKOUT to the target rate. If the DPLL can enter - * low-power bypass, and the target rate is the bypass source clock - * rate, then configure the DPLL for bypass. Otherwise, round the - * target rate if it hasn't been done already, then program and lock - * the DPLL. Returns -EINVAL upon error, or 0 upon success. + * Determines which DPLL mode to use for reaching a desired target rate. + * Checks whether the DPLL shall be in bypass or locked mode, and if + * locked, calculates the M,N values for the DPLL via round-rate. + * Returns a positive clock rate with success, negative error value + * in failure. */ -int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) +long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); - struct clk *new_parent = NULL; - unsigned long rrate; - u16 freqsel = 0; struct dpll_data *dd; - int ret; if (!hw || !rate) return -EINVAL; @@ -489,61 +488,121 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, if (__clk_get_rate(dd->clk_bypass) == rate && (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { - pr_debug("%s: %s: set rate: entering bypass.\n", - __func__, __clk_get_name(hw->clk)); + *best_parent_clk = dd->clk_bypass; + } else { + rate = omap2_dpll_round_rate(hw, rate, best_parent_rate); + *best_parent_clk = dd->clk_ref; + } + + *best_parent_rate = rate; + + return rate; +} + +/** + * omap3_noncore_dpll_set_parent - set parent for a DPLL clock + * @hw: pointer to the clock to set parent for + * @index: parent index to select + * + * Sets parent for a DPLL clock. This sets the DPLL into bypass or + * locked mode. Returns 0 with success, negative error value otherwise. + */ +int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + int ret; - __clk_prepare(dd->clk_bypass); - clk_enable(dd->clk_bypass); + if (!hw) + return -EINVAL; + + if (index) ret = _omap3_noncore_dpll_bypass(clk); - if (!ret) - new_parent = dd->clk_bypass; - clk_disable(dd->clk_bypass); - __clk_unprepare(dd->clk_bypass); - } else { - __clk_prepare(dd->clk_ref); - clk_enable(dd->clk_ref); - - /* XXX this check is probably pointless in the CCF context */ - if (dd->last_rounded_rate != rate) { - rrate = __clk_round_rate(hw->clk, rate); - if (rrate != rate) { - pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n", - __func__, __clk_get_name(hw->clk), - rrate, rate); - rate = rrate; - } - } + else + ret = _omap3_noncore_dpll_lock(clk); - if (dd->last_rounded_rate == 0) - return -EINVAL; + return ret; +} - /* Freqsel is available only on OMAP343X devices */ - if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) { - freqsel = _omap3_dpll_compute_freqsel(clk, - dd->last_rounded_n); - WARN_ON(!freqsel); - } +/** + * omap3_noncore_dpll_set_rate - set rate for a DPLL clock + * @hw: pointer to the clock to set parent for + * @rate: target rate for the clock + * @parent_rate: rate of the parent clock + * + * Sets rate for a DPLL clock. First checks if the clock parent is + * reference clock (in bypass mode, the rate of the clock can't be + * changed) and proceeds with the rate change operation. Returns 0 + * with success, negative error value otherwise. + */ +int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *dd; + u16 freqsel = 0; + int ret; + + if (!hw || !rate) + return -EINVAL; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; - pr_debug("%s: %s: set rate: locking rate to %lu.\n", - __func__, __clk_get_name(hw->clk), rate); + if (__clk_get_parent(hw->clk) != dd->clk_ref) + return -EINVAL; + + if (dd->last_rounded_rate == 0) + return -EINVAL; - ret = omap3_noncore_dpll_program(clk, freqsel); - if (!ret) - new_parent = dd->clk_ref; - clk_disable(dd->clk_ref); - __clk_unprepare(dd->clk_ref); + /* Freqsel is available only on OMAP343X devices */ + if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) { + freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); + WARN_ON(!freqsel); } - /* - * FIXME - this is all wrong. common code handles reparenting and - * migrating prepare/enable counts. dplls should be a multiplexer - * clock and this should be a set_parent operation so that all of that - * stuff is inherited for free - */ - if (!ret && clk_get_parent(hw->clk) != new_parent) - __clk_reparent(hw->clk, new_parent); + pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__, + __clk_get_name(hw->clk), rate); - return 0; + ret = omap3_noncore_dpll_program(clk, freqsel); + + return ret; +} + +/** + * omap3_noncore_dpll_set_rate_and_parent - set rate and parent for a DPLL clock + * @hw: pointer to the clock to set rate and parent for + * @rate: target rate for the DPLL + * @parent_rate: clock rate of the DPLL parent + * @index: new parent index for the DPLL, 0 - reference, 1 - bypass + * + * Sets rate and parent for a DPLL clock. If new parent is the bypass + * clock, only selects the parent. Otherwise proceeds with a rate + * change, as this will effectively also change the parent as the + * DPLL is put into locked mode. Returns 0 with success, negative error + * value otherwise. + */ +int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate, + u8 index) +{ + int ret; + + if (!hw || !rate) + return -EINVAL; + + /* + * clk-ref at index[0], in which case we only need to set rate, + * the parent will be changed automatically with the lock sequence. + * With clk-bypass case we only need to change parent. + */ + if (index) + ret = omap3_noncore_dpll_set_parent(hw, index); + else + ret = omap3_noncore_dpll_set_rate(hw, rate, parent_rate); + + return ret; } /* DPLL autoidle read/set code */ diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c index 4613f1e86988..535822fcf4bb 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/arch/arm/mach-omap2/dpll44xx.c @@ -207,3 +207,44 @@ out: return dd->last_rounded_rate; } + +/** + * omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL + * @hw: pointer to the clock to determine rate for + * @rate: target rate for the DPLL + * @best_parent_rate: pointer for returning best parent rate + * @best_parent_clk: pointer for returning best parent clock + * + * Determines which DPLL mode to use for reaching a desired rate. + * Checks whether the DPLL shall be in bypass or locked mode, and if + * locked, calculates the M,N values for the DPLL via round-rate. + * Returns a positive clock rate with success, negative error value + * in failure. + */ +long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *dd; + + if (!hw || !rate) + return -EINVAL; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; + + if (__clk_get_rate(dd->clk_bypass) == rate && + (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { + *best_parent_clk = dd->clk_bypass; + } else { + rate = omap4_dpll_regm4xen_round_rate(hw, rate, + best_parent_rate); + *best_parent_clk = dd->clk_ref; + } + + *best_parent_rate = rate; + + return rate; +} diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 03cbb16898a3..4fc838354e31 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -45,13 +45,15 @@ #include "sram.h" #include "cm2xxx.h" #include "cm3xxx.h" +#include "cm33xx.h" +#include "cm44xx.h" #include "prm.h" #include "cm.h" #include "prcm_mpu44xx.h" #include "prminst44xx.h" -#include "cminst44xx.h" #include "prm2xxx.h" #include "prm3xxx.h" +#include "prm33xx.h" #include "prm44xx.h" #include "opp2xxx.h" @@ -565,6 +567,8 @@ void __init am33xx_init_early(void) omap2_set_globals_cm(AM33XX_L4_WK_IO_ADDRESS(AM33XX_PRCM_BASE), NULL); omap3xxx_check_revision(); am33xx_check_features(); + am33xx_prm_init(); + am33xx_cm_init(); am33xx_powerdomains_init(); am33xx_clockdomains_init(); am33xx_hwmod_init(); @@ -591,6 +595,8 @@ void __init am43xx_init_early(void) omap_cm_base_init(); omap3xxx_check_revision(); am33xx_check_features(); + omap44xx_prm_init(); + omap4_cm_init(); am43xx_powerdomains_init(); am43xx_clockdomains_init(); am43xx_hwmod_init(); @@ -620,6 +626,7 @@ void __init omap4430_init_early(void) omap_cm_base_init(); omap4xxx_check_revision(); omap4xxx_check_features(); + omap4_cm_init(); omap4_pm_init_early(); omap44xx_prm_init(); omap44xx_voltagedomains_init(); @@ -655,6 +662,7 @@ void __init omap5_init_early(void) omap_cm_base_init(); omap44xx_prm_init(); omap5xxx_check_revision(); + omap4_cm_init(); omap54xx_voltagedomains_init(); omap54xx_powerdomains_init(); omap54xx_clockdomains_init(); @@ -686,6 +694,7 @@ void __init dra7xx_init_early(void) omap_cm_base_init(); omap44xx_prm_init(); dra7xxx_check_revision(); + omap4_cm_init(); dra7xx_powerdomains_init(); dra7xx_clockdomains_init(); dra7xx_hwmod_init(); diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index 6944ae3674e8..79f49d904a06 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -227,7 +227,7 @@ static void __init save_l2x0_context(void) int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) { struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); - unsigned int save_state = 0; + unsigned int save_state = 0, cpu_logic_state = PWRDM_POWER_RET; unsigned int wakeup_cpu; if (omap_rev() == OMAP4430_REV_ES1_0) @@ -239,6 +239,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) save_state = 0; break; case PWRDM_POWER_OFF: + cpu_logic_state = PWRDM_POWER_OFF; save_state = 1; break; case PWRDM_POWER_RET: @@ -270,6 +271,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) cpu_clear_prev_logic_pwrst(cpu); pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); + pwrdm_set_logic_retst(pm_info->pwrdm, cpu_logic_state); set_cpu_wakeup_addr(cpu, virt_to_phys(omap_pm_ops.resume)); omap_pm_ops.scu_prepare(cpu, power_state); l2x0_pwrst_prepare(cpu, save_state); diff --git a/arch/arm/mach-omap2/omap2-restart.c b/arch/arm/mach-omap2/omap2-restart.c index 68423e26399d..d937b2e4040b 100644 --- a/arch/arm/mach-omap2/omap2-restart.c +++ b/arch/arm/mach-omap2/omap2-restart.c @@ -15,7 +15,7 @@ #include "soc.h" #include "common.h" -#include "prm2xxx.h" +#include "prm.h" /* * reset_virt_prcm_set_ck, reset_sys_ck: pointers to the virt_prcm_set @@ -40,8 +40,7 @@ void omap2xxx_restart(enum reboot_mode mode, const char *cmd) /* XXX Should save the cmd argument for use after the reboot */ - omap2xxx_prm_dpll_reset(); /* never returns */ - while (1); + omap_prm_reset_system(); } /** diff --git a/arch/arm/mach-omap2/omap3-restart.c b/arch/arm/mach-omap2/omap3-restart.c index 5de2a0c2979d..103a49f68bcb 100644 --- a/arch/arm/mach-omap2/omap3-restart.c +++ b/arch/arm/mach-omap2/omap3-restart.c @@ -14,10 +14,8 @@ #include <linux/init.h> #include <linux/reboot.h> -#include "iomap.h" -#include "common.h" #include "control.h" -#include "prm3xxx.h" +#include "prm.h" /* Global address base setup code */ @@ -32,6 +30,5 @@ void omap3xxx_restart(enum reboot_mode mode, const char *cmd) { omap3_ctrl_write_boot_mode((cmd ? (u8)*cmd : 0)); - omap3xxx_prm_dpll3_reset(); /* never returns */ - while (1); + omap_prm_reset_system(); } diff --git a/arch/arm/mach-omap2/omap4-restart.c b/arch/arm/mach-omap2/omap4-restart.c index 41dfd7da8170..a99e7f7fb5be 100644 --- a/arch/arm/mach-omap2/omap4-restart.c +++ b/arch/arm/mach-omap2/omap4-restart.c @@ -9,7 +9,7 @@ #include <linux/types.h> #include <linux/reboot.h> -#include "prminst44xx.h" +#include "prm.h" /** * omap44xx_restart - trigger a software restart of the SoC @@ -22,7 +22,5 @@ void omap44xx_restart(enum reboot_mode mode, const char *cmd) { /* XXX Should save 'cmd' into scratchpad for use after reboot */ - omap4_prminst_global_warm_sw_reset(); /* never returns */ - while (1) - ; + omap_prm_reset_system(); } diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 716247ed9e0c..ee5f38df477d 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -153,7 +153,6 @@ #include "powerdomain.h" #include "cm2xxx.h" #include "cm3xxx.h" -#include "cminst44xx.h" #include "cm33xx.h" #include "prm.h" #include "prm3xxx.h" @@ -979,31 +978,9 @@ static void _omap4_enable_module(struct omap_hwmod *oh) pr_debug("omap_hwmod: %s: %s: %d\n", oh->name, __func__, oh->prcm.omap4.modulemode); - omap4_cminst_module_enable(oh->prcm.omap4.modulemode, - oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); -} - -/** - * _am33xx_enable_module - enable CLKCTRL modulemode on AM33XX - * @oh: struct omap_hwmod * - * - * Enables the PRCM module mode related to the hwmod @oh. - * No return value. - */ -static void _am33xx_enable_module(struct omap_hwmod *oh) -{ - if (!oh->clkdm || !oh->prcm.omap4.modulemode) - return; - - pr_debug("omap_hwmod: %s: %s: %d\n", - oh->name, __func__, oh->prcm.omap4.modulemode); - - am33xx_cm_module_enable(oh->prcm.omap4.modulemode, oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + omap_cm_module_enable(oh->prcm.omap4.modulemode, + oh->clkdm->prcm_partition, + oh->clkdm->cm_inst, oh->prcm.omap4.clkctrl_offs); } /** @@ -1026,35 +1003,9 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh) if (oh->flags & HWMOD_NO_IDLEST) return 0; - return omap4_cminst_wait_module_idle(oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); -} - -/** - * _am33xx_wait_target_disable - wait for a module to be disabled on AM33XX - * @oh: struct omap_hwmod * - * - * Wait for a module @oh to enter slave idle. Returns 0 if the module - * does not have an IDLEST bit or if the module successfully enters - * slave idle; otherwise, pass along the return value of the - * appropriate *_cm*_wait_module_idle() function. - */ -static int _am33xx_wait_target_disable(struct omap_hwmod *oh) -{ - if (!oh) - return -EINVAL; - - if (oh->_int_flags & _HWMOD_NO_MPU_PORT) - return 0; - - if (oh->flags & HWMOD_NO_IDLEST) - return 0; - - return am33xx_cm_wait_module_idle(oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + return omap_cm_wait_module_idle(oh->clkdm->prcm_partition, + oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs, 0); } /** @@ -1859,10 +1810,8 @@ static int _omap4_disable_module(struct omap_hwmod *oh) pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); - omap4_cminst_module_disable(oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + omap_cm_module_disable(oh->clkdm->prcm_partition, oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs); v = _omap4_wait_target_disable(oh); if (v) @@ -1873,36 +1822,6 @@ static int _omap4_disable_module(struct omap_hwmod *oh) } /** - * _am33xx_disable_module - enable CLKCTRL modulemode on AM33XX - * @oh: struct omap_hwmod * - * - * Disable the PRCM module mode related to the hwmod @oh. - * Return EINVAL if the modulemode is not supported and 0 in case of success. - */ -static int _am33xx_disable_module(struct omap_hwmod *oh) -{ - int v; - - if (!oh->clkdm || !oh->prcm.omap4.modulemode) - return -EINVAL; - - pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); - - if (_are_any_hardreset_lines_asserted(oh)) - return 0; - - am33xx_cm_module_disable(oh->clkdm->cm_inst, oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); - - v = _am33xx_wait_target_disable(oh); - if (v) - pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", - oh->name); - - return 0; -} - -/** * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit * @oh: struct omap_hwmod * * @@ -2065,10 +1984,7 @@ static void _reconfigure_io_chain(void) spin_lock_irqsave(&io_chain_lock, flags); - if (cpu_is_omap34xx()) - omap3xxx_prm_reconfigure_io_chain(); - else if (cpu_is_omap44xx()) - omap44xx_prm_reconfigure_io_chain(); + omap_prm_reconfigure_io_chain(); spin_unlock_irqrestore(&io_chain_lock, flags); } @@ -2832,12 +2748,10 @@ static int __init _add_link(struct omap_hwmod_ocp_if *oi) _alloc_links(&ml, &sl); ml->ocp_if = oi; - INIT_LIST_HEAD(&ml->node); list_add(&ml->node, &oi->master->master_ports); oi->master->masters_cnt++; sl->ocp_if = oi; - INIT_LIST_HEAD(&sl->node); list_add(&sl->node, &oi->slave->slave_ports); oi->slave->slaves_cnt++; @@ -2927,7 +2841,7 @@ static int __init _alloc_linkspace(struct omap_hwmod_ocp_if **ois) /* Static functions intended only for use in soc_ops field function pointers */ /** - * _omap2xxx_wait_target_ready - wait for a module to leave slave idle + * _omap2xxx_3xxx_wait_target_ready - wait for a module to leave slave idle * @oh: struct omap_hwmod * * * Wait for a module @oh to leave slave idle. Returns 0 if the module @@ -2935,7 +2849,7 @@ static int __init _alloc_linkspace(struct omap_hwmod_ocp_if **ois) * slave idle; otherwise, pass along the return value of the * appropriate *_cm*_wait_module_ready() function. */ -static int _omap2xxx_wait_target_ready(struct omap_hwmod *oh) +static int _omap2xxx_3xxx_wait_target_ready(struct omap_hwmod *oh) { if (!oh) return -EINVAL; @@ -2948,36 +2862,9 @@ static int _omap2xxx_wait_target_ready(struct omap_hwmod *oh) /* XXX check module SIDLEMODE, hardreset status, enabled clocks */ - return omap2xxx_cm_wait_module_ready(oh->prcm.omap2.module_offs, - oh->prcm.omap2.idlest_reg_id, - oh->prcm.omap2.idlest_idle_bit); -} - -/** - * _omap3xxx_wait_target_ready - wait for a module to leave slave idle - * @oh: struct omap_hwmod * - * - * Wait for a module @oh to leave slave idle. Returns 0 if the module - * does not have an IDLEST bit or if the module successfully leaves - * slave idle; otherwise, pass along the return value of the - * appropriate *_cm*_wait_module_ready() function. - */ -static int _omap3xxx_wait_target_ready(struct omap_hwmod *oh) -{ - if (!oh) - return -EINVAL; - - if (oh->flags & HWMOD_NO_IDLEST) - return 0; - - if (!_find_mpu_rt_port(oh)) - return 0; - - /* XXX check module SIDLEMODE, hardreset status, enabled clocks */ - - return omap3xxx_cm_wait_module_ready(oh->prcm.omap2.module_offs, - oh->prcm.omap2.idlest_reg_id, - oh->prcm.omap2.idlest_idle_bit); + return omap_cm_wait_module_ready(0, oh->prcm.omap2.module_offs, + oh->prcm.omap2.idlest_reg_id, + oh->prcm.omap2.idlest_idle_bit); } /** @@ -3002,37 +2889,9 @@ static int _omap4_wait_target_ready(struct omap_hwmod *oh) /* XXX check module SIDLEMODE, hardreset status */ - return omap4_cminst_wait_module_ready(oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); -} - -/** - * _am33xx_wait_target_ready - wait for a module to leave slave idle - * @oh: struct omap_hwmod * - * - * Wait for a module @oh to leave slave idle. Returns 0 if the module - * does not have an IDLEST bit or if the module successfully leaves - * slave idle; otherwise, pass along the return value of the - * appropriate *_cm*_wait_module_ready() function. - */ -static int _am33xx_wait_target_ready(struct omap_hwmod *oh) -{ - if (!oh || !oh->clkdm) - return -EINVAL; - - if (oh->flags & HWMOD_NO_IDLEST) - return 0; - - if (!_find_mpu_rt_port(oh)) - return 0; - - /* XXX check module SIDLEMODE, hardreset status */ - - return am33xx_cm_wait_module_ready(oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + return omap_cm_wait_module_ready(oh->clkdm->prcm_partition, + oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs, 0); } /** @@ -3049,8 +2908,8 @@ static int _am33xx_wait_target_ready(struct omap_hwmod *oh) static int _omap2_assert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs, - ohri->rst_shift); + return omap_prm_assert_hardreset(ohri->rst_shift, 0, + oh->prcm.omap2.module_offs, 0); } /** @@ -3067,9 +2926,8 @@ static int _omap2_assert_hardreset(struct omap_hwmod *oh, static int _omap2_deassert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs, - ohri->rst_shift, - ohri->st_shift); + return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0, + oh->prcm.omap2.module_offs, 0, 0); } /** @@ -3087,8 +2945,8 @@ static int _omap2_deassert_hardreset(struct omap_hwmod *oh, static int _omap2_is_hardreset_asserted(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs, - ohri->st_shift); + return omap_prm_is_hardreset_asserted(ohri->st_shift, 0, + oh->prcm.omap2.module_offs, 0); } /** @@ -3109,10 +2967,10 @@ static int _omap4_assert_hardreset(struct omap_hwmod *oh, if (!oh->clkdm) return -EINVAL; - return omap4_prminst_assert_hardreset(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_partition, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_assert_hardreset(ohri->rst_shift, + oh->clkdm->pwrdm.ptr->prcm_partition, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs); } /** @@ -3136,10 +2994,10 @@ static int _omap4_deassert_hardreset(struct omap_hwmod *oh, if (ohri->st_shift) pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n", oh->name, ohri->name); - return omap4_prminst_deassert_hardreset(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_partition, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_deassert_hardreset(ohri->rst_shift, 0, + oh->clkdm->pwrdm.ptr->prcm_partition, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs, 0); } /** @@ -3160,10 +3018,11 @@ static int _omap4_is_hardreset_asserted(struct omap_hwmod *oh, if (!oh->clkdm) return -EINVAL; - return omap4_prminst_is_hardreset_asserted(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_partition, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_is_hardreset_asserted(ohri->rst_shift, + oh->clkdm->pwrdm.ptr-> + prcm_partition, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs); } /** @@ -3182,9 +3041,9 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return am33xx_prm_assert_hardreset(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_assert_hardreset(ohri->rst_shift, 0, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs); } /** @@ -3202,11 +3061,10 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh, static int _am33xx_deassert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return am33xx_prm_deassert_hardreset(ohri->rst_shift, - ohri->st_shift, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs, - oh->prcm.omap4.rstst_offs); + return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs, + oh->prcm.omap4.rstst_offs); } /** @@ -3224,9 +3082,9 @@ static int _am33xx_deassert_hardreset(struct omap_hwmod *oh, static int _am33xx_is_hardreset_asserted(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return am33xx_prm_is_hardreset_asserted(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_is_hardreset_asserted(ohri->rst_shift, 0, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs); } /* Public functions */ @@ -4234,12 +4092,12 @@ int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx) void __init omap_hwmod_init(void) { if (cpu_is_omap24xx()) { - soc_ops.wait_target_ready = _omap2xxx_wait_target_ready; + soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready; soc_ops.assert_hardreset = _omap2_assert_hardreset; soc_ops.deassert_hardreset = _omap2_deassert_hardreset; soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted; } else if (cpu_is_omap34xx()) { - soc_ops.wait_target_ready = _omap3xxx_wait_target_ready; + soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready; soc_ops.assert_hardreset = _omap2_assert_hardreset; soc_ops.deassert_hardreset = _omap2_deassert_hardreset; soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted; @@ -4258,14 +4116,14 @@ void __init omap_hwmod_init(void) soc_ops.enable_module = _omap4_enable_module; soc_ops.disable_module = _omap4_disable_module; soc_ops.wait_target_ready = _omap4_wait_target_ready; - soc_ops.assert_hardreset = _am33xx_assert_hardreset; - soc_ops.deassert_hardreset = _am33xx_deassert_hardreset; - soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted; + soc_ops.assert_hardreset = _omap4_assert_hardreset; + soc_ops.deassert_hardreset = _omap4_deassert_hardreset; + soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted; soc_ops.init_clkdm = _init_clkdm; } else if (soc_is_am33xx()) { - soc_ops.enable_module = _am33xx_enable_module; - soc_ops.disable_module = _am33xx_disable_module; - soc_ops.wait_target_ready = _am33xx_wait_target_ready; + soc_ops.enable_module = _omap4_enable_module; + soc_ops.disable_module = _omap4_disable_module; + soc_ops.wait_target_ready = _omap4_wait_target_ready; soc_ops.assert_hardreset = _am33xx_assert_hardreset; soc_ops.deassert_hardreset = _am33xx_deassert_hardreset; soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted; diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 503097c72b82..d697cecf762b 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -37,6 +37,16 @@ struct power_state { struct list_head node; }; +/** + * struct static_dep_map - Static dependency map + * @from: from clockdomain + * @to: to clockdomain + */ +struct static_dep_map { + const char *from; + const char *to; +}; + static u32 cpu_suspend_state = PWRDM_POWER_OFF; static LIST_HEAD(pwrst_list); @@ -148,94 +158,61 @@ static void omap_default_idle(void) omap_do_wfi(); } -/** - * omap4_init_static_deps - Add OMAP4 static dependencies - * - * Add needed static clockdomain dependencies on OMAP4 devices. - * Return: 0 on success or 'err' on failures +/* + * The dynamic dependency between MPUSS -> MEMIF and + * MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as + * expected. The hardware recommendation is to enable static + * dependencies for these to avoid system lock ups or random crashes. + * The L4 wakeup depedency is added to workaround the OCP sync hardware + * BUG with 32K synctimer which lead to incorrect timer value read + * from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which + * are part of L4 wakeup clockdomain. */ -static inline int omap4_init_static_deps(void) -{ - struct clockdomain *emif_clkdm, *mpuss_clkdm, *l3_1_clkdm; - struct clockdomain *ducati_clkdm, *l3_2_clkdm; - int ret = 0; - - if (omap_rev() == OMAP4430_REV_ES1_0) { - WARN(1, "Power Management not supported on OMAP4430 ES1.0\n"); - return -ENODEV; - } - - pr_err("Power Management for TI OMAP4.\n"); - /* - * OMAP4 chip PM currently works only with certain (newer) - * versions of bootloaders. This is due to missing code in the - * kernel to properly reset and initialize some devices. - * http://www.spinics.net/lists/arm-kernel/msg218641.html - */ - pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n"); - - ret = pwrdm_for_each(pwrdms_setup, NULL); - if (ret) { - pr_err("Failed to setup powerdomains\n"); - return ret; - } - - /* - * The dynamic dependency between MPUSS -> MEMIF and - * MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as - * expected. The hardware recommendation is to enable static - * dependencies for these to avoid system lock ups or random crashes. - * The L4 wakeup depedency is added to workaround the OCP sync hardware - * BUG with 32K synctimer which lead to incorrect timer value read - * from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which - * are part of L4 wakeup clockdomain. - */ - mpuss_clkdm = clkdm_lookup("mpuss_clkdm"); - emif_clkdm = clkdm_lookup("l3_emif_clkdm"); - l3_1_clkdm = clkdm_lookup("l3_1_clkdm"); - l3_2_clkdm = clkdm_lookup("l3_2_clkdm"); - ducati_clkdm = clkdm_lookup("ducati_clkdm"); - if ((!mpuss_clkdm) || (!emif_clkdm) || (!l3_1_clkdm) || - (!l3_2_clkdm) || (!ducati_clkdm)) - return -EINVAL; - - ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm); - ret |= clkdm_add_wkdep(mpuss_clkdm, l3_1_clkdm); - ret |= clkdm_add_wkdep(mpuss_clkdm, l3_2_clkdm); - ret |= clkdm_add_wkdep(ducati_clkdm, l3_1_clkdm); - ret |= clkdm_add_wkdep(ducati_clkdm, l3_2_clkdm); - if (ret) { - pr_err("Failed to add MPUSS -> L3/EMIF/L4PER, DUCATI -> L3 wakeup dependency\n"); - return -EINVAL; - } +static const struct static_dep_map omap4_static_dep_map[] = { + {.from = "mpuss_clkdm", .to = "l3_emif_clkdm"}, + {.from = "mpuss_clkdm", .to = "l3_1_clkdm"}, + {.from = "mpuss_clkdm", .to = "l3_2_clkdm"}, + {.from = "ducati_clkdm", .to = "l3_1_clkdm"}, + {.from = "ducati_clkdm", .to = "l3_2_clkdm"}, + {.from = NULL} /* TERMINATION */ +}; - return ret; -} +static const struct static_dep_map omap5_dra7_static_dep_map[] = { + {.from = "mpu_clkdm", .to = "emif_clkdm"}, + {.from = NULL} /* TERMINATION */ +}; /** - * omap5_dra7_init_static_deps - Init static clkdm dependencies on OMAP5 and - * DRA7 - * - * The dynamic dependency between MPUSS -> EMIF is broken and has - * not worked as expected. The hardware recommendation is to - * enable static dependencies for these to avoid system - * lock ups or random crashes. + * omap4plus_init_static_deps() - Initialize a static dependency map + * @map: Mapping of clock domains */ -static inline int omap5_dra7_init_static_deps(void) +static inline int omap4plus_init_static_deps(const struct static_dep_map *map) { - struct clockdomain *mpuss_clkdm, *emif_clkdm; int ret; + struct clockdomain *from, *to; + + if (!map) + return 0; - mpuss_clkdm = clkdm_lookup("mpu_clkdm"); - emif_clkdm = clkdm_lookup("emif_clkdm"); - if (!mpuss_clkdm || !emif_clkdm) - return -EINVAL; + while (map->from) { + from = clkdm_lookup(map->from); + to = clkdm_lookup(map->to); + if (!from || !to) { + pr_err("Failed lookup %s or %s for wakeup dependency\n", + map->from, map->to); + return -EINVAL; + } + ret = clkdm_add_wkdep(from, to); + if (ret) { + pr_err("Failed to add %s -> %s wakeup dependency(%d)\n", + map->from, map->to, ret); + return ret; + } - ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm); - if (ret) - pr_err("Failed to add MPUSS -> EMIF wakeup dependency\n"); + map++; + }; - return ret; + return 0; } /** @@ -272,6 +249,15 @@ int __init omap4_pm_init(void) pr_info("Power Management for TI OMAP4+ devices.\n"); + /* + * OMAP4 chip PM currently works only with certain (newer) + * versions of bootloaders. This is due to missing code in the + * kernel to properly reset and initialize some devices. + * http://www.spinics.net/lists/arm-kernel/msg218641.html + */ + if (cpu_is_omap44xx()) + pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n"); + ret = pwrdm_for_each(pwrdms_setup, NULL); if (ret) { pr_err("Failed to setup powerdomains.\n"); @@ -279,9 +265,9 @@ int __init omap4_pm_init(void) } if (cpu_is_omap44xx()) - ret = omap4_init_static_deps(); + ret = omap4plus_init_static_deps(omap4_static_dep_map); else if (soc_is_omap54xx() || soc_is_dra7xx()) - ret = omap5_dra7_init_static_deps(); + ret = omap4plus_init_static_deps(omap5_dra7_static_dep_map); if (ret) { pr_err("Failed to initialise static dependencies.\n"); diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index 48480d557b61..77752e49d8d4 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -29,6 +29,7 @@ int of_prcm_init(void); * PRM_HAS_VOLTAGE: has voltage domains */ #define PRM_HAS_IO_WAKEUP (1 << 0) +#define PRM_HAS_VOLTAGE (1 << 1) /* * MAX_MODULE_SOFTRESET_WAIT: Maximum microseconds to wait for OMAP @@ -127,6 +128,8 @@ struct prm_reset_src_map { * @was_any_context_lost_old: ptr to the SoC PRM context loss test fn * @clear_context_loss_flags_old: ptr to the SoC PRM context loss flag clear fn * @late_init: ptr to the late init function + * @assert_hardreset: ptr to the SoC PRM hardreset assert impl + * @deassert_hardreset: ptr to the SoC PRM hardreset deassert impl * * XXX @was_any_context_lost_old and @clear_context_loss_flags_old are * deprecated. @@ -136,14 +139,27 @@ struct prm_ll_data { bool (*was_any_context_lost_old)(u8 part, s16 inst, u16 idx); void (*clear_context_loss_flags_old)(u8 part, s16 inst, u16 idx); int (*late_init)(void); + int (*assert_hardreset)(u8 shift, u8 part, s16 prm_mod, u16 offset); + int (*deassert_hardreset)(u8 shift, u8 st_shift, u8 part, s16 prm_mod, + u16 offset, u16 st_offset); + int (*is_hardreset_asserted)(u8 shift, u8 part, s16 prm_mod, + u16 offset); + void (*reset_system)(void); }; extern int prm_register(struct prm_ll_data *pld); extern int prm_unregister(struct prm_ll_data *pld); +int omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset); +int omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod, + u16 offset, u16 st_offset); +int omap_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset); extern u32 prm_read_reset_sources(void); extern bool prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx); extern void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx); +void omap_prm_reset_system(void); + +void omap_prm_reconfigure_io_chain(void); #endif diff --git a/arch/arm/mach-omap2/prm2xxx.c b/arch/arm/mach-omap2/prm2xxx.c index 86958050547a..af0f15278fc2 100644 --- a/arch/arm/mach-omap2/prm2xxx.c +++ b/arch/arm/mach-omap2/prm2xxx.c @@ -106,7 +106,7 @@ static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst) * Set the DPLL reset bit, which should reboot the SoC. This is the * recommended way to restart the SoC. No return value. */ -void omap2xxx_prm_dpll_reset(void) +static void omap2xxx_prm_dpll_reset(void) { omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD, OMAP2_RM_RSTCTRL); @@ -212,6 +212,10 @@ struct pwrdm_ops omap2_pwrdm_operations = { static struct prm_ll_data omap2xxx_prm_ll_data = { .read_reset_sources = &omap2xxx_prm_read_reset_sources, + .assert_hardreset = &omap2_prm_assert_hardreset, + .deassert_hardreset = &omap2_prm_deassert_hardreset, + .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted, + .reset_system = &omap2xxx_prm_dpll_reset, }; int __init omap2xxx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm2xxx.h b/arch/arm/mach-omap2/prm2xxx.h index d73414139292..1d51643062f7 100644 --- a/arch/arm/mach-omap2/prm2xxx.h +++ b/arch/arm/mach-omap2/prm2xxx.h @@ -124,7 +124,6 @@ extern int omap2xxx_clkdm_sleep(struct clockdomain *clkdm); extern int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm); -extern void omap2xxx_prm_dpll_reset(void); void omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask); extern int __init omap2xxx_prm_init(void); diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c index c13b4e293ffa..cc3341f263cd 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c @@ -24,14 +24,16 @@ /** * omap2_prm_is_hardreset_asserted - read the HW reset line state of * submodules contained in the hwmod module - * @prm_mod: PRM submodule base (e.g. CORE_MOD) * @shift: register bit shift corresponding to the reset line to check + * @part: PRM partition, ignored for OMAP2 + * @prm_mod: PRM submodule base (e.g. CORE_MOD) + * @offset: register offset, ignored for OMAP2 * * Returns 1 if the (sub)module hardreset line is currently asserted, * 0 if the (sub)module hardreset line is not currently asserted, or * -EINVAL if called while running on a non-OMAP2/3 chip. */ -int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) +int omap2_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset) { return omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, (1 << shift)); @@ -39,8 +41,10 @@ int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) /** * omap2_prm_assert_hardreset - assert the HW reset line of a submodule - * @prm_mod: PRM submodule base (e.g. CORE_MOD) * @shift: register bit shift corresponding to the reset line to assert + * @part: PRM partition, ignored for OMAP2 + * @prm_mod: PRM submodule base (e.g. CORE_MOD) + * @offset: register offset, ignored for OMAP2 * * Some IPs like dsp or iva contain processors that require an HW * reset line to be asserted / deasserted in order to fully enable the @@ -49,7 +53,7 @@ int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) * place the submodule into reset. Returns 0 upon success or -EINVAL * upon an argument error. */ -int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift) +int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset) { u32 mask; @@ -64,6 +68,10 @@ int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift) * @prm_mod: PRM submodule base (e.g. CORE_MOD) * @rst_shift: register bit shift corresponding to the reset line to deassert * @st_shift: register bit shift for the status of the deasserted submodule + * @part: PRM partition, not used for OMAP2 + * @prm_mod: PRM submodule base (e.g. CORE_MOD) + * @rst_offset: reset register offset, not used for OMAP2 + * @st_offset: reset status register offset, not used for OMAP2 * * Some IPs like dsp or iva contain processors that require an HW * reset line to be asserted / deasserted in order to fully enable the @@ -74,7 +82,8 @@ int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift) * -EINVAL upon an argument error, -EEXIST if the submodule was already out * of reset, or -EBUSY if the submodule did not exit reset promptly. */ -int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift) +int omap2_prm_deassert_hardreset(u8 rst_shift, u8 st_shift, u8 part, + s16 prm_mod, u16 rst_offset, u16 st_offset) { u32 rst, st; int c; diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h index 1a3a96392b97..f57e29b0e041 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.h +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h @@ -100,9 +100,12 @@ static inline u32 omap2_prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx) } /* These omap2_ PRM functions apply to both OMAP2 and 3 */ -extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift); -extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift); -extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift); +int omap2_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset); +int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, + u16 offset); +int omap2_prm_deassert_hardreset(u8 rst_shift, u8 st_shift, u8 part, + s16 prm_mod, u16 reset_offset, + u16 st_offset); extern int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst); extern int omap2_pwrdm_read_next_pwrst(struct powerdomain *pwrdm); diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c index 62709cd2f9c5..02f628601b09 100644 --- a/arch/arm/mach-omap2/prm33xx.c +++ b/arch/arm/mach-omap2/prm33xx.c @@ -23,20 +23,24 @@ #include "prm33xx.h" #include "prm-regbits-33xx.h" +#define AM33XX_PRM_RSTCTRL_OFFSET 0x0000 + +#define AM33XX_RST_GLOBAL_WARM_SW_MASK (1 << 0) + /* Read a register in a PRM instance */ -u32 am33xx_prm_read_reg(s16 inst, u16 idx) +static u32 am33xx_prm_read_reg(s16 inst, u16 idx) { return readl_relaxed(prm_base + inst + idx); } /* Write into a register in a PRM instance */ -void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx) +static void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx) { writel_relaxed(val, prm_base + inst + idx); } /* Read-modify-write a register in PRM. Caller must lock */ -u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) +static u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) { u32 v; @@ -52,6 +56,7 @@ u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) * am33xx_prm_is_hardreset_asserted - read the HW reset line state of * submodules contained in the hwmod module * @shift: register bit shift corresponding to the reset line to check + * @part: PRM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) * @rstctrl_offs: RM_RSTCTRL register address offset for this module * @@ -59,7 +64,8 @@ u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) * 0 if the (sub)module hardreset line is not currently asserted, or * -EINVAL upon parameter error. */ -int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs) +static int am33xx_prm_is_hardreset_asserted(u8 shift, u8 part, s16 inst, + u16 rstctrl_offs) { u32 v; @@ -73,6 +79,7 @@ int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs) /** * am33xx_prm_assert_hardreset - assert the HW reset line of a submodule * @shift: register bit shift corresponding to the reset line to assert + * @part: CM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) * @rstctrl_reg: RM_RSTCTRL register address for this module * @@ -83,7 +90,8 @@ int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs) * place the submodule into reset. Returns 0 upon success or -EINVAL * upon an argument error. */ -int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs) +static int am33xx_prm_assert_hardreset(u8 shift, u8 part, s16 inst, + u16 rstctrl_offs) { u32 mask = 1 << shift; @@ -96,6 +104,8 @@ int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs) * am33xx_prm_deassert_hardreset - deassert a submodule hardreset line and * wait * @shift: register bit shift corresponding to the reset line to deassert + * @st_shift: reset status register bit shift corresponding to the reset line + * @part: PRM partition, not used for AM33xx * @inst: CM instance register offset (*_INST macro) * @rstctrl_reg: RM_RSTCTRL register address for this module * @rstst_reg: RM_RSTST register address for this module @@ -109,14 +119,15 @@ int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs) * -EINVAL upon an argument error, -EEXIST if the submodule was already out * of reset, or -EBUSY if the submodule did not exit reset promptly. */ -int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst, - u16 rstctrl_offs, u16 rstst_offs) +static int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, + s16 inst, u16 rstctrl_offs, + u16 rstst_offs) { int c; u32 mask = 1 << st_shift; /* Check the current status to avoid de-asserting the line twice */ - if (am33xx_prm_is_hardreset_asserted(shift, inst, rstctrl_offs) == 0) + if (am33xx_prm_is_hardreset_asserted(shift, 0, inst, rstctrl_offs) == 0) return -EEXIST; /* Clear the reset status by writing 1 to the status bit */ @@ -128,7 +139,7 @@ int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst, am33xx_prm_rmw_reg_bits(mask, 0, inst, rstctrl_offs); /* wait the status to be set */ - omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, inst, + omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, 0, inst, rstst_offs), MAX_MODULE_HARDRESET_WAIT, c); @@ -325,6 +336,23 @@ static int am33xx_check_vcvp(void) return 0; } +/** + * am33xx_prm_global_warm_sw_reset - reboot the device via warm reset + * + * Immediately reboots the device through warm reset. + */ +static void am33xx_prm_global_warm_sw_reset(void) +{ + am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK, + AM33XX_RST_GLOBAL_WARM_SW_MASK, + AM33XX_PRM_DEVICE_MOD, + AM33XX_PRM_RSTCTRL_OFFSET); + + /* OCP barrier */ + (void)am33xx_prm_read_reg(AM33XX_PRM_DEVICE_MOD, + AM33XX_PRM_RSTCTRL_OFFSET); +} + struct pwrdm_ops am33xx_pwrdm_operations = { .pwrdm_set_next_pwrst = am33xx_pwrdm_set_next_pwrst, .pwrdm_read_next_pwrst = am33xx_pwrdm_read_next_pwrst, @@ -342,3 +370,21 @@ struct pwrdm_ops am33xx_pwrdm_operations = { .pwrdm_wait_transition = am33xx_pwrdm_wait_transition, .pwrdm_has_voltdm = am33xx_check_vcvp, }; + +static struct prm_ll_data am33xx_prm_ll_data = { + .assert_hardreset = am33xx_prm_assert_hardreset, + .deassert_hardreset = am33xx_prm_deassert_hardreset, + .is_hardreset_asserted = am33xx_prm_is_hardreset_asserted, + .reset_system = am33xx_prm_global_warm_sw_reset, +}; + +int __init am33xx_prm_init(void) +{ + return prm_register(&am33xx_prm_ll_data); +} + +static void __exit am33xx_prm_exit(void) +{ + prm_unregister(&am33xx_prm_ll_data); +} +__exitcall(am33xx_prm_exit); diff --git a/arch/arm/mach-omap2/prm33xx.h b/arch/arm/mach-omap2/prm33xx.h index 9b9918dfb119..98ac41f271da 100644 --- a/arch/arm/mach-omap2/prm33xx.h +++ b/arch/arm/mach-omap2/prm33xx.h @@ -118,14 +118,7 @@ #define AM33XX_PM_CEFUSE_PWRSTST AM33XX_PRM_REGADDR(AM33XX_PRM_CEFUSE_MOD, 0x0004) #ifndef __ASSEMBLER__ -extern u32 am33xx_prm_read_reg(s16 inst, u16 idx); -extern void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx); -extern u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); -extern void am33xx_prm_global_warm_sw_reset(void); -extern int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, - u16 rstctrl_offs); -extern int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs); -extern int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst, - u16 rstctrl_offs, u16 rstst_offs); +int am33xx_prm_init(void); + #endif /* ASSEMBLER */ #endif diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c index ff08da385a2d..c5e00c6714b1 100644 --- a/arch/arm/mach-omap2/prm3xxx.c +++ b/arch/arm/mach-omap2/prm3xxx.c @@ -30,6 +30,11 @@ #include "cm3xxx.h" #include "cm-regbits-34xx.h" +static void omap3xxx_prm_read_pending_irqs(unsigned long *events); +static void omap3xxx_prm_ocp_barrier(void); +static void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask); +static void omap3xxx_prm_restore_irqen(u32 *saved_mask); + static const struct omap_prcm_irq omap3_prcm_irqs[] = { OMAP_PRCM_IRQ("wkup", 0, 0), OMAP_PRCM_IRQ("io", 9, 1), @@ -131,7 +136,7 @@ u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset) * recommended way to restart the SoC, considering Errata i520. No * return value. */ -void omap3xxx_prm_dpll3_reset(void) +static void omap3xxx_prm_dpll3_reset(void) { omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, OMAP3430_GR_MOD, OMAP2_RM_RSTCTRL); @@ -147,7 +152,7 @@ void omap3xxx_prm_dpll3_reset(void) * MPU IRQs, and store the result into the u32 pointed to by @events. * No return value. */ -void omap3xxx_prm_read_pending_irqs(unsigned long *events) +static void omap3xxx_prm_read_pending_irqs(unsigned long *events) { u32 mask, st; @@ -166,7 +171,7 @@ void omap3xxx_prm_read_pending_irqs(unsigned long *events) * block, to avoid race conditions after acknowledging or clearing IRQ * bits. No return value. */ -void omap3xxx_prm_ocp_barrier(void) +static void omap3xxx_prm_ocp_barrier(void) { omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET); } @@ -182,7 +187,7 @@ void omap3xxx_prm_ocp_barrier(void) * returning; otherwise, spurious interrupts might occur. No return * value. */ -void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask) +static void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask) { saved_mask[0] = omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); @@ -202,7 +207,7 @@ void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask) * barrier should be needed here; any pending PRM interrupts will fire * once the writes reach the PRM. No return value. */ -void omap3xxx_prm_restore_irqen(u32 *saved_mask) +static void omap3xxx_prm_restore_irqen(u32 *saved_mask) { omap2_prm_write_mod_reg(saved_mask[0], OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); @@ -375,7 +380,7 @@ void __init omap3_prm_init_pm(bool has_uart4, bool has_iva) * The ST_IO_CHAIN bit does not exist in 3430 before es3.1. The only * thing we can do is toggle EN_IO bit for earlier omaps. */ -void omap3430_pre_es3_1_reconfigure_io_chain(void) +static void omap3430_pre_es3_1_reconfigure_io_chain(void) { omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, PM_WKEN); @@ -393,7 +398,7 @@ void omap3430_pre_es3_1_reconfigure_io_chain(void) * deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit. No * return value. These registers are only available in 3430 es3.1 and later. */ -void omap3_prm_reconfigure_io_chain(void) +static void omap3_prm_reconfigure_io_chain(void) { int i = 0; @@ -416,15 +421,6 @@ void omap3_prm_reconfigure_io_chain(void) } /** - * omap3xxx_prm_reconfigure_io_chain - reconfigure I/O chain - */ -void omap3xxx_prm_reconfigure_io_chain(void) -{ - if (omap3_prcm_irq_setup.reconfigure_io_chain) - omap3_prcm_irq_setup.reconfigure_io_chain(); -} - -/** * omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches * * Activates the I/O wakeup event latches and allows events logged by @@ -664,6 +660,10 @@ static int omap3xxx_prm_late_init(void); static struct prm_ll_data omap3xxx_prm_ll_data = { .read_reset_sources = &omap3xxx_prm_read_reset_sources, .late_init = &omap3xxx_prm_late_init, + .assert_hardreset = &omap2_prm_assert_hardreset, + .deassert_hardreset = &omap2_prm_deassert_hardreset, + .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted, + .reset_system = &omap3xxx_prm_dpll3_reset, }; int __init omap3xxx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm3xxx.h b/arch/arm/mach-omap2/prm3xxx.h index bc37d42a8704..cfde3f4a03cc 100644 --- a/arch/arm/mach-omap2/prm3xxx.h +++ b/arch/arm/mach-omap2/prm3xxx.h @@ -144,22 +144,6 @@ extern u32 omap3_prm_vcvp_read(u8 offset); extern void omap3_prm_vcvp_write(u32 val, u8 offset); extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); -#ifdef CONFIG_ARCH_OMAP3 -void omap3xxx_prm_reconfigure_io_chain(void); -#else -static inline void omap3xxx_prm_reconfigure_io_chain(void) -{ -} -#endif - -/* PRM interrupt-related functions */ -extern void omap3xxx_prm_read_pending_irqs(unsigned long *events); -extern void omap3xxx_prm_ocp_barrier(void); -extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask); -extern void omap3xxx_prm_restore_irqen(u32 *saved_mask); - -extern void omap3xxx_prm_dpll3_reset(void); - extern int __init omap3xxx_prm_init(void); extern u32 omap3xxx_prm_get_reset_sources(void); int omap3xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits); diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index 0958d070d3db..cc170fb81ff7 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -32,6 +32,12 @@ /* Static data */ +static void omap44xx_prm_read_pending_irqs(unsigned long *events); +static void omap44xx_prm_ocp_barrier(void); +static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask); +static void omap44xx_prm_restore_irqen(u32 *saved_mask); +static void omap44xx_prm_reconfigure_io_chain(void); + static const struct omap_prcm_irq omap4_prcm_irqs[] = { OMAP_PRCM_IRQ("io", 9, 1), }; @@ -80,19 +86,19 @@ static struct prm_reset_src_map omap44xx_prm_reset_src_map[] = { /* PRM low-level functions */ /* Read a register in a CM/PRM instance in the PRM module */ -u32 omap4_prm_read_inst_reg(s16 inst, u16 reg) +static u32 omap4_prm_read_inst_reg(s16 inst, u16 reg) { return readl_relaxed(prm_base + inst + reg); } /* Write into a register in a CM/PRM instance in the PRM module */ -void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 reg) +static void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 reg) { writel_relaxed(val, prm_base + inst + reg); } /* Read-modify-write a register in a PRM module. Caller must lock */ -u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 reg) +static u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 reg) { u32 v; @@ -207,7 +213,7 @@ static inline u32 _read_pending_irq_reg(u16 irqen_offs, u16 irqst_offs) * MPU IRQs, and store the result into the two u32s pointed to by @events. * No return value. */ -void omap44xx_prm_read_pending_irqs(unsigned long *events) +static void omap44xx_prm_read_pending_irqs(unsigned long *events) { events[0] = _read_pending_irq_reg(OMAP4_PRM_IRQENABLE_MPU_OFFSET, OMAP4_PRM_IRQSTATUS_MPU_OFFSET); @@ -224,7 +230,7 @@ void omap44xx_prm_read_pending_irqs(unsigned long *events) * block, to avoid race conditions after acknowledging or clearing IRQ * bits. No return value. */ -void omap44xx_prm_ocp_barrier(void) +static void omap44xx_prm_ocp_barrier(void) { omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, OMAP4_REVISION_PRM_OFFSET); @@ -241,7 +247,7 @@ void omap44xx_prm_ocp_barrier(void) * interrupts reaches the PRM before returning; otherwise, spurious * interrupts might occur. No return value. */ -void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask) +static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask) { saved_mask[0] = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, @@ -270,7 +276,7 @@ void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask) * No OCP barrier should be needed here; any pending PRM interrupts will fire * once the writes reach the PRM. No return value. */ -void omap44xx_prm_restore_irqen(u32 *saved_mask) +static void omap44xx_prm_restore_irqen(u32 *saved_mask) { omap4_prm_write_inst_reg(saved_mask[0], OMAP4430_PRM_OCP_SOCKET_INST, OMAP4_PRM_IRQENABLE_MPU_OFFSET); @@ -287,7 +293,7 @@ void omap44xx_prm_restore_irqen(u32 *saved_mask) * deasserting WUCLKIN and waiting for WUCLKOUT to be deasserted. * No return value. XXX Are the final two steps necessary? */ -void omap44xx_prm_reconfigure_io_chain(void) +static void omap44xx_prm_reconfigure_io_chain(void) { int i = 0; s32 inst = omap4_prmst_get_prm_dev_inst(); @@ -652,11 +658,10 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm) static int omap4_check_vcvp(void) { - /* No VC/VP on dra7xx devices */ - if (soc_is_dra7xx()) - return 0; + if (prm_features & PRM_HAS_VOLTAGE) + return 1; - return 1; + return 0; } struct pwrdm_ops omap4_pwrdm_operations = { @@ -689,6 +694,10 @@ static struct prm_ll_data omap44xx_prm_ll_data = { .was_any_context_lost_old = &omap44xx_prm_was_any_context_lost_old, .clear_context_loss_flags_old = &omap44xx_prm_clear_context_loss_flags_old, .late_init = &omap44xx_prm_late_init, + .assert_hardreset = omap4_prminst_assert_hardreset, + .deassert_hardreset = omap4_prminst_deassert_hardreset, + .is_hardreset_asserted = omap4_prminst_is_hardreset_asserted, + .reset_system = omap4_prminst_global_warm_sw_reset, }; int __init omap44xx_prm_init(void) @@ -696,6 +705,9 @@ int __init omap44xx_prm_init(void) if (cpu_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx()) prm_features |= PRM_HAS_IO_WAKEUP; + if (!soc_is_dra7xx()) + prm_features |= PRM_HAS_VOLTAGE; + return prm_register(&omap44xx_prm_ll_data); } diff --git a/arch/arm/mach-omap2/prm44xx_54xx.h b/arch/arm/mach-omap2/prm44xx_54xx.h index 8d95aa543ef5..f7512515fde5 100644 --- a/arch/arm/mach-omap2/prm44xx_54xx.h +++ b/arch/arm/mach-omap2/prm44xx_54xx.h @@ -26,10 +26,6 @@ /* Function prototypes */ #ifndef __ASSEMBLER__ -extern u32 omap4_prm_read_inst_reg(s16 inst, u16 idx); -extern void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 idx); -extern u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); - /* OMAP4/OMAP5-specific VP functions */ u32 omap4_prm_vp_check_txdone(u8 vp_id); void omap4_prm_vp_clear_txdone(u8 vp_id); @@ -42,21 +38,6 @@ extern u32 omap4_prm_vcvp_read(u8 offset); extern void omap4_prm_vcvp_write(u32 val, u8 offset); extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); -#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ - defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM43XX) -void omap44xx_prm_reconfigure_io_chain(void); -#else -static inline void omap44xx_prm_reconfigure_io_chain(void) -{ -} -#endif - -/* PRM interrupt-related functions */ -extern void omap44xx_prm_read_pending_irqs(unsigned long *events); -extern void omap44xx_prm_ocp_barrier(void); -extern void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask); -extern void omap44xx_prm_restore_irqen(u32 *saved_mask); - extern int __init omap44xx_prm_init(void); extern u32 omap44xx_prm_get_reset_sources(void); diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index ee2b5222eac0..779940cb6e56 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c @@ -423,6 +423,105 @@ void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx) } /** + * omap_prm_assert_hardreset - assert hardreset for an IP block + * @shift: register bit shift corresponding to the reset line + * @part: PRM partition + * @prm_mod: PRM submodule base or instance offset + * @offset: register offset + * + * Asserts a hardware reset line for an IP block. + */ +int omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset) +{ + if (!prm_ll_data->assert_hardreset) { + WARN_ONCE(1, "prm: %s: no mapping function defined\n", + __func__); + return -EINVAL; + } + + return prm_ll_data->assert_hardreset(shift, part, prm_mod, offset); +} + +/** + * omap_prm_deassert_hardreset - deassert hardreset for an IP block + * @shift: register bit shift corresponding to the reset line + * @st_shift: reset status bit shift corresponding to the reset line + * @part: PRM partition + * @prm_mod: PRM submodule base or instance offset + * @offset: register offset + * @st_offset: status register offset + * + * Deasserts a hardware reset line for an IP block. + */ +int omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod, + u16 offset, u16 st_offset) +{ + if (!prm_ll_data->deassert_hardreset) { + WARN_ONCE(1, "prm: %s: no mapping function defined\n", + __func__); + return -EINVAL; + } + + return prm_ll_data->deassert_hardreset(shift, st_shift, part, prm_mod, + offset, st_offset); +} + +/** + * omap_prm_is_hardreset_asserted - check the hardreset status for an IP block + * @shift: register bit shift corresponding to the reset line + * @part: PRM partition + * @prm_mod: PRM submodule base or instance offset + * @offset: register offset + * + * Checks if a hardware reset line for an IP block is enabled or not. + */ +int omap_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset) +{ + if (!prm_ll_data->is_hardreset_asserted) { + WARN_ONCE(1, "prm: %s: no mapping function defined\n", + __func__); + return -EINVAL; + } + + return prm_ll_data->is_hardreset_asserted(shift, part, prm_mod, offset); +} + +/** + * omap_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain + * + * Clear any previously-latched I/O wakeup events and ensure that the + * I/O wakeup gates are aligned with the current mux settings. + * Calls SoC specific I/O chain reconfigure function if available, + * otherwise does nothing. + */ +void omap_prm_reconfigure_io_chain(void) +{ + if (!prcm_irq_setup || !prcm_irq_setup->reconfigure_io_chain) + return; + + prcm_irq_setup->reconfigure_io_chain(); +} + +/** + * omap_prm_reset_system - trigger global SW reset + * + * Triggers SoC specific global warm reset to reboot the device. + */ +void omap_prm_reset_system(void) +{ + if (!prm_ll_data->reset_system) { + WARN_ONCE(1, "prm: %s: no mapping function defined\n", + __func__); + return; + } + + prm_ll_data->reset_system(); + + while (1) + cpu_relax(); +} + +/** * prm_register - register per-SoC low-level data with the PRM * @pld: low-level per-SoC OMAP PRM data & function pointers to register * diff --git a/arch/arm/mach-omap2/prminst44xx.c b/arch/arm/mach-omap2/prminst44xx.c index 225e0258d76d..8adf7b1a1dce 100644 --- a/arch/arm/mach-omap2/prminst44xx.c +++ b/arch/arm/mach-omap2/prminst44xx.c @@ -148,8 +148,12 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, /** * omap4_prminst_deassert_hardreset - deassert a submodule hardreset line and * wait - * @rstctrl_reg: RM_RSTCTRL register address for this module * @shift: register bit shift corresponding to the reset line to deassert + * @st_shift: status bit offset, not used for OMAP4+ + * @part: PRM partition + * @inst: PRM instance offset + * @rstctrl_offs: reset register offset + * @st_offs: reset status register offset, not used for OMAP4+ * * Some IPs like dsp, ipu or iva contain processors that require an HW * reset line to be asserted / deasserted in order to fully enable the @@ -160,8 +164,8 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, * -EINVAL upon an argument error, -EEXIST if the submodule was already out * of reset, or -EBUSY if the submodule did not exit reset promptly. */ -int omap4_prminst_deassert_hardreset(u8 shift, u8 part, s16 inst, - u16 rstctrl_offs) +int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 inst, + u16 rstctrl_offs, u16 st_offs) { int c; u32 mask = 1 << shift; diff --git a/arch/arm/mach-omap2/prminst44xx.h b/arch/arm/mach-omap2/prminst44xx.h index 583aa3774571..fb1c9d7a2f9d 100644 --- a/arch/arm/mach-omap2/prminst44xx.h +++ b/arch/arm/mach-omap2/prminst44xx.h @@ -30,8 +30,9 @@ extern int omap4_prminst_is_hardreset_asserted(u8 shift, u8 part, s16 inst, u16 rstctrl_offs); extern int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, u16 rstctrl_offs); -extern int omap4_prminst_deassert_hardreset(u8 shift, u8 part, s16 inst, - u16 rstctrl_offs); +int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part, + s16 inst, u16 rstctrl_offs, + u16 rstst_offs); extern void omap_prm_base_init(void); diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index e6690a44917d..83efe914bf7d 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -4,6 +4,17 @@ menu "Intel PXA2xx/PXA3xx Implementations" comment "Intel/Marvell Dev Platforms (sorted by hardware release time)" +config MACH_PXA27X_DT + bool "Support PXA27x platforms from device tree" + select CPU_PXA27x + select POWER_SUPPLY + select PXA27x + select USE_OF + help + Include support for Marvell PXA27x based platforms using + the device tree. Needn't select any other machine while + MACH_PXA27X_DT is enabled. + config MACH_PXA3XX_DT bool "Support PXA3xx platforms from device tree" select CPU_PXA300 diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 2fe1824c6dcb..eb0bf7678a99 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_CPU_PXA930) += pxa930.o # Device Tree support obj-$(CONFIG_MACH_PXA3XX_DT) += pxa-dt.o +obj-$(CONFIG_MACH_PXA27X_DT) += pxa-dt.o # Intel/Marvell Dev Platforms obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index 6915a9f6b3a3..51531ecffca8 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -378,7 +378,7 @@ static void __init em_x270_init_nand(void) err = gpio_request(GPIO11_NAND_CS, "NAND CS"); if (err) { - pr_warning("EM-X270: failed to request NAND CS gpio\n"); + pr_warn("EM-X270: failed to request NAND CS gpio\n"); return; } @@ -386,7 +386,7 @@ static void __init em_x270_init_nand(void) err = gpio_request(nand_rb, "NAND R/B"); if (err) { - pr_warning("EM-X270: failed to request NAND R/B gpio\n"); + pr_warn("EM-X270: failed to request NAND R/B gpio\n"); gpio_free(GPIO11_NAND_CS); return; } diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h index 8963984d1f43..7a9fa1aa4e41 100644 --- a/arch/arm/mach-pxa/generic.h +++ b/arch/arm/mach-pxa/generic.h @@ -13,11 +13,11 @@ struct irq_data; -extern void pxa_timer_init(void); - -extern void __init pxa_map_io(void); - extern unsigned int get_clk_frequency_khz(int info); +extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, + unsigned int)); +extern void __init pxa_map_io(void); +extern void pxa_timer_init(void); #define SET_BANK(__nr,__start,__size) \ mi->bank[__nr].start = (__start), \ @@ -25,6 +25,43 @@ extern unsigned int get_clk_frequency_khz(int info); #define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) +#define pxa25x_handle_irq icip_handle_irq +extern void __init pxa25x_init_irq(void); +extern void __init pxa25x_map_io(void); +extern void __init pxa26x_init_irq(void); + +#define pxa27x_handle_irq ichp_handle_irq +extern void __init pxa27x_dt_init_irq(void); +extern unsigned pxa27x_get_clk_frequency_khz(int); +extern void __init pxa27x_init_irq(void); +extern void __init pxa27x_map_io(void); + +#define pxa3xx_handle_irq ichp_handle_irq +extern void __init pxa3xx_dt_init_irq(void); +extern void __init pxa3xx_init_irq(void); +extern void __init pxa3xx_map_io(void); + +extern struct syscore_ops pxa_irq_syscore_ops; +extern struct syscore_ops pxa2xx_mfp_syscore_ops; +extern struct syscore_ops pxa3xx_mfp_syscore_ops; + +void __init pxa_set_ffuart_info(void *info); +void __init pxa_set_btuart_info(void *info); +void __init pxa_set_stuart_info(void *info); +void __init pxa_set_hwuart_info(void *info); + +void pxa_restart(enum reboot_mode, const char *); + +#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x) +extern void pxa2xx_clear_reset_status(unsigned int); +#else +static inline void pxa2xx_clear_reset_status(unsigned int mask) {} +#endif + +/* + * Once fully converted to the clock framework, all these functions should be + * removed, and replaced with a clk_get(NULL, "core"). + */ #ifdef CONFIG_PXA25x extern unsigned pxa25x_get_clk_frequency_khz(int); #else @@ -32,30 +69,12 @@ extern unsigned pxa25x_get_clk_frequency_khz(int); #endif #ifdef CONFIG_PXA27x -extern unsigned pxa27x_get_clk_frequency_khz(int); #else #define pxa27x_get_clk_frequency_khz(x) (0) #endif -#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x) -extern void pxa2xx_clear_reset_status(unsigned int); -#else -static inline void pxa2xx_clear_reset_status(unsigned int mask) {} -#endif - #ifdef CONFIG_PXA3xx -extern unsigned pxa3xx_get_clk_frequency_khz(int); +extern unsigned pxa3xx_get_clk_frequency_khz(int); #else #define pxa3xx_get_clk_frequency_khz(x) (0) #endif - -extern struct syscore_ops pxa_irq_syscore_ops; -extern struct syscore_ops pxa2xx_mfp_syscore_ops; -extern struct syscore_ops pxa3xx_mfp_syscore_ops; - -void __init pxa_set_ffuart_info(void *info); -void __init pxa_set_btuart_info(void *info); -void __init pxa_set_stuart_info(void *info); -void __init pxa_set_hwuart_info(void *info); - -void pxa_restart(enum reboot_mode, const char *); diff --git a/arch/arm/mach-pxa/gumstix.c b/arch/arm/mach-pxa/gumstix.c index 00b92dad7b81..f6c76a3ee3b2 100644 --- a/arch/arm/mach-pxa/gumstix.c +++ b/arch/arm/mach-pxa/gumstix.c @@ -140,8 +140,7 @@ static void gumstix_setup_bt_clock(void) int timeout = 500; if (!(OSCC & OSCC_OOK)) - pr_warning("32kHz clock was not on. Bootloader may need to " - "be updated\n"); + pr_warn("32kHz clock was not on. Bootloader may need to be updated\n"); else return; diff --git a/arch/arm/mach-pxa/include/mach/pxa25x.h b/arch/arm/mach-pxa/include/mach/pxa25x.h index 3ac0baac7350..5a341752e32c 100644 --- a/arch/arm/mach-pxa/include/mach/pxa25x.h +++ b/arch/arm/mach-pxa/include/mach/pxa25x.h @@ -6,12 +6,4 @@ #include <mach/mfp-pxa25x.h> #include <mach/irqs.h> -extern void __init pxa25x_map_io(void); -extern void __init pxa25x_init_irq(void); -#ifdef CONFIG_CPU_PXA26x -extern void __init pxa26x_init_irq(void); -#endif - -#define pxa25x_handle_irq icip_handle_irq - #endif /* __MACH_PXA25x_H */ diff --git a/arch/arm/mach-pxa/include/mach/pxa27x.h b/arch/arm/mach-pxa/include/mach/pxa27x.h index 7cff640582b8..599b925a657c 100644 --- a/arch/arm/mach-pxa/include/mach/pxa27x.h +++ b/arch/arm/mach-pxa/include/mach/pxa27x.h @@ -19,11 +19,7 @@ #define ARB_CORE_PARK (1<<24) /* Be parked with core when idle */ #define ARB_LOCK_FLAG (1<<23) /* Only Locking masters gain access to the bus */ -extern void __init pxa27x_map_io(void); -extern void __init pxa27x_init_irq(void); extern int __init pxa27x_set_pwrmode(unsigned int mode); extern void pxa27x_cpu_pm_enter(suspend_state_t state); -#define pxa27x_handle_irq ichp_handle_irq - #endif /* __MACH_PXA27x_H */ diff --git a/arch/arm/mach-pxa/include/mach/pxa3xx.h b/arch/arm/mach-pxa/include/mach/pxa3xx.h index 6dd7fa163e29..b4143fb6631f 100644 --- a/arch/arm/mach-pxa/include/mach/pxa3xx.h +++ b/arch/arm/mach-pxa/include/mach/pxa3xx.h @@ -5,9 +5,4 @@ #include <mach/pxa3xx-regs.h> #include <mach/irqs.h> -extern void __init pxa3xx_map_io(void); -extern void __init pxa3xx_init_irq(void); - -#define pxa3xx_handle_irq ichp_handle_irq - #endif /* __MACH_PXA3XX_H */ diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c index ef0426a159d4..666b78972c40 100644 --- a/arch/arm/mach-pxa/mfp-pxa2xx.c +++ b/arch/arm/mach-pxa/mfp-pxa2xx.c @@ -93,8 +93,8 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c) break; default: /* warning and fall through, treat as MFP_LPM_DEFAULT */ - pr_warning("%s: GPIO%d: unsupported low power mode\n", - __func__, gpio); + pr_warn("%s: GPIO%d: unsupported low power mode\n", + __func__, gpio); break; } @@ -107,14 +107,12 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c) * configurations of those pins not able to wakeup */ if ((c & MFP_LPM_CAN_WAKEUP) && !gpio_desc[gpio].can_wakeup) { - pr_warning("%s: GPIO%d unable to wakeup\n", - __func__, gpio); + pr_warn("%s: GPIO%d unable to wakeup\n", __func__, gpio); return -EINVAL; } if ((c & MFP_LPM_CAN_WAKEUP) && is_out) { - pr_warning("%s: output GPIO%d unable to wakeup\n", - __func__, gpio); + pr_warn("%s: output GPIO%d unable to wakeup\n", __func__, gpio); return -EINVAL; } @@ -126,7 +124,7 @@ static inline int __mfp_validate(int mfp) int gpio = mfp_to_gpio(mfp); if ((mfp > MFP_PIN_GPIO127) || !gpio_desc[gpio].valid) { - pr_warning("%s: GPIO%d is invalid pin\n", __func__, gpio); + pr_warn("%s: GPIO%d is invalid pin\n", __func__, gpio); return -1; } diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 131991629116..29019beae591 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -446,7 +446,7 @@ static void __init poodle_init(void) ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if (ret) - pr_warning("poodle: Unable to register LoCoMo device\n"); + pr_warn("poodle: Unable to register LoCoMo device\n"); pxa_set_fb_info(&poodle_locomo_device.dev, &poodle_fb_info); pxa_set_udc_info(&udc_info); diff --git a/arch/arm/mach-pxa/pxa-dt.c b/arch/arm/mach-pxa/pxa-dt.c index f6a2c4b1c1dc..7e0e5bd0c9de 100644 --- a/arch/arm/mach-pxa/pxa-dt.c +++ b/arch/arm/mach-pxa/pxa-dt.c @@ -15,13 +15,10 @@ #include <asm/mach/arch.h> #include <asm/mach/time.h> #include <mach/irqs.h> -#include <mach/pxa3xx.h> #include "generic.h" #ifdef CONFIG_PXA3xx -extern void __init pxa3xx_dt_init_irq(void); - static const struct of_dev_auxdata pxa3xx_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40100000, "pxa2xx-uart.0", NULL), OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40200000, "pxa2xx-uart.1", NULL), @@ -61,3 +58,18 @@ DT_MACHINE_START(PXA_DT, "Marvell PXA3xx (Device Tree Support)") .dt_compat = pxa3xx_dt_board_compat, MACHINE_END #endif + +#ifdef CONFIG_PXA27x +static const char * const pxa27x_dt_board_compat[] __initconst = { + "marvell,pxa270", + NULL, +}; + +DT_MACHINE_START(PXA27X_DT, "Marvell PXA2xx (Device Tree Support)") + .map_io = pxa27x_map_io, + .init_irq = pxa27x_dt_init_irq, + .handle_irq = pxa27x_handle_irq, + .restart = pxa_restart, + .dt_compat = pxa27x_dt_board_compat, +MACHINE_END +#endif diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index b040d7d14888..af423a48c2e3 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -398,6 +398,12 @@ void __init pxa27x_init_irq(void) pxa_init_irq(34, pxa27x_set_wake); } +void __init pxa27x_dt_init_irq(void) +{ + if (IS_ENABLED(CONFIG_OF)) + pxa_dt_irq_init(pxa27x_set_wake); +} + static struct map_desc pxa27x_io_desc[] __initdata = { { /* Mem Ctl */ .virtual = (unsigned long)SMEMC_VIRT, diff --git a/arch/arm/mach-pxa/pxa3xx-ulpi.c b/arch/arm/mach-pxa/pxa3xx-ulpi.c index e329ccefd364..614003e8b081 100644 --- a/arch/arm/mach-pxa/pxa3xx-ulpi.c +++ b/arch/arm/mach-pxa/pxa3xx-ulpi.c @@ -74,7 +74,7 @@ static int pxa310_ulpi_poll(void) cpu_relax(); } - pr_warning("%s: ULPI access timed out!\n", __func__); + pr_warn("%s: ULPI access timed out!\n", __func__); return -ETIMEDOUT; } @@ -84,7 +84,7 @@ static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg) int err; if (pxa310_ulpi_get_phymode() != SYNCH) { - pr_warning("%s: PHY is not in SYNCH mode!\n", __func__); + pr_warn("%s: PHY is not in SYNCH mode!\n", __func__); return -EBUSY; } @@ -101,7 +101,7 @@ static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg) static int pxa310_ulpi_write(struct usb_phy *otg, u32 val, u32 reg) { if (pxa310_ulpi_get_phymode() != SYNCH) { - pr_warning("%s: PHY is not in SYNCH mode!\n", __func__); + pr_warn("%s: PHY is not in SYNCH mode!\n", __func__); return -EBUSY; } diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index 8386dc30b3e4..a762b23ac830 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -521,7 +521,7 @@ static void __init raumfeld_w1_init(void) "W1 external pullup enable"); if (ret < 0) - pr_warning("Unable to request GPIO_W1_PULLUP_ENABLE\n"); + pr_warn("Unable to request GPIO_W1_PULLUP_ENABLE\n"); else gpio_direction_output(GPIO_W1_PULLUP_ENABLE, 0); @@ -600,7 +600,7 @@ static void __init raumfeld_lcd_init(void) ret = gpio_request(GPIO_TFT_VA_EN, "display VA enable"); if (ret < 0) - pr_warning("Unable to request GPIO_TFT_VA_EN\n"); + pr_warn("Unable to request GPIO_TFT_VA_EN\n"); else gpio_direction_output(GPIO_TFT_VA_EN, 1); @@ -608,7 +608,7 @@ static void __init raumfeld_lcd_init(void) ret = gpio_request(GPIO_DISPLAY_ENABLE, "display enable"); if (ret < 0) - pr_warning("Unable to request GPIO_DISPLAY_ENABLE\n"); + pr_warn("Unable to request GPIO_DISPLAY_ENABLE\n"); else gpio_direction_output(GPIO_DISPLAY_ENABLE, 1); @@ -814,17 +814,17 @@ static void __init raumfeld_power_init(void) /* Set PEN2 high to enable maximum charge current */ ret = gpio_request(GPIO_CHRG_PEN2, "CHRG_PEN2"); if (ret < 0) - pr_warning("Unable to request GPIO_CHRG_PEN2\n"); + pr_warn("Unable to request GPIO_CHRG_PEN2\n"); else gpio_direction_output(GPIO_CHRG_PEN2, 1); ret = gpio_request(GPIO_CHARGE_DC_OK, "CABLE_DC_OK"); if (ret < 0) - pr_warning("Unable to request GPIO_CHARGE_DC_OK\n"); + pr_warn("Unable to request GPIO_CHARGE_DC_OK\n"); ret = gpio_request(GPIO_CHARGE_USB_SUSP, "CHARGE_USB_SUSP"); if (ret < 0) - pr_warning("Unable to request GPIO_CHARGE_USB_SUSP\n"); + pr_warn("Unable to request GPIO_CHARGE_USB_SUSP\n"); else gpio_direction_output(GPIO_CHARGE_USB_SUSP, 0); @@ -976,19 +976,19 @@ static void __init raumfeld_audio_init(void) ret = gpio_request(GPIO_CODEC_RESET, "cs4270 reset"); if (ret < 0) - pr_warning("unable to request GPIO_CODEC_RESET\n"); + pr_warn("unable to request GPIO_CODEC_RESET\n"); else gpio_direction_output(GPIO_CODEC_RESET, 1); ret = gpio_request(GPIO_SPDIF_RESET, "ak4104 s/pdif reset"); if (ret < 0) - pr_warning("unable to request GPIO_SPDIF_RESET\n"); + pr_warn("unable to request GPIO_SPDIF_RESET\n"); else gpio_direction_output(GPIO_SPDIF_RESET, 1); ret = gpio_request(GPIO_MCLK_RESET, "MCLK reset"); if (ret < 0) - pr_warning("unable to request GPIO_MCLK_RESET\n"); + pr_warn("unable to request GPIO_MCLK_RESET\n"); else gpio_direction_output(GPIO_MCLK_RESET, 1); @@ -1019,20 +1019,20 @@ static void __init raumfeld_common_init(void) ret = gpio_request(GPIO_W2W_RESET, "Wi2Wi reset"); if (ret < 0) - pr_warning("Unable to request GPIO_W2W_RESET\n"); + pr_warn("Unable to request GPIO_W2W_RESET\n"); else gpio_direction_output(GPIO_W2W_RESET, 0); ret = gpio_request(GPIO_W2W_PDN, "Wi2Wi powerup"); if (ret < 0) - pr_warning("Unable to request GPIO_W2W_PDN\n"); + pr_warn("Unable to request GPIO_W2W_PDN\n"); else gpio_direction_output(GPIO_W2W_PDN, 0); /* this can be used to switch off the device */ ret = gpio_request(GPIO_SHUTDOWN_SUPPLY, "supply shutdown"); if (ret < 0) - pr_warning("Unable to request GPIO_SHUTDOWN_SUPPLY\n"); + pr_warn("Unable to request GPIO_SHUTDOWN_SUPPLY\n"); else gpio_direction_output(GPIO_SHUTDOWN_SUPPLY, 0); @@ -1051,7 +1051,7 @@ static void __init raumfeld_controller_init(void) ret = gpio_request(GPIO_SHUTDOWN_BATT, "battery shutdown"); if (ret < 0) - pr_warning("Unable to request GPIO_SHUTDOWN_BATT\n"); + pr_warn("Unable to request GPIO_SHUTDOWN_BATT\n"); else gpio_direction_output(GPIO_SHUTDOWN_BATT, 0); diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index c158a6e3e0aa..7780d1faa06f 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -30,7 +30,7 @@ #include <linux/gpio_keys.h> #include <linux/input.h> #include <linux/gpio.h> -#include <linux/pda_power.h> +#include <linux/power/gpio-charger.h> #include <linux/spi/spi.h> #include <linux/spi/pxa2xx_spi.h> #include <linux/input/matrix_keypad.h> @@ -361,44 +361,17 @@ static struct pxaficp_platform_data tosa_ficp_platform_data = { /* * Tosa AC IN */ -static int tosa_power_init(struct device *dev) -{ - int ret = gpio_request(TOSA_GPIO_AC_IN, "ac in"); - if (ret) - goto err_gpio_req; - - ret = gpio_direction_input(TOSA_GPIO_AC_IN); - if (ret) - goto err_gpio_in; - - return 0; - -err_gpio_in: - gpio_free(TOSA_GPIO_AC_IN); -err_gpio_req: - return ret; -} - -static void tosa_power_exit(struct device *dev) -{ - gpio_free(TOSA_GPIO_AC_IN); -} - -static int tosa_power_ac_online(void) -{ - return gpio_get_value(TOSA_GPIO_AC_IN) == 0; -} - static char *tosa_ac_supplied_to[] = { "main-battery", "backup-battery", "jacket-battery", }; -static struct pda_power_pdata tosa_power_data = { - .init = tosa_power_init, - .is_ac_online = tosa_power_ac_online, - .exit = tosa_power_exit, +static struct gpio_charger_platform_data tosa_power_data = { + .name = "charger", + .type = POWER_SUPPLY_TYPE_MAINS, + .gpio = TOSA_GPIO_AC_IN, + .gpio_active_low = 1, .supplied_to = tosa_ac_supplied_to, .num_supplicants = ARRAY_SIZE(tosa_ac_supplied_to), }; @@ -415,7 +388,7 @@ static struct resource tosa_power_resource[] = { }; static struct platform_device tosa_power_device = { - .name = "pda-power", + .name = "gpio-charger", .id = -1, .dev.platform_data = &tosa_power_data, .resource = tosa_power_resource, diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 21f457b56c01..b0a9e1a7955a 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -1,5 +1,6 @@ config ARCH_SHMOBILE bool + select ZONE_DMA if ARM_LPAE config PM_RCAR bool @@ -18,6 +19,7 @@ config ARCH_RCAR_GEN2 select PM_RCAR if PM || SMP select RENESAS_IRQC select SYS_SUPPORTS_SH_CMT + select PCI_DOMAINS if PCI config ARCH_RMOBILE bool diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index e20f2786ec72..71e68ca56886 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -36,6 +36,7 @@ cpu-y := platsmp.o headsmp.o # Shared SoC family objects obj-$(CONFIG_ARCH_RCAR_GEN2) += setup-rcar-gen2.o platsmp-apmu.o $(cpu-y) +CFLAGS_setup-rcar-gen2.o += -march=armv7-a # SMP objects smp-y := $(cpu-y) diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index e70983534403..25813dac77d9 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -1234,8 +1234,15 @@ static void __init eva_init(void) static struct pm_domain_device domain_devices[] __initdata = { { "A4LC", &lcdc0_device }, { "A4LC", &hdmi_lcdc_device }, + { "A4MP", &hdmi_device }, + { "A4MP", &fsi_device }, + { "A4R", &ceu0_device }, + { "A4S", &sh_eth_device }, + { "A3SP", &pwm_device }, + { "A3SP", &sdhi0_device }, + { "A3SP", &sh_mmcif_device }, }; - struct platform_device *usb = NULL; + struct platform_device *usb = NULL, *sdhi1 = NULL; regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers, ARRAY_SIZE(fixed3v3_power_consumers), 3300000); @@ -1304,6 +1311,7 @@ static void __init eva_init(void) platform_device_register(&vcc_sdhi1); platform_device_register(&sdhi1_device); + sdhi1 = &sdhi1_device; } @@ -1324,6 +1332,8 @@ static void __init eva_init(void) ARRAY_SIZE(domain_devices)); if (usb) rmobile_add_device_to_domain("A3SP", usb); + if (sdhi1) + rmobile_add_device_to_domain("A3SP", sdhi1); r8a7740_pm_init(); } diff --git a/arch/arm/mach-shmobile/board-kzm9g-reference.c b/arch/arm/mach-shmobile/board-kzm9g-reference.c index d9cdf9a97e23..0e1de7455c5c 100644 --- a/arch/arm/mach-shmobile/board-kzm9g-reference.c +++ b/arch/arm/mach-shmobile/board-kzm9g-reference.c @@ -43,6 +43,13 @@ static void __init kzm_init(void) #endif } +#define RESCNT2 IOMEM(0xe6188020) +static void kzm9g_restart(enum reboot_mode mode, const char *cmd) +{ + /* Do soft power on reset */ + writel((1 << 31), RESCNT2); +} + static const char *kzm9g_boards_compat_dt[] __initdata = { "renesas,kzm9g-reference", NULL, @@ -54,5 +61,6 @@ DT_MACHINE_START(KZM9G_DT, "kzm9g-reference") .init_early = shmobile_init_delay, .init_machine = kzm_init, .init_late = shmobile_init_late, + .restart = kzm9g_restart, .dt_compat = kzm9g_boards_compat_dt, MACHINE_END diff --git a/arch/arm/mach-shmobile/common.h b/arch/arm/mach-shmobile/common.h index 72087c79ad7b..309025efd4cf 100644 --- a/arch/arm/mach-shmobile/common.h +++ b/arch/arm/mach-shmobile/common.h @@ -19,11 +19,6 @@ extern void shmobile_boot_scu(void); extern void shmobile_smp_scu_prepare_cpus(unsigned int max_cpus); extern void shmobile_smp_scu_cpu_die(unsigned int cpu); extern int shmobile_smp_scu_cpu_kill(unsigned int cpu); -extern void shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus); -extern int shmobile_smp_apmu_boot_secondary(unsigned int cpu, - struct task_struct *idle); -extern void shmobile_smp_apmu_cpu_die(unsigned int cpu); -extern int shmobile_smp_apmu_cpu_kill(unsigned int cpu); struct clk; extern int shmobile_clk_init(void); extern void shmobile_handle_irq_intc(struct pt_regs *); diff --git a/arch/arm/mach-shmobile/platsmp-apmu.c b/arch/arm/mach-shmobile/platsmp-apmu.c index 2c06810d3a70..f483b560b066 100644 --- a/arch/arm/mach-shmobile/platsmp-apmu.c +++ b/arch/arm/mach-shmobile/platsmp-apmu.c @@ -1,6 +1,7 @@ /* * SMP support for SoCs with APMU * + * Copyright (C) 2014 Renesas Electronics Corporation * Copyright (C) 2013 Magnus Damm * * This program is free software; you can redistribute it and/or modify @@ -22,6 +23,7 @@ #include <asm/smp_plat.h> #include <asm/suspend.h> #include "common.h" +#include "platsmp-apmu.h" static struct { void __iomem *iomem; @@ -83,28 +85,15 @@ static void apmu_init_cpu(struct resource *res, int cpu, int bit) pr_debug("apmu ioremap %d %d %pr\n", cpu, bit, res); } -static struct { - struct resource iomem; - int cpus[4]; -} apmu_config[] = { - { - .iomem = DEFINE_RES_MEM(0xe6152000, 0x88), - .cpus = { 0, 1, 2, 3 }, - }, - { - .iomem = DEFINE_RES_MEM(0xe6151000, 0x88), - .cpus = { 0x100, 0x101, 0x102, 0x103 }, - } -}; - -static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit)) +static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit), + struct rcar_apmu_config *apmu_config, int num) { u32 id; int k; int bit, index; bool is_allowed; - for (k = 0; k < ARRAY_SIZE(apmu_config); k++) { + for (k = 0; k < num; k++) { /* only enable the cluster that includes the boot CPU */ is_allowed = false; for (bit = 0; bit < ARRAY_SIZE(apmu_config[k].cpus); bit++) { @@ -128,14 +117,16 @@ static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit)) } } -void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus) +void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus, + struct rcar_apmu_config *apmu_config, + int num) { /* install boot code shared by all CPUs */ shmobile_boot_fn = virt_to_phys(shmobile_smp_boot); shmobile_boot_arg = MPIDR_HWID_BITMASK; /* perform per-cpu setup */ - apmu_parse_cfg(apmu_init_cpu); + apmu_parse_cfg(apmu_init_cpu, apmu_config, num); } #ifdef CONFIG_SMP diff --git a/arch/arm/mach-shmobile/platsmp-apmu.h b/arch/arm/mach-shmobile/platsmp-apmu.h new file mode 100644 index 000000000000..76512c9a2545 --- /dev/null +++ b/arch/arm/mach-shmobile/platsmp-apmu.h @@ -0,0 +1,32 @@ +/* + * rmobile apmu definition + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * 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. + */ + +#ifndef PLATSMP_APMU_H +#define PLATSMP_APMU_H + +struct rcar_apmu_config { + struct resource iomem; + int cpus[4]; +}; + +extern void shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus, + struct rcar_apmu_config *apmu_config, + int num); +extern int shmobile_smp_apmu_boot_secondary(unsigned int cpu, + struct task_struct *idle); +extern void shmobile_smp_apmu_cpu_die(unsigned int cpu); +extern int shmobile_smp_apmu_cpu_kill(unsigned int cpu); + +#endif /* PLATSMP_APMU_H */ diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c index e3f146448237..ac2eecd6f5ea 100644 --- a/arch/arm/mach-shmobile/pm-r8a7740.c +++ b/arch/arm/mach-shmobile/pm-r8a7740.c @@ -14,10 +14,10 @@ #include "pm-rmobile.h" #if defined(CONFIG_PM) && !defined(CONFIG_ARCH_MULTIPLATFORM) -static int r8a7740_pd_a4s_suspend(void) +static int r8a7740_pd_a3sm_suspend(void) { /* - * The A4S domain contains the CPU core and therefore it should + * The A3SM domain contains the CPU core and therefore it should * only be turned off if the CPU is not in use. */ return -EBUSY; @@ -32,29 +32,65 @@ static int r8a7740_pd_a3sp_suspend(void) return console_suspend_enabled ? 0 : -EBUSY; } +static int r8a7740_pd_d4_suspend(void) +{ + /* + * The D4 domain contains the Coresight-ETM hardware block and + * therefore it should only be turned off if the debug module is + * not in use. + */ + return -EBUSY; +} + static struct rmobile_pm_domain r8a7740_pm_domains[] = { { .genpd.name = "A4LC", .bit_shift = 1, }, { + .genpd.name = "A4MP", + .bit_shift = 2, + }, { + .genpd.name = "D4", + .bit_shift = 3, + .gov = &pm_domain_always_on_gov, + .suspend = r8a7740_pd_d4_suspend, + }, { + .genpd.name = "A4R", + .bit_shift = 5, + }, { + .genpd.name = "A3RV", + .bit_shift = 6, + }, { .genpd.name = "A4S", .bit_shift = 10, - .gov = &pm_domain_always_on_gov, .no_debug = true, - .suspend = r8a7740_pd_a4s_suspend, }, { .genpd.name = "A3SP", .bit_shift = 11, .gov = &pm_domain_always_on_gov, .no_debug = true, .suspend = r8a7740_pd_a3sp_suspend, + }, { + .genpd.name = "A3SM", + .bit_shift = 12, + .gov = &pm_domain_always_on_gov, + .suspend = r8a7740_pd_a3sm_suspend, + }, { + .genpd.name = "A3SG", + .bit_shift = 13, + }, { + .genpd.name = "A4SU", + .bit_shift = 20, }, }; void __init r8a7740_init_pm_domains(void) { rmobile_init_domains(r8a7740_pm_domains, ARRAY_SIZE(r8a7740_pm_domains)); + pm_genpd_add_subdomain_names("A4R", "A3RV"); pm_genpd_add_subdomain_names("A4S", "A3SP"); + pm_genpd_add_subdomain_names("A4S", "A3SM"); + pm_genpd_add_subdomain_names("A4S", "A3SG"); } #endif /* CONFIG_PM && !CONFIG_ARCH_MULTIPLATFORM */ diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 8894e1b7ab0e..b77c226ab891 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -746,6 +746,12 @@ static void r8a7740_i2c_workaround(struct platform_device *pdev) void __init r8a7740_add_standard_devices(void) { static struct pm_domain_device domain_devices[] __initdata = { + { "A4R", &tmu0_device }, + { "A4R", &i2c0_device }, + { "A4S", &irqpin0_device }, + { "A4S", &irqpin1_device }, + { "A4S", &irqpin2_device }, + { "A4S", &irqpin3_device }, { "A3SP", &scif0_device }, { "A3SP", &scif1_device }, { "A3SP", &scif2_device }, @@ -756,6 +762,11 @@ void __init r8a7740_add_standard_devices(void) { "A3SP", &scif7_device }, { "A3SP", &scif8_device }, { "A3SP", &i2c1_device }, + { "A3SP", &ipmmu_device }, + { "A3SP", &dma0_device }, + { "A3SP", &dma1_device }, + { "A3SP", &dma2_device }, + { "A3SP", &usb_dma_device }, }; /* I2C work-around */ diff --git a/arch/arm/mach-shmobile/setup-rcar-gen2.c b/arch/arm/mach-shmobile/setup-rcar-gen2.c index 42d5b4308923..7ed92790d13f 100644 --- a/arch/arm/mach-shmobile/setup-rcar-gen2.c +++ b/arch/arm/mach-shmobile/setup-rcar-gen2.c @@ -3,6 +3,7 @@ * * Copyright (C) 2013 Renesas Solutions Corp. * Copyright (C) 2013 Magnus Damm + * Copyright (C) 2014 Ulrich Hecht * * 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 @@ -24,6 +25,7 @@ #include <linux/dma-contiguous.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/of.h> #include <linux/of_fdt.h> #include <asm/mach/arch.h> #include "common.h" @@ -54,37 +56,61 @@ void __init rcar_gen2_timer_init(void) { #if defined(CONFIG_ARM_ARCH_TIMER) || defined(CONFIG_COMMON_CLK) u32 mode = rcar_gen2_read_mode_pins(); + bool is_e2 = (bool)of_find_compatible_node(NULL, NULL, + "renesas,r8a7794"); #endif #ifdef CONFIG_ARM_ARCH_TIMER void __iomem *base; int extal_mhz = 0; u32 freq; - /* At Linux boot time the r8a7790 arch timer comes up - * with the counter disabled. Moreover, it may also report - * a potentially incorrect fixed 13 MHz frequency. To be - * correct these registers need to be updated to use the - * frequency EXTAL / 2 which can be determined by the MD pins. - */ - - switch (mode & (MD(14) | MD(13))) { - case 0: - extal_mhz = 15; - break; - case MD(13): - extal_mhz = 20; - break; - case MD(14): - extal_mhz = 26; - break; - case MD(13) | MD(14): - extal_mhz = 30; - break; + if (is_e2) { + freq = 260000000 / 8; /* ZS / 8 */ + /* CNTVOFF has to be initialized either from non-secure + * Hypervisor mode or secure Monitor mode with SCR.NS==1. + * If TrustZone is enabled then it should be handled by the + * secure code. + */ + asm volatile( + " cps 0x16\n" + " mrc p15, 0, r1, c1, c1, 0\n" + " orr r0, r1, #1\n" + " mcr p15, 0, r0, c1, c1, 0\n" + " isb\n" + " mov r0, #0\n" + " mcrr p15, 4, r0, r0, c14\n" + " isb\n" + " mcr p15, 0, r1, c1, c1, 0\n" + " isb\n" + " cps 0x13\n" + : : : "r0", "r1"); + } else { + /* At Linux boot time the r8a7790 arch timer comes up + * with the counter disabled. Moreover, it may also report + * a potentially incorrect fixed 13 MHz frequency. To be + * correct these registers need to be updated to use the + * frequency EXTAL / 2 which can be determined by the MD pins. + */ + + switch (mode & (MD(14) | MD(13))) { + case 0: + extal_mhz = 15; + break; + case MD(13): + extal_mhz = 20; + break; + case MD(14): + extal_mhz = 26; + break; + case MD(13) | MD(14): + extal_mhz = 30; + break; + } + + /* The arch timer frequency equals EXTAL / 2 */ + freq = extal_mhz * (1000000 / 2); } - /* The arch timer frequency equals EXTAL / 2 */ - freq = extal_mhz * (1000000 / 2); - /* Remap "armgcnt address map" space */ base = ioremap(0xe6080000, PAGE_SIZE); diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index d646c8d12423..769ff008571d 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -1012,6 +1012,7 @@ DT_MACHINE_START(SH7372_DT, "Generic SH7372 (Flattened Device Tree)") .init_irq = sh7372_init_irq, .handle_irq = shmobile_handle_irq_intc, .init_machine = sh7372_add_standard_devices_dt, + .init_late = shmobile_init_late, .dt_compat = sh7372_boards_compat_dt, MACHINE_END diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index b7bd8e509668..3447ca7e90d9 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -775,6 +775,13 @@ void __init sh73a0_add_standard_devices_dt(void) of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } +#define RESCNT2 IOMEM(0xe6188020) +static void sh73a0_restart(enum reboot_mode mode, const char *cmd) +{ + /* Do soft power on reset */ + writel((1 << 31), RESCNT2); +} + static const char *sh73a0_boards_compat_dt[] __initdata = { "renesas,sh73a0", NULL, @@ -786,6 +793,7 @@ DT_MACHINE_START(SH73A0_DT, "Generic SH73A0 (Flattened Device Tree)") .init_early = sh73a0_init_delay, .init_machine = sh73a0_add_standard_devices_dt, .init_late = shmobile_init_late, + .restart = sh73a0_restart, .dt_compat = sh73a0_boards_compat_dt, MACHINE_END #endif /* CONFIG_USE_OF */ diff --git a/arch/arm/mach-shmobile/smp-r8a7790.c b/arch/arm/mach-shmobile/smp-r8a7790.c index 2311694636e1..9c3da1345b8b 100644 --- a/arch/arm/mach-shmobile/smp-r8a7790.c +++ b/arch/arm/mach-shmobile/smp-r8a7790.c @@ -21,6 +21,7 @@ #include <asm/smp_plat.h> #include "common.h" +#include "platsmp-apmu.h" #include "pm-rcar.h" #include "r8a7790.h" @@ -34,10 +35,23 @@ static struct rcar_sysc_ch r8a7790_ca7_scu = { .isr_bit = 21, /* CA7-SCU */ }; +static struct rcar_apmu_config r8a7790_apmu_config[] = { + { + .iomem = DEFINE_RES_MEM(0xe6152000, 0x88), + .cpus = { 0, 1, 2, 3 }, + }, + { + .iomem = DEFINE_RES_MEM(0xe6151000, 0x88), + .cpus = { 0x100, 0x0101, 0x102, 0x103 }, + } +}; + static void __init r8a7790_smp_prepare_cpus(unsigned int max_cpus) { /* let APMU code install data related to shmobile_boot_vector */ - shmobile_smp_apmu_prepare_cpus(max_cpus); + shmobile_smp_apmu_prepare_cpus(max_cpus, + r8a7790_apmu_config, + ARRAY_SIZE(r8a7790_apmu_config)); /* turn on power to SCU */ r8a7790_pm_init(); diff --git a/arch/arm/mach-shmobile/smp-r8a7791.c b/arch/arm/mach-shmobile/smp-r8a7791.c index f743386166fb..7e49e0a52e32 100644 --- a/arch/arm/mach-shmobile/smp-r8a7791.c +++ b/arch/arm/mach-shmobile/smp-r8a7791.c @@ -21,13 +21,23 @@ #include <asm/smp_plat.h> #include "common.h" +#include "platsmp-apmu.h" #include "r8a7791.h" #include "rcar-gen2.h" +static struct rcar_apmu_config r8a7791_apmu_config[] = { + { + .iomem = DEFINE_RES_MEM(0xe6152000, 0x88), + .cpus = { 0, 1 }, + } +}; + static void __init r8a7791_smp_prepare_cpus(unsigned int max_cpus) { /* let APMU code install data related to shmobile_boot_vector */ - shmobile_smp_apmu_prepare_cpus(max_cpus); + shmobile_smp_apmu_prepare_cpus(max_cpus, + r8a7791_apmu_config, + ARRAY_SIZE(r8a7791_apmu_config)); r8a7791_pm_init(); } diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c index 87c6be1e79bd..32ee335d2632 100644 --- a/arch/arm/mach-shmobile/timer.c +++ b/arch/arm/mach-shmobile/timer.c @@ -45,6 +45,7 @@ void __init shmobile_init_delay(void) struct device_node *np, *cpus; bool is_a7_a8_a9 = false; bool is_a15 = false; + bool has_arch_timer = false; u32 max_freq = 0; cpus = of_find_node_by_path("/cpus"); @@ -57,12 +58,16 @@ void __init shmobile_init_delay(void) if (!of_property_read_u32(np, "clock-frequency", &freq)) max_freq = max(max_freq, freq); - if (of_device_is_compatible(np, "arm,cortex-a7") || - of_device_is_compatible(np, "arm,cortex-a8") || - of_device_is_compatible(np, "arm,cortex-a9")) + if (of_device_is_compatible(np, "arm,cortex-a8") || + of_device_is_compatible(np, "arm,cortex-a9")) { is_a7_a8_a9 = true; - else if (of_device_is_compatible(np, "arm,cortex-a15")) + } else if (of_device_is_compatible(np, "arm,cortex-a7")) { + is_a7_a8_a9 = true; + has_arch_timer = true; + } else if (of_device_is_compatible(np, "arm,cortex-a15")) { is_a15 = true; + has_arch_timer = true; + } } of_node_put(cpus); @@ -70,10 +75,12 @@ void __init shmobile_init_delay(void) if (!max_freq) return; - if (is_a7_a8_a9) - shmobile_setup_delay_hz(max_freq, 1, 3); - else if (is_a15 && !IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) - shmobile_setup_delay_hz(max_freq, 2, 4); + if (!has_arch_timer || !IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) { + if (is_a7_a8_a9) + shmobile_setup_delay_hz(max_freq, 1, 3); + else if (is_a15) + shmobile_setup_delay_hz(max_freq, 2, 4); + } } static void __init shmobile_late_time_init(void) diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h index 60c443dadb58..483cb467bf65 100644 --- a/arch/arm/mach-socfpga/core.h +++ b/arch/arm/mach-socfpga/core.h @@ -21,6 +21,7 @@ #define __MACH_CORE_H #define SOCFPGA_RSTMGR_CTRL 0x04 +#define SOCFPGA_RSTMGR_MODMPURST 0x10 #define SOCFPGA_RSTMGR_MODPERRST 0x14 #define SOCFPGA_RSTMGR_BRGMODRST 0x1c @@ -28,6 +29,8 @@ #define RSTMGR_CTRL_SWCOLDRSTREQ 0x1 /* Cold Reset */ #define RSTMGR_CTRL_SWWARMRSTREQ 0x2 /* Warm Reset */ +#define RSTMGR_MPUMODRST_CPU1 0x2 /* CPU1 Reset */ + extern void socfpga_secondary_startup(void); extern void __iomem *socfpga_scu_base_addr; diff --git a/arch/arm/mach-socfpga/platsmp.c b/arch/arm/mach-socfpga/platsmp.c index 16ca97b039f9..c64d89b7c0ca 100644 --- a/arch/arm/mach-socfpga/platsmp.c +++ b/arch/arm/mach-socfpga/platsmp.c @@ -34,17 +34,21 @@ static int socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle) int trampoline_size = &secondary_trampoline_end - &secondary_trampoline; if (socfpga_cpu1start_addr) { + /* This will put CPU #1 into reset. */ + writel(RSTMGR_MPUMODRST_CPU1, + rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST); + memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size); - __raw_writel(virt_to_phys(socfpga_secondary_startup), - (sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff))); + writel(virt_to_phys(socfpga_secondary_startup), + sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff)); flush_cache_all(); smp_wmb(); outer_clean_range(0, trampoline_size); - /* This will release CPU #1 out of reset.*/ - __raw_writel(0, rst_manager_base_addr + 0x10); + /* This will release CPU #1 out of reset. */ + writel(0, rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST); } return 0; @@ -86,10 +90,9 @@ static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus) */ static void socfpga_cpu_die(unsigned int cpu) { - cpu_do_idle(); - - /* We should have never returned from idle */ - panic("cpu %d unexpectedly exit from shutdown\n", cpu); + /* Do WFI. If we wake up early, go back into WFI */ + while (1) + cpu_do_idle(); } struct smp_operations socfpga_smp_ops __initdata = { diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index e3ebdce3e71f..425b6c8f0cb0 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -49,7 +49,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev, call_firmware_op(prepare_idle); /* Do suspend by ourselves if the firmware does not implement it */ - if (call_firmware_op(do_idle) == -ENOSYS) + if (call_firmware_op(do_idle, 0) == -ENOSYS) cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); diff --git a/arch/arm/mach-u300/dummyspichip.c b/arch/arm/mach-u300/dummyspichip.c index ec0283cf9a32..131996805690 100644 --- a/arch/arm/mach-u300/dummyspichip.c +++ b/arch/arm/mach-u300/dummyspichip.c @@ -80,8 +80,8 @@ static ssize_t dummy_looptest(struct device *dev, "in 8bit mode\n"); status = spi_w8r8(spi, 0xAA); if (status < 0) - pr_warning("Siple test 1: FAILURE: spi_write_then_read " - "failed with status %d\n", status); + pr_warn("Simple test 1: FAILURE: spi_write_then_read failed with status %d\n", + status); else pr_info("Simple test 1: SUCCESS!\n"); @@ -89,8 +89,8 @@ static ssize_t dummy_looptest(struct device *dev, "in 8bit mode (full FIFO)\n"); status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8); if (status < 0) - pr_warning("Simple test 2: FAILURE: spi_write_then_read() " - "failed with status %d\n", status); + pr_warn("Simple test 2: FAILURE: spi_write_then_read() failed with status %d\n", + status); else pr_info("Simple test 2: SUCCESS!\n"); @@ -98,8 +98,8 @@ static ssize_t dummy_looptest(struct device *dev, "in 8bit mode (see if we overflow FIFO)\n"); status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14); if (status < 0) - pr_warning("Simple test 3: FAILURE: failed with status %d " - "(probably FIFO overrun)\n", status); + pr_warn("Simple test 3: FAILURE: failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 3: SUCCESS!\n"); @@ -107,14 +107,14 @@ static ssize_t dummy_looptest(struct device *dev, "bytes garbage with spi_read() in 8bit mode\n"); status = spi_write(spi, &txbuf[0], 8); if (status < 0) - pr_warning("Simple test 4 step 1: FAILURE: spi_write() " - "failed with status %d\n", status); + pr_warn("Simple test 4 step 1: FAILURE: spi_write() failed with status %d\n", + status); else pr_info("Simple test 4 step 1: SUCCESS!\n"); status = spi_read(spi, &rxbuf[0], 8); if (status < 0) - pr_warning("Simple test 4 step 2: FAILURE: spi_read() " - "failed with status %d\n", status); + pr_warn("Simple test 4 step 2: FAILURE: spi_read() failed with status %d\n", + status); else pr_info("Simple test 4 step 2: SUCCESS!\n"); @@ -122,16 +122,14 @@ static ssize_t dummy_looptest(struct device *dev, "14 bytes garbage with spi_read() in 8bit mode\n"); status = spi_write(spi, &txbuf[0], 14); if (status < 0) - pr_warning("Simple test 5 step 1: FAILURE: spi_write() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 5 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 5 step 1: SUCCESS!\n"); status = spi_read(spi, &rxbuf[0], 14); if (status < 0) - pr_warning("Simple test 5 step 2: FAILURE: spi_read() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 5 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 5: SUCCESS!\n"); @@ -140,16 +138,14 @@ static ssize_t dummy_looptest(struct device *dev, DMA_TEST_SIZE, DMA_TEST_SIZE); status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE); if (status < 0) - pr_warning("Simple test 6 step 1: FAILURE: spi_write() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 6 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 6 step 1: SUCCESS!\n"); status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE); if (status < 0) - pr_warning("Simple test 6 step 2: FAILURE: spi_read() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 6 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 6: SUCCESS!\n"); @@ -169,18 +165,17 @@ static ssize_t dummy_looptest(struct device *dev, pr_info("Simple test 7: SUCCESS! (expected failure with " "status EIO)\n"); else if (status < 0) - pr_warning("Siple test 7: FAILURE: spi_write_then_read " - "failed with status %d\n", status); + pr_warn("Simple test 7: FAILURE: spi_write_then_read failed with status %d\n", + status); else - pr_warning("Siple test 7: FAILURE: spi_write_then_read " - "succeeded but it was expected to fail!\n"); + pr_warn("Simple test 7: FAILURE: spi_write_then_read succeeded but it was expected to fail!\n"); pr_info("Simple test 8: write 8 bytes, read back 8 bytes garbage " "in 16bit mode (full FIFO)\n"); status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8); if (status < 0) - pr_warning("Simple test 8: FAILURE: spi_write_then_read() " - "failed with status %d\n", status); + pr_warn("Simple test 8: FAILURE: spi_write_then_read() failed with status %d\n", + status); else pr_info("Simple test 8: SUCCESS!\n"); @@ -188,8 +183,8 @@ static ssize_t dummy_looptest(struct device *dev, "in 16bit mode (see if we overflow FIFO)\n"); status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14); if (status < 0) - pr_warning("Simple test 9: FAILURE: failed with status %d " - "(probably FIFO overrun)\n", status); + pr_warn("Simple test 9: FAILURE: failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 9: SUCCESS!\n"); @@ -198,17 +193,15 @@ static ssize_t dummy_looptest(struct device *dev, DMA_TEST_SIZE, DMA_TEST_SIZE); status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE); if (status < 0) - pr_warning("Simple test 10 step 1: FAILURE: spi_write() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 10 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 10 step 1: SUCCESS!\n"); status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE); if (status < 0) - pr_warning("Simple test 10 step 2: FAILURE: spi_read() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 10 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 10: SUCCESS!\n"); diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index 699e8601dbf0..c9ac19b24e5a 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -32,6 +32,7 @@ config UX500_SOC_DB8500 select PINCTRL_AB8540 select REGULATOR select REGULATOR_DB8500_PRCMU + select PM_GENERIC_DOMAINS if PM config MACH_MOP500 bool "U8500 Development platform, MOP500 versions" diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index 9741de956b3e..4418a5078833 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile @@ -9,5 +9,6 @@ obj-$(CONFIG_MACH_MOP500) += board-mop500-regulators.o \ board-mop500-audio.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o CFLAGS_hotplug.o += -march=armv7-a diff --git a/arch/arm/mach-ux500/pm.c b/arch/arm/mach-ux500/pm.c index b80a9a2e356e..2cb587b50905 100644 --- a/arch/arm/mach-ux500/pm.c +++ b/arch/arm/mach-ux500/pm.c @@ -17,6 +17,7 @@ #include <linux/platform_data/arm-ux500-pm.h> #include "db8500-regs.h" +#include "pm_domains.h" /* ARM WFI Standby signal register */ #define PRCM_ARM_WFI_STANDBY (prcmu_base + 0x130) @@ -191,4 +192,7 @@ void __init ux500_pm_init(u32 phy_base, u32 size) /* Set up ux500 suspend callbacks. */ suspend_set_ops(UX500_SUSPEND_OPS); + + /* Initialize ux500 power domains */ + ux500_pm_domains_init(); } diff --git a/arch/arm/mach-ux500/pm_domains.c b/arch/arm/mach-ux500/pm_domains.c new file mode 100644 index 000000000000..0d4b5b46f15b --- /dev/null +++ b/arch/arm/mach-ux500/pm_domains.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2014 Linaro Ltd. + * + * Author: Ulf Hansson <ulf.hansson@linaro.org> + * License terms: GNU General Public License (GPL) version 2 + * + * Implements PM domains using the generic PM domain for ux500. + */ +#include <linux/printk.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/pm_domain.h> + +#include <dt-bindings/arm/ux500_pm_domains.h> +#include "pm_domains.h" + +static int pd_power_off(struct generic_pm_domain *domain) +{ + /* + * Handle the gating of the PM domain regulator here. + * + * Drivers/subsystems handling devices in the PM domain needs to perform + * register context save/restore from their respective runtime PM + * callbacks, to be able to enable PM domain gating/ungating. + */ + return 0; +} + +static int pd_power_on(struct generic_pm_domain *domain) +{ + /* + * Handle the ungating of the PM domain regulator here. + * + * Drivers/subsystems handling devices in the PM domain needs to perform + * register context save/restore from their respective runtime PM + * callbacks, to be able to enable PM domain gating/ungating. + */ + return 0; +} + +static struct generic_pm_domain ux500_pm_domain_vape = { + .name = "VAPE", + .power_off = pd_power_off, + .power_on = pd_power_on, +}; + +static struct generic_pm_domain *ux500_pm_domains[NR_DOMAINS] = { + [DOMAIN_VAPE] = &ux500_pm_domain_vape, +}; + +static struct of_device_id ux500_pm_domain_matches[] = { + { .compatible = "stericsson,ux500-pm-domains", }, + { }, +}; + +int __init ux500_pm_domains_init(void) +{ + struct device_node *np; + struct genpd_onecell_data *genpd_data; + int i; + + np = of_find_matching_node(NULL, ux500_pm_domain_matches); + if (!np) + return -ENODEV; + + genpd_data = kzalloc(sizeof(*genpd_data), GFP_KERNEL); + if (!genpd_data) + return -ENOMEM; + + genpd_data->domains = ux500_pm_domains; + genpd_data->num_domains = ARRAY_SIZE(ux500_pm_domains); + + for (i = 0; i < ARRAY_SIZE(ux500_pm_domains); ++i) + pm_genpd_init(ux500_pm_domains[i], NULL, false); + + of_genpd_add_provider_onecell(np, genpd_data); + return 0; +} diff --git a/arch/arm/mach-ux500/pm_domains.h b/arch/arm/mach-ux500/pm_domains.h new file mode 100644 index 000000000000..263d3ba97177 --- /dev/null +++ b/arch/arm/mach-ux500/pm_domains.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2014 Linaro Ltd. + * + * Author: Ulf Hansson <ulf.hansson@linaro.org> + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __MACH_UX500_PM_DOMAINS_H +#define __MACH_UX500_PM_DOMAINS_H + +#ifdef CONFIG_PM_GENERIC_DOMAINS +extern int __init ux500_pm_domains_init(void); +#else +static inline int ux500_pm_domains_init(void) { return 0; } +#endif + +#endif diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index ae69809a9e47..179a100493f5 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -21,7 +21,7 @@ config CPU_ARM7TDMI # ARM720T config CPU_ARM720T - bool "Support ARM720T processor" if ARCH_INTEGRATOR + bool "Support ARM720T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) select CPU_32v4T select CPU_ABRT_LV4T select CPU_CACHE_V4 @@ -39,7 +39,7 @@ config CPU_ARM720T # ARM740T config CPU_ARM740T - bool "Support ARM740T processor" if ARCH_INTEGRATOR + bool "Support ARM740T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) depends on !MMU select CPU_32v4T select CPU_ABRT_LV4T @@ -71,7 +71,7 @@ config CPU_ARM9TDMI # ARM920T config CPU_ARM920T - bool "Support ARM920T processor" if ARCH_INTEGRATOR + bool "Support ARM920T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) select CPU_32v4T select CPU_ABRT_EV4T select CPU_CACHE_V4WT @@ -89,7 +89,7 @@ config CPU_ARM920T # ARM922T config CPU_ARM922T - bool "Support ARM922T processor" if ARCH_INTEGRATOR + bool "Support ARM922T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) select CPU_32v4T select CPU_ABRT_EV4T select CPU_CACHE_V4WT @@ -127,7 +127,7 @@ config CPU_ARM925T # ARM926T config CPU_ARM926T - bool "Support ARM926T processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB + bool "Support ARM926T processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V5) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB) select CPU_32v5 select CPU_ABRT_EV5TJ select CPU_CACHE_VIVT @@ -163,7 +163,7 @@ config CPU_FA526 # ARM940T config CPU_ARM940T - bool "Support ARM940T processor" if ARCH_INTEGRATOR + bool "Support ARM940T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) depends on !MMU select CPU_32v4T select CPU_ABRT_NOMMU @@ -181,7 +181,7 @@ config CPU_ARM940T # ARM946E-S config CPU_ARM946E - bool "Support ARM946E-S processor" if ARCH_INTEGRATOR + bool "Support ARM946E-S processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) depends on !MMU select CPU_32v5 select CPU_ABRT_NOMMU @@ -198,7 +198,7 @@ config CPU_ARM946E # ARM1020 - needs validating config CPU_ARM1020 - bool "Support ARM1020T (rev 0) processor" if ARCH_INTEGRATOR + bool "Support ARM1020T (rev 0) processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) select CPU_32v5 select CPU_ABRT_EV4T select CPU_CACHE_V4WT @@ -216,7 +216,7 @@ config CPU_ARM1020 # ARM1020E - needs validating config CPU_ARM1020E - bool "Support ARM1020E processor" if ARCH_INTEGRATOR + bool "Support ARM1020E processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) depends on n select CPU_32v5 select CPU_ABRT_EV4T @@ -229,7 +229,7 @@ config CPU_ARM1020E # ARM1022E config CPU_ARM1022 - bool "Support ARM1022E processor" if ARCH_INTEGRATOR + bool "Support ARM1022E processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) select CPU_32v5 select CPU_ABRT_EV4T select CPU_CACHE_VIVT @@ -247,7 +247,7 @@ config CPU_ARM1022 # ARM1026EJ-S config CPU_ARM1026 - bool "Support ARM1026EJ-S processor" if ARCH_INTEGRATOR + bool "Support ARM1026EJ-S processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) select CPU_32v5 select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10 select CPU_CACHE_VIVT @@ -358,7 +358,7 @@ config CPU_PJ4B # ARMv6 config CPU_V6 - bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX + bool "Support ARM V6 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX) select CPU_32v6 select CPU_ABRT_EV6 select CPU_CACHE_V6 @@ -371,7 +371,7 @@ config CPU_V6 # ARMv6k config CPU_V6K - bool "Support ARM V6K processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX + bool "Support ARM V6K processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX) select CPU_32v6 select CPU_32v6K select CPU_ABRT_EV6 @@ -385,7 +385,7 @@ config CPU_V6K # ARMv7 config CPU_V7 - bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX + bool "Support ARM V7 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V7) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX) select CPU_32v6K select CPU_32v7 select CPU_ABRT_EV7 diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index f0a008496993..87746c37f030 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_SAMSUNG_DMADEV) += dma-ops.o # PM support obj-$(CONFIG_PM_SLEEP) += pm-common.o +obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm-common.o obj-$(CONFIG_SAMSUNG_PM) += pm.o obj-$(CONFIG_SAMSUNG_PM_GPIO) += pm-gpio.o obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c index f2cd6a2d40b4..e7ccd21a45c9 100644 --- a/drivers/bus/brcmstb_gisb.c +++ b/drivers/bus/brcmstb_gisb.c @@ -23,6 +23,7 @@ #include <linux/list.h> #include <linux/of.h> #include <linux/bitops.h> +#include <linux/pm.h> #include <asm/bug.h> #include <asm/signal.h> @@ -48,6 +49,7 @@ struct brcmstb_gisb_arb_device { struct list_head next; u32 valid_mask; const char *master_names[sizeof(u32) * BITS_PER_BYTE]; + u32 saved_timeout; }; static LIST_HEAD(brcmstb_gisb_arb_device_list); @@ -160,12 +162,6 @@ static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr, return ret; } -void __init brcmstb_hook_fault_code(void) -{ - hook_fault_code(22, brcmstb_bus_error_handler, SIGBUS, 0, - "imprecise external abort"); -} - static irqreturn_t brcmstb_gisb_timeout_handler(int irq, void *dev_id) { brcmstb_gisb_arb_decode_addr(dev_id, "timeout"); @@ -261,12 +257,48 @@ static int brcmstb_gisb_arb_probe(struct platform_device *pdev) list_add_tail(&gdev->next, &brcmstb_gisb_arb_device_list); + hook_fault_code(22, brcmstb_bus_error_handler, SIGBUS, 0, + "imprecise external abort"); + dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n", gdev->base, timeout_irq, tea_irq); return 0; } +#ifdef CONFIG_PM_SLEEP +static int brcmstb_gisb_arb_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); + + gdev->saved_timeout = ioread32(gdev->base + ARB_TIMER); + + return 0; +} + +/* Make sure we provide the same timeout value that was configured before, and + * do this before the GISB timeout interrupt handler has any chance to run. + */ +static int brcmstb_gisb_arb_resume_noirq(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); + + iowrite32(gdev->saved_timeout, gdev->base + ARB_TIMER); + + return 0; +} +#else +#define brcmstb_gisb_arb_suspend NULL +#define brcmstb_gisb_arb_resume_noirq NULL +#endif + +static const struct dev_pm_ops brcmstb_gisb_arb_pm_ops = { + .suspend = brcmstb_gisb_arb_suspend, + .resume_noirq = brcmstb_gisb_arb_resume_noirq, +}; + static const struct of_device_id brcmstb_gisb_arb_of_match[] = { { .compatible = "brcm,gisb-arb" }, { }, @@ -278,6 +310,7 @@ static struct platform_driver brcmstb_gisb_arb_driver = { .name = "brcm-gisb-arb", .owner = THIS_MODULE, .of_match_table = brcmstb_gisb_arb_of_match, + .pm = &brcmstb_gisb_arb_pm_ops, }, }; diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 79791e1bf282..85ac0dd501de 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -33,6 +33,9 @@ static const struct clk_ops dpll_m4xen_ck_ops = { .recalc_rate = &omap4_dpll_regm4xen_recalc, .round_rate = &omap4_dpll_regm4xen_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, + .determine_rate = &omap4_dpll_regm4xen_determine_rate, .get_parent = &omap2_init_dpll_parent, }; #else @@ -53,6 +56,9 @@ static const struct clk_ops dpll_ck_ops = { .recalc_rate = &omap3_dpll_recalc, .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, + .determine_rate = &omap3_noncore_dpll_determine_rate, .get_parent = &omap2_init_dpll_parent, }; @@ -61,6 +67,9 @@ static const struct clk_ops dpll_no_gate_ck_ops = { .get_parent = &omap2_init_dpll_parent, .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, + .determine_rate = &omap3_noncore_dpll_determine_rate, }; #else static const struct clk_ops dpll_core_ck_ops = {}; @@ -97,6 +106,9 @@ static const struct clk_ops omap3_dpll_ck_ops = { .get_parent = &omap2_init_dpll_parent, .recalc_rate = &omap3_dpll_recalc, .set_rate = &omap3_noncore_dpll_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, + .determine_rate = &omap3_noncore_dpll_determine_rate, .round_rate = &omap2_dpll_round_rate, }; @@ -106,6 +118,9 @@ static const struct clk_ops omap3_dpll_per_ck_ops = { .get_parent = &omap2_init_dpll_parent, .recalc_rate = &omap3_dpll_recalc, .set_rate = &omap3_dpll4_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_dpll4_set_rate_and_parent, + .determine_rate = &omap3_noncore_dpll_determine_rate, .round_rate = &omap2_dpll_round_rate, }; #endif diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 756f6f10efa0..fae0435cc23d 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -45,4 +45,5 @@ obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o +obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c new file mode 100644 index 000000000000..b9efd30513d5 --- /dev/null +++ b/drivers/clocksource/timer-integrator-ap.c @@ -0,0 +1,210 @@ +/* + * Integrator/AP timer driver + * Copyright (C) 2000-2003 Deep Blue Solutions Ltd + * Copyright (c) 2014, Linaro Limited + * + * 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. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/clk.h> +#include <linux/clocksource.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/sched_clock.h> +#include <asm/hardware/arm_timer.h> + +static void __iomem * sched_clk_base; + +static u64 notrace integrator_read_sched_clock(void) +{ + return -readl(sched_clk_base + TIMER_VALUE); +} + +static void integrator_clocksource_init(unsigned long inrate, + void __iomem *base) +{ + u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; + unsigned long rate = inrate; + + if (rate >= 1500000) { + rate /= 16; + ctrl |= TIMER_CTRL_DIV16; + } + + writel(0xffff, base + TIMER_LOAD); + writel(ctrl, base + TIMER_CTRL); + + clocksource_mmio_init(base + TIMER_VALUE, "timer2", + rate, 200, 16, clocksource_mmio_readl_down); + + sched_clk_base = base; + sched_clock_register(integrator_read_sched_clock, 16, rate); +} + +static unsigned long timer_reload; +static void __iomem * clkevt_base; + +/* + * IRQ handler for the timer + */ +static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + /* clear the interrupt */ + writel(1, clkevt_base + TIMER_INTCLR); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) +{ + u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; + + /* Disable timer */ + writel(ctrl, clkevt_base + TIMER_CTRL); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* Enable the timer and start the periodic tick */ + writel(timer_reload, clkevt_base + TIMER_LOAD); + ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + writel(ctrl, clkevt_base + TIMER_CTRL); + break; + case CLOCK_EVT_MODE_ONESHOT: + /* Leave the timer disabled, .set_next_event will enable it */ + ctrl &= ~TIMER_CTRL_PERIODIC; + writel(ctrl, clkevt_base + TIMER_CTRL); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_RESUME: + default: + /* Just leave in disabled state */ + break; + } + +} + +static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) +{ + unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); + + writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); + writel(next, clkevt_base + TIMER_LOAD); + writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); + + return 0; +} + +static struct clock_event_device integrator_clockevent = { + .name = "timer1", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = clkevt_set_mode, + .set_next_event = clkevt_set_next_event, + .rating = 300, +}; + +static struct irqaction integrator_timer_irq = { + .name = "timer", + .flags = IRQF_TIMER | IRQF_IRQPOLL, + .handler = integrator_timer_interrupt, + .dev_id = &integrator_clockevent, +}; + +static void integrator_clockevent_init(unsigned long inrate, + void __iomem *base, int irq) +{ + unsigned long rate = inrate; + unsigned int ctrl = 0; + + clkevt_base = base; + /* Calculate and program a divisor */ + if (rate > 0x100000 * HZ) { + rate /= 256; + ctrl |= TIMER_CTRL_DIV256; + } else if (rate > 0x10000 * HZ) { + rate /= 16; + ctrl |= TIMER_CTRL_DIV16; + } + timer_reload = rate / HZ; + writel(ctrl, clkevt_base + TIMER_CTRL); + + setup_irq(irq, &integrator_timer_irq); + clockevents_config_and_register(&integrator_clockevent, + rate, + 1, + 0xffffU); +} + +static void __init integrator_ap_timer_init_of(struct device_node *node) +{ + const char *path; + void __iomem *base; + int err; + int irq; + struct clk *clk; + unsigned long rate; + struct device_node *pri_node; + struct device_node *sec_node; + + base = of_io_request_and_map(node, 0, "integrator-timer"); + if (!base) + return; + + clk = of_clk_get(node, 0); + if (IS_ERR(clk)) { + pr_err("No clock for %s\n", node->name); + return; + } + clk_prepare_enable(clk); + rate = clk_get_rate(clk); + writel(0, base + TIMER_CTRL); + + err = of_property_read_string(of_aliases, + "arm,timer-primary", &path); + if (WARN_ON(err)) + return; + pri_node = of_find_node_by_path(path); + err = of_property_read_string(of_aliases, + "arm,timer-secondary", &path); + if (WARN_ON(err)) + return; + sec_node = of_find_node_by_path(path); + + if (node == pri_node) { + /* The primary timer lacks IRQ, use as clocksource */ + integrator_clocksource_init(rate, base); + return; + } + + if (node == sec_node) { + /* The secondary timer will drive the clock event */ + irq = irq_of_parse_and_map(node, 0); + integrator_clockevent_init(rate, base, irq); + return; + } + + pr_info("Timer @%p unused\n", base); + clk_disable_unprepare(clk); +} + +CLOCKSOURCE_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer", + integrator_ap_timer_init_of); diff --git a/drivers/soc/versatile/Kconfig b/drivers/soc/versatile/Kconfig index bf5ee9c85330..a928a7fc6be4 100644 --- a/drivers/soc/versatile/Kconfig +++ b/drivers/soc/versatile/Kconfig @@ -1,6 +1,15 @@ # # ARM Versatile SoC drivers # +config SOC_INTEGRATOR_CM + bool "SoC bus device for the ARM Integrator platform core modules" + depends on ARCH_INTEGRATOR + select SOC_BUS + help + Include support for the SoC bus on the ARM Integrator platform + core modules providing some sysfs information about the ASIC + variant. + config SOC_REALVIEW bool "SoC bus device for the ARM RealView platforms" depends on ARCH_REALVIEW diff --git a/drivers/soc/versatile/Makefile b/drivers/soc/versatile/Makefile index ad547435648e..cf612fe3a659 100644 --- a/drivers/soc/versatile/Makefile +++ b/drivers/soc/versatile/Makefile @@ -1 +1,2 @@ +obj-$(CONFIG_SOC_INTEGRATOR_CM) += soc-integrator.o obj-$(CONFIG_SOC_REALVIEW) += soc-realview.o diff --git a/drivers/soc/versatile/soc-integrator.c b/drivers/soc/versatile/soc-integrator.c new file mode 100644 index 000000000000..ccaa53739ab4 --- /dev/null +++ b/drivers/soc/versatile/soc-integrator.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2014 Linaro Ltd. + * + * Author: Linus Walleij <linus.walleij@linaro.org> + * + * 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/init.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/sys_soc.h> +#include <linux/platform_device.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include <linux/of.h> + +#define INTEGRATOR_HDR_ID_OFFSET 0x00 + +static u32 integrator_coreid; + +static const struct of_device_id integrator_cm_match[] = { + { .compatible = "arm,core-module-integrator", }, +}; + +static const char *integrator_arch_str(u32 id) +{ + switch ((id >> 16) & 0xff) { + case 0x00: + return "ASB little-endian"; + case 0x01: + return "AHB little-endian"; + case 0x03: + return "AHB-Lite system bus, bi-endian"; + case 0x04: + return "AHB"; + case 0x08: + return "AHB system bus, ASB processor bus"; + default: + return "Unknown"; + } +} + +static const char *integrator_fpga_str(u32 id) +{ + switch ((id >> 12) & 0xf) { + case 0x01: + return "XC4062"; + case 0x02: + return "XC4085"; + case 0x03: + return "XVC600"; + case 0x04: + return "EPM7256AE (Altera PLD)"; + default: + return "Unknown"; + } +} + +static ssize_t integrator_get_manf(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%02x\n", integrator_coreid >> 24); +} + +static struct device_attribute integrator_manf_attr = + __ATTR(manufacturer, S_IRUGO, integrator_get_manf, NULL); + +static ssize_t integrator_get_arch(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", integrator_arch_str(integrator_coreid)); +} + +static struct device_attribute integrator_arch_attr = + __ATTR(arch, S_IRUGO, integrator_get_arch, NULL); + +static ssize_t integrator_get_fpga(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", integrator_fpga_str(integrator_coreid)); +} + +static struct device_attribute integrator_fpga_attr = + __ATTR(fpga, S_IRUGO, integrator_get_fpga, NULL); + +static ssize_t integrator_get_build(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%02x\n", (integrator_coreid >> 4) & 0xFF); +} + +static struct device_attribute integrator_build_attr = + __ATTR(build, S_IRUGO, integrator_get_build, NULL); + +static int __init integrator_soc_init(void) +{ + static struct regmap *syscon_regmap; + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + struct device_node *np; + struct device *dev; + u32 val; + int ret; + + np = of_find_matching_node(NULL, integrator_cm_match); + if (!np) + return -ENODEV; + + syscon_regmap = syscon_node_to_regmap(np); + if (IS_ERR(syscon_regmap)) + return PTR_ERR(syscon_regmap); + + ret = regmap_read(syscon_regmap, INTEGRATOR_HDR_ID_OFFSET, + &val); + if (ret) + return -ENODEV; + integrator_coreid = val; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->soc_id = "Integrator"; + soc_dev_attr->machine = "Integrator"; + soc_dev_attr->family = "Versatile"; + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr); + return -ENODEV; + } + dev = soc_device_to_device(soc_dev); + + device_create_file(dev, &integrator_manf_attr); + device_create_file(dev, &integrator_arch_attr); + device_create_file(dev, &integrator_fpga_attr); + device_create_file(dev, &integrator_build_attr); + + dev_info(dev, "Detected ARM core module:\n"); + dev_info(dev, " Manufacturer: %02x\n", (val >> 24)); + dev_info(dev, " Architecture: %s\n", integrator_arch_str(val)); + dev_info(dev, " FPGA: %s\n", integrator_fpga_str(val)); + dev_info(dev, " Build: %02x\n", (val >> 4) & 0xFF); + dev_info(dev, " Rev: %c\n", ('A' + (val & 0x03))); + + return 0; +} +device_initcall(integrator_soc_init); diff --git a/include/dt-bindings/arm/ux500_pm_domains.h b/include/dt-bindings/arm/ux500_pm_domains.h new file mode 100644 index 000000000000..398a6c0288d1 --- /dev/null +++ b/include/dt-bindings/arm/ux500_pm_domains.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2014 Linaro Ltd. + * + * Author: Ulf Hansson <ulf.hansson@linaro.org> + * License terms: GNU General Public License (GPL) version 2 + */ +#ifndef _DT_BINDINGS_ARM_UX500_PM_DOMAINS_H +#define _DT_BINDINGS_ARM_UX500_PM_DOMAINS_H + +#define DOMAIN_VAPE 0 + +/* Number of PM domains. */ +#define NR_DOMAINS (DOMAIN_VAPE + 1) + +#endif diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index f75acbf70e96..74e5341463c9 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -254,13 +254,26 @@ extern const struct clk_ops ti_clk_mux_ops; void omap2_init_clk_hw_omap_clocks(struct clk *clk); int omap3_noncore_dpll_enable(struct clk_hw *hw); void omap3_noncore_dpll_disable(struct clk_hw *hw); +int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index); int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate); +int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate, + u8 index); +long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk); unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, unsigned long parent_rate); long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, unsigned long target_rate, unsigned long *parent_rate); +long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk); u8 omap2_init_dpll_parent(struct clk_hw *hw); unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, @@ -278,6 +291,8 @@ int omap2_clk_disable_autoidle_all(void); void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, unsigned long parent_rate); +int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate, u8 index); int omap2_dflt_clk_enable(struct clk_hw *hw); void omap2_dflt_clk_disable(struct clk_hw *hw); int omap2_dflt_clk_is_enabled(struct clk_hw *hw); |