ARM: SoC platform changes for 3.19
New and updated SoC support, notable changes include: * bcm: brcmstb SMP support * bcm: initial iproc/cygnus support * exynos: Exynos4415 SoC support * exynos: PMU and suspend support for Exynos5420 * exynos: PMU support for Exynos3250 * exynos: pm related maintenance * imx: new LS1021A SoC support * imx: vybrid 610 global timer support * integrator: convert to using multiplatform configuration * mediatek: earlyprintk support for mt8127/mt8135 * meson: meson8 soc and l2 cache controller support * mvebu: Armada 38x CPU hotplug support * mvebu: drop support for prerelease Armada 375 Z1 stepping * mvebu: extended suspend support, now works on Armada 370/XP * omap: hwmod related maintenance * omap: prcm cleanup * pxa: initial pxa27x DT handling * rockchip: SMP support for rk3288 * rockchip: add cpu frequency scaling support * shmobile: r8a7740 power domain support * shmobile: various small restart, timer, pci apmu changes * sunxi: Allwinner A80 (sun9i) earlyprintk support * ux500: power domain support Overall, a significant chunk of changes, coming mostly from the usual suspects: omap, shmobile, samsung and mvebu, all of which already contain a lot of platform specific code in arch/arm. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIVAwUAVIcjyGCrR//JCVInAQJJCRAA1Tm+HZGiAiTvXEAcm/T9tIA08uqtawHt cqyEAUyrnE8QxE4EhUd2pTw4EunVusqKF5EsDxOzw7b3ukUdLAWZE7bqBOSIJLqn hrfsQQ8dXLbyC7T/CHPnBVeM+pn9LiIc9qzpZ0YToiMnHBBI4vKFQntBjd31yoRE hN08I6AmDjQolOzzlqR1fuM0uZaKiHIcytdauTt3Vfqgg7FTHcTy3u1kClHTR1Lp m/KuDothGpR5OKjSnUQz7EO5V3KJEnaKey8z2xM1a7DLLAvJ6r2+DUaDopv9Dbz1 W/V3H7fi5tLvillVa8xmlmzqWZbPc1xw8MWqvHZSWIMRZqloAHpC1VWKn0ZuH4SW 5Bj4ubSrpYjJxjKYfrxtjmuzru3A2jWBNTSP5A4nsny0C3AUsXkfRmRS0VNdegF8 sUdQ1MF8vEMpQT3QPH88+ccFHeIgqbcayhKqLPf7r8q0kwlym5N7Y2amU2A/O6qz +324r+yzfSA70VgJZ5EhXxWVDOPB4Lc8EtoWnH6T/kjncIMwzEsbEbyB3X1OaREW pVn3PNo06VjHLYoiHX+8G99pOFR/JZvaQs6jGCXLs+Orjp5WfP+kafkWqcB5GAKU Pfd3AQsl6rKAITdu0XsTdPiICNS4CmBiWYPepQsTa3pQaNgB7fwZNQKelNRIdGc+ dF1lnQ7CXLQ= =lFoH -----END PGP SIGNATURE----- Merge tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc Pull ARM SoC platform changes from Arnd Bergmann: "New and updated SoC support, notable changes include: - bcm: brcmstb SMP support initial iproc/cygnus support - exynos: Exynos4415 SoC support PMU and suspend support for Exynos5420 PMU support for Exynos3250 pm related maintenance - imx: new LS1021A SoC support vybrid 610 global timer support - integrator: convert to using multiplatform configuration - mediatek: earlyprintk support for mt8127/mt8135 - meson: meson8 soc and l2 cache controller support - mvebu: Armada 38x CPU hotplug support drop support for prerelease Armada 375 Z1 stepping extended suspend support, now works on Armada 370/XP - omap: hwmod related maintenance prcm cleanup - pxa: initial pxa27x DT handling - rockchip: SMP support for rk3288 add cpu frequency scaling support - shmobile: r8a7740 power domain support various small restart, timer, pci apmu changes - sunxi: Allwinner A80 (sun9i) earlyprintk support - ux500: power domain support Overall, a significant chunk of changes, coming mostly from the usual suspects: omap, shmobile, samsung and mvebu, all of which already contain a lot of platform specific code in arch/arm" * tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (187 commits) ARM: mvebu: use the cpufreq-dt platform_data for independent clocks soc: integrator: Add terminating entry for integrator_cm_match ARM: mvebu: add SDRAM controller description for Armada XP ARM: mvebu: adjust mbus controller description on Armada 370/XP ARM: mvebu: add suspend/resume DT information for Armada XP GP ARM: mvebu: synchronize secondary CPU clocks on resume ARM: mvebu: make sure MMU is disabled in armada_370_xp_cpu_resume ARM: mvebu: Armada XP GP specific suspend/resume code ARM: mvebu: reserve the first 10 KB of each memory bank for suspend/resume ARM: mvebu: implement suspend/resume support for Armada XP clk: mvebu: add suspend/resume for gatable clocks bus: mvebu-mbus: provide a mechanism to save SDRAM window configuration bus: mvebu-mbus: suspend/resume support clocksource: time-armada-370-xp: add suspend/resume support irqchip: armada-370-xp: Add suspend/resume support ARM: add lolevel debug support for asm9260 ARM: add mach-asm9260 ARM: EXYNOS: use u8 for val[] in struct exynos_pmu_conf power: reset: imx-snvs-poweroff: add power off driver for i.mx6 ARM: imx: temporarily remove CONFIG_SOC_FSL from LS1021A ...
This commit is contained in:
commit
6cd94d5e57
@ -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.
|
||||
|
@ -37,16 +37,26 @@ SunXi family
|
||||
http://dl.linux-sunxi.org/A20/A20%20User%20Manual%202013-03-22.pdf
|
||||
|
||||
- Allwinner A23
|
||||
+ Not Supported
|
||||
+ Datasheet
|
||||
http://dl.linux-sunxi.org/A23/A23%20Datasheet%20V1.0%2020130830.pdf
|
||||
+ User Manual
|
||||
http://dl.linux-sunxi.org/A23/A23%20User%20Manual%20V1.0%2020130830.pdf
|
||||
|
||||
* Quad ARM Cortex-A7 based SoCs
|
||||
- Allwinner A31 (sun6i)
|
||||
+ Datasheet
|
||||
http://dl.linux-sunxi.org/A31/A31%20Datasheet%20-%20v1.00%20(2012-12-24).pdf
|
||||
http://dl.linux-sunxi.org/A31/A3x_release_document/A31/IC/A31%20datasheet%20V1.3%2020131106.pdf
|
||||
+ User Manual
|
||||
http://dl.linux-sunxi.org/A31/A3x_release_document/A31/IC/A31%20user%20manual%20V1.1%2020130630.pdf
|
||||
|
||||
- Allwinner A31s (sun6i)
|
||||
+ Not Supported
|
||||
+ Datasheet
|
||||
http://dl.linux-sunxi.org/A31/A3x_release_document/A31s/IC/A31s%20datasheet%20V1.3%2020131106.pdf
|
||||
+ User Manual
|
||||
http://dl.linux-sunxi.org/A31/A3x_release_document/A31s/IC/A31s%20User%20Manual%20%20V1.0%2020130322.pdf
|
||||
|
||||
* Quad ARM Cortex-A15, Quad ARM Cortex-A7 based SoCs
|
||||
- Allwinner A80
|
||||
+ Not Supported
|
||||
+ Datasheet
|
||||
http://dl.linux-sunxi.org/A80/A80_Datasheet_Revision_1.0_0404.pdf
|
||||
|
@ -2,7 +2,9 @@ Amlogic MesonX device tree bindings
|
||||
-------------------------------------------
|
||||
|
||||
Boards with the Amlogic Meson6 SoC shall have the following properties:
|
||||
Required root node property:
|
||||
compatible: "amlogic,meson6"
|
||||
|
||||
Required root node property:
|
||||
|
||||
compatible = "amlogic,meson6";
|
||||
Boards with the Amlogic Meson8 SoC shall have the following properties:
|
||||
Required root node property:
|
||||
compatible: "amlogic,meson8";
|
||||
|
@ -227,6 +227,15 @@ nodes to be present and contain the properties described below.
|
||||
# List of phandles to idle state nodes supported
|
||||
by this cpu [3].
|
||||
|
||||
- rockchip,pmu
|
||||
Usage: optional for systems that have an "enable-method"
|
||||
property value of "rockchip,rk3066-smp"
|
||||
While optional, it is the preferred way to get access to
|
||||
the cpu-core power-domains.
|
||||
Value type: <phandle>
|
||||
Definition: Specifies the syscon node controlling the cpu core
|
||||
power domains.
|
||||
|
||||
Example 1 (dual-cluster big.LITTLE system 32-bit):
|
||||
|
||||
cpus {
|
||||
|
12
Documentation/devicetree/bindings/arm/sunxi.txt
Normal file
12
Documentation/devicetree/bindings/arm/sunxi.txt
Normal file
@ -0,0 +1,12 @@
|
||||
Allwinner sunXi Platforms Device Tree Bindings
|
||||
|
||||
Each device tree must specify which Allwinner SoC it uses,
|
||||
using one of the following compatible strings:
|
||||
|
||||
allwinner,sun4i-a10
|
||||
allwinner,sun5i-a10s
|
||||
allwinner,sun5i-a13
|
||||
allwinner,sun6i-a31
|
||||
allwinner,sun7i-a20
|
||||
allwinner,sun8i-a23
|
||||
allwinner,sun9i-a80
|
35
Documentation/devicetree/bindings/arm/ux500/power_domain.txt
Normal file
35
Documentation/devicetree/bindings/arm/ux500/power_domain.txt
Normal file
@ -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>
|
||||
};
|
@ -48,9 +48,12 @@ Required properties:
|
||||
- compatible: Should be set to "marvell,mbus-controller".
|
||||
|
||||
- reg: Device's register space.
|
||||
Two entries are expected (see the examples below):
|
||||
the first one controls the devices decoding window and
|
||||
the second one controls the SDRAM decoding window.
|
||||
Two or three entries are expected (see the examples below):
|
||||
the first one controls the devices decoding window,
|
||||
the second one controls the SDRAM decoding window and
|
||||
the third controls the MBus bridge (only with the
|
||||
marvell,armada370-mbus and marvell,armadaxp-mbus
|
||||
compatible strings)
|
||||
|
||||
Example:
|
||||
|
||||
@ -67,7 +70,7 @@ Example:
|
||||
|
||||
mbusc: mbus-controller@20000 {
|
||||
compatible = "marvell,mbus-controller";
|
||||
reg = <0x20000 0x100>, <0x20180 0x20>;
|
||||
reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
|
||||
};
|
||||
|
||||
/* more children ...*/
|
||||
@ -126,7 +129,7 @@ are skipped.
|
||||
|
||||
mbusc: mbus-controller@20000 {
|
||||
compatible = "marvell,mbus-controller";
|
||||
reg = <0x20000 0x100>, <0x20180 0x20>;
|
||||
reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
|
||||
};
|
||||
|
||||
/* more children ...*/
|
||||
@ -170,7 +173,7 @@ Using this macro, the above example would be:
|
||||
|
||||
mbusc: mbus-controller@20000 {
|
||||
compatible = "marvell,mbus-controller";
|
||||
reg = <0x20000 0x100>, <0x20180 0x20>;
|
||||
reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
|
||||
};
|
||||
|
||||
/* other children */
|
||||
@ -266,7 +269,7 @@ See the example below, where a more complete device tree is shown:
|
||||
ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>;
|
||||
|
||||
mbusc: mbus-controller@20000 {
|
||||
reg = <0x20000 0x100>, <0x20180 0x20>;
|
||||
reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
|
||||
};
|
||||
|
||||
interrupt-controller@20000 {
|
||||
|
@ -0,0 +1,21 @@
|
||||
Device Tree bindings for MVEBU SDRAM controllers
|
||||
|
||||
The Marvell EBU SoCs all have a SDRAM controller. The SDRAM controller
|
||||
differs from one SoC variant to another, but they also share a number
|
||||
of commonalities.
|
||||
|
||||
For now, this Device Tree binding documentation only documents the
|
||||
Armada XP SDRAM controller.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: for Armada XP, "marvell,armada-xp-sdram-controller"
|
||||
- reg: a resource specifier for the register space, which should
|
||||
include all SDRAM controller registers as per the datasheet.
|
||||
|
||||
Example:
|
||||
|
||||
sdramc@1400 {
|
||||
compatible = "marvell,armada-xp-sdram-controller";
|
||||
reg = <0x1400 0x500>;
|
||||
};
|
@ -0,0 +1,23 @@
|
||||
i.mx6 Poweroff Driver
|
||||
|
||||
SNVS_LPCR in SNVS module can power off the whole system by pull
|
||||
PMIC_ON_REQ low if PMIC_ON_REQ is connected with external PMIC.
|
||||
If you don't want to use PMIC_ON_REQ as power on/off control,
|
||||
please set status='disabled' to disable this driver.
|
||||
|
||||
Required Properties:
|
||||
-compatible: "fsl,sec-v4.0-poweroff"
|
||||
-reg: Specifies the physical address of the SNVS_LPCR register
|
||||
|
||||
Example:
|
||||
snvs@020cc000 {
|
||||
compatible = "fsl,sec-v4.0-mon", "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0 0x020cc000 0x4000>;
|
||||
.....
|
||||
snvs_poweroff: snvs-poweroff@38 {
|
||||
compatible = "fsl,sec-v4.0-poweroff";
|
||||
reg = <0x38 0x4>;
|
||||
};
|
||||
}
|
@ -91,6 +91,7 @@ lltc Linear Technology Corporation
|
||||
marvell Marvell Technology Group Ltd.
|
||||
maxim Maxim Integrated Products
|
||||
mediatek MediaTek Inc.
|
||||
merrii Merrii Technology Co., Ltd.
|
||||
micrel Micrel Inc.
|
||||
microchip Microchip Technology Inc.
|
||||
micron Micron Technology Inc.
|
||||
|
@ -1379,6 +1379,7 @@ F: arch/arm/configs/lager_defconfig
|
||||
F: arch/arm/configs/mackerel_defconfig
|
||||
F: arch/arm/configs/marzen_defconfig
|
||||
F: arch/arm/configs/shmobile_defconfig
|
||||
F: arch/arm/include/debug/renesas-scif.S
|
||||
F: arch/arm/mach-shmobile/
|
||||
F: drivers/sh/
|
||||
|
||||
|
@ -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
|
||||
@ -857,6 +839,8 @@ config ARCH_VIRT
|
||||
#
|
||||
source "arch/arm/mach-mvebu/Kconfig"
|
||||
|
||||
source "arch/arm/mach-asm9260/Kconfig"
|
||||
|
||||
source "arch/arm/mach-at91/Kconfig"
|
||||
|
||||
source "arch/arm/mach-axxia/Kconfig"
|
||||
|
@ -93,6 +93,27 @@ choice
|
||||
prompt "Kernel low-level debugging port"
|
||||
depends on DEBUG_LL
|
||||
|
||||
config DEBUG_ASM9260_UART
|
||||
bool "Kernel low-level debugging via asm9260 UART"
|
||||
depends on MACH_ASM9260
|
||||
help
|
||||
Say Y here if you want the debug print routines to direct
|
||||
their output to an UART or USART port on asm9260 based
|
||||
machines.
|
||||
|
||||
DEBUG_UART_PHYS | DEBUG_UART_VIRT
|
||||
|
||||
0x80000000 | 0xf0000000 | UART0
|
||||
0x80004000 | 0xf0004000 | UART1
|
||||
0x80008000 | 0xf0008000 | UART2
|
||||
0x8000c000 | 0xf000c000 | UART3
|
||||
0x80010000 | 0xf0010000 | UART4
|
||||
0x80014000 | 0xf0014000 | UART5
|
||||
0x80018000 | 0xf0018000 | UART6
|
||||
0x8001c000 | 0xf001c000 | UART7
|
||||
0x80020000 | 0xf0020000 | UART8
|
||||
0x80024000 | 0xf0024000 | UART9
|
||||
|
||||
config AT91_DEBUG_LL_DBGU0
|
||||
bool "Kernel low-level debugging on rm9200, 9260/9g20, 9261/9g10 and 9rl"
|
||||
depends on HAVE_AT91_DBGU0
|
||||
@ -113,7 +134,7 @@ choice
|
||||
config DEBUG_BCM_5301X
|
||||
bool "Kernel low-level debugging on BCM5301X UART1"
|
||||
depends on ARCH_BCM_5301X
|
||||
select DEBUG_UART_PL01X
|
||||
select DEBUG_UART_8250
|
||||
|
||||
config DEBUG_BCM_KONA_UART
|
||||
bool "Kernel low-level debugging messages via BCM KONA UART"
|
||||
@ -139,6 +160,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
|
||||
@ -653,6 +685,64 @@ choice
|
||||
Say Y here if you want kernel low-level debugging support
|
||||
on Rockchip RK32xx based platforms.
|
||||
|
||||
config DEBUG_R7S72100_SCIF2
|
||||
bool "Kernel low-level debugging messages via SCIF2 on R7S72100"
|
||||
depends on ARCH_R7S72100
|
||||
help
|
||||
Say Y here if you want kernel low-level debugging support
|
||||
via SCIF2 on Renesas RZ/A1H (R7S72100).
|
||||
|
||||
config DEBUG_RCAR_GEN1_SCIF0
|
||||
bool "Kernel low-level debugging messages via SCIF0 on R8A7778"
|
||||
depends on ARCH_R8A7778
|
||||
help
|
||||
Say Y here if you want kernel low-level debugging support
|
||||
via SCIF0 on Renesas R-Car M1A (R8A7778).
|
||||
|
||||
config DEBUG_RCAR_GEN1_SCIF2
|
||||
bool "Kernel low-level debugging messages via SCIF2 on R8A7779"
|
||||
depends on ARCH_R8A7779
|
||||
help
|
||||
Say Y here if you want kernel low-level debugging support
|
||||
via SCIF2 on Renesas R-Car H1 (R8A7779).
|
||||
|
||||
config DEBUG_RCAR_GEN2_SCIF0
|
||||
bool "Kernel low-level debugging messages via SCIF0 on R8A7790/R8A7791/R8A7793)"
|
||||
depends on ARCH_R8A7790 || ARCH_R8A7791 || ARCH_R8A7793
|
||||
help
|
||||
Say Y here if you want kernel low-level debugging support
|
||||
via SCIF0 on Renesas R-Car H2 (R8A7790), M2-W (R8A7791), or
|
||||
M2-N (R8A7793).
|
||||
|
||||
config DEBUG_RCAR_GEN2_SCIF2
|
||||
bool "Kernel low-level debugging messages via SCIF2 on R8A7794"
|
||||
depends on ARCH_R8A7794
|
||||
help
|
||||
Say Y here if you want kernel low-level debugging support
|
||||
via SCIF2 on Renesas R-Car E2 (R8A7794).
|
||||
|
||||
config DEBUG_RMOBILE_SCIFA0
|
||||
bool "Kernel low-level debugging messages via SCIFA0 on R8A73A4/SH7372"
|
||||
depends on ARCH_R8A73A4 || ARCH_SH7372
|
||||
help
|
||||
Say Y here if you want kernel low-level debugging support
|
||||
via SCIFA0 on Renesas R-Mobile APE6 (R8A73A4) or SH-Mobile
|
||||
AP4 (SH7372).
|
||||
|
||||
config DEBUG_RMOBILE_SCIFA1
|
||||
bool "Kernel low-level debugging messages via SCIFA1 on R8A7740"
|
||||
depends on ARCH_R8A7740
|
||||
help
|
||||
Say Y here if you want kernel low-level debugging support
|
||||
via SCIFA1 on Renesas R-Mobile A1 (R8A7740).
|
||||
|
||||
config DEBUG_RMOBILE_SCIFA4
|
||||
bool "Kernel low-level debugging messages via SCIFA4 on SH73A0"
|
||||
depends on ARCH_SH73A0
|
||||
help
|
||||
Say Y here if you want kernel low-level debugging support
|
||||
via SCIFA4 on Renesas SH-Mobile AG5 (SH73A0).
|
||||
|
||||
config DEBUG_S3C_UART0
|
||||
depends on PLAT_SAMSUNG
|
||||
select DEBUG_EXYNOS_UART if ARCH_EXYNOS
|
||||
@ -723,6 +813,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"
|
||||
@ -731,6 +829,14 @@ choice
|
||||
Say Y here if you want kernel low-level debugging support
|
||||
on SOCFPGA based platforms.
|
||||
|
||||
config DEBUG_SUN9I_UART0
|
||||
bool "Kernel low-level debugging messages via sun9i UART0"
|
||||
depends on MACH_SUN9I
|
||||
select DEBUG_UART_8250
|
||||
help
|
||||
Say Y here if you want kernel low-level debugging support
|
||||
on Allwinner A80 based platforms on the UART0.
|
||||
|
||||
config DEBUG_SUNXI_UART0
|
||||
bool "Kernel low-level debugging messages via sunXi UART0"
|
||||
depends on ARCH_SUNXI
|
||||
@ -866,6 +972,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,7 +1163,9 @@ 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/asm9260.S" if DEBUG_ASM9260_UART
|
||||
default "debug/clps711x.S" if DEBUG_CLPS711X_UART1 || DEBUG_CLPS711X_UART2
|
||||
default "debug/meson.S" if DEBUG_MESON_UARTAO
|
||||
default "debug/pl01x.S" if DEBUG_LL_UART_PL01X || DEBUG_UART_PL01X
|
||||
@ -1061,6 +1185,14 @@ config DEBUG_LL_INCLUDE
|
||||
DEBUG_IMX6SX_UART
|
||||
default "debug/msm.S" if DEBUG_MSM_UART || DEBUG_QCOM_UARTDM
|
||||
default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART
|
||||
default "debug/renesas-scif.S" if DEBUG_R7S72100_SCIF2
|
||||
default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF0
|
||||
default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF2
|
||||
default "debug/renesas-scif.S" if DEBUG_RCAR_GEN2_SCIF0
|
||||
default "debug/renesas-scif.S" if DEBUG_RCAR_GEN2_SCIF2
|
||||
default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA0
|
||||
default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA1
|
||||
default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA4
|
||||
default "debug/s3c24xx.S" if DEBUG_S3C24XX_UART
|
||||
default "debug/s5pv210.S" if DEBUG_S5PV210_UART
|
||||
default "debug/sirf.S" if DEBUG_SIRFPRIMA2_UART1 || DEBUG_SIRFMARCO_UART1
|
||||
@ -1106,6 +1238,7 @@ config DEBUG_UART_PHYS
|
||||
default 0x02530c00 if DEBUG_KEYSTONE_UART0
|
||||
default 0x02531000 if DEBUG_KEYSTONE_UART1
|
||||
default 0x03010fe0 if ARCH_RPC
|
||||
default 0x07000000 if DEBUG_SUN9I_UART0
|
||||
default 0x10009000 if DEBUG_REALVIEW_STD_PORT || \
|
||||
DEBUG_VEXPRESS_UART0_CA9
|
||||
default 0x1010c000 if DEBUG_REALVIEW_PB1176_PORT
|
||||
@ -1113,7 +1246,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
|
||||
@ -1135,6 +1270,7 @@ config DEBUG_UART_PHYS
|
||||
default 0x78000000 if DEBUG_CNS3XXX
|
||||
default 0x7c0003f8 if FOOTBRIDGE
|
||||
default 0x78000000 if DEBUG_CNS3XXX
|
||||
default 0x80010000 if DEBUG_ASM9260_UART
|
||||
default 0x80070000 if DEBUG_IMX23_UART
|
||||
default 0x80074000 if DEBUG_IMX28_UART
|
||||
default 0x80230000 if DEBUG_PICOXCELL_UART
|
||||
@ -1152,7 +1288,14 @@ config DEBUG_UART_PHYS
|
||||
default 0xd4018000 if DEBUG_MMP_UART3
|
||||
default 0xe0000000 if ARCH_SPEAR13XX
|
||||
default 0xe4007000 if DEBUG_HIP04_UART
|
||||
default 0xe6c40000 if DEBUG_RMOBILE_SCIFA0
|
||||
default 0xe6c50000 if DEBUG_RMOBILE_SCIFA1
|
||||
default 0xe6c80000 if DEBUG_RMOBILE_SCIFA4
|
||||
default 0xe6e58000 if DEBUG_RCAR_GEN2_SCIF2
|
||||
default 0xe6e60000 if DEBUG_RCAR_GEN2_SCIF0
|
||||
default 0xe8008000 if DEBUG_R7S72100_SCIF2
|
||||
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
|
||||
@ -1164,24 +1307,33 @@ config DEBUG_UART_PHYS
|
||||
default 0xff690000 if DEBUG_RK32_UART2
|
||||
default 0xffc02000 if DEBUG_SOCFPGA_UART
|
||||
default 0xffd82340 if ARCH_IOP13XX
|
||||
default 0xffe40000 if DEBUG_RCAR_GEN1_SCIF0
|
||||
default 0xffe42000 if DEBUG_RCAR_GEN1_SCIF2
|
||||
default 0xfff36000 if DEBUG_HIGHBANK_UART
|
||||
default 0xfffe8600 if DEBUG_UART_BCM63XX
|
||||
default 0xfffff700 if ARCH_IOP33X
|
||||
depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \
|
||||
DEBUG_LL_UART_EFM32 || \
|
||||
DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \
|
||||
DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \
|
||||
DEBUG_UART_BCM63XX
|
||||
DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_R7S72100_SCIF2 || \
|
||||
DEBUG_RCAR_GEN1_SCIF0 || DEBUG_RCAR_GEN1_SCIF2 || \
|
||||
DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF2 || \
|
||||
DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \
|
||||
DEBUG_RMOBILE_SCIFA4 || DEBUG_S3C24XX_UART || \
|
||||
DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART
|
||||
|
||||
config DEBUG_UART_VIRT
|
||||
hex "Virtual base address of debug UART"
|
||||
default 0xe0010fe0 if ARCH_RPC
|
||||
default 0xe1000000 if DEBUG_MSM_UART
|
||||
default 0xf0000be0 if ARCH_EBSA110
|
||||
default 0xf0010000 if DEBUG_ASM9260_UART
|
||||
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
|
||||
@ -1190,6 +1342,7 @@ config DEBUG_UART_VIRT
|
||||
default 0xf6200000 if DEBUG_PXA_UART1
|
||||
default 0xf4090000 if ARCH_LPC32XX
|
||||
default 0xf4200000 if ARCH_GEMINI
|
||||
default 0xf7000000 if DEBUG_SUN9I_UART0
|
||||
default 0xf7000000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART0 || \
|
||||
DEBUG_S3C2410_UART0)
|
||||
default 0xf7004000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART1 || \
|
||||
@ -1204,6 +1357,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
|
||||
@ -1244,12 +1398,12 @@ config DEBUG_UART_VIRT
|
||||
depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \
|
||||
DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \
|
||||
DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \
|
||||
DEBUG_UART_BCM63XX
|
||||
DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART
|
||||
|
||||
config DEBUG_UART_8250_SHIFT
|
||||
int "Register offset shift for the 8250 debug UART"
|
||||
depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250
|
||||
default 0 if FOOTBRIDGE || ARCH_IOP32X
|
||||
default 0 if FOOTBRIDGE || ARCH_IOP32X || DEBUG_BCM_5301X
|
||||
default 2
|
||||
|
||||
config DEBUG_UART_8250_WORD
|
||||
@ -1260,7 +1414,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"
|
||||
|
@ -180,7 +180,8 @@
|
||||
|
||||
mbusc: mbus-controller@20000 {
|
||||
compatible = "marvell,mbus-controller";
|
||||
reg = <0x20000 0x100>, <0x20180 0x20>;
|
||||
reg = <0x20000 0x100>, <0x20180 0x20>,
|
||||
<0x20250 0x8>;
|
||||
};
|
||||
|
||||
mpic: interrupt-controller@20000 {
|
||||
|
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include "armada-xp-mv78460.dtsi"
|
||||
|
||||
/ {
|
||||
@ -48,6 +49,14 @@
|
||||
<0x00000001 0x00000000 0x00000001 0x00000000>;
|
||||
};
|
||||
|
||||
cpus {
|
||||
pm_pic {
|
||||
ctrl-gpios = <&gpio0 16 GPIO_ACTIVE_LOW>,
|
||||
<&gpio0 17 GPIO_ACTIVE_LOW>,
|
||||
<&gpio0 18 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
soc {
|
||||
ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
|
||||
MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
|
||||
@ -115,7 +124,15 @@
|
||||
serial@12300 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinctrl {
|
||||
pinctrl-0 = <&pic_pins>;
|
||||
pinctrl-names = "default";
|
||||
pic_pins: pic-pins-0 {
|
||||
marvell,pins = "mpp16", "mpp17",
|
||||
"mpp18";
|
||||
marvell,function = "gpio";
|
||||
};
|
||||
};
|
||||
sata@a0000 {
|
||||
nr-ports = <2>;
|
||||
status = "okay";
|
||||
|
@ -35,6 +35,11 @@
|
||||
};
|
||||
|
||||
internal-regs {
|
||||
sdramc@1400 {
|
||||
compatible = "marvell,armada-xp-sdram-controller";
|
||||
reg = <0x1400 0x500>;
|
||||
};
|
||||
|
||||
L2: l2-cache {
|
||||
compatible = "marvell,aurora-system-cache";
|
||||
reg = <0x08000 0x1000>;
|
||||
|
@ -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";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -64,6 +64,7 @@
|
||||
|
||||
#include "twl4030.dtsi"
|
||||
#include "twl4030_omap3.dtsi"
|
||||
#include <dt-bindings/input/input.h>
|
||||
|
||||
&mmc1 {
|
||||
vmmc-supply = <&vmmc1>;
|
||||
@ -75,6 +76,22 @@
|
||||
ti,pullups = <0x000001>;
|
||||
};
|
||||
|
||||
&twl_keypad {
|
||||
linux,keymap = <
|
||||
MATRIX_KEY(0x00, 0x01, KEY_A)
|
||||
MATRIX_KEY(0x00, 0x02, KEY_B)
|
||||
MATRIX_KEY(0x00, 0x03, KEY_LEFT)
|
||||
|
||||
MATRIX_KEY(0x01, 0x01, KEY_UP)
|
||||
MATRIX_KEY(0x01, 0x02, KEY_ENTER)
|
||||
MATRIX_KEY(0x01, 0x03, KEY_DOWN)
|
||||
|
||||
MATRIX_KEY(0x02, 0x01, KEY_RIGHT)
|
||||
MATRIX_KEY(0x02, 0x02, KEY_C)
|
||||
MATRIX_KEY(0x02, 0x03, KEY_D)
|
||||
>;
|
||||
};
|
||||
|
||||
&hsusb1_phy {
|
||||
reset-gpios = <&twl_gpio 6 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
@ -895,7 +895,7 @@
|
||||
reg = <0x58002000 0x1000>;
|
||||
status = "disabled";
|
||||
ti,hwmods = "dss_rfbi";
|
||||
clocks = <&dss_dss_clk>, <&dss_fck>;
|
||||
clocks = <&dss_dss_clk>, <&l3_div_ck>;
|
||||
clock-names = "fck", "ick";
|
||||
};
|
||||
|
||||
|
@ -1018,14 +1018,6 @@
|
||||
reg = <0x1120>;
|
||||
};
|
||||
|
||||
dss_fck: dss_fck {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,gate-clock";
|
||||
clocks = <&l3_div_ck>;
|
||||
ti,bit-shift = <1>;
|
||||
reg = <0x1120>;
|
||||
};
|
||||
|
||||
fdif_fck: fdif_fck {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,divider-clock";
|
||||
|
@ -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";
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
29
arch/arm/include/debug/asm9260.S
Normal file
29
arch/arm/include/debug/asm9260.S
Normal file
@ -0,0 +1,29 @@
|
||||
/* Debugging macro include header
|
||||
*
|
||||
* Copyright (C) 1994-1999 Russell King
|
||||
* Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
|
||||
* Modified for ASM9260 by Oleksij Remepl <linux@rempel-privat.de>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
.macro addruart, rp, rv, tmp
|
||||
ldr \rp, = CONFIG_DEBUG_UART_PHYS
|
||||
ldr \rv, = CONFIG_DEBUG_UART_VIRT
|
||||
.endm
|
||||
|
||||
.macro waituart,rd,rx
|
||||
.endm
|
||||
|
||||
.macro senduart,rd,rx
|
||||
str \rd, [\rx, #0x50] @ TXDATA
|
||||
.endm
|
||||
|
||||
.macro busyuart,rd,rx
|
||||
1002: ldr \rd, [\rx, #0x60] @ STAT
|
||||
tst \rd, #1 << 27 @ TXEMPTY
|
||||
beq 1002b @ wait until transmit done
|
||||
.endm
|
52
arch/arm/include/debug/renesas-scif.S
Normal file
52
arch/arm/include/debug/renesas-scif.S
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Renesas SCIF(A) debugging macro include header
|
||||
*
|
||||
* Based on r8a7790.S
|
||||
*
|
||||
* Copyright (C) 2012-2013 Renesas Electronics Corporation
|
||||
* Copyright (C) 1994-1999 Russell King
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#define SCIF_PHYS CONFIG_DEBUG_UART_PHYS
|
||||
#define SCIF_VIRT ((SCIF_PHYS & 0x00ffffff) | 0xfd000000)
|
||||
|
||||
#if CONFIG_DEBUG_UART_PHYS < 0xe6e00000
|
||||
/* SCIFA */
|
||||
#define FTDR 0x20
|
||||
#define FSR 0x14
|
||||
#else
|
||||
/* SCIF */
|
||||
#define FTDR 0x0c
|
||||
#define FSR 0x10
|
||||
#endif
|
||||
|
||||
#define TDFE (1 << 5)
|
||||
#define TEND (1 << 6)
|
||||
|
||||
.macro addruart, rp, rv, tmp
|
||||
ldr \rp, =SCIF_PHYS
|
||||
ldr \rv, =SCIF_VIRT
|
||||
.endm
|
||||
|
||||
.macro waituart, rd, rx
|
||||
1001: ldrh \rd, [\rx, #FSR]
|
||||
tst \rd, #TDFE
|
||||
beq 1001b
|
||||
.endm
|
||||
|
||||
.macro senduart, rd, rx
|
||||
strb \rd, [\rx, #FTDR]
|
||||
ldrh \rd, [\rx, #FSR]
|
||||
bic \rd, \rd, #TEND
|
||||
strh \rd, [\rx, #FSR]
|
||||
.endm
|
||||
|
||||
.macro busyuart, rd, rx
|
||||
1001: ldrh \rd, [\rx, #FSR]
|
||||
tst \rd, #TEND
|
||||
beq 1001b
|
||||
.endm
|
@ -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
|
6
arch/arm/mach-asm9260/Kconfig
Normal file
6
arch/arm/mach-asm9260/Kconfig
Normal file
@ -0,0 +1,6 @@
|
||||
config MACH_ASM9260
|
||||
bool "Alphascale ASM9260"
|
||||
depends on ARCH_MULTI_V5
|
||||
select CPU_ARM926T
|
||||
help
|
||||
Support for Alphascale ASM9260 based platform.
|
@ -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
|
||||
|
@ -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
|
||||
|
25
arch/arm/mach-bcm/bcm_cygnus.c
Normal file
25
arch/arm/mach-bcm/bcm_cygnus.c
Normal file
@ -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
|
19
arch/arm/mach-bcm/brcmstb.h
Normal file
19
arch/arm/mach-bcm/brcmstb.h
Normal file
@ -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__ */
|
33
arch/arm/mach-bcm/headsmp-brcmstb.S
Normal file
33
arch/arm/mach-bcm/headsmp-brcmstb.S
Normal file
@ -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)
|
329
arch/arm/mach-bcm/platsmp-brcmstb.c
Normal file
329
arch/arm/mach-bcm/platsmp-brcmstb.c
Normal file
@ -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);
|
@ -1,10 +1,11 @@
|
||||
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
|
||||
|
||||
if ARCH_BERLIN
|
||||
|
@ -24,6 +24,7 @@ menuconfig ARCH_EXYNOS
|
||||
select PM_GENERIC_DOMAINS if PM_RUNTIME
|
||||
select S5P_DEV_MFC
|
||||
select SRAM
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5)
|
||||
|
||||
@ -75,6 +76,11 @@ config SOC_EXYNOS4412
|
||||
default y
|
||||
depends on ARCH_EXYNOS4
|
||||
|
||||
config SOC_EXYNOS4415
|
||||
bool "SAMSUNG EXYNOS4415"
|
||||
default y
|
||||
depends on ARCH_EXYNOS4
|
||||
|
||||
config SOC_EXYNOS5250
|
||||
bool "SAMSUNG EXYNOS5250"
|
||||
default y
|
||||
@ -123,4 +129,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
|
||||
|
@ -11,13 +11,15 @@ 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
|
||||
|
||||
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
|
||||
|
@ -12,7 +12,6 @@
|
||||
#ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H
|
||||
#define __ARCH_ARM_MACH_EXYNOS_COMMON_H
|
||||
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define EXYNOS3250_SOC_ID 0xE3472000
|
||||
@ -111,11 +110,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,32 +134,20 @@ 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;
|
||||
|
||||
/* PMU(Power Management Unit) support */
|
||||
|
||||
#define PMU_TABLE_END (-1U)
|
||||
|
||||
enum sys_powerdown {
|
||||
SYS_AFTR,
|
||||
SYS_LPA,
|
||||
SYS_SLEEP,
|
||||
NUM_SYS_POWERDOWN,
|
||||
};
|
||||
|
||||
struct exynos_pmu_conf {
|
||||
unsigned int offset;
|
||||
unsigned int val[NUM_SYS_POWERDOWN];
|
||||
};
|
||||
|
||||
extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
|
||||
extern void exynos_cpu_power_down(int cpu);
|
||||
extern void exynos_cpu_power_up(int cpu);
|
||||
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);
|
||||
|
24
arch/arm/mach-exynos/exynos-pmu.h
Normal file
24
arch/arm/mach-exynos/exynos-pmu.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Header for EXYNOS PMU Driver support
|
||||
*
|
||||
* 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 __EXYNOS_PMU_H
|
||||
#define __EXYNOS_PMU_H
|
||||
|
||||
enum sys_powerdown {
|
||||
SYS_AFTR,
|
||||
SYS_LPA,
|
||||
SYS_SLEEP,
|
||||
NUM_SYS_POWERDOWN,
|
||||
};
|
||||
|
||||
extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
|
||||
|
||||
#endif /* __EXYNOS_PMU_H */
|
@ -87,28 +87,6 @@ static struct map_desc exynos5_iodesc[] __initdata = {
|
||||
},
|
||||
};
|
||||
|
||||
static void exynos_restart(enum reboot_mode mode, const char *cmd)
|
||||
{
|
||||
struct device_node *np;
|
||||
u32 val = 0x1;
|
||||
void __iomem *addr = pmu_base_addr + EXYNOS_SWRESET;
|
||||
|
||||
if (of_machine_is_compatible("samsung,exynos5440")) {
|
||||
u32 status;
|
||||
np = of_find_compatible_node(NULL, NULL, "samsung,exynos5440-clock");
|
||||
|
||||
addr = of_iomap(np, 0) + 0xbc;
|
||||
status = __raw_readl(addr);
|
||||
|
||||
addr = of_iomap(np, 0) + 0xcc;
|
||||
val = __raw_readl(addr);
|
||||
|
||||
val = (val & 0xffff0000) | (status & 0xffff);
|
||||
}
|
||||
|
||||
__raw_writel(val, addr);
|
||||
}
|
||||
|
||||
static struct platform_device exynos_cpuidle = {
|
||||
.name = "exynos_cpuidle",
|
||||
#ifdef CONFIG_ARM_EXYNOS_CPUIDLE
|
||||
@ -202,6 +180,7 @@ static const struct of_device_id exynos_dt_pmu_match[] = {
|
||||
{ .compatible = "samsung,exynos4210-pmu" },
|
||||
{ .compatible = "samsung,exynos4212-pmu" },
|
||||
{ .compatible = "samsung,exynos4412-pmu" },
|
||||
{ .compatible = "samsung,exynos4415-pmu" },
|
||||
{ .compatible = "samsung,exynos5250-pmu" },
|
||||
{ .compatible = "samsung,exynos5260-pmu" },
|
||||
{ .compatible = "samsung,exynos5410-pmu" },
|
||||
@ -268,7 +247,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);
|
||||
@ -283,6 +265,7 @@ static char const *exynos_dt_compat[] __initconst = {
|
||||
"samsung,exynos4210",
|
||||
"samsung,exynos4212",
|
||||
"samsung,exynos4412",
|
||||
"samsung,exynos4415",
|
||||
"samsung,exynos5",
|
||||
"samsung,exynos5250",
|
||||
"samsung,exynos5260",
|
||||
@ -328,7 +311,6 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
|
||||
.init_machine = exynos_dt_machine_init,
|
||||
.init_late = exynos_init_late,
|
||||
.dt_compat = exynos_dt_compat,
|
||||
.restart = exynos_restart,
|
||||
.reserve = exynos_reserve,
|
||||
.dt_fixup = exynos_dt_fixup,
|
||||
MACHINE_END
|
||||
|
@ -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)
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/cp15.h>
|
||||
@ -30,6 +31,8 @@
|
||||
#define EXYNOS5420_USE_ARM_CORE_DOWN_STATE BIT(29)
|
||||
#define EXYNOS5420_USE_L2_COMMON_UP_STATE BIT(30)
|
||||
|
||||
static void __iomem *ns_sram_base_addr;
|
||||
|
||||
/*
|
||||
* The common v7_exit_coherency_flush API could not be used because of the
|
||||
* Erratum 799270 workaround. This macro is the same as the common one (in
|
||||
@ -318,10 +321,26 @@ static const struct of_device_id exynos_dt_mcpm_match[] = {
|
||||
{},
|
||||
};
|
||||
|
||||
static void exynos_mcpm_setup_entry_point(void)
|
||||
{
|
||||
/*
|
||||
* U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr
|
||||
* as part of secondary_cpu_start(). Let's redirect it to the
|
||||
* mcpm_entry_point(). This is done during both secondary boot-up as
|
||||
* well as system resume.
|
||||
*/
|
||||
__raw_writel(0xe59f0000, ns_sram_base_addr); /* ldr r0, [pc, #0] */
|
||||
__raw_writel(0xe12fff10, ns_sram_base_addr + 4); /* bx r0 */
|
||||
__raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 8);
|
||||
}
|
||||
|
||||
static struct syscore_ops exynos_mcpm_syscore_ops = {
|
||||
.resume = exynos_mcpm_setup_entry_point,
|
||||
};
|
||||
|
||||
static int __init exynos_mcpm_init(void)
|
||||
{
|
||||
struct device_node *node;
|
||||
void __iomem *ns_sram_base_addr;
|
||||
unsigned int value, i;
|
||||
int ret;
|
||||
|
||||
@ -387,16 +406,9 @@ static int __init exynos_mcpm_init(void)
|
||||
pmu_raw_writel(value, EXYNOS_COMMON_OPTION(i));
|
||||
}
|
||||
|
||||
/*
|
||||
* U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr
|
||||
* as part of secondary_cpu_start(). Let's redirect it to the
|
||||
* mcpm_entry_point().
|
||||
*/
|
||||
__raw_writel(0xe59f0000, ns_sram_base_addr); /* ldr r0, [pc, #0] */
|
||||
__raw_writel(0xe12fff10, ns_sram_base_addr + 4); /* bx r0 */
|
||||
__raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 8);
|
||||
exynos_mcpm_setup_entry_point();
|
||||
|
||||
iounmap(ns_sram_base_addr);
|
||||
register_syscore_ops(&exynos_mcpm_syscore_ops);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -126,6 +126,18 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
|
||||
*/
|
||||
void exynos_cpu_power_down(int cpu)
|
||||
{
|
||||
if (cpu == 0 && (of_machine_is_compatible("samsung,exynos5420") ||
|
||||
of_machine_is_compatible("samsung,exynos5800"))) {
|
||||
/*
|
||||
* Bypass power down for CPU0 during suspend. Check for
|
||||
* the SYS_PWR_REG value to decide if we are suspending
|
||||
* the system.
|
||||
*/
|
||||
int val = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG);
|
||||
|
||||
if (!(val & S5P_CORE_LOCAL_PWR_EN))
|
||||
return;
|
||||
}
|
||||
pmu_raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu));
|
||||
}
|
||||
|
||||
@ -203,6 +215,26 @@ static inline void __iomem *cpu_boot_reg(int cpu)
|
||||
return boot_reg;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -279,6 +311,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,
|
||||
|
@ -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,45 @@
|
||||
|
||||
#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 "exynos-pmu.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 +70,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 +89,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 +97,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 +134,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 +163,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);
|
||||
}
|
||||
|
@ -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 - CPU PMU(Power Management Unit) support
|
||||
@ -10,12 +10,136 @@
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/reboot.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "exynos-pmu.h"
|
||||
#include "regs-pmu.h"
|
||||
|
||||
static const struct exynos_pmu_conf *exynos_pmu_config;
|
||||
#define PMU_TABLE_END (-1U)
|
||||
|
||||
struct exynos_pmu_conf {
|
||||
unsigned int offset;
|
||||
u8 val[NUM_SYS_POWERDOWN];
|
||||
};
|
||||
|
||||
struct exynos_pmu_data {
|
||||
const struct exynos_pmu_conf *pmu_config;
|
||||
const struct exynos_pmu_conf *pmu_config_extra;
|
||||
|
||||
void (*pmu_init)(void);
|
||||
void (*powerdown_conf)(enum sys_powerdown);
|
||||
void (*powerdown_conf_extra)(enum sys_powerdown);
|
||||
};
|
||||
|
||||
struct exynos_pmu_context {
|
||||
struct device *dev;
|
||||
const struct exynos_pmu_data *pmu_data;
|
||||
};
|
||||
|
||||
static void __iomem *pmu_base_addr;
|
||||
static struct exynos_pmu_context *pmu_context;
|
||||
|
||||
static inline void pmu_raw_writel(u32 val, u32 offset)
|
||||
{
|
||||
writel_relaxed(val, pmu_base_addr + offset);
|
||||
}
|
||||
|
||||
static inline u32 pmu_raw_readl(u32 offset)
|
||||
{
|
||||
return readl_relaxed(pmu_base_addr + offset);
|
||||
}
|
||||
|
||||
static struct exynos_pmu_conf exynos3250_pmu_config[] = {
|
||||
/* { .offset = offset, .val = { AFTR, W-AFTR, SLEEP } */
|
||||
{ EXYNOS3_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x2} },
|
||||
{ EXYNOS3_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS3_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS3_ARM_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x2} },
|
||||
{ EXYNOS3_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS3_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS3_ISP_ARM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS3_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS3_ARM_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x2} },
|
||||
{ EXYNOS3_ARM_L2_SYS_PWR_REG, { 0x0, 0x0, 0x3} },
|
||||
{ EXYNOS3_CMU_ACLKSTOP_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_CMU_SCLKSTOP_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_CMU_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_DRAM_FREQ_DOWN_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
|
||||
{ EXYNOS3_DDRPHY_DLLOFF_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
|
||||
{ EXYNOS3_LPDDR_PHY_DLL_LOCK_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
|
||||
{ EXYNOS3_CMU_ACLKSTOP_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_SCLKSTOP_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_APLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_MPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_BPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_VPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_EPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_UPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
|
||||
{ EXYNOS3_EPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_MPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_BPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_CLKSTOP_CAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_CLKSTOP_MFC_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_CLKSTOP_G3D_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_CLKSTOP_LCD0_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_CLKSTOP_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_CLKSTOP_MAUDIO_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_RESET_CAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_RESET_MFC_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_RESET_G3D_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_RESET_LCD0_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_RESET_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_RESET_MAUDIO_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS3_TOP_BUS_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
|
||||
{ EXYNOS3_TOP_RETENTION_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
|
||||
{ EXYNOS3_TOP_PWR_SYS_PWR_REG, { 0x3, 0x3, 0x3} },
|
||||
{ EXYNOS3_TOP_BUS_COREBLK_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
|
||||
{ EXYNOS3_TOP_RETENTION_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
|
||||
{ EXYNOS3_TOP_PWR_COREBLK_SYS_PWR_REG, { 0x3, 0x3, 0x3} },
|
||||
{ EXYNOS3_LOGIC_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_OSCCLK_GATE_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
|
||||
{ EXYNOS3_LOGIC_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_OSCCLK_GATE_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
|
||||
{ EXYNOS3_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_PAD_RETENTION_MAUDIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_PAD_RETENTION_GPIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_PAD_RETENTION_UART_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_PAD_RETENTION_MMC0_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_PAD_RETENTION_MMC1_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_PAD_RETENTION_MMC2_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_PAD_RETENTION_SPI_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_PAD_RETENTION_EBIA_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_PAD_RETENTION_EBIB_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_PAD_RETENTION_JTAG_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_PAD_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_PAD_ALV_SEL_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_XUSBXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_XXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_EXT_REGULATOR_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_EXT_REGULATOR_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_GPIO_MODE_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_GPIO_MODE_MAUDIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_TOP_ASB_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_TOP_ASB_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_TOP_ASB_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_TOP_ASB_ISOLATION_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS3_CAM_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS3_MFC_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS3_G3D_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS3_LCD0_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS3_ISP_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS3_MAUDIO_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS3_CMU_SYSCLK_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ PMU_TABLE_END,},
|
||||
};
|
||||
|
||||
static const struct exynos_pmu_conf exynos4210_pmu_config[] = {
|
||||
/* { .offset = offset, .val = { AFTR, LPA, SLEEP } */
|
||||
@ -264,6 +388,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} },
|
||||
@ -315,6 +440,189 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = {
|
||||
{ PMU_TABLE_END,},
|
||||
};
|
||||
|
||||
static struct exynos_pmu_conf exynos5420_pmu_config[] = {
|
||||
/* { .offset = offset, .val = { AFTR, LPA, SLEEP } */
|
||||
{ EXYNOS5_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_ARM_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_ARM_CORE2_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_DIS_IRQ_ARM_CORE2_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_DIS_IRQ_ARM_CORE2_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_ARM_CORE3_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_DIS_IRQ_ARM_CORE3_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_DIS_IRQ_ARM_CORE3_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_KFC_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_DIS_IRQ_KFC_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_DIS_IRQ_KFC_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_KFC_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_DIS_IRQ_KFC_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_DIS_IRQ_KFC_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_KFC_CORE2_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_DIS_IRQ_KFC_CORE2_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_DIS_IRQ_KFC_CORE2_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_KFC_CORE3_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_DIS_IRQ_KFC_CORE3_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_DIS_IRQ_KFC_CORE3_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_ISP_ARM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_ARM_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_KFC_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_ARM_L2_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_KFC_L2_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_ACLKSTOP_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_SCLKSTOP_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
|
||||
{ EXYNOS5_CMU_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS5_CMU_ACLKSTOP_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_SCLKSTOP_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
|
||||
{ EXYNOS5_CMU_RESET_SYSMEM_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS5_DRAM_FREQ_DOWN_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
|
||||
{ EXYNOS5_DDRPHY_DLLOFF_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
|
||||
{ EXYNOS5_DDRPHY_DLLLOCK_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
|
||||
{ EXYNOS5_APLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_MPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_VPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_EPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS5_BPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_CPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_DPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_IPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_KPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_MPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_BPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_RPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_SPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_TOP_BUS_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
|
||||
{ EXYNOS5_TOP_RETENTION_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
|
||||
{ EXYNOS5_TOP_PWR_SYS_PWR_REG, { 0x3, 0x3, 0x0} },
|
||||
{ EXYNOS5_TOP_BUS_SYSMEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
|
||||
{ EXYNOS5_TOP_RETENTION_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
|
||||
{ EXYNOS5_TOP_PWR_SYSMEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
|
||||
{ EXYNOS5_LOGIC_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS5_OSCCLK_GATE_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
|
||||
{ EXYNOS5_LOGIC_RESET_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_OSCCLK_GATE_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x3} },
|
||||
{ EXYNOS5420_INTROM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x3} },
|
||||
{ EXYNOS5_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_PAD_RETENTION_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS5420_PAD_RETENTION_JTAG_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS5420_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_PAD_RETENTION_UART_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_PAD_RETENTION_MMC0_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_PAD_RETENTION_MMC1_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_PAD_RETENTION_MMC2_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_PAD_RETENTION_HSI_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_PAD_RETENTION_EBIA_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_PAD_RETENTION_EBIB_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_PAD_RETENTION_SPI_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5420_PAD_RETENTION_DRAM_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_PAD_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS5_PAD_ISOLATION_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_PAD_ALV_SEL_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_XUSBXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS5_XXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS5_EXT_REGULATOR_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS5_GPIO_MODE_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_GPIO_MODE_SYSMEM_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS5_GPIO_MODE_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS5_TOP_ASB_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
|
||||
{ EXYNOS5_TOP_ASB_ISOLATION_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
|
||||
{ EXYNOS5_GSCL_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS5_ISP_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS5_MFC_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS5_G3D_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS5420_DISP1_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS5420_MAU_SYS_PWR_REG, { 0x7, 0x7, 0x0} },
|
||||
{ EXYNOS5420_G2D_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS5420_MSC_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS5420_FSYS_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS5420_FSYS2_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS5420_PSGEN_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS5420_PERIC_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS5420_WCORE_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_CLKSTOP_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_SYSCLK_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_RESET_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
|
||||
{ PMU_TABLE_END,},
|
||||
};
|
||||
|
||||
static unsigned int const exynos3250_list_feed[] = {
|
||||
EXYNOS3_ARM_CORE_OPTION(0),
|
||||
EXYNOS3_ARM_CORE_OPTION(1),
|
||||
EXYNOS3_ARM_CORE_OPTION(2),
|
||||
EXYNOS3_ARM_CORE_OPTION(3),
|
||||
EXYNOS3_ARM_COMMON_OPTION,
|
||||
EXYNOS3_TOP_PWR_OPTION,
|
||||
EXYNOS3_CORE_TOP_PWR_OPTION,
|
||||
S5P_CAM_OPTION,
|
||||
S5P_MFC_OPTION,
|
||||
S5P_G3D_OPTION,
|
||||
S5P_LCD0_OPTION,
|
||||
S5P_ISP_OPTION,
|
||||
};
|
||||
|
||||
static void exynos3250_powerdown_conf_extra(enum sys_powerdown mode)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int tmp;
|
||||
|
||||
/* Enable only SC_FEEDBACK */
|
||||
for (i = 0; i < ARRAY_SIZE(exynos3250_list_feed); i++) {
|
||||
tmp = pmu_raw_readl(exynos3250_list_feed[i]);
|
||||
tmp &= ~(EXYNOS3_OPTION_USE_SC_COUNTER);
|
||||
tmp |= EXYNOS3_OPTION_USE_SC_FEEDBACK;
|
||||
pmu_raw_writel(tmp, exynos3250_list_feed[i]);
|
||||
}
|
||||
|
||||
if (mode != SYS_SLEEP)
|
||||
return;
|
||||
|
||||
pmu_raw_writel(XUSBXTI_DURATION, EXYNOS3_XUSBXTI_DURATION);
|
||||
pmu_raw_writel(XXTI_DURATION, EXYNOS3_XXTI_DURATION);
|
||||
pmu_raw_writel(EXT_REGULATOR_DURATION, EXYNOS3_EXT_REGULATOR_DURATION);
|
||||
pmu_raw_writel(EXT_REGULATOR_COREBLK_DURATION,
|
||||
EXYNOS3_EXT_REGULATOR_COREBLK_DURATION);
|
||||
}
|
||||
|
||||
static unsigned int const exynos5_list_both_cnt_feed[] = {
|
||||
EXYNOS5_ARM_CORE0_OPTION,
|
||||
EXYNOS5_ARM_CORE1_OPTION,
|
||||
@ -335,7 +643,76 @@ static unsigned int const exynos5_list_disable_wfi_wfe[] = {
|
||||
EXYNOS5_ISP_ARM_OPTION,
|
||||
};
|
||||
|
||||
static void exynos5_init_pmu(void)
|
||||
static unsigned int const exynos5420_list_disable_pmu_reg[] = {
|
||||
EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG,
|
||||
EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG,
|
||||
EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG,
|
||||
EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG,
|
||||
EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG,
|
||||
EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG,
|
||||
EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG,
|
||||
EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG,
|
||||
EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG,
|
||||
EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG,
|
||||
};
|
||||
|
||||
static void exynos5_power_off(void)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
pr_info("Power down.\n");
|
||||
tmp = pmu_raw_readl(EXYNOS_PS_HOLD_CONTROL);
|
||||
tmp ^= (1 << 8);
|
||||
pmu_raw_writel(tmp, EXYNOS_PS_HOLD_CONTROL);
|
||||
|
||||
/* Wait a little so we don't give a false warning below */
|
||||
mdelay(100);
|
||||
|
||||
pr_err("Power down failed, please power off system manually.\n");
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void exynos5420_powerdown_conf(enum sys_powerdown mode)
|
||||
{
|
||||
u32 this_cluster;
|
||||
|
||||
this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
|
||||
|
||||
/*
|
||||
* set the cluster id to IROM register to ensure that we wake
|
||||
* up with the current cluster.
|
||||
*/
|
||||
pmu_raw_writel(this_cluster, EXYNOS_IROM_DATA2);
|
||||
}
|
||||
|
||||
|
||||
static void exynos5_powerdown_conf(enum sys_powerdown mode)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int tmp;
|
||||
@ -343,7 +720,7 @@ static void exynos5_init_pmu(void)
|
||||
/*
|
||||
* Enable both SC_FEEDBACK and SC_COUNTER
|
||||
*/
|
||||
for (i = 0 ; i < ARRAY_SIZE(exynos5_list_both_cnt_feed) ; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(exynos5_list_both_cnt_feed); i++) {
|
||||
tmp = pmu_raw_readl(exynos5_list_both_cnt_feed[i]);
|
||||
tmp |= (EXYNOS5_USE_SC_FEEDBACK |
|
||||
EXYNOS5_USE_SC_COUNTER);
|
||||
@ -360,7 +737,7 @@ static void exynos5_init_pmu(void)
|
||||
/*
|
||||
* Disable WFI/WFE on XXX_OPTION
|
||||
*/
|
||||
for (i = 0 ; i < ARRAY_SIZE(exynos5_list_disable_wfi_wfe) ; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(exynos5_list_disable_wfi_wfe); i++) {
|
||||
tmp = pmu_raw_readl(exynos5_list_disable_wfi_wfe[i]);
|
||||
tmp &= ~(EXYNOS5_OPTION_USE_STANDBYWFE |
|
||||
EXYNOS5_OPTION_USE_STANDBYWFI);
|
||||
@ -372,51 +749,257 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (soc_is_exynos5250())
|
||||
exynos5_init_pmu();
|
||||
const struct exynos_pmu_data *pmu_data = pmu_context->pmu_data;
|
||||
|
||||
for (i = 0; (exynos_pmu_config[i].offset != PMU_TABLE_END) ; i++)
|
||||
pmu_raw_writel(exynos_pmu_config[i].val[mode],
|
||||
exynos_pmu_config[i].offset);
|
||||
if (pmu_data->powerdown_conf)
|
||||
pmu_data->powerdown_conf(mode);
|
||||
|
||||
if (soc_is_exynos4412()) {
|
||||
for (i = 0; exynos4412_pmu_config[i].offset != PMU_TABLE_END ; i++)
|
||||
pmu_raw_writel(exynos4412_pmu_config[i].val[mode],
|
||||
exynos4412_pmu_config[i].offset);
|
||||
if (pmu_data->pmu_config) {
|
||||
for (i = 0; (pmu_data->pmu_config[i].offset != PMU_TABLE_END); i++)
|
||||
pmu_raw_writel(pmu_data->pmu_config[i].val[mode],
|
||||
pmu_data->pmu_config[i].offset);
|
||||
}
|
||||
|
||||
if (pmu_data->powerdown_conf_extra)
|
||||
pmu_data->powerdown_conf_extra(mode);
|
||||
|
||||
if (pmu_data->pmu_config_extra) {
|
||||
for (i = 0; pmu_data->pmu_config_extra[i].offset != PMU_TABLE_END; i++)
|
||||
pmu_raw_writel(pmu_data->pmu_config_extra[i].val[mode],
|
||||
pmu_data->pmu_config_extra[i].offset);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init exynos_pmu_init(void)
|
||||
static void exynos3250_pmu_init(void)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
exynos_pmu_config = exynos4210_pmu_config;
|
||||
/*
|
||||
* To prevent from issuing new bus request form L2 memory system
|
||||
* If core status is power down, should be set '1' to L2 power down
|
||||
*/
|
||||
value = pmu_raw_readl(EXYNOS3_ARM_COMMON_OPTION);
|
||||
value |= EXYNOS3_OPTION_SKIP_DEACTIVATE_ACEACP_IN_PWDN;
|
||||
pmu_raw_writel(value, EXYNOS3_ARM_COMMON_OPTION);
|
||||
|
||||
if (soc_is_exynos4210()) {
|
||||
exynos_pmu_config = exynos4210_pmu_config;
|
||||
pr_info("EXYNOS4210 PMU Initialize\n");
|
||||
} else if (soc_is_exynos4212() || soc_is_exynos4412()) {
|
||||
exynos_pmu_config = exynos4x12_pmu_config;
|
||||
pr_info("EXYNOS4x12 PMU Initialize\n");
|
||||
} else if (soc_is_exynos5250()) {
|
||||
/*
|
||||
* When SYS_WDTRESET is set, watchdog timer reset request
|
||||
* is ignored by power management unit.
|
||||
*/
|
||||
value = pmu_raw_readl(EXYNOS5_AUTO_WDTRESET_DISABLE);
|
||||
value &= ~EXYNOS5_SYS_WDTRESET;
|
||||
pmu_raw_writel(value, EXYNOS5_AUTO_WDTRESET_DISABLE);
|
||||
/* Enable USE_STANDBY_WFI for all CORE */
|
||||
pmu_raw_writel(S5P_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION);
|
||||
|
||||
value = pmu_raw_readl(EXYNOS5_MASK_WDTRESET_REQUEST);
|
||||
value &= ~EXYNOS5_SYS_WDTRESET;
|
||||
pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST);
|
||||
/*
|
||||
* Set PSHOLD port for output high
|
||||
*/
|
||||
value = pmu_raw_readl(S5P_PS_HOLD_CONTROL);
|
||||
value |= S5P_PS_HOLD_OUTPUT_HIGH;
|
||||
pmu_raw_writel(value, S5P_PS_HOLD_CONTROL);
|
||||
|
||||
exynos_pmu_config = exynos5250_pmu_config;
|
||||
pr_info("EXYNOS5250 PMU Initialize\n");
|
||||
} else {
|
||||
pr_info("EXYNOS: PMU not supported\n");
|
||||
/*
|
||||
* Enable signal for PSHOLD port
|
||||
*/
|
||||
value = pmu_raw_readl(S5P_PS_HOLD_CONTROL);
|
||||
value |= S5P_PS_HOLD_EN;
|
||||
pmu_raw_writel(value, S5P_PS_HOLD_CONTROL);
|
||||
}
|
||||
|
||||
static void exynos5250_pmu_init(void)
|
||||
{
|
||||
unsigned int value;
|
||||
/*
|
||||
* When SYS_WDTRESET is set, watchdog timer reset request
|
||||
* is ignored by power management unit.
|
||||
*/
|
||||
value = pmu_raw_readl(EXYNOS5_AUTO_WDTRESET_DISABLE);
|
||||
value &= ~EXYNOS5_SYS_WDTRESET;
|
||||
pmu_raw_writel(value, EXYNOS5_AUTO_WDTRESET_DISABLE);
|
||||
|
||||
value = pmu_raw_readl(EXYNOS5_MASK_WDTRESET_REQUEST);
|
||||
value &= ~EXYNOS5_SYS_WDTRESET;
|
||||
pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST);
|
||||
}
|
||||
|
||||
static void exynos5420_pmu_init(void)
|
||||
{
|
||||
unsigned int value;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Set the CMU_RESET, CMU_SYSCLK and CMU_CLKSTOP registers
|
||||
* for local power blocks to Low initially as per Table 8-4:
|
||||
* "System-Level Power-Down Configuration Registers".
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(exynos5420_list_disable_pmu_reg); i++)
|
||||
pmu_raw_writel(0, exynos5420_list_disable_pmu_reg[i]);
|
||||
|
||||
/* Enable USE_STANDBY_WFI for all CORE */
|
||||
pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION);
|
||||
|
||||
value = pmu_raw_readl(EXYNOS_L2_OPTION(0));
|
||||
value &= ~EXYNOS5_USE_RETENTION;
|
||||
pmu_raw_writel(value, EXYNOS_L2_OPTION(0));
|
||||
|
||||
value = pmu_raw_readl(EXYNOS_L2_OPTION(1));
|
||||
value &= ~EXYNOS5_USE_RETENTION;
|
||||
pmu_raw_writel(value, EXYNOS_L2_OPTION(1));
|
||||
|
||||
/*
|
||||
* If L2_COMMON is turned off, clocks related to ATB async
|
||||
* bridge are gated. Thus, when ISP power is gated, LPI
|
||||
* may get stuck.
|
||||
*/
|
||||
value = pmu_raw_readl(EXYNOS5420_LPI_MASK);
|
||||
value |= EXYNOS5420_ATB_ISP_ARM;
|
||||
pmu_raw_writel(value, EXYNOS5420_LPI_MASK);
|
||||
|
||||
value = pmu_raw_readl(EXYNOS5420_LPI_MASK1);
|
||||
value |= EXYNOS5420_ATB_KFC;
|
||||
pmu_raw_writel(value, EXYNOS5420_LPI_MASK1);
|
||||
|
||||
/* Prevent issue of new bus request from L2 memory */
|
||||
value = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION);
|
||||
value |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN;
|
||||
pmu_raw_writel(value, EXYNOS5420_ARM_COMMON_OPTION);
|
||||
|
||||
value = pmu_raw_readl(EXYNOS5420_KFC_COMMON_OPTION);
|
||||
value |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN;
|
||||
pmu_raw_writel(value, EXYNOS5420_KFC_COMMON_OPTION);
|
||||
|
||||
/* This setting is to reduce suspend/resume time */
|
||||
pmu_raw_writel(DUR_WAIT_RESET, EXYNOS5420_LOGIC_RESET_DURATION3);
|
||||
|
||||
/* Serialized CPU wakeup of Eagle */
|
||||
pmu_raw_writel(SPREAD_ENABLE, EXYNOS5420_ARM_INTR_SPREAD_ENABLE);
|
||||
|
||||
pmu_raw_writel(SPREAD_USE_STANDWFI,
|
||||
EXYNOS5420_ARM_INTR_SPREAD_USE_STANDBYWFI);
|
||||
|
||||
pmu_raw_writel(0x1, EXYNOS5420_UP_SCHEDULER);
|
||||
|
||||
pm_power_off = exynos5_power_off;
|
||||
pr_info("EXYNOS5420 PMU initialized\n");
|
||||
}
|
||||
|
||||
static int pmu_restart_notify(struct notifier_block *this,
|
||||
unsigned long code, void *unused)
|
||||
{
|
||||
pmu_raw_writel(0x1, EXYNOS_SWRESET);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static const struct exynos_pmu_data exynos3250_pmu_data = {
|
||||
.pmu_config = exynos3250_pmu_config,
|
||||
.pmu_init = exynos3250_pmu_init,
|
||||
.powerdown_conf_extra = exynos3250_powerdown_conf_extra,
|
||||
};
|
||||
|
||||
static const struct exynos_pmu_data exynos4210_pmu_data = {
|
||||
.pmu_config = exynos4210_pmu_config,
|
||||
};
|
||||
|
||||
static const struct exynos_pmu_data exynos4212_pmu_data = {
|
||||
.pmu_config = exynos4x12_pmu_config,
|
||||
};
|
||||
|
||||
static const struct exynos_pmu_data exynos4412_pmu_data = {
|
||||
.pmu_config = exynos4x12_pmu_config,
|
||||
.pmu_config_extra = exynos4412_pmu_config,
|
||||
};
|
||||
|
||||
static const struct exynos_pmu_data exynos5250_pmu_data = {
|
||||
.pmu_config = exynos5250_pmu_config,
|
||||
.pmu_init = exynos5250_pmu_init,
|
||||
.powerdown_conf = exynos5_powerdown_conf,
|
||||
};
|
||||
|
||||
static struct exynos_pmu_data exynos5420_pmu_data = {
|
||||
.pmu_config = exynos5420_pmu_config,
|
||||
.pmu_init = exynos5420_pmu_init,
|
||||
.powerdown_conf = exynos5420_powerdown_conf,
|
||||
};
|
||||
|
||||
/*
|
||||
* PMU platform driver and devicetree bindings.
|
||||
*/
|
||||
static const struct of_device_id exynos_pmu_of_device_ids[] = {
|
||||
{
|
||||
.compatible = "samsung,exynos3250-pmu",
|
||||
.data = &exynos3250_pmu_data,
|
||||
}, {
|
||||
.compatible = "samsung,exynos4210-pmu",
|
||||
.data = &exynos4210_pmu_data,
|
||||
}, {
|
||||
.compatible = "samsung,exynos4212-pmu",
|
||||
.data = &exynos4212_pmu_data,
|
||||
}, {
|
||||
.compatible = "samsung,exynos4412-pmu",
|
||||
.data = &exynos4412_pmu_data,
|
||||
}, {
|
||||
.compatible = "samsung,exynos5250-pmu",
|
||||
.data = &exynos5250_pmu_data,
|
||||
}, {
|
||||
.compatible = "samsung,exynos5420-pmu",
|
||||
.data = &exynos5420_pmu_data,
|
||||
},
|
||||
{ /*sentinel*/ },
|
||||
};
|
||||
|
||||
/*
|
||||
* Exynos PMU restart notifier, handles restart functionality
|
||||
*/
|
||||
static struct notifier_block pmu_restart_handler = {
|
||||
.notifier_call = pmu_restart_notify,
|
||||
.priority = 128,
|
||||
};
|
||||
|
||||
static int exynos_pmu_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pmu_base_addr = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(pmu_base_addr))
|
||||
return PTR_ERR(pmu_base_addr);
|
||||
|
||||
pmu_context = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct exynos_pmu_context),
|
||||
GFP_KERNEL);
|
||||
if (!pmu_context) {
|
||||
dev_err(dev, "Cannot allocate memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
pmu_context->dev = dev;
|
||||
|
||||
match = of_match_node(exynos_pmu_of_device_ids, dev->of_node);
|
||||
|
||||
pmu_context->pmu_data = match->data;
|
||||
|
||||
if (pmu_context->pmu_data->pmu_init)
|
||||
pmu_context->pmu_data->pmu_init();
|
||||
|
||||
platform_set_drvdata(pdev, pmu_context);
|
||||
|
||||
ret = register_restart_handler(&pmu_restart_handler);
|
||||
if (ret)
|
||||
dev_warn(dev, "can't register restart handler err=%d\n", ret);
|
||||
|
||||
dev_dbg(dev, "Exynos PMU Driver probe done\n");
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(exynos_pmu_init);
|
||||
|
||||
static struct platform_driver exynos_pmu_driver = {
|
||||
.driver = {
|
||||
.name = "exynos-pmu",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = exynos_pmu_of_device_ids,
|
||||
},
|
||||
.probe = exynos_pmu_probe,
|
||||
};
|
||||
|
||||
static int __init exynos_pmu_init(void)
|
||||
{
|
||||
return platform_driver_register(&exynos_pmu_driver);
|
||||
|
||||
}
|
||||
postcore_initcall(exynos_pmu_init);
|
||||
|
@ -19,9 +19,24 @@
|
||||
#define S5P_CENTRAL_SEQ_OPTION 0x0208
|
||||
|
||||
#define S5P_USE_STANDBY_WFI0 (1 << 16)
|
||||
#define S5P_USE_STANDBY_WFI1 (1 << 17)
|
||||
#define S5P_USE_STANDBY_WFI2 (1 << 19)
|
||||
#define S5P_USE_STANDBY_WFI3 (1 << 20)
|
||||
#define S5P_USE_STANDBY_WFE0 (1 << 24)
|
||||
#define S5P_USE_STANDBY_WFE1 (1 << 25)
|
||||
#define S5P_USE_STANDBY_WFE2 (1 << 27)
|
||||
#define S5P_USE_STANDBY_WFE3 (1 << 28)
|
||||
|
||||
#define S5P_USE_STANDBY_WFI_ALL \
|
||||
(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFI1 | \
|
||||
S5P_USE_STANDBY_WFI2 | S5P_USE_STANDBY_WFI3 | \
|
||||
S5P_USE_STANDBY_WFE0 | S5P_USE_STANDBY_WFE1 | \
|
||||
S5P_USE_STANDBY_WFE2 | S5P_USE_STANDBY_WFE3)
|
||||
|
||||
#define S5P_USE_DELAYED_RESET_ASSERTION BIT(12)
|
||||
|
||||
#define EXYNOS_CORE_PO_RESET(n) ((1 << 4) << n)
|
||||
#define EXYNOS_WAKEUP_FROM_LOWPWR (1 << 28)
|
||||
#define EXYNOS_SWRESET 0x0400
|
||||
#define EXYNOS5440_SWRESET 0x00C4
|
||||
|
||||
@ -36,6 +51,7 @@
|
||||
#define S5P_INFORM7 0x081C
|
||||
#define S5P_PMU_SPARE3 0x090C
|
||||
|
||||
#define EXYNOS_IROM_DATA2 0x0988
|
||||
#define S5P_ARM_CORE0_LOWPWR 0x1000
|
||||
#define S5P_DIS_IRQ_CORE0 0x1004
|
||||
#define S5P_DIS_IRQ_CENTRAL0 0x1008
|
||||
@ -118,6 +134,31 @@
|
||||
#define EXYNOS_COMMON_OPTION(_nr) \
|
||||
(EXYNOS_COMMON_CONFIGURATION(_nr) + 0x8)
|
||||
|
||||
#define EXYNOS_CORE_LOCAL_PWR_EN 0x3
|
||||
|
||||
#define EXYNOS_ARM_COMMON_STATUS 0x2504
|
||||
#define EXYNOS_COMMON_OPTION(_nr) \
|
||||
(EXYNOS_COMMON_CONFIGURATION(_nr) + 0x8)
|
||||
|
||||
#define EXYNOS_ARM_L2_CONFIGURATION 0x2600
|
||||
#define EXYNOS_L2_CONFIGURATION(_nr) \
|
||||
(EXYNOS_ARM_L2_CONFIGURATION + ((_nr) * 0x80))
|
||||
#define EXYNOS_L2_STATUS(_nr) \
|
||||
(EXYNOS_L2_CONFIGURATION(_nr) + 0x4)
|
||||
#define EXYNOS_L2_OPTION(_nr) \
|
||||
(EXYNOS_L2_CONFIGURATION(_nr) + 0x8)
|
||||
#define EXYNOS_L2_COMMON_PWR_EN 0x3
|
||||
|
||||
#define EXYNOS_ARM_CORE_X_STATUS_OFFSET 0x4
|
||||
|
||||
#define EXYNOS5_APLL_SYSCLK_CONFIGURATION 0x2A00
|
||||
#define EXYNOS5_APLL_SYSCLK_STATUS 0x2A04
|
||||
|
||||
#define EXYNOS5_ARM_L2_OPTION 0x2608
|
||||
#define EXYNOS5_USE_RETENTION BIT(4)
|
||||
|
||||
#define EXYNOS5_L2RSTDISABLE_VALUE BIT(3)
|
||||
|
||||
#define S5P_PAD_RET_MAUDIO_OPTION 0x3028
|
||||
#define S5P_PAD_RET_GPIO_OPTION 0x3108
|
||||
#define S5P_PAD_RET_UART_OPTION 0x3128
|
||||
@ -126,7 +167,19 @@
|
||||
#define S5P_PAD_RET_EBIA_OPTION 0x3188
|
||||
#define S5P_PAD_RET_EBIB_OPTION 0x31A8
|
||||
|
||||
#define S5P_PS_HOLD_CONTROL 0x330C
|
||||
#define S5P_PS_HOLD_EN (1 << 31)
|
||||
#define S5P_PS_HOLD_OUTPUT_HIGH (3 << 8)
|
||||
|
||||
#define S5P_CAM_OPTION 0x3C08
|
||||
#define S5P_MFC_OPTION 0x3C48
|
||||
#define S5P_G3D_OPTION 0x3C68
|
||||
#define S5P_LCD0_OPTION 0x3C88
|
||||
#define S5P_LCD1_OPTION 0x3CA8
|
||||
#define S5P_ISP_OPTION S5P_LCD1_OPTION
|
||||
|
||||
#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
|
||||
@ -185,11 +238,116 @@
|
||||
#define S5P_DIS_IRQ_CORE3 0x1034
|
||||
#define S5P_DIS_IRQ_CENTRAL3 0x1038
|
||||
|
||||
/* Only for EXYNOS3XXX */
|
||||
#define EXYNOS3_ARM_CORE0_SYS_PWR_REG 0x1000
|
||||
#define EXYNOS3_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG 0x1004
|
||||
#define EXYNOS3_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG 0x1008
|
||||
#define EXYNOS3_ARM_CORE1_SYS_PWR_REG 0x1010
|
||||
#define EXYNOS3_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG 0x1014
|
||||
#define EXYNOS3_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG 0x1018
|
||||
#define EXYNOS3_ISP_ARM_SYS_PWR_REG 0x1050
|
||||
#define EXYNOS3_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG 0x1054
|
||||
#define EXYNOS3_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG 0x1058
|
||||
#define EXYNOS3_ARM_COMMON_SYS_PWR_REG 0x1080
|
||||
#define EXYNOS3_ARM_L2_SYS_PWR_REG 0x10C0
|
||||
#define EXYNOS3_CMU_ACLKSTOP_SYS_PWR_REG 0x1100
|
||||
#define EXYNOS3_CMU_SCLKSTOP_SYS_PWR_REG 0x1104
|
||||
#define EXYNOS3_CMU_RESET_SYS_PWR_REG 0x110C
|
||||
#define EXYNOS3_CMU_ACLKSTOP_COREBLK_SYS_PWR_REG 0x1110
|
||||
#define EXYNOS3_CMU_SCLKSTOP_COREBLK_SYS_PWR_REG 0x1114
|
||||
#define EXYNOS3_CMU_RESET_COREBLK_SYS_PWR_REG 0x111C
|
||||
#define EXYNOS3_APLL_SYSCLK_SYS_PWR_REG 0x1120
|
||||
#define EXYNOS3_MPLL_SYSCLK_SYS_PWR_REG 0x1124
|
||||
#define EXYNOS3_VPLL_SYSCLK_SYS_PWR_REG 0x1128
|
||||
#define EXYNOS3_EPLL_SYSCLK_SYS_PWR_REG 0x112C
|
||||
#define EXYNOS3_MPLLUSER_SYSCLK_SYS_PWR_REG 0x1130
|
||||
#define EXYNOS3_BPLLUSER_SYSCLK_SYS_PWR_REG 0x1134
|
||||
#define EXYNOS3_EPLLUSER_SYSCLK_SYS_PWR_REG 0x1138
|
||||
#define EXYNOS3_CMU_CLKSTOP_CAM_SYS_PWR_REG 0x1140
|
||||
#define EXYNOS3_CMU_CLKSTOP_MFC_SYS_PWR_REG 0x1148
|
||||
#define EXYNOS3_CMU_CLKSTOP_G3D_SYS_PWR_REG 0x114C
|
||||
#define EXYNOS3_CMU_CLKSTOP_LCD0_SYS_PWR_REG 0x1150
|
||||
#define EXYNOS3_CMU_CLKSTOP_ISP_SYS_PWR_REG 0x1154
|
||||
#define EXYNOS3_CMU_CLKSTOP_MAUDIO_SYS_PWR_REG 0x1158
|
||||
#define EXYNOS3_CMU_RESET_CAM_SYS_PWR_REG 0x1160
|
||||
#define EXYNOS3_CMU_RESET_MFC_SYS_PWR_REG 0x1168
|
||||
#define EXYNOS3_CMU_RESET_G3D_SYS_PWR_REG 0x116C
|
||||
#define EXYNOS3_CMU_RESET_LCD0_SYS_PWR_REG 0x1170
|
||||
#define EXYNOS3_CMU_RESET_ISP_SYS_PWR_REG 0x1174
|
||||
#define EXYNOS3_CMU_RESET_MAUDIO_SYS_PWR_REG 0x1178
|
||||
#define EXYNOS3_TOP_BUS_SYS_PWR_REG 0x1180
|
||||
#define EXYNOS3_TOP_RETENTION_SYS_PWR_REG 0x1184
|
||||
#define EXYNOS3_TOP_PWR_SYS_PWR_REG 0x1188
|
||||
#define EXYNOS3_TOP_BUS_COREBLK_SYS_PWR_REG 0x1190
|
||||
#define EXYNOS3_TOP_RETENTION_COREBLK_SYS_PWR_REG 0x1194
|
||||
#define EXYNOS3_TOP_PWR_COREBLK_SYS_PWR_REG 0x1198
|
||||
#define EXYNOS3_LOGIC_RESET_SYS_PWR_REG 0x11A0
|
||||
#define EXYNOS3_OSCCLK_GATE_SYS_PWR_REG 0x11A4
|
||||
#define EXYNOS3_LOGIC_RESET_COREBLK_SYS_PWR_REG 0x11B0
|
||||
#define EXYNOS3_OSCCLK_GATE_COREBLK_SYS_PWR_REG 0x11B4
|
||||
#define EXYNOS3_PAD_RETENTION_DRAM_SYS_PWR_REG 0x1200
|
||||
#define EXYNOS3_PAD_RETENTION_MAUDIO_SYS_PWR_REG 0x1204
|
||||
#define EXYNOS3_PAD_RETENTION_SPI_SYS_PWR_REG 0x1208
|
||||
#define EXYNOS3_PAD_RETENTION_MMC2_SYS_PWR_REG 0x1218
|
||||
#define EXYNOS3_PAD_RETENTION_GPIO_SYS_PWR_REG 0x1220
|
||||
#define EXYNOS3_PAD_RETENTION_UART_SYS_PWR_REG 0x1224
|
||||
#define EXYNOS3_PAD_RETENTION_MMC0_SYS_PWR_REG 0x1228
|
||||
#define EXYNOS3_PAD_RETENTION_MMC1_SYS_PWR_REG 0x122C
|
||||
#define EXYNOS3_PAD_RETENTION_EBIA_SYS_PWR_REG 0x1230
|
||||
#define EXYNOS3_PAD_RETENTION_EBIB_SYS_PWR_REG 0x1234
|
||||
#define EXYNOS3_PAD_RETENTION_JTAG_SYS_PWR_REG 0x1238
|
||||
#define EXYNOS3_PAD_ISOLATION_SYS_PWR_REG 0x1240
|
||||
#define EXYNOS3_PAD_ALV_SEL_SYS_PWR_REG 0x1260
|
||||
#define EXYNOS3_XUSBXTI_SYS_PWR_REG 0x1280
|
||||
#define EXYNOS3_XXTI_SYS_PWR_REG 0x1284
|
||||
#define EXYNOS3_EXT_REGULATOR_SYS_PWR_REG 0x12C0
|
||||
#define EXYNOS3_EXT_REGULATOR_COREBLK_SYS_PWR_REG 0x12C4
|
||||
#define EXYNOS3_GPIO_MODE_SYS_PWR_REG 0x1300
|
||||
#define EXYNOS3_GPIO_MODE_MAUDIO_SYS_PWR_REG 0x1340
|
||||
#define EXYNOS3_TOP_ASB_RESET_SYS_PWR_REG 0x1344
|
||||
#define EXYNOS3_TOP_ASB_ISOLATION_SYS_PWR_REG 0x1348
|
||||
#define EXYNOS3_TOP_ASB_RESET_COREBLK_SYS_PWR_REG 0x1350
|
||||
#define EXYNOS3_TOP_ASB_ISOLATION_COREBLK_SYS_PWR_REG 0x1354
|
||||
#define EXYNOS3_CAM_SYS_PWR_REG 0x1380
|
||||
#define EXYNOS3_MFC_SYS_PWR_REG 0x1388
|
||||
#define EXYNOS3_G3D_SYS_PWR_REG 0x138C
|
||||
#define EXYNOS3_LCD0_SYS_PWR_REG 0x1390
|
||||
#define EXYNOS3_ISP_SYS_PWR_REG 0x1394
|
||||
#define EXYNOS3_MAUDIO_SYS_PWR_REG 0x1398
|
||||
#define EXYNOS3_DRAM_FREQ_DOWN_SYS_PWR_REG 0x13B0
|
||||
#define EXYNOS3_DDRPHY_DLLOFF_SYS_PWR_REG 0x13B4
|
||||
#define EXYNOS3_CMU_SYSCLK_ISP_SYS_PWR_REG 0x13B8
|
||||
#define EXYNOS3_LPDDR_PHY_DLL_LOCK_SYS_PWR_REG 0x13C0
|
||||
#define EXYNOS3_BPLL_SYSCLK_SYS_PWR_REG 0x13C4
|
||||
#define EXYNOS3_UPLL_SYSCLK_SYS_PWR_REG 0x13C8
|
||||
|
||||
#define EXYNOS3_ARM_CORE0_OPTION 0x2008
|
||||
#define EXYNOS3_ARM_CORE_OPTION(_nr) \
|
||||
(EXYNOS3_ARM_CORE0_OPTION + ((_nr) * 0x80))
|
||||
|
||||
#define EXYNOS3_ARM_COMMON_OPTION 0x2408
|
||||
#define EXYNOS3_TOP_PWR_OPTION 0x2C48
|
||||
#define EXYNOS3_CORE_TOP_PWR_OPTION 0x2CA8
|
||||
#define EXYNOS3_XUSBXTI_DURATION 0x341C
|
||||
#define EXYNOS3_XXTI_DURATION 0x343C
|
||||
#define EXYNOS3_EXT_REGULATOR_DURATION 0x361C
|
||||
#define EXYNOS3_EXT_REGULATOR_COREBLK_DURATION 0x363C
|
||||
#define XUSBXTI_DURATION 0x00000BB8
|
||||
#define XXTI_DURATION XUSBXTI_DURATION
|
||||
#define EXT_REGULATOR_DURATION 0x00001D4C
|
||||
#define EXT_REGULATOR_COREBLK_DURATION EXT_REGULATOR_DURATION
|
||||
|
||||
/* for XXX_OPTION */
|
||||
#define EXYNOS3_OPTION_USE_SC_COUNTER (1 << 0)
|
||||
#define EXYNOS3_OPTION_USE_SC_FEEDBACK (1 << 1)
|
||||
#define EXYNOS3_OPTION_SKIP_DEACTIVATE_ACEACP_IN_PWDN (1 << 7)
|
||||
|
||||
/* For EXYNOS5 */
|
||||
|
||||
#define EXYNOS5_AUTO_WDTRESET_DISABLE 0x0408
|
||||
#define EXYNOS5_MASK_WDTRESET_REQUEST 0x040C
|
||||
|
||||
#define EXYNOS5_USE_RETENTION BIT(4)
|
||||
#define EXYNOS5_SYS_WDTRESET (1 << 20)
|
||||
|
||||
#define EXYNOS5_ARM_CORE0_SYS_PWR_REG 0x1000
|
||||
@ -329,4 +487,204 @@ static inline unsigned int exynos_pmu_cpunr(unsigned int mpidr)
|
||||
+ MPIDR_AFFINITY_LEVEL(mpidr, 0));
|
||||
}
|
||||
|
||||
/* Only for EXYNOS5420 */
|
||||
#define EXYNOS5420_ISP_ARM_OPTION 0x2488
|
||||
#define EXYNOS5420_L2RSTDISABLE_VALUE BIT(3)
|
||||
|
||||
#define EXYNOS5420_LPI_MASK 0x0004
|
||||
#define EXYNOS5420_LPI_MASK1 0x0008
|
||||
#define EXYNOS5420_UFS BIT(8)
|
||||
#define EXYNOS5420_ATB_KFC BIT(13)
|
||||
#define EXYNOS5420_ATB_ISP_ARM BIT(19)
|
||||
#define EXYNOS5420_EMULATION BIT(31)
|
||||
#define ATB_ISP_ARM BIT(12)
|
||||
#define ATB_KFC BIT(13)
|
||||
#define ATB_NOC BIT(14)
|
||||
|
||||
#define EXYNOS5420_ARM_INTR_SPREAD_ENABLE 0x0100
|
||||
#define EXYNOS5420_ARM_INTR_SPREAD_USE_STANDBYWFI 0x0104
|
||||
#define EXYNOS5420_UP_SCHEDULER 0x0120
|
||||
#define SPREAD_ENABLE 0xF
|
||||
#define SPREAD_USE_STANDWFI 0xF
|
||||
|
||||
#define EXYNOS5420_BB_CON1 0x0784
|
||||
#define EXYNOS5420_BB_SEL_EN BIT(31)
|
||||
#define EXYNOS5420_BB_PMOS_EN BIT(7)
|
||||
#define EXYNOS5420_BB_1300X 0XF
|
||||
|
||||
#define EXYNOS5420_ARM_CORE2_SYS_PWR_REG 0x1020
|
||||
#define EXYNOS5420_DIS_IRQ_ARM_CORE2_LOCAL_SYS_PWR_REG 0x1024
|
||||
#define EXYNOS5420_DIS_IRQ_ARM_CORE2_CENTRAL_SYS_PWR_REG 0x1028
|
||||
#define EXYNOS5420_ARM_CORE3_SYS_PWR_REG 0x1030
|
||||
#define EXYNOS5420_DIS_IRQ_ARM_CORE3_LOCAL_SYS_PWR_REG 0x1034
|
||||
#define EXYNOS5420_DIS_IRQ_ARM_CORE3_CENTRAL_SYS_PWR_REG 0x1038
|
||||
#define EXYNOS5420_KFC_CORE0_SYS_PWR_REG 0x1040
|
||||
#define EXYNOS5420_DIS_IRQ_KFC_CORE0_LOCAL_SYS_PWR_REG 0x1044
|
||||
#define EXYNOS5420_DIS_IRQ_KFC_CORE0_CENTRAL_SYS_PWR_REG 0x1048
|
||||
#define EXYNOS5420_KFC_CORE1_SYS_PWR_REG 0x1050
|
||||
#define EXYNOS5420_DIS_IRQ_KFC_CORE1_LOCAL_SYS_PWR_REG 0x1054
|
||||
#define EXYNOS5420_DIS_IRQ_KFC_CORE1_CENTRAL_SYS_PWR_REG 0x1058
|
||||
#define EXYNOS5420_KFC_CORE2_SYS_PWR_REG 0x1060
|
||||
#define EXYNOS5420_DIS_IRQ_KFC_CORE2_LOCAL_SYS_PWR_REG 0x1064
|
||||
#define EXYNOS5420_DIS_IRQ_KFC_CORE2_CENTRAL_SYS_PWR_REG 0x1068
|
||||
#define EXYNOS5420_KFC_CORE3_SYS_PWR_REG 0x1070
|
||||
#define EXYNOS5420_DIS_IRQ_KFC_CORE3_LOCAL_SYS_PWR_REG 0x1074
|
||||
#define EXYNOS5420_DIS_IRQ_KFC_CORE3_CENTRAL_SYS_PWR_REG 0x1078
|
||||
#define EXYNOS5420_ISP_ARM_SYS_PWR_REG 0x1090
|
||||
#define EXYNOS5420_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG 0x1094
|
||||
#define EXYNOS5420_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG 0x1098
|
||||
#define EXYNOS5420_ARM_COMMON_SYS_PWR_REG 0x10A0
|
||||
#define EXYNOS5420_KFC_COMMON_SYS_PWR_REG 0x10B0
|
||||
#define EXYNOS5420_KFC_L2_SYS_PWR_REG 0x10D0
|
||||
#define EXYNOS5420_DPLL_SYSCLK_SYS_PWR_REG 0x1158
|
||||
#define EXYNOS5420_IPLL_SYSCLK_SYS_PWR_REG 0x115C
|
||||
#define EXYNOS5420_KPLL_SYSCLK_SYS_PWR_REG 0x1160
|
||||
#define EXYNOS5420_RPLL_SYSCLK_SYS_PWR_REG 0x1174
|
||||
#define EXYNOS5420_SPLL_SYSCLK_SYS_PWR_REG 0x1178
|
||||
#define EXYNOS5420_INTRAM_MEM_SYS_PWR_REG 0x11B8
|
||||
#define EXYNOS5420_INTROM_MEM_SYS_PWR_REG 0x11BC
|
||||
#define EXYNOS5420_ONENANDXL_MEM_SYS_PWR 0x11C0
|
||||
#define EXYNOS5420_USBDEV_MEM_SYS_PWR 0x11CC
|
||||
#define EXYNOS5420_USBDEV1_MEM_SYS_PWR 0x11D0
|
||||
#define EXYNOS5420_SDMMC_MEM_SYS_PWR 0x11D4
|
||||
#define EXYNOS5420_CSSYS_MEM_SYS_PWR 0x11D8
|
||||
#define EXYNOS5420_SECSS_MEM_SYS_PWR 0x11DC
|
||||
#define EXYNOS5420_ROTATOR_MEM_SYS_PWR 0x11E0
|
||||
#define EXYNOS5420_INTRAM_MEM_SYS_PWR 0x11E4
|
||||
#define EXYNOS5420_INTROM_MEM_SYS_PWR 0x11E8
|
||||
#define EXYNOS5420_PAD_RETENTION_JTAG_SYS_PWR_REG 0x1208
|
||||
#define EXYNOS5420_PAD_RETENTION_DRAM_SYS_PWR_REG 0x1210
|
||||
#define EXYNOS5420_PAD_RETENTION_UART_SYS_PWR_REG 0x1214
|
||||
#define EXYNOS5420_PAD_RETENTION_MMC0_SYS_PWR_REG 0x1218
|
||||
#define EXYNOS5420_PAD_RETENTION_MMC1_SYS_PWR_REG 0x121C
|
||||
#define EXYNOS5420_PAD_RETENTION_MMC2_SYS_PWR_REG 0x1220
|
||||
#define EXYNOS5420_PAD_RETENTION_HSI_SYS_PWR_REG 0x1224
|
||||
#define EXYNOS5420_PAD_RETENTION_EBIA_SYS_PWR_REG 0x1228
|
||||
#define EXYNOS5420_PAD_RETENTION_EBIB_SYS_PWR_REG 0x122C
|
||||
#define EXYNOS5420_PAD_RETENTION_SPI_SYS_PWR_REG 0x1230
|
||||
#define EXYNOS5420_PAD_RETENTION_DRAM_COREBLK_SYS_PWR_REG 0x1234
|
||||
#define EXYNOS5420_DISP1_SYS_PWR_REG 0x1410
|
||||
#define EXYNOS5420_MAU_SYS_PWR_REG 0x1414
|
||||
#define EXYNOS5420_G2D_SYS_PWR_REG 0x1418
|
||||
#define EXYNOS5420_MSC_SYS_PWR_REG 0x141C
|
||||
#define EXYNOS5420_FSYS_SYS_PWR_REG 0x1420
|
||||
#define EXYNOS5420_FSYS2_SYS_PWR_REG 0x1424
|
||||
#define EXYNOS5420_PSGEN_SYS_PWR_REG 0x1428
|
||||
#define EXYNOS5420_PERIC_SYS_PWR_REG 0x142C
|
||||
#define EXYNOS5420_WCORE_SYS_PWR_REG 0x1430
|
||||
#define EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG 0x1490
|
||||
#define EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG 0x1494
|
||||
#define EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG 0x1498
|
||||
#define EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG 0x149C
|
||||
#define EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG 0x14A0
|
||||
#define EXYNOS5420_CMU_CLKSTOP_FSYS2_SYS_PWR_REG 0x14A4
|
||||
#define EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG 0x14A8
|
||||
#define EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG 0x14AC
|
||||
#define EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG 0x14B0
|
||||
#define EXYNOS5420_CMU_SYSCLK_TOPPWR_SYS_PWR_REG 0x14BC
|
||||
#define EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG 0x14D0
|
||||
#define EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG 0x14D4
|
||||
#define EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG 0x14D8
|
||||
#define EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG 0x14DC
|
||||
#define EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG 0x14E0
|
||||
#define EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG 0x14E4
|
||||
#define EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG 0x14E8
|
||||
#define EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG 0x14EC
|
||||
#define EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG 0x14F0
|
||||
#define EXYNOS5420_CMU_SYSCLK_SYSMEM_TOPPWR_SYS_PWR_REG 0x14F4
|
||||
#define EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG 0x1570
|
||||
#define EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG 0x1574
|
||||
#define EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG 0x1578
|
||||
#define EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG 0x157C
|
||||
#define EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG 0x1590
|
||||
#define EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG 0x1594
|
||||
#define EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG 0x1598
|
||||
#define EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG 0x159C
|
||||
#define EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG 0x15A0
|
||||
#define EXYNOS5420_SFR_AXI_CGDIS1 0x15E4
|
||||
#define EXYNOS_ARM_CORE2_CONFIGURATION 0x2100
|
||||
#define EXYNOS5420_ARM_CORE2_OPTION 0x2108
|
||||
#define EXYNOS_ARM_CORE3_CONFIGURATION 0x2180
|
||||
#define EXYNOS5420_ARM_CORE3_OPTION 0x2188
|
||||
#define EXYNOS5420_ARM_COMMON_STATUS 0x2504
|
||||
#define EXYNOS5420_ARM_COMMON_OPTION 0x2508
|
||||
#define EXYNOS5420_KFC_COMMON_STATUS 0x2584
|
||||
#define EXYNOS5420_KFC_COMMON_OPTION 0x2588
|
||||
#define EXYNOS5420_LOGIC_RESET_DURATION3 0x2D1C
|
||||
|
||||
#define EXYNOS5420_PAD_RET_GPIO_OPTION 0x30C8
|
||||
#define EXYNOS5420_PAD_RET_UART_OPTION 0x30E8
|
||||
#define EXYNOS5420_PAD_RET_MMCA_OPTION 0x3108
|
||||
#define EXYNOS5420_PAD_RET_MMCB_OPTION 0x3128
|
||||
#define EXYNOS5420_PAD_RET_MMCC_OPTION 0x3148
|
||||
#define EXYNOS5420_PAD_RET_HSI_OPTION 0x3168
|
||||
#define EXYNOS5420_PAD_RET_SPI_OPTION 0x31C8
|
||||
#define EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION 0x31E8
|
||||
#define EXYNOS_PAD_RET_DRAM_OPTION 0x3008
|
||||
#define EXYNOS_PAD_RET_MAUDIO_OPTION 0x3028
|
||||
#define EXYNOS_PAD_RET_JTAG_OPTION 0x3048
|
||||
#define EXYNOS_PAD_RET_GPIO_OPTION 0x3108
|
||||
#define EXYNOS_PAD_RET_UART_OPTION 0x3128
|
||||
#define EXYNOS_PAD_RET_MMCA_OPTION 0x3148
|
||||
#define EXYNOS_PAD_RET_MMCB_OPTION 0x3168
|
||||
#define EXYNOS_PAD_RET_EBIA_OPTION 0x3188
|
||||
#define EXYNOS_PAD_RET_EBIB_OPTION 0x31A8
|
||||
|
||||
#define EXYNOS_PS_HOLD_CONTROL 0x330C
|
||||
|
||||
/* For SYS_PWR_REG */
|
||||
#define EXYNOS_SYS_PWR_CFG BIT(0)
|
||||
|
||||
#define EXYNOS5420_MFC_CONFIGURATION 0x4060
|
||||
#define EXYNOS5420_MFC_STATUS 0x4064
|
||||
#define EXYNOS5420_MFC_OPTION 0x4068
|
||||
#define EXYNOS5420_G3D_CONFIGURATION 0x4080
|
||||
#define EXYNOS5420_G3D_STATUS 0x4084
|
||||
#define EXYNOS5420_G3D_OPTION 0x4088
|
||||
#define EXYNOS5420_DISP0_CONFIGURATION 0x40A0
|
||||
#define EXYNOS5420_DISP0_STATUS 0x40A4
|
||||
#define EXYNOS5420_DISP0_OPTION 0x40A8
|
||||
#define EXYNOS5420_DISP1_CONFIGURATION 0x40C0
|
||||
#define EXYNOS5420_DISP1_STATUS 0x40C4
|
||||
#define EXYNOS5420_DISP1_OPTION 0x40C8
|
||||
#define EXYNOS5420_MAU_CONFIGURATION 0x40E0
|
||||
#define EXYNOS5420_MAU_STATUS 0x40E4
|
||||
#define EXYNOS5420_MAU_OPTION 0x40E8
|
||||
#define EXYNOS5420_FSYS2_OPTION 0x4168
|
||||
#define EXYNOS5420_PSGEN_OPTION 0x4188
|
||||
|
||||
/* For EXYNOS_CENTRAL_SEQ_OPTION */
|
||||
#define EXYNOS5_USE_STANDBYWFI_ARM_CORE0 BIT(16)
|
||||
#define EXYNOS5_USE_STANDBYWFI_ARM_CORE1 BUT(17)
|
||||
#define EXYNOS5_USE_STANDBYWFE_ARM_CORE0 BIT(24)
|
||||
#define EXYNOS5_USE_STANDBYWFE_ARM_CORE1 BIT(25)
|
||||
|
||||
#define EXYNOS5420_ARM_USE_STANDBY_WFI0 BIT(4)
|
||||
#define EXYNOS5420_ARM_USE_STANDBY_WFI1 BIT(5)
|
||||
#define EXYNOS5420_ARM_USE_STANDBY_WFI2 BIT(6)
|
||||
#define EXYNOS5420_ARM_USE_STANDBY_WFI3 BIT(7)
|
||||
#define EXYNOS5420_KFC_USE_STANDBY_WFI0 BIT(8)
|
||||
#define EXYNOS5420_KFC_USE_STANDBY_WFI1 BIT(9)
|
||||
#define EXYNOS5420_KFC_USE_STANDBY_WFI2 BIT(10)
|
||||
#define EXYNOS5420_KFC_USE_STANDBY_WFI3 BIT(11)
|
||||
#define EXYNOS5420_ARM_USE_STANDBY_WFE0 BIT(16)
|
||||
#define EXYNOS5420_ARM_USE_STANDBY_WFE1 BIT(17)
|
||||
#define EXYNOS5420_ARM_USE_STANDBY_WFE2 BIT(18)
|
||||
#define EXYNOS5420_ARM_USE_STANDBY_WFE3 BIT(19)
|
||||
#define EXYNOS5420_KFC_USE_STANDBY_WFE0 BIT(20)
|
||||
#define EXYNOS5420_KFC_USE_STANDBY_WFE1 BIT(21)
|
||||
#define EXYNOS5420_KFC_USE_STANDBY_WFE2 BIT(22)
|
||||
#define EXYNOS5420_KFC_USE_STANDBY_WFE3 BIT(23)
|
||||
|
||||
#define DUR_WAIT_RESET 0xF
|
||||
|
||||
#define EXYNOS5420_USE_STANDBY_WFI_ALL (EXYNOS5420_ARM_USE_STANDBY_WFI0 \
|
||||
| EXYNOS5420_ARM_USE_STANDBY_WFI1 \
|
||||
| EXYNOS5420_ARM_USE_STANDBY_WFI2 \
|
||||
| EXYNOS5420_ARM_USE_STANDBY_WFI3 \
|
||||
| EXYNOS5420_KFC_USE_STANDBY_WFI0 \
|
||||
| EXYNOS5420_KFC_USE_STANDBY_WFI1 \
|
||||
| EXYNOS5420_KFC_USE_STANDBY_WFI2 \
|
||||
| EXYNOS5420_KFC_USE_STANDBY_WFI3)
|
||||
|
||||
#endif /* __ASM_ARCH_REGS_PMU_H */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
566
arch/arm/mach-exynos/suspend.c
Normal file
566
arch/arm/mach-exynos/suspend.c
Normal file
@ -0,0 +1,566 @@
|
||||
/*
|
||||
* 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 <linux/regulator/machine.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/hardware/cache-l2x0.h>
|
||||
#include <asm/firmware.h>
|
||||
#include <asm/mcpm.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"
|
||||
#include "exynos-pmu.h"
|
||||
|
||||
#define S5P_CHECK_SLEEP 0x00000BAD
|
||||
|
||||
#define REG_TABLE_END (-1U)
|
||||
|
||||
#define EXYNOS5420_CPU_STATE 0x28
|
||||
|
||||
/**
|
||||
* 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_prepare)(void);
|
||||
void (*pm_resume)(void);
|
||||
int (*pm_suspend)(void);
|
||||
int (*cpu_suspend)(unsigned long);
|
||||
};
|
||||
|
||||
struct exynos_pm_data *pm_data;
|
||||
|
||||
static int exynos5420_cpu_state;
|
||||
static unsigned int exynos_pmu_spare3;
|
||||
|
||||
/*
|
||||
* 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,
|
||||
};
|
||||
|
||||
unsigned int exynos5420_release_ret_regs[] = {
|
||||
EXYNOS_PAD_RET_DRAM_OPTION,
|
||||
EXYNOS_PAD_RET_MAUDIO_OPTION,
|
||||
EXYNOS_PAD_RET_JTAG_OPTION,
|
||||
EXYNOS5420_PAD_RET_GPIO_OPTION,
|
||||
EXYNOS5420_PAD_RET_UART_OPTION,
|
||||
EXYNOS5420_PAD_RET_MMCA_OPTION,
|
||||
EXYNOS5420_PAD_RET_MMCB_OPTION,
|
||||
EXYNOS5420_PAD_RET_MMCC_OPTION,
|
||||
EXYNOS5420_PAD_RET_HSI_OPTION,
|
||||
EXYNOS_PAD_RET_EBIA_OPTION,
|
||||
EXYNOS_PAD_RET_EBIB_OPTION,
|
||||
EXYNOS5420_PAD_RET_SPI_OPTION,
|
||||
EXYNOS5420_PAD_RET_DRAM_COREBLK_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 void exynos_flush_cache_all(void)
|
||||
{
|
||||
flush_cache_all();
|
||||
outer_flush_all();
|
||||
}
|
||||
|
||||
static int exynos_cpu_suspend(unsigned long arg)
|
||||
{
|
||||
exynos_flush_cache_all();
|
||||
return exynos_cpu_do_idle();
|
||||
}
|
||||
|
||||
static int exynos5420_cpu_suspend(unsigned long arg)
|
||||
{
|
||||
/* MCPM works with HW CPU identifiers */
|
||||
unsigned int mpidr = read_cpuid_mpidr();
|
||||
unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
|
||||
unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
|
||||
|
||||
__raw_writel(0x0, sysram_base_addr + EXYNOS5420_CPU_STATE);
|
||||
|
||||
if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) {
|
||||
mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume);
|
||||
|
||||
/*
|
||||
* Residency value passed to mcpm_cpu_suspend back-end
|
||||
* has to be given clear semantics. Set to 0 as a
|
||||
* temporary value.
|
||||
*/
|
||||
mcpm_cpu_suspend(0);
|
||||
}
|
||||
|
||||
pr_info("Failed to suspend the system\n");
|
||||
|
||||
/* return value != 0 means failure */
|
||||
return 1;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
/* ensure at least INFORM0 has the resume address */
|
||||
pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0);
|
||||
}
|
||||
|
||||
static void exynos5420_pm_prepare(void)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
/* Set wake-up mask registers */
|
||||
exynos_pm_set_wakeup_mask();
|
||||
|
||||
s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save));
|
||||
|
||||
exynos_pmu_spare3 = pmu_raw_readl(S5P_PMU_SPARE3);
|
||||
/*
|
||||
* The cpu state needs to be saved and restored so that the
|
||||
* secondary CPUs will enter low power start. Though the U-Boot
|
||||
* is setting the cpu state with low power flag, the kernel
|
||||
* needs to restore it back in case, the primary cpu fails to
|
||||
* suspend for any reason.
|
||||
*/
|
||||
exynos5420_cpu_state = __raw_readl(sysram_base_addr +
|
||||
EXYNOS5420_CPU_STATE);
|
||||
|
||||
exynos_pm_enter_sleep_mode();
|
||||
|
||||
/* ensure at least INFORM0 has the resume address */
|
||||
if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
|
||||
pmu_raw_writel(virt_to_phys(mcpm_entry_point), S5P_INFORM0);
|
||||
|
||||
tmp = pmu_raw_readl(EXYNOS5_ARM_L2_OPTION);
|
||||
tmp &= ~EXYNOS5_USE_RETENTION;
|
||||
pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION);
|
||||
|
||||
tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1);
|
||||
tmp |= EXYNOS5420_UFS;
|
||||
pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1);
|
||||
|
||||
tmp = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION);
|
||||
tmp &= ~EXYNOS5420_L2RSTDISABLE_VALUE;
|
||||
pmu_raw_writel(tmp, EXYNOS5420_ARM_COMMON_OPTION);
|
||||
|
||||
tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION);
|
||||
tmp |= EXYNOS5420_EMULATION;
|
||||
pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION);
|
||||
|
||||
tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION);
|
||||
tmp |= EXYNOS5420_EMULATION;
|
||||
pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION);
|
||||
}
|
||||
|
||||
|
||||
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 int exynos5420_pm_suspend(void)
|
||||
{
|
||||
u32 this_cluster;
|
||||
|
||||
exynos_pm_central_suspend();
|
||||
|
||||
/* Setting SEQ_OPTION register */
|
||||
|
||||
this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
|
||||
if (!this_cluster)
|
||||
pmu_raw_writel(EXYNOS5420_ARM_USE_STANDBY_WFI0,
|
||||
S5P_CENTRAL_SEQ_OPTION);
|
||||
else
|
||||
pmu_raw_writel(EXYNOS5420_KFC_USE_STANDBY_WFI0,
|
||||
S5P_CENTRAL_SEQ_OPTION);
|
||||
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);
|
||||
}
|
||||
|
||||
static void exynos5420_prepare_pm_resume(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
|
||||
WARN_ON(mcpm_cpu_powered_up());
|
||||
}
|
||||
|
||||
static void exynos5420_pm_resume(void)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
||||
/* Restore the CPU0 low power state register */
|
||||
tmp = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG);
|
||||
pmu_raw_writel(tmp | S5P_CORE_LOCAL_PWR_EN,
|
||||
EXYNOS5_ARM_CORE0_SYS_PWR_REG);
|
||||
|
||||
/* Restore the sysram cpu state register */
|
||||
__raw_writel(exynos5420_cpu_state,
|
||||
sysram_base_addr + EXYNOS5420_CPU_STATE);
|
||||
|
||||
pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL,
|
||||
S5P_CENTRAL_SEQ_OPTION);
|
||||
|
||||
if (exynos_pm_central_resume())
|
||||
goto early_wakeup;
|
||||
|
||||
/* For release retention */
|
||||
exynos_pm_release_retention();
|
||||
|
||||
pmu_raw_writel(exynos_pmu_spare3, S5P_PMU_SPARE3);
|
||||
|
||||
s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
|
||||
|
||||
early_wakeup:
|
||||
|
||||
tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1);
|
||||
tmp &= ~EXYNOS5420_UFS;
|
||||
pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1);
|
||||
|
||||
tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION);
|
||||
tmp &= ~EXYNOS5420_EMULATION;
|
||||
pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION);
|
||||
|
||||
tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION);
|
||||
tmp &= ~EXYNOS5420_EMULATION;
|
||||
pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION);
|
||||
|
||||
/* 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;
|
||||
|
||||
if (pm_data->pm_resume_prepare)
|
||||
pm_data->pm_resume_prepare();
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* REVISIT: It would be better if struct platform_suspend_ops
|
||||
* .prepare handler get the suspend_state_t as a parameter to
|
||||
* avoid hard-coding the suspend to mem state. It's safe to do
|
||||
* it now only because the suspend_valid_only_mem function is
|
||||
* used as the .valid callback used to check if a given state
|
||||
* is supported by the platform anyways.
|
||||
*/
|
||||
ret = regulator_suspend_prepare(PM_SUSPEND_MEM);
|
||||
if (ret) {
|
||||
pr_err("Failed to prepare regulators for suspend (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
s3c_pm_check_prepare();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos_suspend_finish(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
s3c_pm_check_cleanup();
|
||||
|
||||
ret = regulator_suspend_finish();
|
||||
if (ret)
|
||||
pr_warn("Failed to resume regulators from suspend (%d)\n", ret);
|
||||
}
|
||||
|
||||
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 exynos_pm_data exynos5420_pm_data = {
|
||||
.wkup_irq = exynos5250_wkup_irq,
|
||||
.wake_disable_mask = (0x7F << 7) | (0x1F << 1),
|
||||
.release_ret_regs = exynos5420_release_ret_regs,
|
||||
.pm_resume_prepare = exynos5420_prepare_pm_resume,
|
||||
.pm_resume = exynos5420_pm_resume,
|
||||
.pm_suspend = exynos5420_pm_suspend,
|
||||
.pm_prepare = exynos5420_pm_prepare,
|
||||
.cpu_suspend = exynos5420_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,
|
||||
}, {
|
||||
.compatible = "samsung,exynos5420-pmu",
|
||||
.data = &exynos5420_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);
|
||||
}
|
@ -633,12 +633,41 @@ config SOC_VF610
|
||||
bool "Vybrid Family VF610 support"
|
||||
select ARM_GIC
|
||||
select PINCTRL_VF610
|
||||
select VF_PIT_TIMER
|
||||
select PL310_ERRATA_769419 if CACHE_L2X0
|
||||
|
||||
help
|
||||
This enable support for Freescale Vybrid VF610 processor.
|
||||
|
||||
choice
|
||||
prompt "Clocksource for scheduler clock"
|
||||
depends on SOC_VF610
|
||||
default VF_USE_ARM_GLOBAL_TIMER
|
||||
|
||||
config VF_USE_ARM_GLOBAL_TIMER
|
||||
bool "Use ARM Global Timer"
|
||||
select ARM_GLOBAL_TIMER
|
||||
select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
|
||||
help
|
||||
Use the ARM Global Timer as clocksource
|
||||
|
||||
config VF_USE_PIT_TIMER
|
||||
bool "Use PIT timer"
|
||||
select VF_PIT_TIMER
|
||||
help
|
||||
Use SoC Periodic Interrupt Timer (PIT) as clocksource
|
||||
|
||||
endchoice
|
||||
|
||||
config SOC_LS1021A
|
||||
bool "Freescale LS1021A support"
|
||||
select ARM_GIC
|
||||
select HAVE_ARM_ARCH_TIMER
|
||||
select PCI_DOMAINS if PCI
|
||||
select ZONE_DMA if ARM_LPAE
|
||||
|
||||
help
|
||||
This enable support for Freescale LS1021A processor.
|
||||
|
||||
endif
|
||||
|
||||
source "arch/arm/mach-imx/devices/Kconfig"
|
||||
|
@ -12,7 +12,7 @@ obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clk-imx31.o iomux-imx31.o ehci-
|
||||
obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clk-imx35.o ehci-imx35.o pm-imx3.o
|
||||
|
||||
imx5-pm-$(CONFIG_PM) += pm-imx5.o
|
||||
obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o $(imx5-pm-y)
|
||||
obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o clk-cpu.o $(imx5-pm-y)
|
||||
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \
|
||||
clk-pfd.o clk-busy.o clk.o \
|
||||
@ -89,7 +89,7 @@ obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o
|
||||
obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
|
||||
obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
|
||||
obj-$(CONFIG_HAVE_IMX_SRC) += src.o
|
||||
ifdef CONFIG_SOC_IMX6
|
||||
ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),)
|
||||
AFLAGS_headsmp.o :=-Wa,-march=armv7-a
|
||||
obj-$(CONFIG_SMP) += headsmp.o platsmp.o
|
||||
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||
@ -110,4 +110,6 @@ obj-$(CONFIG_SOC_IMX53) += mach-imx53.o
|
||||
|
||||
obj-$(CONFIG_SOC_VF610) += clk-vf610.o mach-vf610.o
|
||||
|
||||
obj-$(CONFIG_SOC_LS1021A) += mach-ls1021a.o
|
||||
|
||||
obj-y += devices/
|
||||
|
@ -30,8 +30,11 @@
|
||||
#define ANADIG_DIGPROG_IMX6SL 0x280
|
||||
|
||||
#define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG 0x40000
|
||||
#define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN 0x8
|
||||
#define BM_ANADIG_REG_CORE_FET_ODRIVE 0x20000000
|
||||
#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG 0x1000
|
||||
/* Below MISC0_DISCON_HIGH_SNVS is only for i.MX6SL */
|
||||
#define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS 0x2000
|
||||
#define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B 0x80000
|
||||
#define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x100000
|
||||
|
||||
@ -56,16 +59,43 @@ static void imx_anatop_enable_fet_odrive(bool enable)
|
||||
BM_ANADIG_REG_CORE_FET_ODRIVE);
|
||||
}
|
||||
|
||||
static inline void imx_anatop_enable_2p5_pulldown(bool enable)
|
||||
{
|
||||
regmap_write(anatop, ANADIG_REG_2P5 + (enable ? REG_SET : REG_CLR),
|
||||
BM_ANADIG_REG_2P5_ENABLE_PULLDOWN);
|
||||
}
|
||||
|
||||
static inline void imx_anatop_disconnect_high_snvs(bool enable)
|
||||
{
|
||||
regmap_write(anatop, ANADIG_ANA_MISC0 + (enable ? REG_SET : REG_CLR),
|
||||
BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS);
|
||||
}
|
||||
|
||||
void imx_anatop_pre_suspend(void)
|
||||
{
|
||||
imx_anatop_enable_weak2p5(true);
|
||||
if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
|
||||
imx_anatop_enable_2p5_pulldown(true);
|
||||
else
|
||||
imx_anatop_enable_weak2p5(true);
|
||||
|
||||
imx_anatop_enable_fet_odrive(true);
|
||||
|
||||
if (cpu_is_imx6sl())
|
||||
imx_anatop_disconnect_high_snvs(true);
|
||||
}
|
||||
|
||||
void imx_anatop_post_resume(void)
|
||||
{
|
||||
if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
|
||||
imx_anatop_enable_2p5_pulldown(false);
|
||||
else
|
||||
imx_anatop_enable_weak2p5(false);
|
||||
|
||||
imx_anatop_enable_fet_odrive(false);
|
||||
imx_anatop_enable_weak2p5(false);
|
||||
|
||||
if (cpu_is_imx6sl())
|
||||
imx_anatop_disconnect_high_snvs(false);
|
||||
|
||||
}
|
||||
|
||||
static void imx_anatop_usb_chrg_detect_disable(void)
|
||||
|
107
arch/arm/mach-imx/clk-cpu.c
Normal file
107
arch/arm/mach-imx/clk-cpu.c
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Lucas Stach <l.stach@pengutronix.de>, Pengutronix
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct clk_cpu {
|
||||
struct clk_hw hw;
|
||||
struct clk *div;
|
||||
struct clk *mux;
|
||||
struct clk *pll;
|
||||
struct clk *step;
|
||||
};
|
||||
|
||||
static inline struct clk_cpu *to_clk_cpu(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct clk_cpu, hw);
|
||||
}
|
||||
|
||||
static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_cpu *cpu = to_clk_cpu(hw);
|
||||
|
||||
return clk_get_rate(cpu->div);
|
||||
}
|
||||
|
||||
static long clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_cpu *cpu = to_clk_cpu(hw);
|
||||
|
||||
return clk_round_rate(cpu->pll, rate);
|
||||
}
|
||||
|
||||
static int clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_cpu *cpu = to_clk_cpu(hw);
|
||||
int ret;
|
||||
|
||||
/* switch to PLL bypass clock */
|
||||
ret = clk_set_parent(cpu->mux, cpu->step);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* reprogram PLL */
|
||||
ret = clk_set_rate(cpu->pll, rate);
|
||||
if (ret) {
|
||||
clk_set_parent(cpu->mux, cpu->pll);
|
||||
return ret;
|
||||
}
|
||||
/* switch back to PLL clock */
|
||||
clk_set_parent(cpu->mux, cpu->pll);
|
||||
|
||||
/* Ensure the divider is what we expect */
|
||||
clk_set_rate(cpu->div, rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_cpu_ops = {
|
||||
.recalc_rate = clk_cpu_recalc_rate,
|
||||
.round_rate = clk_cpu_round_rate,
|
||||
.set_rate = clk_cpu_set_rate,
|
||||
};
|
||||
|
||||
struct clk *imx_clk_cpu(const char *name, const char *parent_name,
|
||||
struct clk *div, struct clk *mux, struct clk *pll,
|
||||
struct clk *step)
|
||||
{
|
||||
struct clk_cpu *cpu;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
cpu = kzalloc(sizeof(*cpu), GFP_KERNEL);
|
||||
if (!cpu)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
cpu->div = div;
|
||||
cpu->mux = mux;
|
||||
cpu->pll = pll;
|
||||
cpu->step = step;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_cpu_ops;
|
||||
init.flags = 0;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
|
||||
cpu->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &cpu->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(cpu);
|
||||
|
||||
return clk;
|
||||
}
|
@ -125,6 +125,8 @@ static const char *mx53_spdif_xtal_sel[] = { "osc", "ckih", "ckih2", "pll4_sw",
|
||||
static const char *spdif_sel[] = { "pll1_sw", "pll2_sw", "pll3_sw", "spdif_xtal_sel", };
|
||||
static const char *spdif0_com_sel[] = { "spdif0_podf", "ssi1_root_gate", };
|
||||
static const char *mx51_spdif1_com_sel[] = { "spdif1_podf", "ssi2_root_gate", };
|
||||
static const char *step_sels[] = { "lp_apm", };
|
||||
static const char *cpu_podf_sels[] = { "pll1_sw", "step_sel" };
|
||||
|
||||
static struct clk *clk[IMX5_CLK_END];
|
||||
static struct clk_onecell_data clk_data;
|
||||
@ -193,7 +195,9 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base)
|
||||
clk[IMX5_CLK_USB_PHY_PODF] = imx_clk_divider("usb_phy_podf", "usb_phy_pred", MXC_CCM_CDCDR, 0, 3);
|
||||
clk[IMX5_CLK_USB_PHY_SEL] = imx_clk_mux("usb_phy_sel", MXC_CCM_CSCMR1, 26, 1,
|
||||
usb_phy_sel_str, ARRAY_SIZE(usb_phy_sel_str));
|
||||
clk[IMX5_CLK_CPU_PODF] = imx_clk_divider("cpu_podf", "pll1_sw", MXC_CCM_CACRR, 0, 3);
|
||||
clk[IMX5_CLK_STEP_SEL] = imx_clk_mux("step_sel", MXC_CCM_CCSR, 7, 2, step_sels, ARRAY_SIZE(step_sels));
|
||||
clk[IMX5_CLK_CPU_PODF_SEL] = imx_clk_mux("cpu_podf_sel", MXC_CCM_CCSR, 2, 1, cpu_podf_sels, ARRAY_SIZE(cpu_podf_sels));
|
||||
clk[IMX5_CLK_CPU_PODF] = imx_clk_divider("cpu_podf", "cpu_podf_sel", MXC_CCM_CACRR, 0, 3);
|
||||
clk[IMX5_CLK_DI_PRED] = imx_clk_divider("di_pred", "pll3_sw", MXC_CCM_CDCDR, 6, 3);
|
||||
clk[IMX5_CLK_IIM_GATE] = imx_clk_gate2("iim_gate", "ipg", MXC_CCM_CCGR0, 30);
|
||||
clk[IMX5_CLK_UART1_IPG_GATE] = imx_clk_gate2("uart1_ipg_gate", "ipg", MXC_CCM_CCGR1, 6);
|
||||
@ -537,6 +541,11 @@ static void __init mx53_clocks_init(struct device_node *np)
|
||||
clk[IMX5_CLK_CKO2] = imx_clk_gate2("cko2", "cko2_podf", MXC_CCM_CCOSR, 24);
|
||||
clk[IMX5_CLK_SPDIF_XTAL_SEL] = imx_clk_mux("spdif_xtal_sel", MXC_CCM_CSCMR1, 2, 2,
|
||||
mx53_spdif_xtal_sel, ARRAY_SIZE(mx53_spdif_xtal_sel));
|
||||
clk[IMX5_CLK_ARM] = imx_clk_cpu("arm", "cpu_podf",
|
||||
clk[IMX5_CLK_CPU_PODF],
|
||||
clk[IMX5_CLK_CPU_PODF_SEL],
|
||||
clk[IMX5_CLK_PLL1_SW],
|
||||
clk[IMX5_CLK_STEP_SEL]);
|
||||
|
||||
imx_check_clocks(clk, ARRAY_SIZE(clk));
|
||||
|
||||
@ -551,6 +560,9 @@ static void __init mx53_clocks_init(struct device_node *np)
|
||||
/* move can bus clk to 24MHz */
|
||||
clk_set_parent(clk[IMX5_CLK_CAN_SEL], clk[IMX5_CLK_LP_APM]);
|
||||
|
||||
/* make sure step clock is running from 24MHz */
|
||||
clk_set_parent(clk[IMX5_CLK_STEP_SEL], clk[IMX5_CLK_LP_APM]);
|
||||
|
||||
clk_prepare_enable(clk[IMX5_CLK_IIM_GATE]);
|
||||
imx_print_silicon_rev("i.MX53", mx53_revision());
|
||||
clk_disable_unprepare(clk[IMX5_CLK_IIM_GATE]);
|
||||
|
@ -120,6 +120,17 @@ static unsigned int const clks_init_on[] __initconst = {
|
||||
VF610_CLK_DDR_SEL,
|
||||
};
|
||||
|
||||
static struct clk * __init vf610_get_fixed_clock(
|
||||
struct device_node *ccm_node, const char *name)
|
||||
{
|
||||
struct clk *clk = of_clk_get_by_name(ccm_node, name);
|
||||
|
||||
/* Backward compatibility if device tree is missing clks assignments */
|
||||
if (IS_ERR(clk))
|
||||
clk = imx_obtain_fixed_clock(name, 0);
|
||||
return clk;
|
||||
};
|
||||
|
||||
static void __init vf610_clocks_init(struct device_node *ccm_node)
|
||||
{
|
||||
struct device_node *np;
|
||||
@ -130,13 +141,13 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
|
||||
clk[VF610_CLK_SIRC_32K] = imx_clk_fixed("sirc_32k", 32000);
|
||||
clk[VF610_CLK_FIRC] = imx_clk_fixed("firc", 24000000);
|
||||
|
||||
clk[VF610_CLK_SXOSC] = imx_obtain_fixed_clock("sxosc", 0);
|
||||
clk[VF610_CLK_FXOSC] = imx_obtain_fixed_clock("fxosc", 0);
|
||||
clk[VF610_CLK_AUDIO_EXT] = imx_obtain_fixed_clock("audio_ext", 0);
|
||||
clk[VF610_CLK_ENET_EXT] = imx_obtain_fixed_clock("enet_ext", 0);
|
||||
clk[VF610_CLK_SXOSC] = vf610_get_fixed_clock(ccm_node, "sxosc");
|
||||
clk[VF610_CLK_FXOSC] = vf610_get_fixed_clock(ccm_node, "fxosc");
|
||||
clk[VF610_CLK_AUDIO_EXT] = vf610_get_fixed_clock(ccm_node, "audio_ext");
|
||||
clk[VF610_CLK_ENET_EXT] = vf610_get_fixed_clock(ccm_node, "enet_ext");
|
||||
|
||||
/* Clock source from external clock via LVDs PAD */
|
||||
clk[VF610_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
|
||||
clk[VF610_CLK_ANACLK1] = vf610_get_fixed_clock(ccm_node, "anaclk1");
|
||||
|
||||
clk[VF610_CLK_FXOSC_HALF] = imx_clk_fixed_factor("fxosc_half", "fxosc", 1, 2);
|
||||
|
||||
|
@ -131,4 +131,8 @@ static inline struct clk *imx_clk_fixed_factor(const char *name,
|
||||
CLK_SET_RATE_PARENT, mult, div);
|
||||
}
|
||||
|
||||
struct clk *imx_clk_cpu(const char *name, const char *parent_name,
|
||||
struct clk *div, struct clk *mux, struct clk *pll,
|
||||
struct clk *step);
|
||||
|
||||
#endif
|
||||
|
@ -115,6 +115,7 @@ void imx_anatop_post_resume(void);
|
||||
int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
|
||||
void imx6q_set_int_mem_clk_lpm(bool enable);
|
||||
void imx6sl_set_wait_clk(bool enter);
|
||||
int imx_mmdc_get_ddr_type(void);
|
||||
|
||||
void imx_cpu_die(unsigned int cpu);
|
||||
int imx_cpu_kill(unsigned int cpu);
|
||||
@ -156,5 +157,6 @@ static inline void imx_init_l2cache(void) {}
|
||||
#endif
|
||||
|
||||
extern struct smp_operations imx_smp_ops;
|
||||
extern struct smp_operations ls1021a_smp_ops;
|
||||
|
||||
#endif
|
||||
|
@ -40,6 +40,8 @@ static void __init imx53_dt_init(void)
|
||||
static void __init imx53_init_late(void)
|
||||
{
|
||||
imx53_pm_init();
|
||||
|
||||
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
|
||||
}
|
||||
|
||||
static const char * const imx53_dt_board_compat[] __initconst = {
|
||||
|
@ -8,12 +8,62 @@
|
||||
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "cpuidle.h"
|
||||
|
||||
static int ar8031_phy_fixup(struct phy_device *dev)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
/* Set RGMII IO voltage to 1.8V */
|
||||
phy_write(dev, 0x1d, 0x1f);
|
||||
phy_write(dev, 0x1e, 0x8);
|
||||
|
||||
/* introduce tx clock delay */
|
||||
phy_write(dev, 0x1d, 0x5);
|
||||
val = phy_read(dev, 0x1e);
|
||||
val |= 0x0100;
|
||||
phy_write(dev, 0x1e, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PHY_ID_AR8031 0x004dd074
|
||||
static void __init imx6sx_enet_phy_init(void)
|
||||
{
|
||||
if (IS_BUILTIN(CONFIG_PHYLIB))
|
||||
phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,
|
||||
ar8031_phy_fixup);
|
||||
}
|
||||
|
||||
static void __init imx6sx_enet_clk_sel(void)
|
||||
{
|
||||
struct regmap *gpr;
|
||||
|
||||
gpr = syscon_regmap_lookup_by_compatible("fsl,imx6sx-iomuxc-gpr");
|
||||
if (!IS_ERR(gpr)) {
|
||||
regmap_update_bits(gpr, IOMUXC_GPR1,
|
||||
IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_MASK, 0);
|
||||
regmap_update_bits(gpr, IOMUXC_GPR1,
|
||||
IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK, 0);
|
||||
} else {
|
||||
pr_err("failed to find fsl,imx6sx-iomux-gpr regmap\n");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void imx6sx_enet_init(void)
|
||||
{
|
||||
imx6sx_enet_phy_init();
|
||||
imx6sx_enet_clk_sel();
|
||||
}
|
||||
|
||||
static void __init imx6sx_init_machine(void)
|
||||
{
|
||||
struct device *parent;
|
||||
@ -24,6 +74,7 @@ static void __init imx6sx_init_machine(void)
|
||||
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);
|
||||
|
||||
imx6sx_enet_init();
|
||||
imx_anatop_init();
|
||||
imx6sx_pm_init();
|
||||
}
|
||||
|
22
arch/arm/mach-imx/mach-ls1021a.c
Normal file
22
arch/arm/mach-imx/mach-ls1021a.c
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2013-2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static const char * const ls1021a_dt_compat[] __initconst = {
|
||||
"fsl,ls1021a",
|
||||
NULL,
|
||||
};
|
||||
|
||||
DT_MACHINE_START(LS1021A, "Freescale LS1021A")
|
||||
.smp = smp_ops(ls1021a_smp_ops),
|
||||
.dt_compat = ls1021a_dt_compat,
|
||||
MACHINE_END
|
@ -21,6 +21,12 @@
|
||||
#define BP_MMDC_MAPSR_PSD 0
|
||||
#define BP_MMDC_MAPSR_PSS 4
|
||||
|
||||
#define MMDC_MDMISC 0x18
|
||||
#define BM_MMDC_MDMISC_DDR_TYPE 0x18
|
||||
#define BP_MMDC_MDMISC_DDR_TYPE 0x3
|
||||
|
||||
static int ddr_type;
|
||||
|
||||
static int imx_mmdc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
@ -31,6 +37,12 @@ static int imx_mmdc_probe(struct platform_device *pdev)
|
||||
mmdc_base = of_iomap(np, 0);
|
||||
WARN_ON(!mmdc_base);
|
||||
|
||||
reg = mmdc_base + MMDC_MDMISC;
|
||||
/* Get ddr type */
|
||||
val = readl_relaxed(reg);
|
||||
ddr_type = (val & BM_MMDC_MDMISC_DDR_TYPE) >>
|
||||
BP_MMDC_MDMISC_DDR_TYPE;
|
||||
|
||||
reg = mmdc_base + MMDC_MAPSR;
|
||||
|
||||
/* Enable automatic power saving */
|
||||
@ -51,6 +63,11 @@ static int imx_mmdc_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int imx_mmdc_get_ddr_type(void)
|
||||
{
|
||||
return ddr_type;
|
||||
}
|
||||
|
||||
static struct of_device_id imx_mmdc_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx6q-mmdc", },
|
||||
{ /* sentinel */ }
|
||||
|
@ -55,6 +55,8 @@
|
||||
#define IMX_CHIP_REVISION_3_3 0x33
|
||||
#define IMX_CHIP_REVISION_UNKNOWN 0xff
|
||||
|
||||
#define IMX_DDR_TYPE_LPDDR2 1
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
extern unsigned int __mxc_cpu_type;
|
||||
#endif
|
||||
|
@ -11,7 +11,10 @@
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/smp_scu.h>
|
||||
@ -94,3 +97,33 @@ struct smp_operations imx_smp_ops __initdata = {
|
||||
.cpu_kill = imx_cpu_kill,
|
||||
#endif
|
||||
};
|
||||
|
||||
#define DCFG_CCSR_SCRATCHRW1 0x200
|
||||
|
||||
static int ls1021a_boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
{
|
||||
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init ls1021a_smp_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
struct device_node *np;
|
||||
void __iomem *dcfg_base;
|
||||
unsigned long paddr;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-dcfg");
|
||||
dcfg_base = of_iomap(np, 0);
|
||||
BUG_ON(!dcfg_base);
|
||||
|
||||
paddr = virt_to_phys(secondary_startup);
|
||||
writel_relaxed(cpu_to_be32(paddr), dcfg_base + DCFG_CCSR_SCRATCHRW1);
|
||||
|
||||
iounmap(dcfg_base);
|
||||
}
|
||||
|
||||
struct smp_operations ls1021a_smp_ops __initdata = {
|
||||
.smp_prepare_cpus = ls1021a_smp_prepare_cpus,
|
||||
.smp_boot_secondary = ls1021a_boot_secondary,
|
||||
};
|
||||
|
@ -88,7 +88,7 @@ struct imx6_pm_base {
|
||||
};
|
||||
|
||||
struct imx6_pm_socdata {
|
||||
u32 cpu_type;
|
||||
u32 ddr_type;
|
||||
const char *mmdc_compat;
|
||||
const char *src_compat;
|
||||
const char *iomuxc_compat;
|
||||
@ -138,7 +138,6 @@ static const u32 imx6sx_mmdc_io_offset[] __initconst = {
|
||||
};
|
||||
|
||||
static const struct imx6_pm_socdata imx6q_pm_data __initconst = {
|
||||
.cpu_type = MXC_CPU_IMX6Q,
|
||||
.mmdc_compat = "fsl,imx6q-mmdc",
|
||||
.src_compat = "fsl,imx6q-src",
|
||||
.iomuxc_compat = "fsl,imx6q-iomuxc",
|
||||
@ -148,7 +147,6 @@ static const struct imx6_pm_socdata imx6q_pm_data __initconst = {
|
||||
};
|
||||
|
||||
static const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
|
||||
.cpu_type = MXC_CPU_IMX6DL,
|
||||
.mmdc_compat = "fsl,imx6q-mmdc",
|
||||
.src_compat = "fsl,imx6q-src",
|
||||
.iomuxc_compat = "fsl,imx6dl-iomuxc",
|
||||
@ -158,7 +156,6 @@ static const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
|
||||
};
|
||||
|
||||
static const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
|
||||
.cpu_type = MXC_CPU_IMX6SL,
|
||||
.mmdc_compat = "fsl,imx6sl-mmdc",
|
||||
.src_compat = "fsl,imx6sl-src",
|
||||
.iomuxc_compat = "fsl,imx6sl-iomuxc",
|
||||
@ -168,7 +165,6 @@ static const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
|
||||
};
|
||||
|
||||
static const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
|
||||
.cpu_type = MXC_CPU_IMX6SX,
|
||||
.mmdc_compat = "fsl,imx6sx-mmdc",
|
||||
.src_compat = "fsl,imx6sx-src",
|
||||
.iomuxc_compat = "fsl,imx6sx-iomuxc",
|
||||
@ -187,7 +183,7 @@ static const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
|
||||
struct imx6_cpu_pm_info {
|
||||
phys_addr_t pbase; /* The physical address of pm_info. */
|
||||
phys_addr_t resume_addr; /* The physical resume address for asm code */
|
||||
u32 cpu_type;
|
||||
u32 ddr_type;
|
||||
u32 pm_info_size; /* Size of pm_info. */
|
||||
struct imx6_pm_base mmdc_base;
|
||||
struct imx6_pm_base src_base;
|
||||
@ -521,7 +517,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
|
||||
goto pl310_cache_map_failed;
|
||||
}
|
||||
|
||||
pm_info->cpu_type = socdata->cpu_type;
|
||||
pm_info->ddr_type = imx_mmdc_get_ddr_type();
|
||||
pm_info->mmdc_io_num = socdata->mmdc_io_num;
|
||||
mmdc_offset_array = socdata->mmdc_io_offset;
|
||||
|
||||
|
@ -45,7 +45,7 @@
|
||||
*/
|
||||
#define PM_INFO_PBASE_OFFSET 0x0
|
||||
#define PM_INFO_RESUME_ADDR_OFFSET 0x4
|
||||
#define PM_INFO_CPU_TYPE_OFFSET 0x8
|
||||
#define PM_INFO_DDR_TYPE_OFFSET 0x8
|
||||
#define PM_INFO_PM_INFO_SIZE_OFFSET 0xC
|
||||
#define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10
|
||||
#define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14
|
||||
@ -110,7 +110,7 @@
|
||||
ldreq r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
|
||||
ldrne r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET]
|
||||
|
||||
cmp r3, #MXC_CPU_IMX6SL
|
||||
cmp r3, #IMX_DDR_TYPE_LPDDR2
|
||||
bne 4f
|
||||
|
||||
/* reset read FIFO, RST_RD_FIFO */
|
||||
@ -151,7 +151,7 @@
|
||||
ENTRY(imx6_suspend)
|
||||
ldr r1, [r0, #PM_INFO_PBASE_OFFSET]
|
||||
ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
|
||||
ldr r3, [r0, #PM_INFO_CPU_TYPE_OFFSET]
|
||||
ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
|
||||
ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
|
||||
|
||||
/*
|
||||
@ -209,8 +209,8 @@ poll_dvfs_set:
|
||||
ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
|
||||
ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET
|
||||
add r8, r8, r0
|
||||
/* i.MX6SL's last 3 IOs need special setting */
|
||||
cmp r3, #MXC_CPU_IMX6SL
|
||||
/* LPDDR2's last 3 IOs need special setting */
|
||||
cmp r3, #IMX_DDR_TYPE_LPDDR2
|
||||
subeq r7, r7, #0x3
|
||||
set_mmdc_io_lpm:
|
||||
ldr r9, [r8], #0x8
|
||||
@ -218,7 +218,7 @@ set_mmdc_io_lpm:
|
||||
subs r7, r7, #0x1
|
||||
bne set_mmdc_io_lpm
|
||||
|
||||
cmp r3, #MXC_CPU_IMX6SL
|
||||
cmp r3, #IMX_DDR_TYPE_LPDDR2
|
||||
bne set_mmdc_io_lpm_done
|
||||
ldr r6, =0x1000
|
||||
ldr r9, [r8], #0x8
|
||||
@ -324,7 +324,7 @@ resume:
|
||||
str r7, [r11, #MX6Q_SRC_GPR1]
|
||||
str r7, [r11, #MX6Q_SRC_GPR2]
|
||||
|
||||
ldr r3, [r0, #PM_INFO_CPU_TYPE_OFFSET]
|
||||
ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
|
||||
mov r5, #0x1
|
||||
resume_mmdc
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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()
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -2,6 +2,7 @@ menuconfig ARCH_MESON
|
||||
bool "Amlogic Meson SoCs" if ARCH_MULTI_V7
|
||||
select GENERIC_IRQ_CHIP
|
||||
select ARM_GIC
|
||||
select CACHE_L2X0
|
||||
|
||||
if ARCH_MESON
|
||||
|
||||
@ -10,4 +11,9 @@ config MACH_MESON6
|
||||
default ARCH_MESON
|
||||
select MESON6_TIMER
|
||||
|
||||
config MACH_MESON8
|
||||
bool "Amlogic Meson8 SoCs support"
|
||||
default ARCH_MESON
|
||||
select MESON6_TIMER
|
||||
|
||||
endif
|
||||
|
@ -16,12 +16,14 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
static const char * const m6_common_board_compat[] = {
|
||||
static const char * const meson_common_board_compat[] = {
|
||||
"amlogic,meson6",
|
||||
"amlogic,meson8",
|
||||
NULL,
|
||||
};
|
||||
|
||||
DT_MACHINE_START(AML8726_MX, "Amlogic Meson6 platform")
|
||||
.dt_compat = m6_common_board_compat,
|
||||
DT_MACHINE_START(MESON, "Amlogic Meson platform")
|
||||
.dt_compat = meson_common_board_compat,
|
||||
.l2c_aux_val = 0,
|
||||
.l2c_aux_mask = ~0,
|
||||
MACHINE_END
|
||||
|
||||
|
@ -7,7 +7,7 @@ CFLAGS_pmsu.o := -march=armv7-a
|
||||
obj-$(CONFIG_MACH_MVEBU_ANY) += system-controller.o mvebu-soc-id.o
|
||||
|
||||
ifeq ($(CONFIG_MACH_MVEBU_V7),y)
|
||||
obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o
|
||||
obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o pm.o pm-board.o
|
||||
obj-$(CONFIG_SMP) += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o
|
||||
endif
|
||||
|
||||
|
@ -16,14 +16,8 @@
|
||||
#define __MACH_ARMADA_370_XP_H
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
#define ARMADA_XP_MAX_CPUS 4
|
||||
|
||||
void armada_xp_secondary_startup(void);
|
||||
extern struct smp_operations armada_xp_smp_ops;
|
||||
#endif
|
||||
|
||||
int armada_370_xp_pmsu_idle_enter(unsigned long deepidle);
|
||||
|
||||
#endif /* __MACH_ARMADA_370_XP_H */
|
||||
|
@ -16,10 +16,12 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/mbus.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/slab.h>
|
||||
@ -56,6 +58,54 @@ void __iomem *mvebu_get_scu_base(void)
|
||||
return scu_base;
|
||||
}
|
||||
|
||||
/*
|
||||
* When returning from suspend, the platform goes through the
|
||||
* bootloader, which executes its DDR3 training code. This code has
|
||||
* the unfortunate idea of using the first 10 KB of each DRAM bank to
|
||||
* exercise the RAM and calculate the optimal timings. Therefore, this
|
||||
* area of RAM is overwritten, and shouldn't be used by the kernel if
|
||||
* suspend/resume is supported.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SUSPEND
|
||||
#define MVEBU_DDR_TRAINING_AREA_SZ (10 * SZ_1K)
|
||||
static int __init mvebu_scan_mem(unsigned long node, const char *uname,
|
||||
int depth, void *data)
|
||||
{
|
||||
const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
|
||||
const __be32 *reg, *endp;
|
||||
int l;
|
||||
|
||||
if (type == NULL || strcmp(type, "memory"))
|
||||
return 0;
|
||||
|
||||
reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
|
||||
if (reg == NULL)
|
||||
reg = of_get_flat_dt_prop(node, "reg", &l);
|
||||
if (reg == NULL)
|
||||
return 0;
|
||||
|
||||
endp = reg + (l / sizeof(__be32));
|
||||
while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
|
||||
u64 base, size;
|
||||
|
||||
base = dt_mem_next_cell(dt_root_addr_cells, ®);
|
||||
size = dt_mem_next_cell(dt_root_size_cells, ®);
|
||||
|
||||
memblock_reserve(base, MVEBU_DDR_TRAINING_AREA_SZ);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init mvebu_memblock_reserve(void)
|
||||
{
|
||||
of_scan_flat_dt(mvebu_scan_mem, NULL);
|
||||
}
|
||||
#else
|
||||
static void __init mvebu_memblock_reserve(void) {}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Early versions of Armada 375 SoC have a bug where the BootROM
|
||||
* leaves an external data abort pending. The kernel is hit by this
|
||||
@ -124,76 +174,12 @@ static void __init i2c_quirk(void)
|
||||
return;
|
||||
}
|
||||
|
||||
#define A375_Z1_THERMAL_FIXUP_OFFSET 0xc
|
||||
|
||||
static void __init thermal_quirk(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
u32 dev, rev;
|
||||
int res;
|
||||
|
||||
/*
|
||||
* The early SoC Z1 revision needs a quirk to be applied in order
|
||||
* for the thermal controller to work properly. This quirk breaks
|
||||
* the thermal support if applied on a SoC that doesn't need it,
|
||||
* so we enforce the SoC revision to be known.
|
||||
*/
|
||||
res = mvebu_get_soc_id(&dev, &rev);
|
||||
if (res < 0 || (res == 0 && rev > ARMADA_375_Z1_REV))
|
||||
return;
|
||||
|
||||
for_each_compatible_node(np, NULL, "marvell,armada375-thermal") {
|
||||
struct property *prop;
|
||||
__be32 newval, *newprop, *oldprop;
|
||||
int len;
|
||||
|
||||
/*
|
||||
* The register offset is at a wrong location. This quirk
|
||||
* creates a new reg property as a clone of the previous
|
||||
* one and corrects the offset.
|
||||
*/
|
||||
oldprop = (__be32 *)of_get_property(np, "reg", &len);
|
||||
if (!oldprop)
|
||||
continue;
|
||||
|
||||
/* Create a duplicate of the 'reg' property */
|
||||
prop = kzalloc(sizeof(*prop), GFP_KERNEL);
|
||||
prop->length = len;
|
||||
prop->name = kstrdup("reg", GFP_KERNEL);
|
||||
prop->value = kzalloc(len, GFP_KERNEL);
|
||||
memcpy(prop->value, oldprop, len);
|
||||
|
||||
/* Fixup the register offset of the second entry */
|
||||
oldprop += 2;
|
||||
newprop = (__be32 *)prop->value + 2;
|
||||
newval = cpu_to_be32(be32_to_cpu(*oldprop) -
|
||||
A375_Z1_THERMAL_FIXUP_OFFSET);
|
||||
*newprop = newval;
|
||||
of_update_property(np, prop);
|
||||
|
||||
/*
|
||||
* The thermal controller needs some quirk too, so let's change
|
||||
* the compatible string to reflect this and allow the driver
|
||||
* the take the necessary action.
|
||||
*/
|
||||
prop = kzalloc(sizeof(*prop), GFP_KERNEL);
|
||||
prop->name = kstrdup("compatible", GFP_KERNEL);
|
||||
prop->length = sizeof("marvell,armada375-z1-thermal");
|
||||
prop->value = kstrdup("marvell,armada375-z1-thermal",
|
||||
GFP_KERNEL);
|
||||
of_update_property(np, prop);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void __init mvebu_dt_init(void)
|
||||
{
|
||||
if (of_machine_is_compatible("marvell,armadaxp"))
|
||||
i2c_quirk();
|
||||
if (of_machine_is_compatible("marvell,a375-db")) {
|
||||
if (of_machine_is_compatible("marvell,a375-db"))
|
||||
external_abort_quirk();
|
||||
thermal_quirk();
|
||||
}
|
||||
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
}
|
||||
@ -206,10 +192,16 @@ static const char * const armada_370_xp_dt_compat[] = {
|
||||
DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)")
|
||||
.l2c_aux_val = 0,
|
||||
.l2c_aux_mask = ~0,
|
||||
/*
|
||||
* The following field (.smp) is still needed to ensure backward
|
||||
* compatibility with old Device Trees that were not specifying the
|
||||
* cpus enable-method property.
|
||||
*/
|
||||
.smp = smp_ops(armada_xp_smp_ops),
|
||||
.init_machine = mvebu_dt_init,
|
||||
.init_irq = mvebu_init_irq,
|
||||
.restart = mvebu_restart,
|
||||
.reserve = mvebu_memblock_reserve,
|
||||
.dt_compat = armada_370_xp_dt_compat,
|
||||
MACHINE_END
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Coherency fabric (Aurora) support for Armada 370 and XP platforms.
|
||||
* Coherency fabric (Aurora) support for Armada 370, 375, 38x and XP
|
||||
* platforms.
|
||||
*
|
||||
* Copyright (C) 2012 Marvell
|
||||
*
|
||||
@ -11,7 +12,7 @@
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*
|
||||
* The Armada 370 and Armada XP SOCs have a coherency fabric which is
|
||||
* The Armada 370, 375, 38x and XP SOCs have a coherency fabric which is
|
||||
* responsible for ensuring hardware coherency between all CPUs and between
|
||||
* CPUs and I/O masters. This file initializes the coherency fabric and
|
||||
* supplies basic routines for configuring and controlling hardware coherency
|
||||
@ -28,12 +29,10 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mbus.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/smp_plat.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/mach/map.h>
|
||||
#include "armada-370-xp.h"
|
||||
#include "coherency.h"
|
||||
#include "mvebu-soc-id.h"
|
||||
|
||||
@ -42,8 +41,6 @@ void __iomem *coherency_base;
|
||||
static void __iomem *coherency_cpu_base;
|
||||
|
||||
/* Coherency fabric registers */
|
||||
#define COHERENCY_FABRIC_CFG_OFFSET 0x4
|
||||
|
||||
#define IO_SYNC_BARRIER_CTL_OFFSET 0x0
|
||||
|
||||
enum {
|
||||
@ -79,157 +76,8 @@ int set_cpu_coherent(void)
|
||||
return ll_enable_coherency();
|
||||
}
|
||||
|
||||
/*
|
||||
* The below code implements the I/O coherency workaround on Armada
|
||||
* 375. This workaround consists in using the two channels of the
|
||||
* first XOR engine to trigger a XOR transaction that serves as the
|
||||
* I/O coherency barrier.
|
||||
*/
|
||||
|
||||
static void __iomem *xor_base, *xor_high_base;
|
||||
static dma_addr_t coherency_wa_buf_phys[CONFIG_NR_CPUS];
|
||||
static void *coherency_wa_buf[CONFIG_NR_CPUS];
|
||||
static bool coherency_wa_enabled;
|
||||
|
||||
#define XOR_CONFIG(chan) (0x10 + (chan * 4))
|
||||
#define XOR_ACTIVATION(chan) (0x20 + (chan * 4))
|
||||
#define WINDOW_BAR_ENABLE(chan) (0x240 + ((chan) << 2))
|
||||
#define WINDOW_BASE(w) (0x250 + ((w) << 2))
|
||||
#define WINDOW_SIZE(w) (0x270 + ((w) << 2))
|
||||
#define WINDOW_REMAP_HIGH(w) (0x290 + ((w) << 2))
|
||||
#define WINDOW_OVERRIDE_CTRL(chan) (0x2A0 + ((chan) << 2))
|
||||
#define XOR_DEST_POINTER(chan) (0x2B0 + (chan * 4))
|
||||
#define XOR_BLOCK_SIZE(chan) (0x2C0 + (chan * 4))
|
||||
#define XOR_INIT_VALUE_LOW 0x2E0
|
||||
#define XOR_INIT_VALUE_HIGH 0x2E4
|
||||
|
||||
static inline void mvebu_hwcc_armada375_sync_io_barrier_wa(void)
|
||||
{
|
||||
int idx = smp_processor_id();
|
||||
|
||||
/* Write '1' to the first word of the buffer */
|
||||
writel(0x1, coherency_wa_buf[idx]);
|
||||
|
||||
/* Wait until the engine is idle */
|
||||
while ((readl(xor_base + XOR_ACTIVATION(idx)) >> 4) & 0x3)
|
||||
;
|
||||
|
||||
dmb();
|
||||
|
||||
/* Trigger channel */
|
||||
writel(0x1, xor_base + XOR_ACTIVATION(idx));
|
||||
|
||||
/* Poll the data until it is cleared by the XOR transaction */
|
||||
while (readl(coherency_wa_buf[idx]))
|
||||
;
|
||||
}
|
||||
|
||||
static void __init armada_375_coherency_init_wa(void)
|
||||
{
|
||||
const struct mbus_dram_target_info *dram;
|
||||
struct device_node *xor_node;
|
||||
struct property *xor_status;
|
||||
struct clk *xor_clk;
|
||||
u32 win_enable = 0;
|
||||
int i;
|
||||
|
||||
pr_warn("enabling coherency workaround for Armada 375 Z1, one XOR engine disabled\n");
|
||||
|
||||
/*
|
||||
* Since the workaround uses one XOR engine, we grab a
|
||||
* reference to its Device Tree node first.
|
||||
*/
|
||||
xor_node = of_find_compatible_node(NULL, NULL, "marvell,orion-xor");
|
||||
BUG_ON(!xor_node);
|
||||
|
||||
/*
|
||||
* Then we mark it as disabled so that the real XOR driver
|
||||
* will not use it.
|
||||
*/
|
||||
xor_status = kzalloc(sizeof(struct property), GFP_KERNEL);
|
||||
BUG_ON(!xor_status);
|
||||
|
||||
xor_status->value = kstrdup("disabled", GFP_KERNEL);
|
||||
BUG_ON(!xor_status->value);
|
||||
|
||||
xor_status->length = 8;
|
||||
xor_status->name = kstrdup("status", GFP_KERNEL);
|
||||
BUG_ON(!xor_status->name);
|
||||
|
||||
of_update_property(xor_node, xor_status);
|
||||
|
||||
/*
|
||||
* And we remap the registers, get the clock, and do the
|
||||
* initial configuration of the XOR engine.
|
||||
*/
|
||||
xor_base = of_iomap(xor_node, 0);
|
||||
xor_high_base = of_iomap(xor_node, 1);
|
||||
|
||||
xor_clk = of_clk_get_by_name(xor_node, NULL);
|
||||
BUG_ON(!xor_clk);
|
||||
|
||||
clk_prepare_enable(xor_clk);
|
||||
|
||||
dram = mv_mbus_dram_info();
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
writel(0, xor_base + WINDOW_BASE(i));
|
||||
writel(0, xor_base + WINDOW_SIZE(i));
|
||||
if (i < 4)
|
||||
writel(0, xor_base + WINDOW_REMAP_HIGH(i));
|
||||
}
|
||||
|
||||
for (i = 0; i < dram->num_cs; i++) {
|
||||
const struct mbus_dram_window *cs = dram->cs + i;
|
||||
writel((cs->base & 0xffff0000) |
|
||||
(cs->mbus_attr << 8) |
|
||||
dram->mbus_dram_target_id, xor_base + WINDOW_BASE(i));
|
||||
writel((cs->size - 1) & 0xffff0000, xor_base + WINDOW_SIZE(i));
|
||||
|
||||
win_enable |= (1 << i);
|
||||
win_enable |= 3 << (16 + (2 * i));
|
||||
}
|
||||
|
||||
writel(win_enable, xor_base + WINDOW_BAR_ENABLE(0));
|
||||
writel(win_enable, xor_base + WINDOW_BAR_ENABLE(1));
|
||||
writel(0, xor_base + WINDOW_OVERRIDE_CTRL(0));
|
||||
writel(0, xor_base + WINDOW_OVERRIDE_CTRL(1));
|
||||
|
||||
for (i = 0; i < CONFIG_NR_CPUS; i++) {
|
||||
coherency_wa_buf[i] = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
BUG_ON(!coherency_wa_buf[i]);
|
||||
|
||||
/*
|
||||
* We can't use the DMA mapping API, since we don't
|
||||
* have a valid 'struct device' pointer
|
||||
*/
|
||||
coherency_wa_buf_phys[i] =
|
||||
virt_to_phys(coherency_wa_buf[i]);
|
||||
BUG_ON(!coherency_wa_buf_phys[i]);
|
||||
|
||||
/*
|
||||
* Configure the XOR engine for memset operation, with
|
||||
* a 128 bytes block size
|
||||
*/
|
||||
writel(0x444, xor_base + XOR_CONFIG(i));
|
||||
writel(128, xor_base + XOR_BLOCK_SIZE(i));
|
||||
writel(coherency_wa_buf_phys[i],
|
||||
xor_base + XOR_DEST_POINTER(i));
|
||||
}
|
||||
|
||||
writel(0x0, xor_base + XOR_INIT_VALUE_LOW);
|
||||
writel(0x0, xor_base + XOR_INIT_VALUE_HIGH);
|
||||
|
||||
coherency_wa_enabled = true;
|
||||
}
|
||||
|
||||
static inline void mvebu_hwcc_sync_io_barrier(void)
|
||||
{
|
||||
if (coherency_wa_enabled) {
|
||||
mvebu_hwcc_armada375_sync_io_barrier_wa();
|
||||
return;
|
||||
}
|
||||
|
||||
writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET);
|
||||
while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1);
|
||||
}
|
||||
@ -361,25 +209,41 @@ static int coherency_type(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
const struct of_device_id *match;
|
||||
int type;
|
||||
|
||||
/*
|
||||
* The coherency fabric is needed:
|
||||
* - For coherency between processors on Armada XP, so only
|
||||
* when SMP is enabled.
|
||||
* - For coherency between the processor and I/O devices, but
|
||||
* this coherency requires many pre-requisites (write
|
||||
* allocate cache policy, shareable pages, SMP bit set) that
|
||||
* are only meant in SMP situations.
|
||||
*
|
||||
* Note that this means that on Armada 370, there is currently
|
||||
* no way to use hardware I/O coherency, because even when
|
||||
* CONFIG_SMP is enabled, is_smp() returns false due to the
|
||||
* Armada 370 being a single-core processor. To lift this
|
||||
* limitation, we would have to find a way to make the cache
|
||||
* policy set to write-allocate (on all Armada SoCs), and to
|
||||
* set the shareable attribute in page tables (on all Armada
|
||||
* SoCs except the Armada 370). Unfortunately, such decisions
|
||||
* are taken very early in the kernel boot process, at a point
|
||||
* where we don't know yet on which SoC we are running.
|
||||
|
||||
*/
|
||||
if (!is_smp())
|
||||
return COHERENCY_FABRIC_TYPE_NONE;
|
||||
|
||||
np = of_find_matching_node_and_match(NULL, of_coherency_table, &match);
|
||||
if (np) {
|
||||
int type = (int) match->data;
|
||||
if (!np)
|
||||
return COHERENCY_FABRIC_TYPE_NONE;
|
||||
|
||||
/* Armada 370/XP coherency works in both UP and SMP */
|
||||
if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP)
|
||||
return type;
|
||||
type = (int) match->data;
|
||||
|
||||
/* Armada 375 coherency works only on SMP */
|
||||
else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 && is_smp())
|
||||
return type;
|
||||
of_node_put(np);
|
||||
|
||||
/* Armada 380 coherency works only on SMP */
|
||||
else if (type == COHERENCY_FABRIC_TYPE_ARMADA_380 && is_smp())
|
||||
return type;
|
||||
}
|
||||
|
||||
return COHERENCY_FABRIC_TYPE_NONE;
|
||||
return type;
|
||||
}
|
||||
|
||||
int coherency_available(void)
|
||||
@ -407,22 +271,9 @@ int __init coherency_init(void)
|
||||
|
||||
static int __init coherency_late_init(void)
|
||||
{
|
||||
int type = coherency_type();
|
||||
|
||||
if (type == COHERENCY_FABRIC_TYPE_NONE)
|
||||
return 0;
|
||||
|
||||
if (type == COHERENCY_FABRIC_TYPE_ARMADA_375) {
|
||||
u32 dev, rev;
|
||||
|
||||
if (mvebu_get_soc_id(&dev, &rev) == 0 &&
|
||||
rev == ARMADA_375_Z1_REV)
|
||||
armada_375_coherency_init_wa();
|
||||
}
|
||||
|
||||
bus_register_notifier(&platform_bus_type,
|
||||
&mvebu_hwcc_nb);
|
||||
|
||||
if (coherency_available())
|
||||
bus_register_notifier(&platform_bus_type,
|
||||
&mvebu_hwcc_nb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,10 @@
|
||||
#include <asm/cp15.h>
|
||||
|
||||
.text
|
||||
/* Returns the coherency base address in r1 (r0 is untouched) */
|
||||
/*
|
||||
* Returns the coherency base address in r1 (r0 is untouched), or 0 if
|
||||
* the coherency fabric is not enabled.
|
||||
*/
|
||||
ENTRY(ll_get_coherency_base)
|
||||
mrc p15, 0, r1, c1, c0, 0
|
||||
tst r1, #CR_M @ Check MMU bit enabled
|
||||
@ -32,8 +35,13 @@ ENTRY(ll_get_coherency_base)
|
||||
|
||||
/*
|
||||
* MMU is disabled, use the physical address of the coherency
|
||||
* base address.
|
||||
* base address. However, if the coherency fabric isn't mapped
|
||||
* (i.e its virtual address is zero), it means coherency is
|
||||
* not enabled, so we return 0.
|
||||
*/
|
||||
ldr r1, =coherency_base
|
||||
cmp r1, #0
|
||||
beq 2f
|
||||
adr r1, 3f
|
||||
ldr r3, [r1]
|
||||
ldr r1, [r1, r3]
|
||||
@ -85,6 +93,9 @@ ENTRY(ll_add_cpu_to_smp_group)
|
||||
*/
|
||||
mov r0, lr
|
||||
bl ll_get_coherency_base
|
||||
/* Bail out if the coherency is not enabled */
|
||||
cmp r1, #0
|
||||
reteq r0
|
||||
bl ll_get_coherency_cpumask
|
||||
mov lr, r0
|
||||
add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET
|
||||
@ -107,6 +118,9 @@ ENTRY(ll_enable_coherency)
|
||||
*/
|
||||
mov r0, lr
|
||||
bl ll_get_coherency_base
|
||||
/* Bail out if the coherency is not enabled */
|
||||
cmp r1, #0
|
||||
reteq r0
|
||||
bl ll_get_coherency_cpumask
|
||||
mov lr, r0
|
||||
add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
|
||||
@ -131,6 +145,9 @@ ENTRY(ll_disable_coherency)
|
||||
*/
|
||||
mov r0, lr
|
||||
bl ll_get_coherency_base
|
||||
/* Bail out if the coherency is not enabled */
|
||||
cmp r1, #0
|
||||
reteq r0
|
||||
bl ll_get_coherency_cpumask
|
||||
mov lr, r0
|
||||
add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
|
||||
|
@ -25,4 +25,6 @@ int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev);
|
||||
|
||||
void __iomem *mvebu_get_scu_base(void);
|
||||
|
||||
int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd));
|
||||
|
||||
#endif
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/resource.h>
|
||||
#include "armada-370-xp.h"
|
||||
|
||||
static void __iomem *cpu_reset_base;
|
||||
static size_t cpu_reset_size;
|
||||
|
@ -22,5 +22,6 @@
|
||||
ENTRY(mvebu_cortex_a9_secondary_startup)
|
||||
ARM_BE8(setend be)
|
||||
bl v7_invalidate_l1
|
||||
bl armada_38x_scu_power_up
|
||||
b secondary_startup
|
||||
ENDPROC(mvebu_cortex_a9_secondary_startup)
|
||||
|
@ -43,21 +43,70 @@ static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu,
|
||||
else
|
||||
mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup);
|
||||
smp_wmb();
|
||||
|
||||
/*
|
||||
* Doing this before deasserting the CPUs is needed to wake up CPUs
|
||||
* in the offline state after using CPU hotplug.
|
||||
*/
|
||||
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
|
||||
|
||||
ret = mvebu_cpu_reset_deassert(hw_cpu);
|
||||
if (ret) {
|
||||
pr_err("Could not start the secondary CPU: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* When a CPU is brought back online, either through CPU hotplug, or
|
||||
* because of the boot of a kexec'ed kernel, the PMSU configuration
|
||||
* for this CPU might be in the deep idle state, preventing this CPU
|
||||
* from receiving interrupts. Here, we therefore take out the current
|
||||
* CPU from this state, which was entered by armada_38x_cpu_die()
|
||||
* below.
|
||||
*/
|
||||
static void armada_38x_secondary_init(unsigned int cpu)
|
||||
{
|
||||
mvebu_v7_pmsu_idle_exit();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static void armada_38x_cpu_die(unsigned int cpu)
|
||||
{
|
||||
/*
|
||||
* CPU hotplug is implemented by putting offline CPUs into the
|
||||
* deep idle sleep state.
|
||||
*/
|
||||
armada_38x_do_cpu_suspend(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need a dummy function, so that platform_can_cpu_hotplug() knows
|
||||
* we support CPU hotplug. However, the function does not need to do
|
||||
* anything, because CPUs going offline can enter the deep idle state
|
||||
* by themselves, without any help from a still alive CPU.
|
||||
*/
|
||||
static int armada_38x_cpu_kill(unsigned int cpu)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = {
|
||||
.smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
|
||||
};
|
||||
|
||||
static struct smp_operations armada_38x_smp_ops __initdata = {
|
||||
.smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
|
||||
.smp_secondary_init = armada_38x_secondary_init,
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
.cpu_die = armada_38x_cpu_die,
|
||||
.cpu_kill = armada_38x_cpu_kill,
|
||||
#endif
|
||||
};
|
||||
|
||||
CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp",
|
||||
&mvebu_cortex_a9_smp_ops);
|
||||
CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp",
|
||||
&mvebu_cortex_a9_smp_ops);
|
||||
&armada_38x_smp_ops);
|
||||
|
@ -30,10 +30,12 @@
|
||||
#include "pmsu.h"
|
||||
#include "coherency.h"
|
||||
|
||||
#define ARMADA_XP_MAX_CPUS 4
|
||||
|
||||
#define AXP_BOOTROM_BASE 0xfff00000
|
||||
#define AXP_BOOTROM_SIZE 0x100000
|
||||
|
||||
static struct clk *__init get_cpu_clk(int cpu)
|
||||
static struct clk *get_cpu_clk(int cpu)
|
||||
{
|
||||
struct clk *cpu_clk;
|
||||
struct device_node *np = of_get_cpu_node(cpu, NULL);
|
||||
@ -46,29 +48,28 @@ static struct clk *__init get_cpu_clk(int cpu)
|
||||
return cpu_clk;
|
||||
}
|
||||
|
||||
static void __init set_secondary_cpus_clock(void)
|
||||
static void set_secondary_cpu_clock(unsigned int cpu)
|
||||
{
|
||||
int thiscpu, cpu;
|
||||
int thiscpu;
|
||||
unsigned long rate;
|
||||
struct clk *cpu_clk;
|
||||
|
||||
thiscpu = smp_processor_id();
|
||||
thiscpu = get_cpu();
|
||||
|
||||
cpu_clk = get_cpu_clk(thiscpu);
|
||||
if (!cpu_clk)
|
||||
return;
|
||||
goto out;
|
||||
clk_prepare_enable(cpu_clk);
|
||||
rate = clk_get_rate(cpu_clk);
|
||||
|
||||
/* set all the other CPU clk to the same rate than the boot CPU */
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (cpu == thiscpu)
|
||||
continue;
|
||||
cpu_clk = get_cpu_clk(cpu);
|
||||
if (!cpu_clk)
|
||||
return;
|
||||
clk_set_rate(cpu_clk, rate);
|
||||
clk_prepare_enable(cpu_clk);
|
||||
}
|
||||
cpu_clk = get_cpu_clk(cpu);
|
||||
if (!cpu_clk)
|
||||
goto out;
|
||||
clk_set_rate(cpu_clk, rate);
|
||||
clk_prepare_enable(cpu_clk);
|
||||
|
||||
out:
|
||||
put_cpu();
|
||||
}
|
||||
|
||||
static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
@ -78,6 +79,7 @@ static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||
pr_info("Booting CPU %d\n", cpu);
|
||||
|
||||
hw_cpu = cpu_logical_map(cpu);
|
||||
set_secondary_cpu_clock(hw_cpu);
|
||||
mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_xp_secondary_startup);
|
||||
|
||||
/*
|
||||
@ -126,7 +128,6 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
|
||||
struct resource res;
|
||||
int err;
|
||||
|
||||
set_secondary_cpus_clock();
|
||||
flush_cache_all();
|
||||
set_cpu_coherent();
|
||||
|
||||
|
141
arch/arm/mach-mvebu/pm-board.c
Normal file
141
arch/arm/mach-mvebu/pm-board.c
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Board-level suspend/resume support.
|
||||
*
|
||||
* Copyright (C) 2014 Marvell
|
||||
*
|
||||
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include "common.h"
|
||||
|
||||
#define ARMADA_XP_GP_PIC_NR_GPIOS 3
|
||||
|
||||
static void __iomem *gpio_ctrl;
|
||||
static int pic_gpios[ARMADA_XP_GP_PIC_NR_GPIOS];
|
||||
static int pic_raw_gpios[ARMADA_XP_GP_PIC_NR_GPIOS];
|
||||
|
||||
static void mvebu_armada_xp_gp_pm_enter(void __iomem *sdram_reg, u32 srcmd)
|
||||
{
|
||||
u32 reg, ackcmd;
|
||||
int i;
|
||||
|
||||
/* Put 001 as value on the GPIOs */
|
||||
reg = readl(gpio_ctrl);
|
||||
for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++)
|
||||
reg &= ~BIT(pic_raw_gpios[i]);
|
||||
reg |= BIT(pic_raw_gpios[0]);
|
||||
writel(reg, gpio_ctrl);
|
||||
|
||||
/* Prepare writing 111 to the GPIOs */
|
||||
ackcmd = readl(gpio_ctrl);
|
||||
for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++)
|
||||
ackcmd |= BIT(pic_raw_gpios[i]);
|
||||
|
||||
/*
|
||||
* Wait a while, the PIC needs quite a bit of time between the
|
||||
* two GPIO commands.
|
||||
*/
|
||||
mdelay(3000);
|
||||
|
||||
asm volatile (
|
||||
/* Align to a cache line */
|
||||
".balign 32\n\t"
|
||||
|
||||
/* Enter self refresh */
|
||||
"str %[srcmd], [%[sdram_reg]]\n\t"
|
||||
|
||||
/*
|
||||
* Wait 100 cycles for DDR to enter self refresh, by
|
||||
* doing 50 times two instructions.
|
||||
*/
|
||||
"mov r1, #50\n\t"
|
||||
"1: subs r1, r1, #1\n\t"
|
||||
"bne 1b\n\t"
|
||||
|
||||
/* Issue the command ACK */
|
||||
"str %[ackcmd], [%[gpio_ctrl]]\n\t"
|
||||
|
||||
/* Trap the processor */
|
||||
"b .\n\t"
|
||||
: : [srcmd] "r" (srcmd), [sdram_reg] "r" (sdram_reg),
|
||||
[ackcmd] "r" (ackcmd), [gpio_ctrl] "r" (gpio_ctrl) : "r1");
|
||||
}
|
||||
|
||||
static int mvebu_armada_xp_gp_pm_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct device_node *gpio_ctrl_np;
|
||||
int ret = 0, i;
|
||||
|
||||
if (!of_machine_is_compatible("marvell,axp-gp"))
|
||||
return -ENODEV;
|
||||
|
||||
np = of_find_node_by_name(NULL, "pm_pic");
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++) {
|
||||
char *name;
|
||||
struct of_phandle_args args;
|
||||
|
||||
pic_gpios[i] = of_get_named_gpio(np, "ctrl-gpios", i);
|
||||
if (pic_gpios[i] < 0) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
name = kasprintf(GFP_KERNEL, "pic-pin%d", i);
|
||||
if (!name) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = gpio_request(pic_gpios[i], name);
|
||||
if (ret < 0) {
|
||||
kfree(name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = gpio_direction_output(pic_gpios[i], 0);
|
||||
if (ret < 0) {
|
||||
gpio_free(pic_gpios[i]);
|
||||
kfree(name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(np, "ctrl-gpios", 2,
|
||||
i, &args);
|
||||
if (ret < 0) {
|
||||
gpio_free(pic_gpios[i]);
|
||||
kfree(name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
gpio_ctrl_np = args.np;
|
||||
pic_raw_gpios[i] = args.args[0];
|
||||
}
|
||||
|
||||
gpio_ctrl = of_iomap(gpio_ctrl_np, 0);
|
||||
if (!gpio_ctrl)
|
||||
return -ENOMEM;
|
||||
|
||||
mvebu_pm_init(mvebu_armada_xp_gp_pm_enter);
|
||||
|
||||
out:
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
late_initcall(mvebu_armada_xp_gp_pm_init);
|
218
arch/arm/mach-mvebu/pm.c
Normal file
218
arch/arm/mach-mvebu/pm.c
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Suspend/resume support. Currently supporting Armada XP only.
|
||||
*
|
||||
* Copyright (C) 2014 Marvell
|
||||
*
|
||||
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mbus.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/outercache.h>
|
||||
#include <asm/suspend.h>
|
||||
|
||||
#include "coherency.h"
|
||||
#include "pmsu.h"
|
||||
|
||||
#define SDRAM_CONFIG_OFFS 0x0
|
||||
#define SDRAM_CONFIG_SR_MODE_BIT BIT(24)
|
||||
#define SDRAM_OPERATION_OFFS 0x18
|
||||
#define SDRAM_OPERATION_SELF_REFRESH 0x7
|
||||
#define SDRAM_DLB_EVICTION_OFFS 0x30c
|
||||
#define SDRAM_DLB_EVICTION_THRESHOLD_MASK 0xff
|
||||
|
||||
static void (*mvebu_board_pm_enter)(void __iomem *sdram_reg, u32 srcmd);
|
||||
static void __iomem *sdram_ctrl;
|
||||
|
||||
static int mvebu_pm_powerdown(unsigned long data)
|
||||
{
|
||||
u32 reg, srcmd;
|
||||
|
||||
flush_cache_all();
|
||||
outer_flush_all();
|
||||
|
||||
/*
|
||||
* Issue a Data Synchronization Barrier instruction to ensure
|
||||
* that all state saving has been completed.
|
||||
*/
|
||||
dsb();
|
||||
|
||||
/* Flush the DLB and wait ~7 usec */
|
||||
reg = readl(sdram_ctrl + SDRAM_DLB_EVICTION_OFFS);
|
||||
reg &= ~SDRAM_DLB_EVICTION_THRESHOLD_MASK;
|
||||
writel(reg, sdram_ctrl + SDRAM_DLB_EVICTION_OFFS);
|
||||
|
||||
udelay(7);
|
||||
|
||||
/* Set DRAM in battery backup mode */
|
||||
reg = readl(sdram_ctrl + SDRAM_CONFIG_OFFS);
|
||||
reg &= ~SDRAM_CONFIG_SR_MODE_BIT;
|
||||
writel(reg, sdram_ctrl + SDRAM_CONFIG_OFFS);
|
||||
|
||||
/* Prepare to go to self-refresh */
|
||||
|
||||
srcmd = readl(sdram_ctrl + SDRAM_OPERATION_OFFS);
|
||||
srcmd &= ~0x1F;
|
||||
srcmd |= SDRAM_OPERATION_SELF_REFRESH;
|
||||
|
||||
mvebu_board_pm_enter(sdram_ctrl + SDRAM_OPERATION_OFFS, srcmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BOOT_INFO_ADDR 0x3000
|
||||
#define BOOT_MAGIC_WORD 0xdeadb002
|
||||
#define BOOT_MAGIC_LIST_END 0xffffffff
|
||||
|
||||
/*
|
||||
* Those registers are accessed before switching the internal register
|
||||
* base, which is why we hardcode the 0xd0000000 base address, the one
|
||||
* used by the SoC out of reset.
|
||||
*/
|
||||
#define MBUS_WINDOW_12_CTRL 0xd00200b0
|
||||
#define MBUS_INTERNAL_REG_ADDRESS 0xd0020080
|
||||
|
||||
#define SDRAM_WIN_BASE_REG(x) (0x20180 + (0x8*x))
|
||||
#define SDRAM_WIN_CTRL_REG(x) (0x20184 + (0x8*x))
|
||||
|
||||
static phys_addr_t mvebu_internal_reg_base(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
__be32 in_addr[2];
|
||||
|
||||
np = of_find_node_by_name(NULL, "internal-regs");
|
||||
BUG_ON(!np);
|
||||
|
||||
/*
|
||||
* Ask the DT what is the internal register address on this
|
||||
* platform. In the mvebu-mbus DT binding, 0xf0010000
|
||||
* corresponds to the internal register window.
|
||||
*/
|
||||
in_addr[0] = cpu_to_be32(0xf0010000);
|
||||
in_addr[1] = 0x0;
|
||||
|
||||
return of_translate_address(np, in_addr);
|
||||
}
|
||||
|
||||
static void mvebu_pm_store_bootinfo(void)
|
||||
{
|
||||
u32 *store_addr;
|
||||
phys_addr_t resume_pc;
|
||||
|
||||
store_addr = phys_to_virt(BOOT_INFO_ADDR);
|
||||
resume_pc = virt_to_phys(armada_370_xp_cpu_resume);
|
||||
|
||||
/*
|
||||
* The bootloader expects the first two words to be a magic
|
||||
* value (BOOT_MAGIC_WORD), followed by the address of the
|
||||
* resume code to jump to. Then, it expects a sequence of
|
||||
* (address, value) pairs, which can be used to restore the
|
||||
* value of certain registers. This sequence must end with the
|
||||
* BOOT_MAGIC_LIST_END magic value.
|
||||
*/
|
||||
|
||||
writel(BOOT_MAGIC_WORD, store_addr++);
|
||||
writel(resume_pc, store_addr++);
|
||||
|
||||
/*
|
||||
* Some platforms remap their internal register base address
|
||||
* to 0xf1000000. However, out of reset, window 12 starts at
|
||||
* 0xf0000000 and ends at 0xf7ffffff, which would overlap with
|
||||
* the internal registers. Therefore, disable window 12.
|
||||
*/
|
||||
writel(MBUS_WINDOW_12_CTRL, store_addr++);
|
||||
writel(0x0, store_addr++);
|
||||
|
||||
/*
|
||||
* Set the internal register base address to the value
|
||||
* expected by Linux, as read from the Device Tree.
|
||||
*/
|
||||
writel(MBUS_INTERNAL_REG_ADDRESS, store_addr++);
|
||||
writel(mvebu_internal_reg_base(), store_addr++);
|
||||
|
||||
/*
|
||||
* Ask the mvebu-mbus driver to store the SDRAM window
|
||||
* configuration, which has to be restored by the bootloader
|
||||
* before re-entering the kernel on resume.
|
||||
*/
|
||||
store_addr += mvebu_mbus_save_cpu_target(store_addr);
|
||||
|
||||
writel(BOOT_MAGIC_LIST_END, store_addr);
|
||||
}
|
||||
|
||||
static int mvebu_pm_enter(suspend_state_t state)
|
||||
{
|
||||
if (state != PM_SUSPEND_MEM)
|
||||
return -EINVAL;
|
||||
|
||||
cpu_pm_enter();
|
||||
|
||||
mvebu_pm_store_bootinfo();
|
||||
cpu_suspend(0, mvebu_pm_powerdown);
|
||||
|
||||
outer_resume();
|
||||
|
||||
mvebu_v7_pmsu_idle_exit();
|
||||
|
||||
set_cpu_coherent();
|
||||
|
||||
cpu_pm_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_suspend_ops mvebu_pm_ops = {
|
||||
.enter = mvebu_pm_enter,
|
||||
.valid = suspend_valid_only_mem,
|
||||
};
|
||||
|
||||
int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd))
|
||||
{
|
||||
struct device_node *np;
|
||||
struct resource res;
|
||||
|
||||
if (!of_machine_is_compatible("marvell,armadaxp"))
|
||||
return -ENODEV;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL,
|
||||
"marvell,armada-xp-sdram-controller");
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
if (of_address_to_resource(np, 0, &res)) {
|
||||
of_node_put(np);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res.start, resource_size(&res),
|
||||
np->full_name)) {
|
||||
of_node_put(np);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
sdram_ctrl = ioremap(res.start, resource_size(&res));
|
||||
if (!sdram_ctrl) {
|
||||
release_mem_region(res.start, resource_size(&res));
|
||||
of_node_put(np);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
of_node_put(np);
|
||||
|
||||
mvebu_board_pm_enter = board_pm_enter;
|
||||
|
||||
suspend_set_ops(&mvebu_pm_ops);
|
||||
|
||||
return 0;
|
||||
}
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/cpufreq-dt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
@ -39,7 +40,6 @@
|
||||
#include <asm/suspend.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include "common.h"
|
||||
#include "armada-370-xp.h"
|
||||
|
||||
|
||||
#define PMSU_BASE_OFFSET 0x100
|
||||
@ -312,7 +312,7 @@ static int armada_370_xp_cpu_suspend(unsigned long deepidle)
|
||||
return cpu_suspend(deepidle, armada_370_xp_pmsu_idle_enter);
|
||||
}
|
||||
|
||||
static int armada_38x_do_cpu_suspend(unsigned long deepidle)
|
||||
int armada_38x_do_cpu_suspend(unsigned long deepidle)
|
||||
{
|
||||
unsigned long flags = 0;
|
||||
|
||||
@ -572,6 +572,10 @@ int mvebu_pmsu_dfs_request(int cpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cpufreq_dt_platform_data cpufreq_dt_pd = {
|
||||
.independent_clocks = true,
|
||||
};
|
||||
|
||||
static int __init armada_xp_pmsu_cpufreq_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
@ -644,7 +648,8 @@ static int __init armada_xp_pmsu_cpufreq_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
|
||||
platform_device_register_data(NULL, "cpufreq-dt", -1,
|
||||
&cpufreq_dt_pd, sizeof(cpufreq_dt_pd));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -17,5 +17,8 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target,
|
||||
phys_addr_t resume_addr_reg);
|
||||
|
||||
void mvebu_v7_pmsu_idle_exit(void);
|
||||
void armada_370_xp_cpu_resume(void);
|
||||
|
||||
int armada_370_xp_pmsu_idle_enter(unsigned long deepidle);
|
||||
int armada_38x_do_cpu_suspend(unsigned long deepidle);
|
||||
#endif /* __MACH_370_XP_PMSU_H */
|
||||
|
@ -12,12 +12,32 @@
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
|
||||
ENTRY(armada_38x_scu_power_up)
|
||||
mrc p15, 4, r1, c15, c0 @ get SCU base address
|
||||
orr r1, r1, #0x8 @ SCU CPU Power Status Register
|
||||
mrc 15, 0, r0, cr0, cr0, 5 @ get the CPU ID
|
||||
and r0, r0, #15
|
||||
add r1, r1, r0
|
||||
mov r0, #0x0
|
||||
strb r0, [r1] @ switch SCU power state to Normal mode
|
||||
ret lr
|
||||
ENDPROC(armada_38x_scu_power_up)
|
||||
|
||||
/*
|
||||
* This is the entry point through which CPUs exiting cpuidle deep
|
||||
* idle state are going.
|
||||
*/
|
||||
ENTRY(armada_370_xp_cpu_resume)
|
||||
ARM_BE8(setend be ) @ go BE8 if entered LE
|
||||
/*
|
||||
* Disable the MMU that might have been enabled in BootROM if
|
||||
* this code is used in the resume path of a suspend/resume
|
||||
* cycle.
|
||||
*/
|
||||
mrc p15, 0, r1, c1, c0, 0
|
||||
bic r1, #1
|
||||
mcr p15, 0, r1, c1, c0, 0
|
||||
bl ll_add_cpu_to_smp_group
|
||||
bl ll_enable_coherency
|
||||
b cpu_resume
|
||||
@ -27,13 +47,7 @@ ENTRY(armada_38x_cpu_resume)
|
||||
/* do we need it for Armada 38x*/
|
||||
ARM_BE8(setend be ) @ go BE8 if entered LE
|
||||
bl v7_invalidate_l1
|
||||
mrc p15, 4, r1, c15, c0 @ get SCU base address
|
||||
orr r1, r1, #0x8 @ SCU CPU Power Status Register
|
||||
mrc 15, 0, r0, cr0, cr0, 5 @ get the CPU ID
|
||||
and r0, r0, #15
|
||||
add r1, r1, r0
|
||||
mov r0, #0x0
|
||||
strb r0, [r1] @ switch SCU power state to Normal mode
|
||||
bl armada_38x_scu_power_up
|
||||
b cpu_resume
|
||||
ENDPROC(armada_38x_cpu_resume)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user