提交 6cd94d5e 编写于 作者: L Linus Torvalds

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
  ...
...@@ -7,32 +7,14 @@ world, which changes the way some things have to be initialized. This makes ...@@ -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 a need to provide an interface for such platforms to specify available firmware
operations and call them when needed. operations and call them when needed.
Firmware operations can be specified using struct firmware_ops Firmware operations can be specified by filling in a struct firmware_ops
with appropriate callbacks and then registering it with register_firmware_ops()
struct firmware_ops { function.
/*
* 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
void register_firmware_ops(const struct firmware_ops *ops) 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 There is a default, empty set of operations provided, so there is no need to
set anything if platform does not require firmware operations. set anything if platform does not require firmware operations.
......
...@@ -37,16 +37,26 @@ SunXi family ...@@ -37,16 +37,26 @@ SunXi family
http://dl.linux-sunxi.org/A20/A20%20User%20Manual%202013-03-22.pdf http://dl.linux-sunxi.org/A20/A20%20User%20Manual%202013-03-22.pdf
- Allwinner A23 - 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 * Quad ARM Cortex-A7 based SoCs
- Allwinner A31 (sun6i) - Allwinner A31 (sun6i)
+ Datasheet + 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) - Allwinner A31s (sun6i)
+ Not Supported + 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 * Quad ARM Cortex-A15, Quad ARM Cortex-A7 based SoCs
- Allwinner A80 - Allwinner A80
+ Not Supported + Datasheet
\ No newline at end of file http://dl.linux-sunxi.org/A80/A80_Datasheet_Revision_1.0_0404.pdf
...@@ -2,7 +2,9 @@ Amlogic MesonX device tree bindings ...@@ -2,7 +2,9 @@ Amlogic MesonX device tree bindings
------------------------------------------- -------------------------------------------
Boards with the Amlogic Meson6 SoC shall have the following properties: Boards with the Amlogic Meson6 SoC shall have the following properties:
Required root node property:
compatible: "amlogic,meson6"
Required root node property: Boards with the Amlogic Meson8 SoC shall have the following properties:
Required root node property:
compatible = "amlogic,meson6"; compatible: "amlogic,meson8";
...@@ -227,6 +227,15 @@ nodes to be present and contain the properties described below. ...@@ -227,6 +227,15 @@ nodes to be present and contain the properties described below.
# List of phandles to idle state nodes supported # List of phandles to idle state nodes supported
by this cpu [3]. 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): Example 1 (dual-cluster big.LITTLE system 32-bit):
cpus { cpus {
......
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
* 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: ...@@ -48,9 +48,12 @@ Required properties:
- compatible: Should be set to "marvell,mbus-controller". - compatible: Should be set to "marvell,mbus-controller".
- reg: Device's register space. - reg: Device's register space.
Two entries are expected (see the examples below): Two or three entries are expected (see the examples below):
the first one controls the devices decoding window and the first one controls the devices decoding window,
the second one controls the SDRAM 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: Example:
...@@ -67,7 +70,7 @@ Example: ...@@ -67,7 +70,7 @@ Example:
mbusc: mbus-controller@20000 { mbusc: mbus-controller@20000 {
compatible = "marvell,mbus-controller"; compatible = "marvell,mbus-controller";
reg = <0x20000 0x100>, <0x20180 0x20>; reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
}; };
/* more children ...*/ /* more children ...*/
...@@ -126,7 +129,7 @@ are skipped. ...@@ -126,7 +129,7 @@ are skipped.
mbusc: mbus-controller@20000 { mbusc: mbus-controller@20000 {
compatible = "marvell,mbus-controller"; compatible = "marvell,mbus-controller";
reg = <0x20000 0x100>, <0x20180 0x20>; reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
}; };
/* more children ...*/ /* more children ...*/
...@@ -170,7 +173,7 @@ Using this macro, the above example would be: ...@@ -170,7 +173,7 @@ Using this macro, the above example would be:
mbusc: mbus-controller@20000 { mbusc: mbus-controller@20000 {
compatible = "marvell,mbus-controller"; compatible = "marvell,mbus-controller";
reg = <0x20000 0x100>, <0x20180 0x20>; reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
}; };
/* other children */ /* other children */
...@@ -266,7 +269,7 @@ See the example below, where a more complete device tree is shown: ...@@ -266,7 +269,7 @@ See the example below, where a more complete device tree is shown:
ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>; ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>;
mbusc: mbus-controller@20000 { mbusc: mbus-controller@20000 {
reg = <0x20000 0x100>, <0x20180 0x20>; reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
}; };
interrupt-controller@20000 { interrupt-controller@20000 {
......
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>;
};
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 ...@@ -91,6 +91,7 @@ lltc Linear Technology Corporation
marvell Marvell Technology Group Ltd. marvell Marvell Technology Group Ltd.
maxim Maxim Integrated Products maxim Maxim Integrated Products
mediatek MediaTek Inc. mediatek MediaTek Inc.
merrii Merrii Technology Co., Ltd.
micrel Micrel Inc. micrel Micrel Inc.
microchip Microchip Technology Inc. microchip Microchip Technology Inc.
micron Micron Technology Inc. micron Micron Technology Inc.
......
...@@ -1379,6 +1379,7 @@ F: arch/arm/configs/lager_defconfig ...@@ -1379,6 +1379,7 @@ F: arch/arm/configs/lager_defconfig
F: arch/arm/configs/mackerel_defconfig F: arch/arm/configs/mackerel_defconfig
F: arch/arm/configs/marzen_defconfig F: arch/arm/configs/marzen_defconfig
F: arch/arm/configs/shmobile_defconfig F: arch/arm/configs/shmobile_defconfig
F: arch/arm/include/debug/renesas-scif.S
F: arch/arm/mach-shmobile/ F: arch/arm/mach-shmobile/
F: drivers/sh/ F: drivers/sh/
......
...@@ -320,24 +320,6 @@ config ARCH_MULTIPLATFORM ...@@ -320,24 +320,6 @@ config ARCH_MULTIPLATFORM
select SPARSE_IRQ select SPARSE_IRQ
select USE_OF 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 config ARCH_REALVIEW
bool "ARM Ltd. RealView family" bool "ARM Ltd. RealView family"
select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_WANT_OPTIONAL_GPIOLIB
...@@ -857,6 +839,8 @@ config ARCH_VIRT ...@@ -857,6 +839,8 @@ config ARCH_VIRT
# #
source "arch/arm/mach-mvebu/Kconfig" source "arch/arm/mach-mvebu/Kconfig"
source "arch/arm/mach-asm9260/Kconfig"
source "arch/arm/mach-at91/Kconfig" source "arch/arm/mach-at91/Kconfig"
source "arch/arm/mach-axxia/Kconfig" source "arch/arm/mach-axxia/Kconfig"
......
...@@ -93,6 +93,27 @@ choice ...@@ -93,6 +93,27 @@ choice
prompt "Kernel low-level debugging port" prompt "Kernel low-level debugging port"
depends on DEBUG_LL 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 config AT91_DEBUG_LL_DBGU0
bool "Kernel low-level debugging on rm9200, 9260/9g20, 9261/9g10 and 9rl" bool "Kernel low-level debugging on rm9200, 9260/9g20, 9261/9g10 and 9rl"
depends on HAVE_AT91_DBGU0 depends on HAVE_AT91_DBGU0
...@@ -113,7 +134,7 @@ choice ...@@ -113,7 +134,7 @@ choice
config DEBUG_BCM_5301X config DEBUG_BCM_5301X
bool "Kernel low-level debugging on BCM5301X UART1" bool "Kernel low-level debugging on BCM5301X UART1"
depends on ARCH_BCM_5301X depends on ARCH_BCM_5301X
select DEBUG_UART_PL01X select DEBUG_UART_8250
config DEBUG_BCM_KONA_UART config DEBUG_BCM_KONA_UART
bool "Kernel low-level debugging messages via BCM KONA UART" bool "Kernel low-level debugging messages via BCM KONA UART"
...@@ -139,6 +160,17 @@ choice ...@@ -139,6 +160,17 @@ choice
Say Y here if you want kernel low-level debugging support Say Y here if you want kernel low-level debugging support
on Marvell Berlin SoC based platforms. 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 config DEBUG_CLPS711X_UART1
bool "Kernel low-level debugging messages via UART1" bool "Kernel low-level debugging messages via UART1"
depends on ARCH_CLPS711X depends on ARCH_CLPS711X
...@@ -653,6 +685,64 @@ choice ...@@ -653,6 +685,64 @@ choice
Say Y here if you want kernel low-level debugging support Say Y here if you want kernel low-level debugging support
on Rockchip RK32xx based platforms. 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 config DEBUG_S3C_UART0
depends on PLAT_SAMSUNG depends on PLAT_SAMSUNG
select DEBUG_EXYNOS_UART if ARCH_EXYNOS select DEBUG_EXYNOS_UART if ARCH_EXYNOS
...@@ -723,6 +813,14 @@ choice ...@@ -723,6 +813,14 @@ choice
their output to UART 2. The port must have been initialised their output to UART 2. The port must have been initialised
by the boot-loader before use. 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 config DEBUG_SOCFPGA_UART
depends on ARCH_SOCFPGA depends on ARCH_SOCFPGA
bool "Use SOCFPGA UART for low-level debug" bool "Use SOCFPGA UART for low-level debug"
...@@ -731,6 +829,14 @@ choice ...@@ -731,6 +829,14 @@ choice
Say Y here if you want kernel low-level debugging support Say Y here if you want kernel low-level debugging support
on SOCFPGA based platforms. 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 config DEBUG_SUNXI_UART0
bool "Kernel low-level debugging messages via sunXi UART0" bool "Kernel low-level debugging messages via sunXi UART0"
depends on ARCH_SUNXI depends on ARCH_SUNXI
...@@ -866,6 +972,22 @@ choice ...@@ -866,6 +972,22 @@ choice
Say Y here if you want kernel low-level debugging support Say Y here if you want kernel low-level debugging support
for Mediatek mt6589 based platforms on UART0. 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 config DEBUG_VEXPRESS_UART0_DETECT
bool "Autodetect UART0 on Versatile Express Cortex-A core tiles" bool "Autodetect UART0 on Versatile Express Cortex-A core tiles"
depends on ARCH_VEXPRESS && CPU_CP15_MMU depends on ARCH_VEXPRESS && CPU_CP15_MMU
...@@ -1041,7 +1163,9 @@ config DEBUG_STI_UART ...@@ -1041,7 +1163,9 @@ config DEBUG_STI_UART
config DEBUG_LL_INCLUDE config DEBUG_LL_INCLUDE
string string
default "debug/sa1100.S" if DEBUG_SA1100
default "debug/8250.S" if DEBUG_LL_UART_8250 || DEBUG_UART_8250 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/clps711x.S" if DEBUG_CLPS711X_UART1 || DEBUG_CLPS711X_UART2
default "debug/meson.S" if DEBUG_MESON_UARTAO default "debug/meson.S" if DEBUG_MESON_UARTAO
default "debug/pl01x.S" if DEBUG_LL_UART_PL01X || DEBUG_UART_PL01X default "debug/pl01x.S" if DEBUG_LL_UART_PL01X || DEBUG_UART_PL01X
...@@ -1061,6 +1185,14 @@ config DEBUG_LL_INCLUDE ...@@ -1061,6 +1185,14 @@ config DEBUG_LL_INCLUDE
DEBUG_IMX6SX_UART DEBUG_IMX6SX_UART
default "debug/msm.S" if DEBUG_MSM_UART || DEBUG_QCOM_UARTDM default "debug/msm.S" if DEBUG_MSM_UART || DEBUG_QCOM_UARTDM
default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART 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/s3c24xx.S" if DEBUG_S3C24XX_UART
default "debug/s5pv210.S" if DEBUG_S5PV210_UART default "debug/s5pv210.S" if DEBUG_S5PV210_UART
default "debug/sirf.S" if DEBUG_SIRFPRIMA2_UART1 || DEBUG_SIRFMARCO_UART1 default "debug/sirf.S" if DEBUG_SIRFPRIMA2_UART1 || DEBUG_SIRFMARCO_UART1
...@@ -1106,6 +1238,7 @@ config DEBUG_UART_PHYS ...@@ -1106,6 +1238,7 @@ config DEBUG_UART_PHYS
default 0x02530c00 if DEBUG_KEYSTONE_UART0 default 0x02530c00 if DEBUG_KEYSTONE_UART0
default 0x02531000 if DEBUG_KEYSTONE_UART1 default 0x02531000 if DEBUG_KEYSTONE_UART1
default 0x03010fe0 if ARCH_RPC default 0x03010fe0 if ARCH_RPC
default 0x07000000 if DEBUG_SUN9I_UART0
default 0x10009000 if DEBUG_REALVIEW_STD_PORT || \ default 0x10009000 if DEBUG_REALVIEW_STD_PORT || \
DEBUG_VEXPRESS_UART0_CA9 DEBUG_VEXPRESS_UART0_CA9
default 0x1010c000 if DEBUG_REALVIEW_PB1176_PORT default 0x1010c000 if DEBUG_REALVIEW_PB1176_PORT
...@@ -1113,7 +1246,9 @@ config DEBUG_UART_PHYS ...@@ -1113,7 +1246,9 @@ config DEBUG_UART_PHYS
default 0x10126000 if DEBUG_RK3X_UART1 default 0x10126000 if DEBUG_RK3X_UART1
default 0x101f1000 if ARCH_VERSATILE default 0x101f1000 if ARCH_VERSATILE
default 0x101fb000 if DEBUG_NOMADIK_UART default 0x101fb000 if DEBUG_NOMADIK_UART
default 0x11002000 if DEBUG_MT8127_UART0
default 0x11006000 if DEBUG_MT6589_UART0 default 0x11006000 if DEBUG_MT6589_UART0
default 0x11009000 if DEBUG_MT8135_UART3
default 0x16000000 if ARCH_INTEGRATOR default 0x16000000 if ARCH_INTEGRATOR
default 0x18000300 if DEBUG_BCM_5301X default 0x18000300 if DEBUG_BCM_5301X
default 0x1c090000 if DEBUG_VEXPRESS_UART0_RS1 default 0x1c090000 if DEBUG_VEXPRESS_UART0_RS1
...@@ -1135,6 +1270,7 @@ config DEBUG_UART_PHYS ...@@ -1135,6 +1270,7 @@ config DEBUG_UART_PHYS
default 0x78000000 if DEBUG_CNS3XXX default 0x78000000 if DEBUG_CNS3XXX
default 0x7c0003f8 if FOOTBRIDGE default 0x7c0003f8 if FOOTBRIDGE
default 0x78000000 if DEBUG_CNS3XXX default 0x78000000 if DEBUG_CNS3XXX
default 0x80010000 if DEBUG_ASM9260_UART
default 0x80070000 if DEBUG_IMX23_UART default 0x80070000 if DEBUG_IMX23_UART
default 0x80074000 if DEBUG_IMX28_UART default 0x80074000 if DEBUG_IMX28_UART
default 0x80230000 if DEBUG_PICOXCELL_UART default 0x80230000 if DEBUG_PICOXCELL_UART
...@@ -1152,7 +1288,14 @@ config DEBUG_UART_PHYS ...@@ -1152,7 +1288,14 @@ config DEBUG_UART_PHYS
default 0xd4018000 if DEBUG_MMP_UART3 default 0xd4018000 if DEBUG_MMP_UART3
default 0xe0000000 if ARCH_SPEAR13XX default 0xe0000000 if ARCH_SPEAR13XX
default 0xe4007000 if DEBUG_HIP04_UART 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 0xf0000be0 if ARCH_EBSA110
default 0xf040ab00 if DEBUG_BRCMSTB_UART
default 0xf1012000 if DEBUG_MVEBU_UART_ALTERNATE default 0xf1012000 if DEBUG_MVEBU_UART_ALTERNATE
default 0xf1012000 if ARCH_DOVE || ARCH_MV78XX0 || \ default 0xf1012000 if ARCH_DOVE || ARCH_MV78XX0 || \
ARCH_ORION5X ARCH_ORION5X
...@@ -1164,24 +1307,33 @@ config DEBUG_UART_PHYS ...@@ -1164,24 +1307,33 @@ config DEBUG_UART_PHYS
default 0xff690000 if DEBUG_RK32_UART2 default 0xff690000 if DEBUG_RK32_UART2
default 0xffc02000 if DEBUG_SOCFPGA_UART default 0xffc02000 if DEBUG_SOCFPGA_UART
default 0xffd82340 if ARCH_IOP13XX 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 0xfff36000 if DEBUG_HIGHBANK_UART
default 0xfffe8600 if DEBUG_UART_BCM63XX default 0xfffe8600 if DEBUG_UART_BCM63XX
default 0xfffff700 if ARCH_IOP33X default 0xfffff700 if ARCH_IOP33X
depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \
DEBUG_LL_UART_EFM32 || \ DEBUG_LL_UART_EFM32 || \
DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \
DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \ DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_R7S72100_SCIF2 || \
DEBUG_UART_BCM63XX 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 config DEBUG_UART_VIRT
hex "Virtual base address of debug UART" hex "Virtual base address of debug UART"
default 0xe0010fe0 if ARCH_RPC default 0xe0010fe0 if ARCH_RPC
default 0xe1000000 if DEBUG_MSM_UART default 0xe1000000 if DEBUG_MSM_UART
default 0xf0000be0 if ARCH_EBSA110 default 0xf0000be0 if ARCH_EBSA110
default 0xf0010000 if DEBUG_ASM9260_UART
default 0xf01fb000 if DEBUG_NOMADIK_UART default 0xf01fb000 if DEBUG_NOMADIK_UART
default 0xf0201000 if DEBUG_BCM2835 default 0xf0201000 if DEBUG_BCM2835
default 0xf1000300 if DEBUG_BCM_5301X default 0xf1000300 if DEBUG_BCM_5301X
default 0xf1002000 if DEBUG_MT8127_UART0
default 0xf1006000 if DEBUG_MT6589_UART0 default 0xf1006000 if DEBUG_MT6589_UART0
default 0xf1009000 if DEBUG_MT8135_UART3
default 0xf11f1000 if ARCH_VERSATILE default 0xf11f1000 if ARCH_VERSATILE
default 0xf1600000 if ARCH_INTEGRATOR default 0xf1600000 if ARCH_INTEGRATOR
default 0xf1c28000 if DEBUG_SUNXI_UART0 default 0xf1c28000 if DEBUG_SUNXI_UART0
...@@ -1190,6 +1342,7 @@ config DEBUG_UART_VIRT ...@@ -1190,6 +1342,7 @@ config DEBUG_UART_VIRT
default 0xf6200000 if DEBUG_PXA_UART1 default 0xf6200000 if DEBUG_PXA_UART1
default 0xf4090000 if ARCH_LPC32XX default 0xf4090000 if ARCH_LPC32XX
default 0xf4200000 if ARCH_GEMINI default 0xf4200000 if ARCH_GEMINI
default 0xf7000000 if DEBUG_SUN9I_UART0
default 0xf7000000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART0 || \ default 0xf7000000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART0 || \
DEBUG_S3C2410_UART0) DEBUG_S3C2410_UART0)
default 0xf7004000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART1 || \ default 0xf7004000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART1 || \
...@@ -1204,6 +1357,7 @@ config DEBUG_UART_VIRT ...@@ -1204,6 +1357,7 @@ config DEBUG_UART_VIRT
default 0xfb002000 if DEBUG_CNS3XXX default 0xfb002000 if DEBUG_CNS3XXX
default 0xfb009000 if DEBUG_REALVIEW_STD_PORT default 0xfb009000 if DEBUG_REALVIEW_STD_PORT
default 0xfb10c000 if DEBUG_REALVIEW_PB1176_PORT default 0xfb10c000 if DEBUG_REALVIEW_PB1176_PORT
default 0xfc40ab00 if DEBUG_BRCMSTB_UART
default 0xfcfe8600 if DEBUG_UART_BCM63XX default 0xfcfe8600 if DEBUG_UART_BCM63XX
default 0xfd000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX default 0xfd000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX
default 0xfd000000 if ARCH_SPEAR13XX default 0xfd000000 if ARCH_SPEAR13XX
...@@ -1244,12 +1398,12 @@ config DEBUG_UART_VIRT ...@@ -1244,12 +1398,12 @@ config DEBUG_UART_VIRT
depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \
DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \
DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \ DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \
DEBUG_UART_BCM63XX DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART
config DEBUG_UART_8250_SHIFT config DEBUG_UART_8250_SHIFT
int "Register offset shift for the 8250 debug UART" int "Register offset shift for the 8250 debug UART"
depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250 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 default 2
config DEBUG_UART_8250_WORD config DEBUG_UART_8250_WORD
...@@ -1260,7 +1414,8 @@ config DEBUG_UART_8250_WORD ...@@ -1260,7 +1414,8 @@ config DEBUG_UART_8250_WORD
ARCH_KEYSTONE || \ ARCH_KEYSTONE || \
DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \ DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \
DEBUG_DAVINCI_DA8XX_UART2 || \ 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 config DEBUG_UART_8250_FLOW_CONTROL
bool "Enable flow control for 8250 UART" bool "Enable flow control for 8250 UART"
......
...@@ -180,7 +180,8 @@ ...@@ -180,7 +180,8 @@
mbusc: mbus-controller@20000 { mbusc: mbus-controller@20000 {
compatible = "marvell,mbus-controller"; compatible = "marvell,mbus-controller";
reg = <0x20000 0x100>, <0x20180 0x20>; reg = <0x20000 0x100>, <0x20180 0x20>,
<0x20250 0x8>;
}; };
mpic: interrupt-controller@20000 { mpic: interrupt-controller@20000 {
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
*/ */
/dts-v1/; /dts-v1/;
#include <dt-bindings/gpio/gpio.h>
#include "armada-xp-mv78460.dtsi" #include "armada-xp-mv78460.dtsi"
/ { / {
...@@ -48,6 +49,14 @@ ...@@ -48,6 +49,14 @@
<0x00000001 0x00000000 0x00000001 0x00000000>; <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 { soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000 ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
...@@ -115,7 +124,15 @@ ...@@ -115,7 +124,15 @@
serial@12300 { serial@12300 {
status = "okay"; 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 { sata@a0000 {
nr-ports = <2>; nr-ports = <2>;
status = "okay"; status = "okay";
......
...@@ -35,6 +35,11 @@ ...@@ -35,6 +35,11 @@
}; };
internal-regs { internal-regs {
sdramc@1400 {
compatible = "marvell,armada-xp-sdram-controller";
reg = <0x1400 0x500>;
};
L2: l2-cache { L2: l2-cache {
compatible = "marvell,aurora-system-cache"; compatible = "marvell,aurora-system-cache";
reg = <0x08000 0x1000>; reg = <0x08000 0x1000>;
......
...@@ -6,8 +6,18 @@ ...@@ -6,8 +6,18 @@
/ { / {
core-module@10000000 { core-module@10000000 {
compatible = "arm,core-module-integrator"; compatible = "arm,core-module-integrator", "syscon";
reg = <0x10000000 0x200>; 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 { ebi@12000000 {
...@@ -82,5 +92,41 @@ ...@@ -82,5 +92,41 @@
reg = <0x19000000 0x1000>; reg = <0x19000000 0x1000>;
interrupts = <4>; 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 @@ ...@@ -64,6 +64,7 @@
#include "twl4030.dtsi" #include "twl4030.dtsi"
#include "twl4030_omap3.dtsi" #include "twl4030_omap3.dtsi"
#include <dt-bindings/input/input.h>
&mmc1 { &mmc1 {
vmmc-supply = <&vmmc1>; vmmc-supply = <&vmmc1>;
...@@ -75,6 +76,22 @@ ...@@ -75,6 +76,22 @@
ti,pullups = <0x000001>; 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 { &hsusb1_phy {
reset-gpios = <&twl_gpio 6 GPIO_ACTIVE_LOW>; reset-gpios = <&twl_gpio 6 GPIO_ACTIVE_LOW>;
}; };
......
...@@ -895,7 +895,7 @@ ...@@ -895,7 +895,7 @@
reg = <0x58002000 0x1000>; reg = <0x58002000 0x1000>;
status = "disabled"; status = "disabled";
ti,hwmods = "dss_rfbi"; ti,hwmods = "dss_rfbi";
clocks = <&dss_dss_clk>, <&dss_fck>; clocks = <&dss_dss_clk>, <&l3_div_ck>;
clock-names = "fck", "ick"; clock-names = "fck", "ick";
}; };
......
...@@ -1018,14 +1018,6 @@ ...@@ -1018,14 +1018,6 @@
reg = <0x1120>; 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 { fdif_fck: fdif_fck {
#clock-cells = <0>; #clock-cells = <0>;
compatible = "ti,divider-clock"; compatible = "ti,divider-clock";
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/mfd/dbx500-prcmu.h> #include <dt-bindings/mfd/dbx500-prcmu.h>
#include <dt-bindings/arm/ux500_pm_domains.h>
#include "skeleton.dtsi" #include "skeleton.dtsi"
/ { / {
...@@ -43,6 +44,10 @@ ...@@ -43,6 +44,10 @@
interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>; interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>;
}; };
pm_domains: pm_domains0 {
compatible = "stericsson,ux500-pm-domains";
#power-domain-cells = <1>;
};
clocks { clocks {
compatible = "stericsson,u8500-clks"; compatible = "stericsson,u8500-clks";
...@@ -636,6 +641,7 @@ ...@@ -636,6 +641,7 @@
clock-frequency = <400000>; clock-frequency = <400000>;
clocks = <&prcc_kclk 3 3>, <&prcc_pclk 3 3>; clocks = <&prcc_kclk 3 3>, <&prcc_pclk 3 3>;
clock-names = "i2cclk", "apb_pclk"; clock-names = "i2cclk", "apb_pclk";
power-domains = <&pm_domains DOMAIN_VAPE>;
}; };
i2c@80122000 { i2c@80122000 {
...@@ -651,6 +657,7 @@ ...@@ -651,6 +657,7 @@
clocks = <&prcc_kclk 1 2>, <&prcc_pclk 1 2>; clocks = <&prcc_kclk 1 2>, <&prcc_pclk 1 2>;
clock-names = "i2cclk", "apb_pclk"; clock-names = "i2cclk", "apb_pclk";
power-domains = <&pm_domains DOMAIN_VAPE>;
}; };
i2c@80128000 { i2c@80128000 {
...@@ -666,6 +673,7 @@ ...@@ -666,6 +673,7 @@
clocks = <&prcc_kclk 1 6>, <&prcc_pclk 1 6>; clocks = <&prcc_kclk 1 6>, <&prcc_pclk 1 6>;
clock-names = "i2cclk", "apb_pclk"; clock-names = "i2cclk", "apb_pclk";
power-domains = <&pm_domains DOMAIN_VAPE>;
}; };
i2c@80110000 { i2c@80110000 {
...@@ -681,6 +689,7 @@ ...@@ -681,6 +689,7 @@
clocks = <&prcc_kclk 2 0>, <&prcc_pclk 2 0>; clocks = <&prcc_kclk 2 0>, <&prcc_pclk 2 0>;
clock-names = "i2cclk", "apb_pclk"; clock-names = "i2cclk", "apb_pclk";
power-domains = <&pm_domains DOMAIN_VAPE>;
}; };
i2c@8012a000 { i2c@8012a000 {
...@@ -696,6 +705,7 @@ ...@@ -696,6 +705,7 @@
clocks = <&prcc_kclk 1 9>, <&prcc_pclk 1 10>; clocks = <&prcc_kclk 1 9>, <&prcc_pclk 1 10>;
clock-names = "i2cclk", "apb_pclk"; clock-names = "i2cclk", "apb_pclk";
power-domains = <&pm_domains DOMAIN_VAPE>;
}; };
ssp@80002000 { ssp@80002000 {
...@@ -709,6 +719,7 @@ ...@@ -709,6 +719,7 @@
dmas = <&dma 8 0 0x2>, /* Logical - DevToMem */ dmas = <&dma 8 0 0x2>, /* Logical - DevToMem */
<&dma 8 0 0x0>; /* Logical - MemToDev */ <&dma 8 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx"; dma-names = "rx", "tx";
power-domains = <&pm_domains DOMAIN_VAPE>;
}; };
ssp@80003000 { ssp@80003000 {
...@@ -722,6 +733,7 @@ ...@@ -722,6 +733,7 @@
dmas = <&dma 9 0 0x2>, /* Logical - DevToMem */ dmas = <&dma 9 0 0x2>, /* Logical - DevToMem */
<&dma 9 0 0x0>; /* Logical - MemToDev */ <&dma 9 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx"; dma-names = "rx", "tx";
power-domains = <&pm_domains DOMAIN_VAPE>;
}; };
spi@8011a000 { spi@8011a000 {
...@@ -736,6 +748,7 @@ ...@@ -736,6 +748,7 @@
dmas = <&dma 0 0 0x2>, /* Logical - DevToMem */ dmas = <&dma 0 0 0x2>, /* Logical - DevToMem */
<&dma 0 0 0x0>; /* Logical - MemToDev */ <&dma 0 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx"; dma-names = "rx", "tx";
power-domains = <&pm_domains DOMAIN_VAPE>;
}; };
spi@80112000 { spi@80112000 {
...@@ -750,6 +763,7 @@ ...@@ -750,6 +763,7 @@
dmas = <&dma 35 0 0x2>, /* Logical - DevToMem */ dmas = <&dma 35 0 0x2>, /* Logical - DevToMem */
<&dma 35 0 0x0>; /* Logical - MemToDev */ <&dma 35 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx"; dma-names = "rx", "tx";
power-domains = <&pm_domains DOMAIN_VAPE>;
}; };
spi@80111000 { spi@80111000 {
...@@ -764,6 +778,7 @@ ...@@ -764,6 +778,7 @@
dmas = <&dma 33 0 0x2>, /* Logical - DevToMem */ dmas = <&dma 33 0 0x2>, /* Logical - DevToMem */
<&dma 33 0 0x0>; /* Logical - MemToDev */ <&dma 33 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx"; dma-names = "rx", "tx";
power-domains = <&pm_domains DOMAIN_VAPE>;
}; };
spi@80129000 { spi@80129000 {
...@@ -778,6 +793,7 @@ ...@@ -778,6 +793,7 @@
dmas = <&dma 40 0 0x2>, /* Logical - DevToMem */ dmas = <&dma 40 0 0x2>, /* Logical - DevToMem */
<&dma 40 0 0x0>; /* Logical - MemToDev */ <&dma 40 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx"; dma-names = "rx", "tx";
power-domains = <&pm_domains DOMAIN_VAPE>;
}; };
uart@80120000 { uart@80120000 {
...@@ -836,6 +852,7 @@ ...@@ -836,6 +852,7 @@
clocks = <&prcc_kclk 1 5>, <&prcc_pclk 1 5>; clocks = <&prcc_kclk 1 5>, <&prcc_pclk 1 5>;
clock-names = "sdi", "apb_pclk"; clock-names = "sdi", "apb_pclk";
power-domains = <&pm_domains DOMAIN_VAPE>;
status = "disabled"; status = "disabled";
}; };
...@@ -851,6 +868,7 @@ ...@@ -851,6 +868,7 @@
clocks = <&prcc_kclk 2 4>, <&prcc_pclk 2 6>; clocks = <&prcc_kclk 2 4>, <&prcc_pclk 2 6>;
clock-names = "sdi", "apb_pclk"; clock-names = "sdi", "apb_pclk";
power-domains = <&pm_domains DOMAIN_VAPE>;
status = "disabled"; status = "disabled";
}; };
...@@ -866,6 +884,7 @@ ...@@ -866,6 +884,7 @@
clocks = <&prcc_kclk 3 4>, <&prcc_pclk 3 4>; clocks = <&prcc_kclk 3 4>, <&prcc_pclk 3 4>;
clock-names = "sdi", "apb_pclk"; clock-names = "sdi", "apb_pclk";
power-domains = <&pm_domains DOMAIN_VAPE>;
status = "disabled"; status = "disabled";
}; };
...@@ -881,6 +900,7 @@ ...@@ -881,6 +900,7 @@
clocks = <&prcc_kclk 2 5>, <&prcc_pclk 2 7>; clocks = <&prcc_kclk 2 5>, <&prcc_pclk 2 7>;
clock-names = "sdi", "apb_pclk"; clock-names = "sdi", "apb_pclk";
power-domains = <&pm_domains DOMAIN_VAPE>;
status = "disabled"; status = "disabled";
}; };
...@@ -896,6 +916,7 @@ ...@@ -896,6 +916,7 @@
clocks = <&prcc_kclk 2 2>, <&prcc_pclk 2 4>; clocks = <&prcc_kclk 2 2>, <&prcc_pclk 2 4>;
clock-names = "sdi", "apb_pclk"; clock-names = "sdi", "apb_pclk";
power-domains = <&pm_domains DOMAIN_VAPE>;
status = "disabled"; status = "disabled";
}; };
...@@ -911,6 +932,7 @@ ...@@ -911,6 +932,7 @@
clocks = <&prcc_kclk 3 7>, <&prcc_pclk 3 7>; clocks = <&prcc_kclk 3 7>, <&prcc_pclk 3 7>;
clock-names = "sdi", "apb_pclk"; clock-names = "sdi", "apb_pclk";
power-domains = <&pm_domains DOMAIN_VAPE>;
status = "disabled"; status = "disabled";
}; };
......
...@@ -25,7 +25,8 @@ CONFIG_MODULE_UNLOAD=y ...@@ -25,7 +25,8 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set # CONFIG_BLK_DEV_BSG is not set
CONFIG_PARTITION_ADVANCED=y CONFIG_PARTITION_ADVANCED=y
CONFIG_ARCH_BCM=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_ARM_THUMBEE=y
CONFIG_SMP=y CONFIG_SMP=y
CONFIG_PREEMPT=y CONFIG_PREEMPT=y
......
...@@ -8,6 +8,9 @@ CONFIG_BLK_DEV_INITRD=y ...@@ -8,6 +8,9 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_MODULES=y CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=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=y
CONFIG_ARCH_INTEGRATOR_AP=y CONFIG_ARCH_INTEGRATOR_AP=y
CONFIG_ARCH_INTEGRATOR_CP=y CONFIG_ARCH_INTEGRATOR_CP=y
......
...@@ -28,7 +28,7 @@ struct firmware_ops { ...@@ -28,7 +28,7 @@ struct firmware_ops {
/* /*
* Enters CPU idle mode * Enters CPU idle mode
*/ */
int (*do_idle)(void); int (*do_idle)(unsigned long mode);
/* /*
* Sets boot address of specified physical CPU * Sets boot address of specified physical CPU
*/ */
...@@ -41,6 +41,14 @@ struct firmware_ops { ...@@ -41,6 +41,14 @@ struct firmware_ops {
* Initializes L2 cache * Initializes L2 cache
*/ */
int (*l2x0_init)(void); 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. */ /* Global pointer for current firmware_ops structure, can't be NULL. */
......
/* 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
/*
* 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
/* arch/arm/mach-sa1100/include/mach/debug-macro.S /* arch/arm/include/debug/sa1100.S
* *
* Debugging macro include header * Debugging macro include header
* *
...@@ -10,7 +10,13 @@ ...@@ -10,7 +10,13 @@
* published by the Free Software Foundation. * 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 .macro addruart, rp, rv, tmp
mrc p15, 0, \rp, c1, c0 mrc p15, 0, \rp, c1, c0
......
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 ...@@ -5,8 +5,56 @@ menuconfig ARCH_BCM
if 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 config ARCH_BCM_MOBILE
bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7 bool
select ARCH_REQUIRE_GPIOLIB select ARCH_REQUIRE_GPIOLIB
select ARM_ERRATA_754322 select ARM_ERRATA_754322
select ARM_ERRATA_775420 select ARM_ERRATA_775420
...@@ -15,16 +63,13 @@ config ARCH_BCM_MOBILE ...@@ -15,16 +63,13 @@ config ARCH_BCM_MOBILE
select TICK_ONESHOT select TICK_ONESHOT
select HAVE_ARM_ARCH_TIMER select HAVE_ARM_ARCH_TIMER
select PINCTRL select PINCTRL
select ARCH_BCM_MOBILE_SMP if SMP
help help
This enables support for systems based on Broadcom mobile SoCs. This enables support for systems based on Broadcom mobile SoCs.
if ARCH_BCM_MOBILE
menu "Broadcom Mobile SoC Selection"
config ARCH_BCM_281XX config ARCH_BCM_281XX
bool "Broadcom BCM281XX SoC family" bool "Broadcom BCM281XX SoC family"
default y select ARCH_BCM_MOBILE
select HAVE_SMP select HAVE_SMP
help help
Enable support for the BCM281XX family, which includes Enable support for the BCM281XX family, which includes
...@@ -33,7 +78,7 @@ config ARCH_BCM_281XX ...@@ -33,7 +78,7 @@ config ARCH_BCM_281XX
config ARCH_BCM_21664 config ARCH_BCM_21664
bool "Broadcom BCM21664 SoC family" bool "Broadcom BCM21664 SoC family"
default y select ARCH_BCM_MOBILE
select HAVE_SMP select HAVE_SMP
help help
Enable support for the BCM21664 family, which includes Enable support for the BCM21664 family, which includes
...@@ -41,19 +86,18 @@ config ARCH_BCM_21664 ...@@ -41,19 +86,18 @@ config ARCH_BCM_21664
config ARCH_BCM_MOBILE_L2_CACHE config ARCH_BCM_MOBILE_L2_CACHE
bool "Broadcom mobile SoC level 2 cache support" bool "Broadcom mobile SoC level 2 cache support"
depends on (ARCH_BCM_281XX || ARCH_BCM_21664) depends on ARCH_BCM_MOBILE
default y default y
select CACHE_L2X0 select CACHE_L2X0
select ARCH_BCM_MOBILE_SMC select ARCH_BCM_MOBILE_SMC
config ARCH_BCM_MOBILE_SMC config ARCH_BCM_MOBILE_SMC
bool bool
depends on ARCH_BCM_281XX || ARCH_BCM_21664 depends on ARCH_BCM_MOBILE
config ARCH_BCM_MOBILE_SMP config ARCH_BCM_MOBILE_SMP
bool "Broadcom mobile SoC SMP support" bool
depends on (ARCH_BCM_281XX || ARCH_BCM_21664) && SMP depends on ARCH_BCM_MOBILE
default y
select HAVE_ARM_SCU select HAVE_ARM_SCU
select ARM_ERRATA_764369 select ARM_ERRATA_764369
help help
...@@ -61,9 +105,7 @@ config ARCH_BCM_MOBILE_SMP ...@@ -61,9 +105,7 @@ config ARCH_BCM_MOBILE_SMP
Provided as an option so SMP support for SoCs of this type Provided as an option so SMP support for SoCs of this type
can be disabled for an SMP-enabled kernel. can be disabled for an SMP-enabled kernel.
endmenu comment "Other Architectures"
endif
config ARCH_BCM2835 config ARCH_BCM2835
bool "Broadcom BCM2835 family" if ARCH_MULTI_V6 bool "Broadcom BCM2835 family" if ARCH_MULTI_V6
...@@ -78,27 +120,6 @@ config ARCH_BCM2835 ...@@ -78,27 +120,6 @@ config ARCH_BCM2835
This enables support for the Broadcom BCM2835 SoC. This SoC is This enables support for the Broadcom BCM2835 SoC. This SoC is
used in the Raspberry Pi and Roku 2 devices. 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 config ARCH_BCM_63XX
bool "Broadcom BCM63xx DSL SoC" if ARCH_MULTI_V7 bool "Broadcom BCM63xx DSL SoC" if ARCH_MULTI_V7
depends on MMU depends on MMU
...@@ -118,10 +139,7 @@ config ARCH_BCM_63XX ...@@ -118,10 +139,7 @@ config ARCH_BCM_63XX
config ARCH_BRCMSTB config ARCH_BRCMSTB
bool "Broadcom BCM7XXX based boards" if ARCH_MULTI_V7 bool "Broadcom BCM7XXX based boards" if ARCH_MULTI_V7
depends on MMU
select ARM_GIC select ARM_GIC
select MIGHT_HAVE_PCI
select HAVE_SMP
select HAVE_ARM_ARCH_TIMER select HAVE_ARM_ARCH_TIMER
select BRCMSTB_GISB_ARB select BRCMSTB_GISB_ARB
select BRCMSTB_L2_IRQ select BRCMSTB_L2_IRQ
......
...@@ -10,6 +10,9 @@ ...@@ -10,6 +10,9 @@
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# Cygnus
obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o
# BCM281XX # BCM281XX
obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o
...@@ -38,5 +41,7 @@ obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o ...@@ -38,5 +41,7 @@ obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o
obj-$(CONFIG_ARCH_BCM_63XX) := bcm63xx.o obj-$(CONFIG_ARCH_BCM_63XX) := bcm63xx.o
ifeq ($(CONFIG_ARCH_BRCMSTB),y) ifeq ($(CONFIG_ARCH_BRCMSTB),y)
CFLAGS_platsmp-brcmstb.o += -march=armv7-a
obj-y += brcmstb.o obj-y += brcmstb.o
obj-$(CONFIG_SMP) += headsmp-brcmstb.o platsmp-brcmstb.o
endif endif
/*
* 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
/*
* 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__ */
/*
* 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)
/*
* 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);
menuconfig ARCH_BERLIN menuconfig ARCH_BERLIN
bool "Marvell Berlin SoCs" if ARCH_MULTI_V7 bool "Marvell Berlin SoCs" if ARCH_MULTI_V7
select ARCH_HAS_RESET_CONTROLLER
select ARCH_REQUIRE_GPIOLIB select ARCH_REQUIRE_GPIOLIB
select ARM_GIC select ARM_GIC
select GENERIC_IRQ_CHIP
select DW_APB_ICTL select DW_APB_ICTL
select DW_APB_TIMER_OF select DW_APB_TIMER_OF
select GENERIC_IRQ_CHIP
select PINCTRL select PINCTRL
if ARCH_BERLIN if ARCH_BERLIN
......
...@@ -24,6 +24,7 @@ menuconfig ARCH_EXYNOS ...@@ -24,6 +24,7 @@ menuconfig ARCH_EXYNOS
select PM_GENERIC_DOMAINS if PM_RUNTIME select PM_GENERIC_DOMAINS if PM_RUNTIME
select S5P_DEV_MFC select S5P_DEV_MFC
select SRAM select SRAM
select MFD_SYSCON
help help
Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5) Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5)
...@@ -75,6 +76,11 @@ config SOC_EXYNOS4412 ...@@ -75,6 +76,11 @@ config SOC_EXYNOS4412
default y default y
depends on ARCH_EXYNOS4 depends on ARCH_EXYNOS4
config SOC_EXYNOS4415
bool "SAMSUNG EXYNOS4415"
default y
depends on ARCH_EXYNOS4
config SOC_EXYNOS5250 config SOC_EXYNOS5250
bool "SAMSUNG EXYNOS5250" bool "SAMSUNG EXYNOS5250"
default y default y
...@@ -123,4 +129,9 @@ config EXYNOS5420_MCPM ...@@ -123,4 +129,9 @@ config EXYNOS5420_MCPM
This is needed to provide CPU and cluster power management This is needed to provide CPU and cluster power management
on Exynos5420 implementing big.LITTLE. on Exynos5420 implementing big.LITTLE.
config EXYNOS_CPU_SUSPEND
bool
select ARM_CPU_SUSPEND
default PM_SLEEP || ARM_EXYNOS_CPUIDLE
endif endif
...@@ -11,13 +11,15 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) += -I$(srctree)/$(src)/include -I$(srctree) ...@@ -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_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_PM_GENERIC_DOMAINS) += pm_domains.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o
plus_sec := $(call as-instr,.arch_extension sec,+sec) plus_sec := $(call as-instr,.arch_extension sec,+sec)
AFLAGS_exynos-smc.o :=-Wa,-march=armv7-a$(plus_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 obj-$(CONFIG_EXYNOS5420_MCPM) += mcpm-exynos.o
CFLAGS_mcpm-exynos.o += -march=armv7-a CFLAGS_mcpm-exynos.o += -march=armv7-a
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H
#define __ARCH_ARM_MACH_EXYNOS_COMMON_H #define __ARCH_ARM_MACH_EXYNOS_COMMON_H
#include <linux/reboot.h>
#include <linux/of.h> #include <linux/of.h>
#define EXYNOS3250_SOC_ID 0xE3472000 #define EXYNOS3250_SOC_ID 0xE3472000
...@@ -111,11 +110,19 @@ IS_SAMSUNG_CPU(exynos5800, EXYNOS5800_SOC_ID, EXYNOS5_SOC_MASK) ...@@ -111,11 +110,19 @@ IS_SAMSUNG_CPU(exynos5800, EXYNOS5800_SOC_ID, EXYNOS5_SOC_MASK)
#define soc_is_exynos5() (soc_is_exynos5250() || soc_is_exynos5410() || \ #define soc_is_exynos5() (soc_is_exynos5250() || soc_is_exynos5410() || \
soc_is_exynos5420() || soc_is_exynos5800()) 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_ns_base_addr;
extern void __iomem *sysram_base_addr; extern void __iomem *sysram_base_addr;
extern void __iomem *pmu_base_addr; extern void __iomem *pmu_base_addr;
void exynos_sysram_init(void); void exynos_sysram_init(void);
enum {
FW_DO_IDLE_SLEEP,
FW_DO_IDLE_AFTR,
};
void exynos_firmware_init(void); void exynos_firmware_init(void);
extern u32 exynos_get_eint_wake_mask(void); extern u32 exynos_get_eint_wake_mask(void);
...@@ -127,32 +134,20 @@ static inline void exynos_pm_init(void) {} ...@@ -127,32 +134,20 @@ static inline void exynos_pm_init(void) {}
#endif #endif
extern void exynos_cpu_resume(void); extern void exynos_cpu_resume(void);
extern void exynos_cpu_resume_ns(void);
extern struct smp_operations exynos_smp_ops; 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_down(int cpu);
extern void exynos_cpu_power_up(int cpu); extern void exynos_cpu_power_up(int cpu);
extern int exynos_cpu_power_state(int cpu); extern int exynos_cpu_power_state(int cpu);
extern void exynos_cluster_power_down(int cluster); extern void exynos_cluster_power_down(int cluster);
extern void exynos_cluster_power_up(int cluster); extern void exynos_cluster_power_up(int cluster);
extern int exynos_cluster_power_state(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 exynos_enter_aftr(void);
extern void s5p_init_cpu(void __iomem *cpuid_addr); extern void s5p_init_cpu(void __iomem *cpuid_addr);
......
/*
* 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 = { ...@@ -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 = { static struct platform_device exynos_cpuidle = {
.name = "exynos_cpuidle", .name = "exynos_cpuidle",
#ifdef CONFIG_ARM_EXYNOS_CPUIDLE #ifdef CONFIG_ARM_EXYNOS_CPUIDLE
...@@ -202,6 +180,7 @@ static const struct of_device_id exynos_dt_pmu_match[] = { ...@@ -202,6 +180,7 @@ static const struct of_device_id exynos_dt_pmu_match[] = {
{ .compatible = "samsung,exynos4210-pmu" }, { .compatible = "samsung,exynos4210-pmu" },
{ .compatible = "samsung,exynos4212-pmu" }, { .compatible = "samsung,exynos4212-pmu" },
{ .compatible = "samsung,exynos4412-pmu" }, { .compatible = "samsung,exynos4412-pmu" },
{ .compatible = "samsung,exynos4415-pmu" },
{ .compatible = "samsung,exynos5250-pmu" }, { .compatible = "samsung,exynos5250-pmu" },
{ .compatible = "samsung,exynos5260-pmu" }, { .compatible = "samsung,exynos5260-pmu" },
{ .compatible = "samsung,exynos5410-pmu" }, { .compatible = "samsung,exynos5410-pmu" },
...@@ -268,7 +247,10 @@ static void __init exynos_dt_machine_init(void) ...@@ -268,7 +247,10 @@ static void __init exynos_dt_machine_init(void)
exynos_sysram_init(); exynos_sysram_init();
if (of_machine_is_compatible("samsung,exynos4210") || 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(&exynos_cpuidle);
platform_device_register_simple("exynos-cpufreq", -1, NULL, 0); platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
...@@ -283,6 +265,7 @@ static char const *exynos_dt_compat[] __initconst = { ...@@ -283,6 +265,7 @@ static char const *exynos_dt_compat[] __initconst = {
"samsung,exynos4210", "samsung,exynos4210",
"samsung,exynos4212", "samsung,exynos4212",
"samsung,exynos4412", "samsung,exynos4412",
"samsung,exynos4415",
"samsung,exynos5", "samsung,exynos5",
"samsung,exynos5250", "samsung,exynos5250",
"samsung,exynos5260", "samsung,exynos5260",
...@@ -328,7 +311,6 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)") ...@@ -328,7 +311,6 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
.init_machine = exynos_dt_machine_init, .init_machine = exynos_dt_machine_init,
.init_late = exynos_init_late, .init_late = exynos_init_late,
.dt_compat = exynos_dt_compat, .dt_compat = exynos_dt_compat,
.restart = exynos_restart,
.reserve = exynos_reserve, .reserve = exynos_reserve,
.dt_fixup = exynos_dt_fixup, .dt_fixup = exynos_dt_fixup,
MACHINE_END MACHINE_END
...@@ -14,16 +14,44 @@ ...@@ -14,16 +14,44 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <asm/cacheflush.h>
#include <asm/cputype.h>
#include <asm/firmware.h> #include <asm/firmware.h>
#include <asm/suspend.h>
#include <mach/map.h> #include <mach/map.h>
#include "common.h" #include "common.h"
#include "smc.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; return 0;
} }
...@@ -69,10 +97,43 @@ static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr) ...@@ -69,10 +97,43 @@ static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr)
return 0; 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 = { 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, .set_cpu_boot_addr = exynos_set_cpu_boot_addr,
.cpu_boot = exynos_cpu_boot, .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) void __init exynos_firmware_init(void)
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/syscore_ops.h>
#include <asm/cputype.h> #include <asm/cputype.h>
#include <asm/cp15.h> #include <asm/cp15.h>
...@@ -30,6 +31,8 @@ ...@@ -30,6 +31,8 @@
#define EXYNOS5420_USE_ARM_CORE_DOWN_STATE BIT(29) #define EXYNOS5420_USE_ARM_CORE_DOWN_STATE BIT(29)
#define EXYNOS5420_USE_L2_COMMON_UP_STATE BIT(30) #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 * 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 * 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[] = { ...@@ -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) static int __init exynos_mcpm_init(void)
{ {
struct device_node *node; struct device_node *node;
void __iomem *ns_sram_base_addr;
unsigned int value, i; unsigned int value, i;
int ret; int ret;
...@@ -387,16 +406,9 @@ static int __init exynos_mcpm_init(void) ...@@ -387,16 +406,9 @@ static int __init exynos_mcpm_init(void)
pmu_raw_writel(value, EXYNOS_COMMON_OPTION(i)); pmu_raw_writel(value, EXYNOS_COMMON_OPTION(i));
} }
/* exynos_mcpm_setup_entry_point();
* 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);
iounmap(ns_sram_base_addr); register_syscore_ops(&exynos_mcpm_syscore_ops);
return ret; return ret;
} }
......
...@@ -126,6 +126,18 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious) ...@@ -126,6 +126,18 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
*/ */
void exynos_cpu_power_down(int cpu) 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)); pmu_raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu));
} }
...@@ -203,6 +215,26 @@ static inline void __iomem *cpu_boot_reg(int cpu) ...@@ -203,6 +215,26 @@ static inline void __iomem *cpu_boot_reg(int cpu)
return boot_reg; 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 * Write pen_release in a way that is guaranteed to be visible to all
* observers, irrespective of whether they're taking part in coherency * 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) ...@@ -279,6 +311,9 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
return -ETIMEDOUT; return -ETIMEDOUT;
} }
} }
exynos_core_restart(core_id);
/* /*
* Send the secondary CPU a soft interrupt, thereby causing * Send the secondary CPU a soft interrupt, thereby causing
* the boot monitor to read the system wide flags register, * the boot monitor to read the system wide flags register,
......
/* /*
* Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com * http://www.samsung.com
* *
* EXYNOS - Power Management support * EXYNOS - Power Management support
...@@ -15,109 +15,45 @@ ...@@ -15,109 +15,45 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/syscore_ops.h>
#include <linux/cpu_pm.h> #include <linux/cpu_pm.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/clk.h>
#include <asm/cacheflush.h> #include <asm/firmware.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/smp_scu.h> #include <asm/smp_scu.h>
#include <asm/suspend.h> #include <asm/suspend.h>
#include <plat/pm-common.h> #include <plat/pm-common.h>
#include <plat/regs-srom.h>
#include <mach/map.h>
#include "common.h" #include "common.h"
#include "exynos-pmu.h"
#include "regs-pmu.h" #include "regs-pmu.h"
#include "regs-sys.h" #include "regs-sys.h"
/** static inline void __iomem *exynos_boot_vector_addr(void)
* 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)
{ {
const struct exynos_wkup_irq *wkup_irq; if (samsung_rev() == EXYNOS4210_REV_1_1)
return pmu_base_addr + S5P_INFORM7;
if (soc_is_exynos5250()) else if (samsung_rev() == EXYNOS4210_REV_1_0)
wkup_irq = exynos5250_wkup_irq; return sysram_base_addr + 0x24;
else return pmu_base_addr + S5P_INFORM0;
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;
} }
#define EXYNOS_BOOT_VECTOR_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \ static inline void __iomem *exynos_boot_vector_flag(void)
pmu_base_addr + S5P_INFORM7 : \ {
(samsung_rev() == EXYNOS4210_REV_1_0 ? \ if (samsung_rev() == EXYNOS4210_REV_1_1)
(sysram_base_addr + 0x24) : \ return pmu_base_addr + S5P_INFORM6;
pmu_base_addr + S5P_INFORM0)) else if (samsung_rev() == EXYNOS4210_REV_1_0)
#define EXYNOS_BOOT_VECTOR_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ return sysram_base_addr + 0x20;
pmu_base_addr + S5P_INFORM6 : \ return pmu_base_addr + S5P_INFORM1;
(samsung_rev() == EXYNOS4210_REV_1_0 ? \ }
(sysram_base_addr + 0x20) : \
pmu_base_addr + S5P_INFORM1))
#define S5P_CHECK_AFTR 0xFCBA0D10 #define S5P_CHECK_AFTR 0xFCBA0D10
#define S5P_CHECK_SLEEP 0x00000BAD
/* For Cortex-A9 Diagnostic and Power control register */ /* For Cortex-A9 Diagnostic and Power control register */
static unsigned int save_arm_register[2]; static unsigned int save_arm_register[2];
static void exynos_cpu_save_register(void) void exynos_cpu_save_register(void)
{ {
unsigned long tmp; unsigned long tmp;
...@@ -134,7 +70,7 @@ static void exynos_cpu_save_register(void) ...@@ -134,7 +70,7 @@ static void exynos_cpu_save_register(void)
save_arm_register[1] = tmp; save_arm_register[1] = tmp;
} }
static void exynos_cpu_restore_register(void) void exynos_cpu_restore_register(void)
{ {
unsigned long tmp; unsigned long tmp;
...@@ -153,7 +89,7 @@ static void exynos_cpu_restore_register(void) ...@@ -153,7 +89,7 @@ static void exynos_cpu_restore_register(void)
: "cc"); : "cc");
} }
static void exynos_pm_central_suspend(void) void exynos_pm_central_suspend(void)
{ {
unsigned long tmp; unsigned long tmp;
...@@ -161,9 +97,13 @@ static void exynos_pm_central_suspend(void) ...@@ -161,9 +97,13 @@ static void exynos_pm_central_suspend(void)
tmp = pmu_raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); tmp = pmu_raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
tmp &= ~S5P_CENTRAL_LOWPWR_CFG; tmp &= ~S5P_CENTRAL_LOWPWR_CFG;
pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); 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; unsigned long tmp;
...@@ -194,17 +134,26 @@ static void exynos_set_wakeupmask(long mask) ...@@ -194,17 +134,26 @@ static void exynos_set_wakeupmask(long mask)
static void exynos_cpu_set_boot_vector(long flags) static void exynos_cpu_set_boot_vector(long flags)
{ {
__raw_writel(virt_to_phys(exynos_cpu_resume), EXYNOS_BOOT_VECTOR_ADDR); __raw_writel(virt_to_phys(exynos_cpu_resume),
__raw_writel(flags, EXYNOS_BOOT_VECTOR_FLAG); exynos_boot_vector_addr());
__raw_writel(flags, exynos_boot_vector_flag());
} }
static int exynos_aftr_finisher(unsigned long flags) static int exynos_aftr_finisher(unsigned long flags)
{ {
int ret;
exynos_set_wakeupmask(0x0000ff3e); exynos_set_wakeupmask(0x0000ff3e);
exynos_cpu_set_boot_vector(S5P_CHECK_AFTR);
/* Set value of power down register for aftr mode */ /* Set value of power down register for aftr mode */
exynos_sys_powerdown_conf(SYS_AFTR); 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; return 1;
} }
...@@ -214,196 +163,16 @@ void exynos_enter_aftr(void) ...@@ -214,196 +163,16 @@ void exynos_enter_aftr(void)
cpu_pm_enter(); cpu_pm_enter();
exynos_pm_central_suspend(); exynos_pm_central_suspend();
if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
exynos_cpu_save_register();
cpu_suspend(0, exynos_aftr_finisher); cpu_suspend(0, exynos_aftr_finisher);
if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
scu_enable(S5P_VA_SCU); scu_enable(S5P_VA_SCU);
exynos_cpu_restore_register(); if (call_firmware_op(resume) == -ENOSYS)
exynos_cpu_restore_register();
} }
exynos_pm_central_resume(); exynos_pm_central_resume();
cpu_pm_exit(); 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);
}
/* /*
* Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com/ * http://www.samsung.com/
* *
* EXYNOS - CPU PMU(Power Management Unit) support * EXYNOS - CPU PMU(Power Management Unit) support
...@@ -10,12 +10,136 @@ ...@@ -10,12 +10,136 @@
*/ */
#include <linux/io.h> #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" #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[] = { static const struct exynos_pmu_conf exynos4210_pmu_config[] = {
/* { .offset = offset, .val = { AFTR, LPA, SLEEP } */ /* { .offset = offset, .val = { AFTR, LPA, SLEEP } */
...@@ -264,6 +388,7 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = { ...@@ -264,6 +388,7 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = {
{ EXYNOS5_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, { EXYNOS5_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
{ EXYNOS5_INTROM_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_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
{ EXYNOS5_JPEG_MEM_OPTION, { 0x10, 0x10, 0x0} },
{ EXYNOS5_HSI_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, { EXYNOS5_HSI_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
{ EXYNOS5_MCUIOP_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} }, { EXYNOS5_SATA_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
...@@ -315,6 +440,189 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = { ...@@ -315,6 +440,189 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = {
{ PMU_TABLE_END,}, { 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[] = { static unsigned int const exynos5_list_both_cnt_feed[] = {
EXYNOS5_ARM_CORE0_OPTION, EXYNOS5_ARM_CORE0_OPTION,
EXYNOS5_ARM_CORE1_OPTION, EXYNOS5_ARM_CORE1_OPTION,
...@@ -335,7 +643,76 @@ static unsigned int const exynos5_list_disable_wfi_wfe[] = { ...@@ -335,7 +643,76 @@ static unsigned int const exynos5_list_disable_wfi_wfe[] = {
EXYNOS5_ISP_ARM_OPTION, 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 i;
unsigned int tmp; unsigned int tmp;
...@@ -343,7 +720,7 @@ static void exynos5_init_pmu(void) ...@@ -343,7 +720,7 @@ static void exynos5_init_pmu(void)
/* /*
* Enable both SC_FEEDBACK and SC_COUNTER * 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 = pmu_raw_readl(exynos5_list_both_cnt_feed[i]);
tmp |= (EXYNOS5_USE_SC_FEEDBACK | tmp |= (EXYNOS5_USE_SC_FEEDBACK |
EXYNOS5_USE_SC_COUNTER); EXYNOS5_USE_SC_COUNTER);
...@@ -360,7 +737,7 @@ static void exynos5_init_pmu(void) ...@@ -360,7 +737,7 @@ static void exynos5_init_pmu(void)
/* /*
* Disable WFI/WFE on XXX_OPTION * 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 = pmu_raw_readl(exynos5_list_disable_wfi_wfe[i]);
tmp &= ~(EXYNOS5_OPTION_USE_STANDBYWFE | tmp &= ~(EXYNOS5_OPTION_USE_STANDBYWFE |
EXYNOS5_OPTION_USE_STANDBYWFI); EXYNOS5_OPTION_USE_STANDBYWFI);
...@@ -372,51 +749,257 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode) ...@@ -372,51 +749,257 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode)
{ {
unsigned int i; unsigned int i;
if (soc_is_exynos5250()) const struct exynos_pmu_data *pmu_data = pmu_context->pmu_data;
exynos5_init_pmu();
if (pmu_data->powerdown_conf)
pmu_data->powerdown_conf(mode);
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);
}
for (i = 0; (exynos_pmu_config[i].offset != PMU_TABLE_END) ; i++) if (pmu_data->powerdown_conf_extra)
pmu_raw_writel(exynos_pmu_config[i].val[mode], pmu_data->powerdown_conf_extra(mode);
exynos_pmu_config[i].offset);
if (soc_is_exynos4412()) { if (pmu_data->pmu_config_extra) {
for (i = 0; exynos4412_pmu_config[i].offset != PMU_TABLE_END ; i++) for (i = 0; pmu_data->pmu_config_extra[i].offset != PMU_TABLE_END; i++)
pmu_raw_writel(exynos4412_pmu_config[i].val[mode], pmu_raw_writel(pmu_data->pmu_config_extra[i].val[mode],
exynos4412_pmu_config[i].offset); pmu_data->pmu_config_extra[i].offset);
} }
} }
static int __init exynos_pmu_init(void) static void exynos3250_pmu_init(void)
{
unsigned int value;
/*
* 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);
/* Enable USE_STANDBY_WFI for all CORE */
pmu_raw_writel(S5P_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION);
/*
* 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);
/*
* 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; 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,
};
exynos_pmu_config = exynos4210_pmu_config; static const struct exynos_pmu_data exynos4210_pmu_data = {
.pmu_config = exynos4210_pmu_config,
if (soc_is_exynos4210()) { };
exynos_pmu_config = exynos4210_pmu_config;
pr_info("EXYNOS4210 PMU Initialize\n"); static const struct exynos_pmu_data exynos4212_pmu_data = {
} else if (soc_is_exynos4212() || soc_is_exynos4412()) { .pmu_config = exynos4x12_pmu_config,
exynos_pmu_config = exynos4x12_pmu_config; };
pr_info("EXYNOS4x12 PMU Initialize\n");
} else if (soc_is_exynos5250()) { static const struct exynos_pmu_data exynos4412_pmu_data = {
/* .pmu_config = exynos4x12_pmu_config,
* When SYS_WDTRESET is set, watchdog timer reset request .pmu_config_extra = exynos4412_pmu_config,
* is ignored by power management unit. };
*/
value = pmu_raw_readl(EXYNOS5_AUTO_WDTRESET_DISABLE); static const struct exynos_pmu_data exynos5250_pmu_data = {
value &= ~EXYNOS5_SYS_WDTRESET; .pmu_config = exynos5250_pmu_config,
pmu_raw_writel(value, EXYNOS5_AUTO_WDTRESET_DISABLE); .pmu_init = exynos5250_pmu_init,
.powerdown_conf = exynos5_powerdown_conf,
value = pmu_raw_readl(EXYNOS5_MASK_WDTRESET_REQUEST); };
value &= ~EXYNOS5_SYS_WDTRESET;
pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST); static struct exynos_pmu_data exynos5420_pmu_data = {
.pmu_config = exynos5420_pmu_config,
exynos_pmu_config = exynos5250_pmu_config; .pmu_init = exynos5420_pmu_init,
pr_info("EXYNOS5250 PMU Initialize\n"); .powerdown_conf = exynos5420_powerdown_conf,
} else { };
pr_info("EXYNOS: PMU not supported\n");
/*
* 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; 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 @@ ...@@ -19,9 +19,24 @@
#define S5P_CENTRAL_SEQ_OPTION 0x0208 #define S5P_CENTRAL_SEQ_OPTION 0x0208
#define S5P_USE_STANDBY_WFI0 (1 << 16) #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_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 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 EXYNOS_SWRESET 0x0400
#define EXYNOS5440_SWRESET 0x00C4 #define EXYNOS5440_SWRESET 0x00C4
...@@ -36,6 +51,7 @@ ...@@ -36,6 +51,7 @@
#define S5P_INFORM7 0x081C #define S5P_INFORM7 0x081C
#define S5P_PMU_SPARE3 0x090C #define S5P_PMU_SPARE3 0x090C
#define EXYNOS_IROM_DATA2 0x0988
#define S5P_ARM_CORE0_LOWPWR 0x1000 #define S5P_ARM_CORE0_LOWPWR 0x1000
#define S5P_DIS_IRQ_CORE0 0x1004 #define S5P_DIS_IRQ_CORE0 0x1004
#define S5P_DIS_IRQ_CENTRAL0 0x1008 #define S5P_DIS_IRQ_CENTRAL0 0x1008
...@@ -118,6 +134,31 @@ ...@@ -118,6 +134,31 @@
#define EXYNOS_COMMON_OPTION(_nr) \ #define EXYNOS_COMMON_OPTION(_nr) \
(EXYNOS_COMMON_CONFIGURATION(_nr) + 0x8) (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_MAUDIO_OPTION 0x3028
#define S5P_PAD_RET_GPIO_OPTION 0x3108 #define S5P_PAD_RET_GPIO_OPTION 0x3108
#define S5P_PAD_RET_UART_OPTION 0x3128 #define S5P_PAD_RET_UART_OPTION 0x3128
...@@ -126,7 +167,19 @@ ...@@ -126,7 +167,19 @@
#define S5P_PAD_RET_EBIA_OPTION 0x3188 #define S5P_PAD_RET_EBIA_OPTION 0x3188
#define S5P_PAD_RET_EBIB_OPTION 0x31A8 #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_LOCAL_PWR_EN 0x3
#define S5P_CORE_WAKEUP_FROM_LOCAL_CFG (0x3 << 8)
/* Only for EXYNOS4210 */ /* Only for EXYNOS4210 */
#define S5P_CMU_CLKSTOP_LCD1_LOWPWR 0x1154 #define S5P_CMU_CLKSTOP_LCD1_LOWPWR 0x1154
...@@ -185,11 +238,116 @@ ...@@ -185,11 +238,116 @@
#define S5P_DIS_IRQ_CORE3 0x1034 #define S5P_DIS_IRQ_CORE3 0x1034
#define S5P_DIS_IRQ_CENTRAL3 0x1038 #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 */ /* For EXYNOS5 */
#define EXYNOS5_AUTO_WDTRESET_DISABLE 0x0408 #define EXYNOS5_AUTO_WDTRESET_DISABLE 0x0408
#define EXYNOS5_MASK_WDTRESET_REQUEST 0x040C #define EXYNOS5_MASK_WDTRESET_REQUEST 0x040C
#define EXYNOS5_USE_RETENTION BIT(4)
#define EXYNOS5_SYS_WDTRESET (1 << 20) #define EXYNOS5_SYS_WDTRESET (1 << 20)
#define EXYNOS5_ARM_CORE0_SYS_PWR_REG 0x1000 #define EXYNOS5_ARM_CORE0_SYS_PWR_REG 0x1000
...@@ -329,4 +487,204 @@ static inline unsigned int exynos_pmu_cpunr(unsigned int mpidr) ...@@ -329,4 +487,204 @@ static inline unsigned int exynos_pmu_cpunr(unsigned int mpidr)
+ MPIDR_AFFINITY_LEVEL(mpidr, 0)); + 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 */ #endif /* __ASM_ARCH_REGS_PMU_H */
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
*/ */
#include <linux/linkage.h> #include <linux/linkage.h>
#include "smc.h"
#define CPU_MASK 0xff0ffff0 #define CPU_MASK 0xff0ffff0
#define CPU_CORTEX_A9 0x410fc090 #define CPU_CORTEX_A9 0x410fc090
...@@ -55,3 +56,30 @@ ENTRY(exynos_cpu_resume) ...@@ -55,3 +56,30 @@ ENTRY(exynos_cpu_resume)
#endif #endif
b cpu_resume b cpu_resume
ENDPROC(exynos_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 @@ ...@@ -26,6 +26,10 @@
#define SMC_CMD_L2X0INVALL (-24) #define SMC_CMD_L2X0INVALL (-24)
#define SMC_CMD_L2X0DEBUG (-25) #define SMC_CMD_L2X0DEBUG (-25)
#ifndef __ASSEMBLY__
extern void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3); extern void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3);
#endif /* __ASSEMBLY__ */
#endif #endif
/*
* 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 ...@@ -633,12 +633,41 @@ config SOC_VF610
bool "Vybrid Family VF610 support" bool "Vybrid Family VF610 support"
select ARM_GIC select ARM_GIC
select PINCTRL_VF610 select PINCTRL_VF610
select VF_PIT_TIMER
select PL310_ERRATA_769419 if CACHE_L2X0 select PL310_ERRATA_769419 if CACHE_L2X0
help help
This enable support for Freescale Vybrid VF610 processor. 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 endif
source "arch/arm/mach-imx/devices/Kconfig" 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- ...@@ -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 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 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 \ obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \
clk-pfd.o clk-busy.o clk.o \ clk-pfd.o clk-busy.o clk.o \
...@@ -89,7 +89,7 @@ obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o ...@@ -89,7 +89,7 @@ obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o
obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
obj-$(CONFIG_HAVE_IMX_SRC) += src.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 AFLAGS_headsmp.o :=-Wa,-march=armv7-a
obj-$(CONFIG_SMP) += headsmp.o platsmp.o obj-$(CONFIG_SMP) += headsmp.o platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
...@@ -110,4 +110,6 @@ obj-$(CONFIG_SOC_IMX53) += mach-imx53.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_VF610) += clk-vf610.o mach-vf610.o
obj-$(CONFIG_SOC_LS1021A) += mach-ls1021a.o
obj-y += devices/ obj-y += devices/
...@@ -30,8 +30,11 @@ ...@@ -30,8 +30,11 @@
#define ANADIG_DIGPROG_IMX6SL 0x280 #define ANADIG_DIGPROG_IMX6SL 0x280
#define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG 0x40000 #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_REG_CORE_FET_ODRIVE 0x20000000
#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG 0x1000 #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_CHK_CHRG_B 0x80000
#define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x100000 #define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x100000
...@@ -56,16 +59,43 @@ static void imx_anatop_enable_fet_odrive(bool enable) ...@@ -56,16 +59,43 @@ static void imx_anatop_enable_fet_odrive(bool enable)
BM_ANADIG_REG_CORE_FET_ODRIVE); 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) 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); imx_anatop_enable_fet_odrive(true);
if (cpu_is_imx6sl())
imx_anatop_disconnect_high_snvs(true);
} }
void imx_anatop_post_resume(void) 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_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) static void imx_anatop_usb_chrg_detect_disable(void)
......
/*
* 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", ...@@ -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 *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 *spdif0_com_sel[] = { "spdif0_podf", "ssi1_root_gate", };
static const char *mx51_spdif1_com_sel[] = { "spdif1_podf", "ssi2_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 *clk[IMX5_CLK_END];
static struct clk_onecell_data clk_data; static struct clk_onecell_data clk_data;
...@@ -193,7 +195,9 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) ...@@ -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_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, 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)); 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_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_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); 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) ...@@ -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_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, 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)); 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)); imx_check_clocks(clk, ARRAY_SIZE(clk));
...@@ -551,6 +560,9 @@ static void __init mx53_clocks_init(struct device_node *np) ...@@ -551,6 +560,9 @@ static void __init mx53_clocks_init(struct device_node *np)
/* move can bus clk to 24MHz */ /* move can bus clk to 24MHz */
clk_set_parent(clk[IMX5_CLK_CAN_SEL], clk[IMX5_CLK_LP_APM]); 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]); clk_prepare_enable(clk[IMX5_CLK_IIM_GATE]);
imx_print_silicon_rev("i.MX53", mx53_revision()); imx_print_silicon_rev("i.MX53", mx53_revision());
clk_disable_unprepare(clk[IMX5_CLK_IIM_GATE]); clk_disable_unprepare(clk[IMX5_CLK_IIM_GATE]);
......
...@@ -120,6 +120,17 @@ static unsigned int const clks_init_on[] __initconst = { ...@@ -120,6 +120,17 @@ static unsigned int const clks_init_on[] __initconst = {
VF610_CLK_DDR_SEL, 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) static void __init vf610_clocks_init(struct device_node *ccm_node)
{ {
struct device_node *np; struct device_node *np;
...@@ -130,13 +141,13 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) ...@@ -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_SIRC_32K] = imx_clk_fixed("sirc_32k", 32000);
clk[VF610_CLK_FIRC] = imx_clk_fixed("firc", 24000000); clk[VF610_CLK_FIRC] = imx_clk_fixed("firc", 24000000);
clk[VF610_CLK_SXOSC] = imx_obtain_fixed_clock("sxosc", 0); clk[VF610_CLK_SXOSC] = vf610_get_fixed_clock(ccm_node, "sxosc");
clk[VF610_CLK_FXOSC] = imx_obtain_fixed_clock("fxosc", 0); clk[VF610_CLK_FXOSC] = vf610_get_fixed_clock(ccm_node, "fxosc");
clk[VF610_CLK_AUDIO_EXT] = imx_obtain_fixed_clock("audio_ext", 0); clk[VF610_CLK_AUDIO_EXT] = vf610_get_fixed_clock(ccm_node, "audio_ext");
clk[VF610_CLK_ENET_EXT] = imx_obtain_fixed_clock("enet_ext", 0); clk[VF610_CLK_ENET_EXT] = vf610_get_fixed_clock(ccm_node, "enet_ext");
/* Clock source from external clock via LVDs PAD */ /* 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); 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, ...@@ -131,4 +131,8 @@ static inline struct clk *imx_clk_fixed_factor(const char *name,
CLK_SET_RATE_PARENT, mult, div); 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 #endif
...@@ -115,6 +115,7 @@ void imx_anatop_post_resume(void); ...@@ -115,6 +115,7 @@ void imx_anatop_post_resume(void);
int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
void imx6q_set_int_mem_clk_lpm(bool enable); void imx6q_set_int_mem_clk_lpm(bool enable);
void imx6sl_set_wait_clk(bool enter); void imx6sl_set_wait_clk(bool enter);
int imx_mmdc_get_ddr_type(void);
void imx_cpu_die(unsigned int cpu); void imx_cpu_die(unsigned int cpu);
int imx_cpu_kill(unsigned int cpu); int imx_cpu_kill(unsigned int cpu);
...@@ -156,5 +157,6 @@ static inline void imx_init_l2cache(void) {} ...@@ -156,5 +157,6 @@ static inline void imx_init_l2cache(void) {}
#endif #endif
extern struct smp_operations imx_smp_ops; extern struct smp_operations imx_smp_ops;
extern struct smp_operations ls1021a_smp_ops;
#endif #endif
...@@ -40,6 +40,8 @@ static void __init imx53_dt_init(void) ...@@ -40,6 +40,8 @@ static void __init imx53_dt_init(void)
static void __init imx53_init_late(void) static void __init imx53_init_late(void)
{ {
imx53_pm_init(); imx53_pm_init();
platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
} }
static const char * const imx53_dt_board_compat[] __initconst = { static const char * const imx53_dt_board_compat[] __initconst = {
......
...@@ -8,12 +8,62 @@ ...@@ -8,12 +8,62 @@
#include <linux/irqchip.h> #include <linux/irqchip.h>
#include <linux/of_platform.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/arch.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include "common.h" #include "common.h"
#include "cpuidle.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) static void __init imx6sx_init_machine(void)
{ {
struct device *parent; struct device *parent;
...@@ -24,6 +74,7 @@ static void __init imx6sx_init_machine(void) ...@@ -24,6 +74,7 @@ static void __init imx6sx_init_machine(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);
imx6sx_enet_init();
imx_anatop_init(); imx_anatop_init();
imx6sx_pm_init(); imx6sx_pm_init();
} }
......
/*
* 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 @@ ...@@ -21,6 +21,12 @@
#define BP_MMDC_MAPSR_PSD 0 #define BP_MMDC_MAPSR_PSD 0
#define BP_MMDC_MAPSR_PSS 4 #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) static int imx_mmdc_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
...@@ -31,6 +37,12 @@ static int imx_mmdc_probe(struct platform_device *pdev) ...@@ -31,6 +37,12 @@ static int imx_mmdc_probe(struct platform_device *pdev)
mmdc_base = of_iomap(np, 0); mmdc_base = of_iomap(np, 0);
WARN_ON(!mmdc_base); 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; reg = mmdc_base + MMDC_MAPSR;
/* Enable automatic power saving */ /* Enable automatic power saving */
...@@ -51,6 +63,11 @@ static int imx_mmdc_probe(struct platform_device *pdev) ...@@ -51,6 +63,11 @@ static int imx_mmdc_probe(struct platform_device *pdev)
return 0; return 0;
} }
int imx_mmdc_get_ddr_type(void)
{
return ddr_type;
}
static struct of_device_id imx_mmdc_dt_ids[] = { static struct of_device_id imx_mmdc_dt_ids[] = {
{ .compatible = "fsl,imx6q-mmdc", }, { .compatible = "fsl,imx6q-mmdc", },
{ /* sentinel */ } { /* sentinel */ }
......
...@@ -55,6 +55,8 @@ ...@@ -55,6 +55,8 @@
#define IMX_CHIP_REVISION_3_3 0x33 #define IMX_CHIP_REVISION_3_3 0x33
#define IMX_CHIP_REVISION_UNKNOWN 0xff #define IMX_CHIP_REVISION_UNKNOWN 0xff
#define IMX_DDR_TYPE_LPDDR2 1
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
extern unsigned int __mxc_cpu_type; extern unsigned int __mxc_cpu_type;
#endif #endif
......
...@@ -11,7 +11,10 @@ ...@@ -11,7 +11,10 @@
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/smp_scu.h> #include <asm/smp_scu.h>
...@@ -94,3 +97,33 @@ struct smp_operations imx_smp_ops __initdata = { ...@@ -94,3 +97,33 @@ struct smp_operations imx_smp_ops __initdata = {
.cpu_kill = imx_cpu_kill, .cpu_kill = imx_cpu_kill,
#endif #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 { ...@@ -88,7 +88,7 @@ struct imx6_pm_base {
}; };
struct imx6_pm_socdata { struct imx6_pm_socdata {
u32 cpu_type; u32 ddr_type;
const char *mmdc_compat; const char *mmdc_compat;
const char *src_compat; const char *src_compat;
const char *iomuxc_compat; const char *iomuxc_compat;
...@@ -138,7 +138,6 @@ static const u32 imx6sx_mmdc_io_offset[] __initconst = { ...@@ -138,7 +138,6 @@ static const u32 imx6sx_mmdc_io_offset[] __initconst = {
}; };
static const struct imx6_pm_socdata imx6q_pm_data __initconst = { static const struct imx6_pm_socdata imx6q_pm_data __initconst = {
.cpu_type = MXC_CPU_IMX6Q,
.mmdc_compat = "fsl,imx6q-mmdc", .mmdc_compat = "fsl,imx6q-mmdc",
.src_compat = "fsl,imx6q-src", .src_compat = "fsl,imx6q-src",
.iomuxc_compat = "fsl,imx6q-iomuxc", .iomuxc_compat = "fsl,imx6q-iomuxc",
...@@ -148,7 +147,6 @@ static const struct imx6_pm_socdata imx6q_pm_data __initconst = { ...@@ -148,7 +147,6 @@ static const struct imx6_pm_socdata imx6q_pm_data __initconst = {
}; };
static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { static const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
.cpu_type = MXC_CPU_IMX6DL,
.mmdc_compat = "fsl,imx6q-mmdc", .mmdc_compat = "fsl,imx6q-mmdc",
.src_compat = "fsl,imx6q-src", .src_compat = "fsl,imx6q-src",
.iomuxc_compat = "fsl,imx6dl-iomuxc", .iomuxc_compat = "fsl,imx6dl-iomuxc",
...@@ -158,7 +156,6 @@ static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { ...@@ -158,7 +156,6 @@ static const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
}; };
static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { static const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
.cpu_type = MXC_CPU_IMX6SL,
.mmdc_compat = "fsl,imx6sl-mmdc", .mmdc_compat = "fsl,imx6sl-mmdc",
.src_compat = "fsl,imx6sl-src", .src_compat = "fsl,imx6sl-src",
.iomuxc_compat = "fsl,imx6sl-iomuxc", .iomuxc_compat = "fsl,imx6sl-iomuxc",
...@@ -168,7 +165,6 @@ static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { ...@@ -168,7 +165,6 @@ static const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
}; };
static const struct imx6_pm_socdata imx6sx_pm_data __initconst = { static const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
.cpu_type = MXC_CPU_IMX6SX,
.mmdc_compat = "fsl,imx6sx-mmdc", .mmdc_compat = "fsl,imx6sx-mmdc",
.src_compat = "fsl,imx6sx-src", .src_compat = "fsl,imx6sx-src",
.iomuxc_compat = "fsl,imx6sx-iomuxc", .iomuxc_compat = "fsl,imx6sx-iomuxc",
...@@ -187,7 +183,7 @@ static const struct imx6_pm_socdata imx6sx_pm_data __initconst = { ...@@ -187,7 +183,7 @@ static const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
struct imx6_cpu_pm_info { struct imx6_cpu_pm_info {
phys_addr_t pbase; /* The physical address of pm_info. */ phys_addr_t pbase; /* The physical address of pm_info. */
phys_addr_t resume_addr; /* The physical resume address for asm code */ 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. */ u32 pm_info_size; /* Size of pm_info. */
struct imx6_pm_base mmdc_base; struct imx6_pm_base mmdc_base;
struct imx6_pm_base src_base; struct imx6_pm_base src_base;
...@@ -521,7 +517,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) ...@@ -521,7 +517,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
goto pl310_cache_map_failed; 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; pm_info->mmdc_io_num = socdata->mmdc_io_num;
mmdc_offset_array = socdata->mmdc_io_offset; mmdc_offset_array = socdata->mmdc_io_offset;
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
*/ */
#define PM_INFO_PBASE_OFFSET 0x0 #define PM_INFO_PBASE_OFFSET 0x0
#define PM_INFO_RESUME_ADDR_OFFSET 0x4 #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_PM_INFO_SIZE_OFFSET 0xC
#define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10 #define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10
#define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14 #define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14
...@@ -110,7 +110,7 @@ ...@@ -110,7 +110,7 @@
ldreq r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] ldreq r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
ldrne r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET] ldrne r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET]
cmp r3, #MXC_CPU_IMX6SL cmp r3, #IMX_DDR_TYPE_LPDDR2
bne 4f bne 4f
/* reset read FIFO, RST_RD_FIFO */ /* reset read FIFO, RST_RD_FIFO */
...@@ -151,7 +151,7 @@ ...@@ -151,7 +151,7 @@
ENTRY(imx6_suspend) ENTRY(imx6_suspend)
ldr r1, [r0, #PM_INFO_PBASE_OFFSET] ldr r1, [r0, #PM_INFO_PBASE_OFFSET]
ldr r2, [r0, #PM_INFO_RESUME_ADDR_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] ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
/* /*
...@@ -209,8 +209,8 @@ poll_dvfs_set: ...@@ -209,8 +209,8 @@ poll_dvfs_set:
ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET
add r8, r8, r0 add r8, r8, r0
/* i.MX6SL's last 3 IOs need special setting */ /* LPDDR2's last 3 IOs need special setting */
cmp r3, #MXC_CPU_IMX6SL cmp r3, #IMX_DDR_TYPE_LPDDR2
subeq r7, r7, #0x3 subeq r7, r7, #0x3
set_mmdc_io_lpm: set_mmdc_io_lpm:
ldr r9, [r8], #0x8 ldr r9, [r8], #0x8
...@@ -218,7 +218,7 @@ set_mmdc_io_lpm: ...@@ -218,7 +218,7 @@ set_mmdc_io_lpm:
subs r7, r7, #0x1 subs r7, r7, #0x1
bne set_mmdc_io_lpm bne set_mmdc_io_lpm
cmp r3, #MXC_CPU_IMX6SL cmp r3, #IMX_DDR_TYPE_LPDDR2
bne set_mmdc_io_lpm_done bne set_mmdc_io_lpm_done
ldr r6, =0x1000 ldr r6, =0x1000
ldr r9, [r8], #0x8 ldr r9, [r8], #0x8
...@@ -324,7 +324,7 @@ resume: ...@@ -324,7 +324,7 @@ resume:
str r7, [r11, #MX6Q_SRC_GPR1] str r7, [r11, #MX6Q_SRC_GPR1]
str r7, [r11, #MX6Q_SRC_GPR2] 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 mov r5, #0x1
resume_mmdc resume_mmdc
......
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 if ARCH_INTEGRATOR
menu "Integrator Options" menu "Integrator Options"
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# Object file lists. # 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_AP) += integrator_ap.o
obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o
......
...@@ -11,7 +11,6 @@ void cm_clear_irqs(void); ...@@ -11,7 +11,6 @@ void cm_clear_irqs(void);
#define CM_CTRL_LED (1 << 0) #define CM_CTRL_LED (1 << 0)
#define CM_CTRL_nMBDET (1 << 1) #define CM_CTRL_nMBDET (1 << 1)
#define CM_CTRL_REMAP (1 << 2) #define CM_CTRL_REMAP (1 << 2)
#define CM_CTRL_RESET (1 << 3)
/* /*
* Integrator/AP,PP2 specific * Integrator/AP,PP2 specific
......
...@@ -4,5 +4,3 @@ extern struct amba_pl010_data ap_uart_data; ...@@ -4,5 +4,3 @@ extern struct amba_pl010_data ap_uart_data;
void integrator_init_early(void); void integrator_init_early(void);
int integrator_init(bool is_cp); int integrator_init(bool is_cp);
void integrator_reserve(void); 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) ...@@ -60,40 +60,6 @@ void cm_control(u32 mask, u32 set)
raw_spin_unlock_irqrestore(&cm_lock, flags); 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) void cm_clear_irqs(void)
{ {
/* disable core module IRQs */ /* disable core module IRQs */
...@@ -109,7 +75,6 @@ static const struct of_device_id cm_match[] = { ...@@ -109,7 +75,6 @@ static const struct of_device_id cm_match[] = {
void cm_init(void) void cm_init(void)
{ {
struct device_node *cm = of_find_matching_node(NULL, cm_match); struct device_node *cm = of_find_matching_node(NULL, cm_match);
u32 val;
if (!cm) { if (!cm) {
pr_crit("no core module node found in device tree\n"); pr_crit("no core module node found in device tree\n");
...@@ -121,13 +86,6 @@ void cm_init(void) ...@@ -121,13 +86,6 @@ void cm_init(void)
return; return;
} }
cm_clear_irqs(); 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) ...@@ -139,64 +97,3 @@ void __init integrator_reserve(void)
{ {
memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET); 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);
}
/*
* 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 @@ ...@@ -27,22 +27,15 @@
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/amba/kmi.h> #include <linux/amba/kmi.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irqchip.h> #include <linux/irqchip.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/clk.h>
#include <linux/platform_data/clk-integrator.h> #include <linux/platform_data/clk-integrator.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/sys_soc.h>
#include <linux/termios.h> #include <linux/termios.h>
#include <linux/sched_clock.h>
#include <linux/clk-provider.h>
#include <asm/hardware/arm_timer.h> #include <asm/hardware/arm_timer.h>
#include <asm/setup.h> #include <asm/setup.h>
...@@ -89,11 +82,6 @@ static void __iomem *ebi_base; ...@@ -89,11 +82,6 @@ static void __iomem *ebi_base;
static struct map_desc ap_io_desc[] __initdata __maybe_unused = { 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), .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE),
.pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE),
.length = SZ_4K, .length = SZ_4K,
...@@ -257,188 +245,10 @@ struct amba_pl010_data ap_uart_data = { ...@@ -257,188 +245,10 @@ struct amba_pl010_data ap_uart_data = {
.set_mctrl = integrator_uart_set_mctrl, .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) 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) static void __init ap_init_irq_of(void)
{ {
cm_init(); cm_init();
...@@ -477,10 +287,6 @@ static void __init ap_init_of(void) ...@@ -477,10 +287,6 @@ static void __init ap_init_of(void)
unsigned long sc_dec; unsigned long sc_dec;
struct device_node *syscon; struct device_node *syscon;
struct device_node *ebi; 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; int i;
syscon = of_find_matching_node(NULL, ap_syscon_match); syscon = of_find_matching_node(NULL, ap_syscon_match);
...@@ -500,28 +306,6 @@ static void __init ap_init_of(void) ...@@ -500,28 +306,6 @@ static void __init ap_init_of(void)
of_platform_populate(NULL, of_default_bus_match_table, of_platform_populate(NULL, of_default_bus_match_table,
ap_auxdata_lookup, NULL); 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); sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET);
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
struct lm_device *lmdev; struct lm_device *lmdev;
...@@ -553,8 +337,6 @@ DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)") ...@@ -553,8 +337,6 @@ DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)")
.map_io = ap_map_io, .map_io = ap_map_io,
.init_early = ap_init_early, .init_early = ap_init_early,
.init_irq = ap_init_irq_of, .init_irq = ap_init_irq_of,
.init_time = ap_of_timer_init,
.init_machine = ap_init_of, .init_machine = ap_init_of,
.restart = integrator_restart,
.dt_compat = ap_dt_board_compat, .dt_compat = ap_dt_board_compat,
MACHINE_END MACHINE_END
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/sys_soc.h>
#include <linux/sched_clock.h> #include <linux/sched_clock.h>
#include <asm/setup.h> #include <asm/setup.h>
...@@ -274,10 +273,6 @@ static const struct of_device_id intcp_syscon_match[] = { ...@@ -274,10 +273,6 @@ static const struct of_device_id intcp_syscon_match[] = {
static void __init intcp_init_of(void) static void __init intcp_init_of(void)
{ {
struct device_node *cpcon; 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); cpcon = of_find_matching_node(NULL, intcp_syscon_match);
if (!cpcon) if (!cpcon)
...@@ -289,28 +284,6 @@ static void __init intcp_init_of(void) ...@@ -289,28 +284,6 @@ static void __init intcp_init_of(void)
of_platform_populate(NULL, of_default_bus_match_table, of_platform_populate(NULL, of_default_bus_match_table,
intcp_auxdata_lookup, NULL); 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[] = { static const char * intcp_dt_board_compat[] = {
...@@ -324,6 +297,5 @@ DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)") ...@@ -324,6 +297,5 @@ DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)")
.init_early = intcp_init_early, .init_early = intcp_init_early,
.init_irq = intcp_init_irq_of, .init_irq = intcp_init_irq_of,
.init_machine = intcp_init_of, .init_machine = intcp_init_of,
.restart = integrator_restart,
.dt_compat = intcp_dt_board_compat, .dt_compat = intcp_dt_board_compat,
MACHINE_END MACHINE_END
/*
* 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
config ARCH_MEDIATEK config ARCH_MEDIATEK
bool "Mediatek MT6589 SoC" if ARCH_MULTI_V7 bool "Mediatek MT65xx & MT81xx SoC" if ARCH_MULTI_V7
select ARM_GIC select ARM_GIC
select MTK_TIMER select MTK_TIMER
help help
Support for Mediatek Cortex-A7 Quad-Core-SoC MT6589. Support for Mediatek MT65xx & MT81xx SoCs
...@@ -2,6 +2,7 @@ menuconfig ARCH_MESON ...@@ -2,6 +2,7 @@ menuconfig ARCH_MESON
bool "Amlogic Meson SoCs" if ARCH_MULTI_V7 bool "Amlogic Meson SoCs" if ARCH_MULTI_V7
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
select ARM_GIC select ARM_GIC
select CACHE_L2X0
if ARCH_MESON if ARCH_MESON
...@@ -10,4 +11,9 @@ config MACH_MESON6 ...@@ -10,4 +11,9 @@ config MACH_MESON6
default ARCH_MESON default ARCH_MESON
select MESON6_TIMER select MESON6_TIMER
config MACH_MESON8
bool "Amlogic Meson8 SoCs support"
default ARCH_MESON
select MESON6_TIMER
endif endif
...@@ -16,12 +16,14 @@ ...@@ -16,12 +16,14 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <asm/mach/arch.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,meson6",
"amlogic,meson8",
NULL, NULL,
}; };
DT_MACHINE_START(AML8726_MX, "Amlogic Meson6 platform") DT_MACHINE_START(MESON, "Amlogic Meson platform")
.dt_compat = m6_common_board_compat, .dt_compat = meson_common_board_compat,
.l2c_aux_val = 0,
.l2c_aux_mask = ~0,
MACHINE_END MACHINE_END
...@@ -7,7 +7,7 @@ CFLAGS_pmsu.o := -march=armv7-a ...@@ -7,7 +7,7 @@ CFLAGS_pmsu.o := -march=armv7-a
obj-$(CONFIG_MACH_MVEBU_ANY) += system-controller.o mvebu-soc-id.o obj-$(CONFIG_MACH_MVEBU_ANY) += system-controller.o mvebu-soc-id.o
ifeq ($(CONFIG_MACH_MVEBU_V7),y) 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 obj-$(CONFIG_SMP) += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o
endif endif
......
...@@ -16,14 +16,8 @@ ...@@ -16,14 +16,8 @@
#define __MACH_ARMADA_370_XP_H #define __MACH_ARMADA_370_XP_H
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
#include <linux/cpumask.h>
#define ARMADA_XP_MAX_CPUS 4
void armada_xp_secondary_startup(void); void armada_xp_secondary_startup(void);
extern struct smp_operations armada_xp_smp_ops; extern struct smp_operations armada_xp_smp_ops;
#endif #endif
int armada_370_xp_pmsu_idle_enter(unsigned long deepidle);
#endif /* __MACH_ARMADA_370_XP_H */ #endif /* __MACH_ARMADA_370_XP_H */
...@@ -16,10 +16,12 @@ ...@@ -16,10 +16,12 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/memblock.h>
#include <linux/mbus.h> #include <linux/mbus.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -56,6 +58,54 @@ void __iomem *mvebu_get_scu_base(void) ...@@ -56,6 +58,54 @@ void __iomem *mvebu_get_scu_base(void)
return scu_base; 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, &reg);
size = dt_mem_next_cell(dt_root_size_cells, &reg);
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 * Early versions of Armada 375 SoC have a bug where the BootROM
* leaves an external data abort pending. The kernel is hit by this * leaves an external data abort pending. The kernel is hit by this
...@@ -124,76 +174,12 @@ static void __init i2c_quirk(void) ...@@ -124,76 +174,12 @@ static void __init i2c_quirk(void)
return; 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) static void __init mvebu_dt_init(void)
{ {
if (of_machine_is_compatible("marvell,armadaxp")) if (of_machine_is_compatible("marvell,armadaxp"))
i2c_quirk(); i2c_quirk();
if (of_machine_is_compatible("marvell,a375-db")) { if (of_machine_is_compatible("marvell,a375-db"))
external_abort_quirk(); external_abort_quirk();
thermal_quirk();
}
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
} }
...@@ -206,10 +192,16 @@ static const char * const armada_370_xp_dt_compat[] = { ...@@ -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)") DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)")
.l2c_aux_val = 0, .l2c_aux_val = 0,
.l2c_aux_mask = ~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), .smp = smp_ops(armada_xp_smp_ops),
.init_machine = mvebu_dt_init, .init_machine = mvebu_dt_init,
.init_irq = mvebu_init_irq, .init_irq = mvebu_init_irq,
.restart = mvebu_restart, .restart = mvebu_restart,
.reserve = mvebu_memblock_reserve,
.dt_compat = armada_370_xp_dt_compat, .dt_compat = armada_370_xp_dt_compat,
MACHINE_END MACHINE_END
......
/* /*
* 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 * Copyright (C) 2012 Marvell
* *
...@@ -11,7 +12,7 @@ ...@@ -11,7 +12,7 @@
* License version 2. This program is licensed "as is" without any * License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied. * 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 * responsible for ensuring hardware coherency between all CPUs and between
* CPUs and I/O masters. This file initializes the coherency fabric and * CPUs and I/O masters. This file initializes the coherency fabric and
* supplies basic routines for configuring and controlling hardware coherency * supplies basic routines for configuring and controlling hardware coherency
...@@ -28,12 +29,10 @@ ...@@ -28,12 +29,10 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mbus.h> #include <linux/mbus.h>
#include <linux/clk.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/smp_plat.h> #include <asm/smp_plat.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include "armada-370-xp.h"
#include "coherency.h" #include "coherency.h"
#include "mvebu-soc-id.h" #include "mvebu-soc-id.h"
...@@ -42,8 +41,6 @@ void __iomem *coherency_base; ...@@ -42,8 +41,6 @@ void __iomem *coherency_base;
static void __iomem *coherency_cpu_base; static void __iomem *coherency_cpu_base;
/* Coherency fabric registers */ /* Coherency fabric registers */
#define COHERENCY_FABRIC_CFG_OFFSET 0x4
#define IO_SYNC_BARRIER_CTL_OFFSET 0x0 #define IO_SYNC_BARRIER_CTL_OFFSET 0x0
enum { enum {
...@@ -79,157 +76,8 @@ int set_cpu_coherent(void) ...@@ -79,157 +76,8 @@ int set_cpu_coherent(void)
return ll_enable_coherency(); 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) 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); writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET);
while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1); while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1);
} }
...@@ -361,25 +209,41 @@ static int coherency_type(void) ...@@ -361,25 +209,41 @@ static int coherency_type(void)
{ {
struct device_node *np; struct device_node *np;
const struct of_device_id *match; const struct of_device_id *match;
int type;
np = of_find_matching_node_and_match(NULL, of_coherency_table, &match); /*
if (np) { * The coherency fabric is needed:
int type = (int) match->data; * - 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.
/* Armada 370/XP coherency works in both UP and SMP */ */
if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP) if (!is_smp())
return type; return COHERENCY_FABRIC_TYPE_NONE;
/* Armada 375 coherency works only on SMP */ np = of_find_matching_node_and_match(NULL, of_coherency_table, &match);
else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 && is_smp()) if (!np)
return type; return COHERENCY_FABRIC_TYPE_NONE;
/* Armada 380 coherency works only on SMP */ type = (int) match->data;
else if (type == COHERENCY_FABRIC_TYPE_ARMADA_380 && is_smp())
return type;
}
return COHERENCY_FABRIC_TYPE_NONE; of_node_put(np);
return type;
} }
int coherency_available(void) int coherency_available(void)
...@@ -407,22 +271,9 @@ int __init coherency_init(void) ...@@ -407,22 +271,9 @@ int __init coherency_init(void)
static int __init coherency_late_init(void) static int __init coherency_late_init(void)
{ {
int type = coherency_type(); if (coherency_available())
bus_register_notifier(&platform_bus_type,
if (type == COHERENCY_FABRIC_TYPE_NONE) &mvebu_hwcc_nb);
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);
return 0; return 0;
} }
......
...@@ -24,7 +24,10 @@ ...@@ -24,7 +24,10 @@
#include <asm/cp15.h> #include <asm/cp15.h>
.text .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) ENTRY(ll_get_coherency_base)
mrc p15, 0, r1, c1, c0, 0 mrc p15, 0, r1, c1, c0, 0
tst r1, #CR_M @ Check MMU bit enabled tst r1, #CR_M @ Check MMU bit enabled
...@@ -32,8 +35,13 @@ ENTRY(ll_get_coherency_base) ...@@ -32,8 +35,13 @@ ENTRY(ll_get_coherency_base)
/* /*
* MMU is disabled, use the physical address of the coherency * 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 adr r1, 3f
ldr r3, [r1] ldr r3, [r1]
ldr r1, [r1, r3] ldr r1, [r1, r3]
...@@ -85,6 +93,9 @@ ENTRY(ll_add_cpu_to_smp_group) ...@@ -85,6 +93,9 @@ ENTRY(ll_add_cpu_to_smp_group)
*/ */
mov r0, lr mov r0, lr
bl ll_get_coherency_base bl ll_get_coherency_base
/* Bail out if the coherency is not enabled */
cmp r1, #0
reteq r0
bl ll_get_coherency_cpumask bl ll_get_coherency_cpumask
mov lr, r0 mov lr, r0
add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET
...@@ -107,6 +118,9 @@ ENTRY(ll_enable_coherency) ...@@ -107,6 +118,9 @@ ENTRY(ll_enable_coherency)
*/ */
mov r0, lr mov r0, lr
bl ll_get_coherency_base bl ll_get_coherency_base
/* Bail out if the coherency is not enabled */
cmp r1, #0
reteq r0
bl ll_get_coherency_cpumask bl ll_get_coherency_cpumask
mov lr, r0 mov lr, r0
add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
...@@ -131,6 +145,9 @@ ENTRY(ll_disable_coherency) ...@@ -131,6 +145,9 @@ ENTRY(ll_disable_coherency)
*/ */
mov r0, lr mov r0, lr
bl ll_get_coherency_base bl ll_get_coherency_base
/* Bail out if the coherency is not enabled */
cmp r1, #0
reteq r0
bl ll_get_coherency_cpumask bl ll_get_coherency_cpumask
mov lr, r0 mov lr, r0
add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
......
...@@ -25,4 +25,6 @@ int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev); ...@@ -25,4 +25,6 @@ int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev);
void __iomem *mvebu_get_scu_base(void); void __iomem *mvebu_get_scu_base(void);
int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd));
#endif #endif
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/resource.h> #include <linux/resource.h>
#include "armada-370-xp.h"
static void __iomem *cpu_reset_base; static void __iomem *cpu_reset_base;
static size_t cpu_reset_size; static size_t cpu_reset_size;
......
...@@ -22,5 +22,6 @@ ...@@ -22,5 +22,6 @@
ENTRY(mvebu_cortex_a9_secondary_startup) ENTRY(mvebu_cortex_a9_secondary_startup)
ARM_BE8(setend be) ARM_BE8(setend be)
bl v7_invalidate_l1 bl v7_invalidate_l1
bl armada_38x_scu_power_up
b secondary_startup b secondary_startup
ENDPROC(mvebu_cortex_a9_secondary_startup) ENDPROC(mvebu_cortex_a9_secondary_startup)
...@@ -43,21 +43,70 @@ static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu, ...@@ -43,21 +43,70 @@ static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu,
else else
mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup); mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup);
smp_wmb(); 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); ret = mvebu_cpu_reset_deassert(hw_cpu);
if (ret) { if (ret) {
pr_err("Could not start the secondary CPU: %d\n", ret); pr_err("Could not start the secondary CPU: %d\n", ret);
return ret; return ret;
} }
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
return 0; 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 = { static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = {
.smp_boot_secondary = mvebu_cortex_a9_boot_secondary, .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", CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp",
&mvebu_cortex_a9_smp_ops); &mvebu_cortex_a9_smp_ops);
CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp", 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 @@ ...@@ -30,10 +30,12 @@
#include "pmsu.h" #include "pmsu.h"
#include "coherency.h" #include "coherency.h"
#define ARMADA_XP_MAX_CPUS 4
#define AXP_BOOTROM_BASE 0xfff00000 #define AXP_BOOTROM_BASE 0xfff00000
#define AXP_BOOTROM_SIZE 0x100000 #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 clk *cpu_clk;
struct device_node *np = of_get_cpu_node(cpu, NULL); struct device_node *np = of_get_cpu_node(cpu, NULL);
...@@ -46,29 +48,28 @@ static struct clk *__init get_cpu_clk(int cpu) ...@@ -46,29 +48,28 @@ static struct clk *__init get_cpu_clk(int cpu)
return cpu_clk; 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; unsigned long rate;
struct clk *cpu_clk; struct clk *cpu_clk;
thiscpu = smp_processor_id(); thiscpu = get_cpu();
cpu_clk = get_cpu_clk(thiscpu); cpu_clk = get_cpu_clk(thiscpu);
if (!cpu_clk) if (!cpu_clk)
return; goto out;
clk_prepare_enable(cpu_clk); clk_prepare_enable(cpu_clk);
rate = clk_get_rate(cpu_clk); rate = clk_get_rate(cpu_clk);
/* set all the other CPU clk to the same rate than the boot CPU */ cpu_clk = get_cpu_clk(cpu);
for_each_possible_cpu(cpu) { if (!cpu_clk)
if (cpu == thiscpu) goto out;
continue; clk_set_rate(cpu_clk, rate);
cpu_clk = get_cpu_clk(cpu); clk_prepare_enable(cpu_clk);
if (!cpu_clk)
return; out:
clk_set_rate(cpu_clk, rate); put_cpu();
clk_prepare_enable(cpu_clk);
}
} }
static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle) 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) ...@@ -78,6 +79,7 @@ static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle)
pr_info("Booting CPU %d\n", cpu); pr_info("Booting CPU %d\n", cpu);
hw_cpu = cpu_logical_map(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); 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) ...@@ -126,7 +128,6 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
struct resource res; struct resource res;
int err; int err;
set_secondary_cpus_clock();
flush_cache_all(); flush_cache_all();
set_cpu_coherent(); set_cpu_coherent();
......
/*
* 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);
/*
* 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 @@ ...@@ -20,6 +20,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/cpu_pm.h> #include <linux/cpu_pm.h>
#include <linux/cpufreq-dt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -39,7 +40,6 @@ ...@@ -39,7 +40,6 @@
#include <asm/suspend.h> #include <asm/suspend.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include "common.h" #include "common.h"
#include "armada-370-xp.h"
#define PMSU_BASE_OFFSET 0x100 #define PMSU_BASE_OFFSET 0x100
...@@ -312,7 +312,7 @@ static int armada_370_xp_cpu_suspend(unsigned long deepidle) ...@@ -312,7 +312,7 @@ static int armada_370_xp_cpu_suspend(unsigned long deepidle)
return cpu_suspend(deepidle, armada_370_xp_pmsu_idle_enter); 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; unsigned long flags = 0;
...@@ -572,6 +572,10 @@ int mvebu_pmsu_dfs_request(int cpu) ...@@ -572,6 +572,10 @@ int mvebu_pmsu_dfs_request(int cpu)
return 0; return 0;
} }
struct cpufreq_dt_platform_data cpufreq_dt_pd = {
.independent_clocks = true,
};
static int __init armada_xp_pmsu_cpufreq_init(void) static int __init armada_xp_pmsu_cpufreq_init(void)
{ {
struct device_node *np; struct device_node *np;
...@@ -644,7 +648,8 @@ static int __init armada_xp_pmsu_cpufreq_init(void) ...@@ -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; return 0;
} }
......
...@@ -17,5 +17,8 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, ...@@ -17,5 +17,8 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target,
phys_addr_t resume_addr_reg); phys_addr_t resume_addr_reg);
void mvebu_v7_pmsu_idle_exit(void); 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 */ #endif /* __MACH_370_XP_PMSU_H */
...@@ -12,12 +12,32 @@ ...@@ -12,12 +12,32 @@
#include <linux/linkage.h> #include <linux/linkage.h>
#include <asm/assembler.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 * This is the entry point through which CPUs exiting cpuidle deep
* idle state are going. * idle state are going.
*/ */
ENTRY(armada_370_xp_cpu_resume) ENTRY(armada_370_xp_cpu_resume)
ARM_BE8(setend be ) @ go BE8 if entered LE 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_add_cpu_to_smp_group
bl ll_enable_coherency bl ll_enable_coherency
b cpu_resume b cpu_resume
...@@ -27,13 +47,7 @@ ENTRY(armada_38x_cpu_resume) ...@@ -27,13 +47,7 @@ ENTRY(armada_38x_cpu_resume)
/* do we need it for Armada 38x*/ /* do we need it for Armada 38x*/
ARM_BE8(setend be ) @ go BE8 if entered LE ARM_BE8(setend be ) @ go BE8 if entered LE
bl v7_invalidate_l1 bl v7_invalidate_l1
mrc p15, 4, r1, c15, c0 @ get SCU base address bl armada_38x_scu_power_up
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
b cpu_resume b cpu_resume
ENDPROC(armada_38x_cpu_resume) ENDPROC(armada_38x_cpu_resume)
......
...@@ -113,7 +113,7 @@ obj-y += prm_common.o cm_common.o ...@@ -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_OMAP2) += prm2xxx_3xxx.o prm2xxx.o cm2xxx.o
obj-$(CONFIG_ARCH_OMAP3) += prm2xxx_3xxx.o prm3xxx.o cm3xxx.o obj-$(CONFIG_ARCH_OMAP3) += prm2xxx_3xxx.o prm3xxx.o cm3xxx.o
obj-$(CONFIG_ARCH_OMAP3) += vc3xxx_data.o vp3xxx_data.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 \ prcm_mpu44xx.o prminst44xx.o \
vc44xx_data.o vp44xx_data.o vc44xx_data.o vp44xx_data.o
obj-$(CONFIG_ARCH_OMAP4) += $(omap-prcm-4-5-common) obj-$(CONFIG_ARCH_OMAP4) += $(omap-prcm-4-5-common)
......
...@@ -9,8 +9,7 @@ ...@@ -9,8 +9,7 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include "common.h" #include "common.h"
#include "prm-regbits-33xx.h" #include "prm.h"
#include "prm33xx.h"
/** /**
* am3xx_restart - trigger a software restart of the SoC * am3xx_restart - trigger a software restart of the SoC
...@@ -24,12 +23,5 @@ void am33xx_restart(enum reboot_mode mode, const char *cmd) ...@@ -24,12 +23,5 @@ void am33xx_restart(enum reboot_mode mode, const char *cmd)
{ {
/* TODO: Handle mode and cmd if necessary */ /* TODO: Handle mode and cmd if necessary */
am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK, omap_prm_reset_system();
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);
} }
...@@ -257,6 +257,9 @@ static const struct clk_ops dpll1_ck_ops = { ...@@ -257,6 +257,9 @@ static const struct clk_ops dpll1_ck_ops = {
.get_parent = &omap2_init_dpll_parent, .get_parent = &omap2_init_dpll_parent,
.recalc_rate = &omap3_dpll_recalc, .recalc_rate = &omap3_dpll_recalc,
.set_rate = &omap3_noncore_dpll_set_rate, .set_rate = &omap3_noncore_dpll_set_rate,
.set_parent = &omap3_noncore_dpll_set_parent,
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
.determine_rate = &omap3_noncore_dpll_determine_rate,
.round_rate = &omap2_dpll_round_rate, .round_rate = &omap2_dpll_round_rate,
}; };
...@@ -367,6 +370,9 @@ static const struct clk_ops dpll4_ck_ops = { ...@@ -367,6 +370,9 @@ static const struct clk_ops dpll4_ck_ops = {
.get_parent = &omap2_init_dpll_parent, .get_parent = &omap2_init_dpll_parent,
.recalc_rate = &omap3_dpll_recalc, .recalc_rate = &omap3_dpll_recalc,
.set_rate = &omap3_dpll4_set_rate, .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, .round_rate = &omap2_dpll_round_rate,
}; };
......
...@@ -171,7 +171,8 @@ static void _omap2_module_wait_ready(struct clk_hw_omap *clk) ...@@ -171,7 +171,8 @@ static void _omap2_module_wait_ready(struct clk_hw_omap *clk)
_wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit), _wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit),
idlest_val, __clk_get_name(clk->hw.clk)); idlest_val, __clk_get_name(clk->hw.clk));
} else { } 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) ...@@ -771,4 +772,8 @@ void __init ti_clk_init_features(void)
ti_clk_features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL; ti_clk_features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL;
else if (cpu_is_omap34xx()) else if (cpu_is_omap34xx())
ti_clk_features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL; 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 { ...@@ -234,6 +234,7 @@ struct ti_clk_features {
}; };
#define TI_CLK_DPLL_HAS_FREQSEL (1 << 0) #define TI_CLK_DPLL_HAS_FREQSEL (1 << 0)
#define TI_CLK_DPLL4_DENY_REPROGRAM (1 << 1)
extern struct ti_clk_features ti_clk_features; extern struct ti_clk_features ti_clk_features;
......
...@@ -38,6 +38,18 @@ ...@@ -38,6 +38,18 @@
/* needed by omap3_core_dpll_m2_set_rate() */ /* needed by omap3_core_dpll_m2_set_rate() */
struct clk *sdrc_ick_p, *arm_fck_p; 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, int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
...@@ -46,7 +58,7 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long 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 3430ES1 prevents us from changing DPLL multipliers or dividers
* on DPLL4. * 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"); pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
return -EINVAL; return -EINVAL;
} }
...@@ -54,6 +66,30 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -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); 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) void __init omap3_clk_lock_dpll5(void)
{ {
struct clk *dpll5_clk; struct clk *dpll5_clk;
......
...@@ -45,17 +45,29 @@ extern void omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2); ...@@ -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 * 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 * @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_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 { struct cm_ll_data {
int (*split_idlest_reg)(void __iomem *idlest_reg, s16 *prcm_inst, int (*split_idlest_reg)(void __iomem *idlest_reg, s16 *prcm_inst,
u8 *idlest_reg_id); 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, extern int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
u8 *idlest_reg_id); 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_register(struct cm_ll_data *cld);
extern int cm_unregister(struct cm_ll_data *cld); extern int cm_unregister(struct cm_ll_data *cld);
......
...@@ -25,8 +25,6 @@ ...@@ -25,8 +25,6 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CM1_44XX_H #ifndef __ARCH_ARM_MACH_OMAP2_CM1_44XX_H
#define __ARCH_ARM_MACH_OMAP2_CM1_44XX_H #define __ARCH_ARM_MACH_OMAP2_CM1_44XX_H
#include "cm_44xx_54xx.h"
/* CM1 base address */ /* CM1 base address */
#define OMAP4430_CM1_BASE 0x4a004000 #define OMAP4430_CM1_BASE 0x4a004000
......
...@@ -22,8 +22,6 @@ ...@@ -22,8 +22,6 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CM1_54XX_H #ifndef __ARCH_ARM_MACH_OMAP2_CM1_54XX_H
#define __ARCH_ARM_MACH_OMAP2_CM1_54XX_H #define __ARCH_ARM_MACH_OMAP2_CM1_54XX_H
#include "cm_44xx_54xx.h"
/* CM1 base address */ /* CM1 base address */
#define OMAP54XX_CM_CORE_AON_BASE 0x4a004000 #define OMAP54XX_CM_CORE_AON_BASE 0x4a004000
......
...@@ -23,8 +23,6 @@ ...@@ -23,8 +23,6 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CM1_7XX_H #ifndef __ARCH_ARM_MACH_OMAP2_CM1_7XX_H
#define __ARCH_ARM_MACH_OMAP2_CM1_7XX_H #define __ARCH_ARM_MACH_OMAP2_CM1_7XX_H
#include "cm_44xx_54xx.h"
/* CM1 base address */ /* CM1 base address */
#define DRA7XX_CM_CORE_AON_BASE 0x4a005000 #define DRA7XX_CM_CORE_AON_BASE 0x4a005000
......
...@@ -25,8 +25,6 @@ ...@@ -25,8 +25,6 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CM2_44XX_H #ifndef __ARCH_ARM_MACH_OMAP2_CM2_44XX_H
#define __ARCH_ARM_MACH_OMAP2_CM2_44XX_H #define __ARCH_ARM_MACH_OMAP2_CM2_44XX_H
#include "cm_44xx_54xx.h"
/* CM2 base address */ /* CM2 base address */
#define OMAP4430_CM2_BASE 0x4a008000 #define OMAP4430_CM2_BASE 0x4a008000
......
...@@ -21,8 +21,6 @@ ...@@ -21,8 +21,6 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CM2_54XX_H #ifndef __ARCH_ARM_MACH_OMAP2_CM2_54XX_H
#define __ARCH_ARM_MACH_OMAP2_CM2_54XX_H #define __ARCH_ARM_MACH_OMAP2_CM2_54XX_H
#include "cm_44xx_54xx.h"
/* CM2 base address */ /* CM2 base address */
#define OMAP54XX_CM_CORE_BASE 0x4a008000 #define OMAP54XX_CM_CORE_BASE 0x4a008000
......
...@@ -22,8 +22,6 @@ ...@@ -22,8 +22,6 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CM2_7XX_H #ifndef __ARCH_ARM_MACH_OMAP2_CM2_7XX_H
#define __ARCH_ARM_MACH_OMAP2_CM2_7XX_H #define __ARCH_ARM_MACH_OMAP2_CM2_7XX_H
#include "cm_44xx_54xx.h"
/* CM2 base address */ /* CM2 base address */
#define DRA7XX_CM_CORE_BASE 0x4a008000 #define DRA7XX_CM_CORE_BASE 0x4a008000
......
...@@ -53,7 +53,7 @@ static void _write_clktrctrl(u8 c, s16 module, u32 mask) ...@@ -53,7 +53,7 @@ static void _write_clktrctrl(u8 c, s16 module, u32 mask)
omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL); omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL);
} }
bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) static bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask)
{ {
u32 v; u32 v;
...@@ -64,12 +64,12 @@ bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) ...@@ -64,12 +64,12 @@ bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask)
return (v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0; return (v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0;
} }
void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) static void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask)
{ {
_write_clktrctrl(OMAP24XX_CLKSTCTRL_ENABLE_AUTO, module, mask); _write_clktrctrl(OMAP24XX_CLKSTCTRL_ENABLE_AUTO, module, mask);
} }
void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) static void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask)
{ {
_write_clktrctrl(OMAP24XX_CLKSTCTRL_DISABLE_AUTO, module, mask); _write_clktrctrl(OMAP24XX_CLKSTCTRL_DISABLE_AUTO, module, mask);
} }
...@@ -150,7 +150,7 @@ static int _omap2xxx_apll_enable(u8 enable_bit, u8 status_bit) ...@@ -150,7 +150,7 @@ static int _omap2xxx_apll_enable(u8 enable_bit, u8 status_bit)
v |= m; v |= m;
omap2_cm_write_mod_reg(v, PLL_MOD, CM_CLKEN); omap2_cm_write_mod_reg(v, PLL_MOD, CM_CLKEN);
omap2xxx_cm_wait_module_ready(PLL_MOD, 1, status_bit); omap2xxx_cm_wait_module_ready(0, PLL_MOD, 1, status_bit);
/* /*
* REVISIT: Should we return an error code if * REVISIT: Should we return an error code if
...@@ -204,8 +204,9 @@ void omap2xxx_cm_apll96_disable(void) ...@@ -204,8 +204,9 @@ void omap2xxx_cm_apll96_disable(void)
* XXX This function is only needed until absolute register addresses are * XXX This function is only needed until absolute register addresses are
* removed from the OMAP struct clk records. * removed from the OMAP struct clk records.
*/ */
int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, static int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
u8 *idlest_reg_id) s16 *prcm_inst,
u8 *idlest_reg_id)
{ {
unsigned long offs; unsigned long offs;
u8 idlest_offs; u8 idlest_offs;
...@@ -238,6 +239,7 @@ int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, ...@@ -238,6 +239,7 @@ int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
/** /**
* omap2xxx_cm_wait_module_ready - wait for a module to leave idle or standby * omap2xxx_cm_wait_module_ready - wait for a module to leave idle or standby
* @part: PRCM partition, ignored for OMAP2
* @prcm_mod: PRCM module offset * @prcm_mod: PRCM module offset
* @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3)
* @idlest_shift: shift of the bit in the CM_IDLEST* register to check * @idlest_shift: shift of the bit in the CM_IDLEST* register to check
...@@ -246,7 +248,8 @@ int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, ...@@ -246,7 +248,8 @@ int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
* (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon * (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon
* success or -EBUSY if the module doesn't enable in time. * success or -EBUSY if the module doesn't enable in time.
*/ */
int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id,
u8 idlest_shift)
{ {
int ena = 0, i = 0; int ena = 0, i = 0;
u8 cm_idlest_reg; u8 cm_idlest_reg;
......
...@@ -46,9 +46,6 @@ ...@@ -46,9 +46,6 @@
#ifndef __ASSEMBLER__ #ifndef __ASSEMBLER__
extern void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask);
extern void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask);
extern void omap2xxx_cm_set_dpll_disable_autoidle(void); extern void omap2xxx_cm_set_dpll_disable_autoidle(void);
extern void omap2xxx_cm_set_dpll_auto_low_power_stop(void); extern void omap2xxx_cm_set_dpll_auto_low_power_stop(void);
...@@ -57,11 +54,8 @@ extern void omap2xxx_cm_set_apll54_auto_low_power_stop(void); ...@@ -57,11 +54,8 @@ extern void omap2xxx_cm_set_apll54_auto_low_power_stop(void);
extern void omap2xxx_cm_set_apll96_disable_autoidle(void); extern void omap2xxx_cm_set_apll96_disable_autoidle(void);
extern void omap2xxx_cm_set_apll96_auto_low_power_stop(void); extern void omap2xxx_cm_set_apll96_auto_low_power_stop(void);
extern bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask); int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id,
extern int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift);
u8 idlest_shift);
extern int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
s16 *prcm_inst, u8 *idlest_reg_id);
extern int omap2xxx_cm_fclks_active(void); extern int omap2xxx_cm_fclks_active(void);
extern int omap2xxx_cm_mpu_retention_allowed(void); extern int omap2xxx_cm_mpu_retention_allowed(void);
extern u32 omap2xxx_cm_get_core_clk_src(void); extern u32 omap2xxx_cm_get_core_clk_src(void);
......
...@@ -96,13 +96,12 @@ static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask) ...@@ -96,13 +96,12 @@ static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask)
/** /**
* _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
* *
* Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to
* bit 0. * bit 0.
*/ */
static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs) static u32 _clkctrl_idlest(u16 inst, u16 clkctrl_offs)
{ {
u32 v = am33xx_cm_read_reg(inst, clkctrl_offs); u32 v = am33xx_cm_read_reg(inst, clkctrl_offs);
v &= AM33XX_IDLEST_MASK; v &= AM33XX_IDLEST_MASK;
...@@ -113,17 +112,16 @@ static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs) ...@@ -113,17 +112,16 @@ static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs)
/** /**
* _is_module_ready - can module registers be accessed without causing an abort? * _is_module_ready - can module registers be accessed without causing an abort?
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
* *
* Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either
* *FUNCTIONAL or *INTERFACE_IDLE; false otherwise. * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise.
*/ */
static bool _is_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) static bool _is_module_ready(u16 inst, u16 clkctrl_offs)
{ {
u32 v; u32 v;
v = _clkctrl_idlest(inst, cdoffs, clkctrl_offs); v = _clkctrl_idlest(inst, clkctrl_offs);
return (v == CLKCTRL_IDLEST_FUNCTIONAL || return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false; v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
...@@ -158,7 +156,7 @@ static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs) ...@@ -158,7 +156,7 @@ static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs)
* Returns true if the clockdomain referred to by (@inst, @cdoffs) * Returns true if the clockdomain referred to by (@inst, @cdoffs)
* is in hardware-supervised idle mode, or 0 otherwise. * is in hardware-supervised idle mode, or 0 otherwise.
*/ */
bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs) static bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs)
{ {
u32 v; u32 v;
...@@ -177,7 +175,7 @@ bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs) ...@@ -177,7 +175,7 @@ bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs)
* Put a clockdomain referred to by (@inst, @cdoffs) into * Put a clockdomain referred to by (@inst, @cdoffs) into
* hardware-supervised idle mode. No return value. * hardware-supervised idle mode. No return value.
*/ */
void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs) static void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs)
{ {
_clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs); _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs);
} }
...@@ -191,7 +189,7 @@ void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs) ...@@ -191,7 +189,7 @@ void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs)
* software-supervised idle mode, i.e., controlled manually by the * software-supervised idle mode, i.e., controlled manually by the
* Linux OMAP clockdomain code. No return value. * Linux OMAP clockdomain code. No return value.
*/ */
void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs) static void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs)
{ {
_clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs); _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs);
} }
...@@ -204,7 +202,7 @@ void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs) ...@@ -204,7 +202,7 @@ void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs)
* Put a clockdomain referred to by (@inst, @cdoffs) into idle * Put a clockdomain referred to by (@inst, @cdoffs) into idle
* No return value. * No return value.
*/ */
void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs) static void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs)
{ {
_clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs); _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs);
} }
...@@ -217,7 +215,7 @@ void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs) ...@@ -217,7 +215,7 @@ void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs)
* Take a clockdomain referred to by (@inst, @cdoffs) out of idle, * Take a clockdomain referred to by (@inst, @cdoffs) out of idle,
* waking it up. No return value. * waking it up. No return value.
*/ */
void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) static void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs)
{ {
_clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs); _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs);
} }
...@@ -228,20 +226,22 @@ void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) ...@@ -228,20 +226,22 @@ void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs)
/** /**
* am33xx_cm_wait_module_ready - wait for a module to be in 'func' state * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state
* @part: PRCM partition, ignored for AM33xx
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
* @bit_shift: bit shift for the register, ignored for AM33xx
* *
* Wait for the module IDLEST to be functional. If the idle state is in any * Wait for the module IDLEST to be functional. If the idle state is in any
* the non functional state (trans, idle or disabled), module and thus the * the non functional state (trans, idle or disabled), module and thus the
* sysconfig cannot be accessed and will probably lead to an "imprecise * sysconfig cannot be accessed and will probably lead to an "imprecise
* external abort" * external abort"
*/ */
int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
u8 bit_shift)
{ {
int i = 0; int i = 0;
omap_test_timeout(_is_module_ready(inst, cdoffs, clkctrl_offs), omap_test_timeout(_is_module_ready(inst, clkctrl_offs),
MAX_MODULE_READY_TIME, i); MAX_MODULE_READY_TIME, i);
return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
...@@ -250,22 +250,24 @@ int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) ...@@ -250,22 +250,24 @@ int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs)
/** /**
* am33xx_cm_wait_module_idle - wait for a module to be in 'disabled' * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled'
* state * state
* @part: CM partition, ignored for AM33xx
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
* @bit_shift: bit shift for the register, ignored for AM33xx
* *
* Wait for the module IDLEST to be disabled. Some PRCM transition, * Wait for the module IDLEST to be disabled. Some PRCM transition,
* like reset assertion or parent clock de-activation must wait the * like reset assertion or parent clock de-activation must wait the
* module to be fully disabled. * module to be fully disabled.
*/ */
int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, u16 clkctrl_offs) static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
u8 bit_shift)
{ {
int i = 0; int i = 0;
if (!clkctrl_offs) if (!clkctrl_offs)
return 0; return 0;
omap_test_timeout((_clkctrl_idlest(inst, cdoffs, clkctrl_offs) == omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) ==
CLKCTRL_IDLEST_DISABLED), CLKCTRL_IDLEST_DISABLED),
MAX_MODULE_READY_TIME, i); MAX_MODULE_READY_TIME, i);
...@@ -275,13 +277,14 @@ int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, u16 clkctrl_offs) ...@@ -275,13 +277,14 @@ int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, u16 clkctrl_offs)
/** /**
* am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL * am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL
* @mode: Module mode (SW or HW) * @mode: Module mode (SW or HW)
* @part: CM partition, ignored for AM33xx
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
* *
* No return value. * No return value.
*/ */
void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs) static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst,
u16 clkctrl_offs)
{ {
u32 v; u32 v;
...@@ -293,13 +296,13 @@ void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs) ...@@ -293,13 +296,13 @@ void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs)
/** /**
* am33xx_cm_module_disable - Disable the module inside CLKCTRL * am33xx_cm_module_disable - Disable the module inside CLKCTRL
* @part: CM partition, ignored for AM33xx
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
* *
* No return value. * No return value.
*/ */
void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs) static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
{ {
u32 v; u32 v;
...@@ -362,3 +365,21 @@ struct clkdm_ops am33xx_clkdm_operations = { ...@@ -362,3 +365,21 @@ struct clkdm_ops am33xx_clkdm_operations = {
.clkdm_clk_enable = am33xx_clkdm_clk_enable, .clkdm_clk_enable = am33xx_clkdm_clk_enable,
.clkdm_clk_disable = am33xx_clkdm_clk_disable, .clkdm_clk_disable = am33xx_clkdm_clk_disable,
}; };
static struct cm_ll_data am33xx_cm_ll_data = {
.wait_module_ready = &am33xx_cm_wait_module_ready,
.wait_module_idle = &am33xx_cm_wait_module_idle,
.module_enable = &am33xx_cm_module_enable,
.module_disable = &am33xx_cm_module_disable,
};
int __init am33xx_cm_init(void)
{
return cm_register(&am33xx_cm_ll_data);
}
static void __exit am33xx_cm_exit(void)
{
cm_unregister(&am33xx_cm_ll_data);
}
__exitcall(am33xx_cm_exit);
...@@ -374,41 +374,6 @@ ...@@ -374,41 +374,6 @@
#ifndef __ASSEMBLER__ #ifndef __ASSEMBLER__
bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs); int am33xx_cm_init(void);
void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs);
void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs);
void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs);
void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs);
#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
extern int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs,
u16 clkctrl_offs);
extern void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs,
u16 clkctrl_offs);
extern void am33xx_cm_module_disable(u16 inst, s16 cdoffs,
u16 clkctrl_offs);
extern int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs,
u16 clkctrl_offs);
#else
static inline int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs,
u16 clkctrl_offs)
{
return 0;
}
static inline void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs,
u16 clkctrl_offs)
{
}
static inline void am33xx_cm_module_disable(u16 inst, s16 cdoffs,
u16 clkctrl_offs)
{
}
static inline int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs,
u16 clkctrl_offs)
{
return 0;
}
#endif
#endif /* ASSEMBLER */ #endif /* ASSEMBLER */
#endif #endif
...@@ -42,7 +42,7 @@ static void _write_clktrctrl(u8 c, s16 module, u32 mask) ...@@ -42,7 +42,7 @@ static void _write_clktrctrl(u8 c, s16 module, u32 mask)
omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL); omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL);
} }
bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) static bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask)
{ {
u32 v; u32 v;
...@@ -53,22 +53,22 @@ bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) ...@@ -53,22 +53,22 @@ bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask)
return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0; return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0;
} }
void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) static void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask)
{ {
_write_clktrctrl(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, module, mask); _write_clktrctrl(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, module, mask);
} }
void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) static void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask)
{ {
_write_clktrctrl(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, module, mask); _write_clktrctrl(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, module, mask);
} }
void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask) static void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask)
{ {
_write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, module, mask); _write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, module, mask);
} }
void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) static void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask)
{ {
_write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, module, mask); _write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, module, mask);
} }
...@@ -79,6 +79,7 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) ...@@ -79,6 +79,7 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask)
/** /**
* omap3xxx_cm_wait_module_ready - wait for a module to leave idle or standby * omap3xxx_cm_wait_module_ready - wait for a module to leave idle or standby
* @part: PRCM partition, ignored for OMAP3
* @prcm_mod: PRCM module offset * @prcm_mod: PRCM module offset
* @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3)
* @idlest_shift: shift of the bit in the CM_IDLEST* register to check * @idlest_shift: shift of the bit in the CM_IDLEST* register to check
...@@ -87,7 +88,8 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) ...@@ -87,7 +88,8 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask)
* (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon * (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon
* success or -EBUSY if the module doesn't enable in time. * success or -EBUSY if the module doesn't enable in time.
*/ */
int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) static int omap3xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id,
u8 idlest_shift)
{ {
int ena = 0, i = 0; int ena = 0, i = 0;
u8 cm_idlest_reg; u8 cm_idlest_reg;
...@@ -116,8 +118,9 @@ int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) ...@@ -116,8 +118,9 @@ int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
* XXX This function is only needed until absolute register addresses are * XXX This function is only needed until absolute register addresses are
* removed from the OMAP struct clk records. * removed from the OMAP struct clk records.
*/ */
int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, static int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
u8 *idlest_reg_id) s16 *prcm_inst,
u8 *idlest_reg_id)
{ {
unsigned long offs; unsigned long offs;
u8 idlest_offs; u8 idlest_offs;
......
...@@ -68,18 +68,6 @@ ...@@ -68,18 +68,6 @@
#ifndef __ASSEMBLER__ #ifndef __ASSEMBLER__
extern void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask);
extern void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask);
extern void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask);
extern void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask);
extern bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask);
extern int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id,
u8 idlest_shift);
extern int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
s16 *prcm_inst, u8 *idlest_reg_id);
extern void omap3_cm_save_context(void); extern void omap3_cm_save_context(void);
extern void omap3_cm_restore_context(void); extern void omap3_cm_restore_context(void);
extern void omap3_cm_save_scratchpad_contents(u32 *ptr); extern void omap3_cm_save_scratchpad_contents(u32 *ptr);
......
/*
* OMAP4 CM1, CM2 module low-level functions
*
* Copyright (C) 2010 Nokia Corporation
* Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* These functions are intended to be used only by the cminst44xx.c file.
* XXX Perhaps we should just move them there and make them static.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/io.h>
#include "cm.h"
#include "cm1_44xx.h"
#include "cm2_44xx.h"
/* CM1 hardware module low-level functions */
/* Read a register in CM1 */
u32 omap4_cm1_read_inst_reg(s16 inst, u16 reg)
{
return readl_relaxed(cm_base + inst + reg);
}
/* Write into a register in CM1 */
void omap4_cm1_write_inst_reg(u32 val, s16 inst, u16 reg)
{
writel_relaxed(val, cm_base + inst + reg);
}
/* Read a register in CM2 */
u32 omap4_cm2_read_inst_reg(s16 inst, u16 reg)
{
return readl_relaxed(cm2_base + inst + reg);
}
/* Write into a register in CM2 */
void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 reg)
{
writel_relaxed(val, cm2_base + inst + reg);
}
...@@ -23,4 +23,7 @@ ...@@ -23,4 +23,7 @@
#define OMAP4_CM_CLKSTCTRL 0x0000 #define OMAP4_CM_CLKSTCTRL 0x0000
#define OMAP4_CM_STATICDEP 0x0004 #define OMAP4_CM_STATICDEP 0x0004
void omap_cm_base_init(void);
int omap4_cm_init(void);
#endif #endif
/*
* OMAP44xx and OMAP54xx CM1/CM2 function prototypes
*
* Copyright (C) 2009-2013 Texas Instruments, Inc.
* Copyright (C) 2009-2010 Nokia Corporation
*
* Paul Walmsley (paul@pwsan.com)
* Rajendra Nayak (rnayak@ti.com)
* Benoit Cousson (b-cousson@ti.com)
*
* This file is automatically generated from the OMAP hardware databases.
* We respectfully ask that any modifications to this file be coordinated
* with the public linux-omap@vger.kernel.org mailing list and the
* authors above to ensure that the autogeneration scripts are kept
* up-to-date with the file contents.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __ARCH_ARM_MACH_OMAP2_CM_44XX_54XX_H
#define __ARCH_ARM_MACH_OMAP2_CM_44XX_55XX_H
/* CM1 Function prototypes */
extern u32 omap4_cm1_read_inst_reg(s16 inst, u16 idx);
extern void omap4_cm1_write_inst_reg(u32 val, s16 inst, u16 idx);
extern u32 omap4_cm1_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx);
/* CM2 Function prototypes */
extern u32 omap4_cm2_read_inst_reg(s16 inst, u16 idx);
extern void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 idx);
extern u32 omap4_cm2_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx);
#endif
...@@ -72,9 +72,10 @@ int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, ...@@ -72,9 +72,10 @@ int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
} }
/** /**
* cm_wait_module_ready - wait for a module to leave idle or standby * omap_cm_wait_module_ready - wait for a module to leave idle or standby
* @part: PRCM partition
* @prcm_mod: PRCM module offset * @prcm_mod: PRCM module offset
* @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) * @idlest_reg: CM_IDLESTx register
* @idlest_shift: shift of the bit in the CM_IDLEST* register to check * @idlest_shift: shift of the bit in the CM_IDLEST* register to check
* *
* Wait for the PRCM to indicate that the module identified by * Wait for the PRCM to indicate that the module identified by
...@@ -83,7 +84,8 @@ int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, ...@@ -83,7 +84,8 @@ int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
* no per-SoC wait_module_ready() function pointer has been registered * no per-SoC wait_module_ready() function pointer has been registered
* or if the idlest register is unknown on the SoC. * or if the idlest register is unknown on the SoC.
*/ */
int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg,
u8 idlest_shift)
{ {
if (!cm_ll_data->wait_module_ready) { if (!cm_ll_data->wait_module_ready) {
WARN_ONCE(1, "cm: %s: no low-level function defined\n", WARN_ONCE(1, "cm: %s: no low-level function defined\n",
...@@ -91,7 +93,79 @@ int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) ...@@ -91,7 +93,79 @@ int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
return -EINVAL; return -EINVAL;
} }
return cm_ll_data->wait_module_ready(prcm_mod, idlest_id, idlest_shift); return cm_ll_data->wait_module_ready(part, prcm_mod, idlest_reg,
idlest_shift);
}
/**
* omap_cm_wait_module_idle - wait for a module to enter idle or standby
* @part: PRCM partition
* @prcm_mod: PRCM module offset
* @idlest_reg: CM_IDLESTx register
* @idlest_shift: shift of the bit in the CM_IDLEST* register to check
*
* Wait for the PRCM to indicate that the module identified by
* (@prcm_mod, @idlest_id, @idlest_shift) is no longer clocked. Return
* 0 upon success, -EBUSY if the module doesn't enable in time, or
* -EINVAL if no per-SoC wait_module_idle() function pointer has been
* registered or if the idlest register is unknown on the SoC.
*/
int omap_cm_wait_module_idle(u8 part, s16 prcm_mod, u16 idlest_reg,
u8 idlest_shift)
{
if (!cm_ll_data->wait_module_idle) {
WARN_ONCE(1, "cm: %s: no low-level function defined\n",
__func__);
return -EINVAL;
}
return cm_ll_data->wait_module_idle(part, prcm_mod, idlest_reg,
idlest_shift);
}
/**
* omap_cm_module_enable - enable a module
* @mode: target mode for the module
* @part: PRCM partition
* @inst: PRCM instance
* @clkctrl_offs: CM_CLKCTRL register offset for the module
*
* Enables clocks for a module identified by (@part, @inst, @clkctrl_offs)
* making its IO space accessible. Return 0 upon success, -EINVAL if no
* per-SoC module_enable() function pointer has been registered.
*/
int omap_cm_module_enable(u8 mode, u8 part, u16 inst, u16 clkctrl_offs)
{
if (!cm_ll_data->module_enable) {
WARN_ONCE(1, "cm: %s: no low-level function defined\n",
__func__);
return -EINVAL;
}
cm_ll_data->module_enable(mode, part, inst, clkctrl_offs);
return 0;
}
/**
* omap_cm_module_disable - disable a module
* @part: PRCM partition
* @inst: PRCM instance
* @clkctrl_offs: CM_CLKCTRL register offset for the module
*
* Disables clocks for a module identified by (@part, @inst, @clkctrl_offs)
* makings its IO space inaccessible. Return 0 upon success, -EINVAL if
* no per-SoC module_disable() function pointer has been registered.
*/
int omap_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
{
if (!cm_ll_data->module_disable) {
WARN_ONCE(1, "cm: %s: no low-level function defined\n",
__func__);
return -EINVAL;
}
cm_ll_data->module_disable(part, inst, clkctrl_offs);
return 0;
} }
/** /**
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include "cm1_44xx.h" #include "cm1_44xx.h"
#include "cm2_44xx.h" #include "cm2_44xx.h"
#include "cm44xx.h" #include "cm44xx.h"
#include "cminst44xx.h"
#include "cm-regbits-34xx.h" #include "cm-regbits-34xx.h"
#include "prcm44xx.h" #include "prcm44xx.h"
#include "prm44xx.h" #include "prm44xx.h"
...@@ -74,17 +73,18 @@ void omap_cm_base_init(void) ...@@ -74,17 +73,18 @@ void omap_cm_base_init(void)
/* Private functions */ /* Private functions */
static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx);
/** /**
* _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
* @part: PRCM partition ID that the CM_CLKCTRL register exists in * @part: PRCM partition ID that the CM_CLKCTRL register exists in
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
* *
* Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to
* bit 0. * bit 0.
*/ */
static u32 _clkctrl_idlest(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) static u32 _clkctrl_idlest(u8 part, u16 inst, u16 clkctrl_offs)
{ {
u32 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs); u32 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
v &= OMAP4430_IDLEST_MASK; v &= OMAP4430_IDLEST_MASK;
...@@ -96,26 +96,23 @@ static u32 _clkctrl_idlest(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) ...@@ -96,26 +96,23 @@ static u32 _clkctrl_idlest(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs)
* _is_module_ready - can module registers be accessed without causing an abort? * _is_module_ready - can module registers be accessed without causing an abort?
* @part: PRCM partition ID that the CM_CLKCTRL register exists in * @part: PRCM partition ID that the CM_CLKCTRL register exists in
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
* *
* Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either
* *FUNCTIONAL or *INTERFACE_IDLE; false otherwise. * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise.
*/ */
static bool _is_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) static bool _is_module_ready(u8 part, u16 inst, u16 clkctrl_offs)
{ {
u32 v; u32 v;
v = _clkctrl_idlest(part, inst, cdoffs, clkctrl_offs); v = _clkctrl_idlest(part, inst, clkctrl_offs);
return (v == CLKCTRL_IDLEST_FUNCTIONAL || return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false; v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
} }
/* Public functions */
/* Read a register in a CM instance */ /* Read a register in a CM instance */
u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx) static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx)
{ {
BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS || BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
part == OMAP4430_INVALID_PRCM_PARTITION || part == OMAP4430_INVALID_PRCM_PARTITION ||
...@@ -124,7 +121,7 @@ u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx) ...@@ -124,7 +121,7 @@ u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx)
} }
/* Write into a register in a CM instance */ /* Write into a register in a CM instance */
void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx) static void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx)
{ {
BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS || BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
part == OMAP4430_INVALID_PRCM_PARTITION || part == OMAP4430_INVALID_PRCM_PARTITION ||
...@@ -133,8 +130,8 @@ void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx) ...@@ -133,8 +130,8 @@ void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx)
} }
/* Read-modify-write a register in CM1. Caller must lock */ /* Read-modify-write a register in CM1. Caller must lock */
u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst, static u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst,
s16 idx) s16 idx)
{ {
u32 v; u32 v;
...@@ -146,17 +143,18 @@ u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst, ...@@ -146,17 +143,18 @@ u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst,
return v; return v;
} }
u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx) static u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx)
{ {
return omap4_cminst_rmw_inst_reg_bits(bits, bits, part, inst, idx); return omap4_cminst_rmw_inst_reg_bits(bits, bits, part, inst, idx);
} }
u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx) static u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst,
s16 idx)
{ {
return omap4_cminst_rmw_inst_reg_bits(bits, 0x0, part, inst, idx); return omap4_cminst_rmw_inst_reg_bits(bits, 0x0, part, inst, idx);
} }
u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask) static u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask)
{ {
u32 v; u32 v;
...@@ -200,7 +198,7 @@ static void _clktrctrl_write(u8 c, u8 part, u16 inst, u16 cdoffs) ...@@ -200,7 +198,7 @@ static void _clktrctrl_write(u8 c, u8 part, u16 inst, u16 cdoffs)
* Returns true if the clockdomain referred to by (@part, @inst, @cdoffs) * Returns true if the clockdomain referred to by (@part, @inst, @cdoffs)
* is in hardware-supervised idle mode, or 0 otherwise. * is in hardware-supervised idle mode, or 0 otherwise.
*/ */
bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs) static bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs)
{ {
u32 v; u32 v;
...@@ -220,7 +218,7 @@ bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs) ...@@ -220,7 +218,7 @@ bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs)
* Put a clockdomain referred to by (@part, @inst, @cdoffs) into * Put a clockdomain referred to by (@part, @inst, @cdoffs) into
* hardware-supervised idle mode. No return value. * hardware-supervised idle mode. No return value.
*/ */
void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs) static void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs)
{ {
_clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, part, inst, cdoffs); _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, part, inst, cdoffs);
} }
...@@ -235,7 +233,7 @@ void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs) ...@@ -235,7 +233,7 @@ void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs)
* software-supervised idle mode, i.e., controlled manually by the * software-supervised idle mode, i.e., controlled manually by the
* Linux OMAP clockdomain code. No return value. * Linux OMAP clockdomain code. No return value.
*/ */
void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs) static void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs)
{ {
_clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, part, inst, cdoffs); _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, part, inst, cdoffs);
} }
...@@ -249,7 +247,7 @@ void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs) ...@@ -249,7 +247,7 @@ void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs)
* Take a clockdomain referred to by (@part, @inst, @cdoffs) out of idle, * Take a clockdomain referred to by (@part, @inst, @cdoffs) out of idle,
* waking it up. No return value. * waking it up. No return value.
*/ */
void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs) static void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs)
{ {
_clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, part, inst, cdoffs); _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, part, inst, cdoffs);
} }
...@@ -258,7 +256,7 @@ void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs) ...@@ -258,7 +256,7 @@ void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs)
* *
*/ */
void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs) static void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs)
{ {
_clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, part, inst, cdoffs); _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, part, inst, cdoffs);
} }
...@@ -267,23 +265,23 @@ void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs) ...@@ -267,23 +265,23 @@ void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs)
* omap4_cminst_wait_module_ready - wait for a module to be in 'func' state * omap4_cminst_wait_module_ready - wait for a module to be in 'func' state
* @part: PRCM partition ID that the CM_CLKCTRL register exists in * @part: PRCM partition ID that the CM_CLKCTRL register exists in
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
* @bit_shift: bit shift for the register, ignored for OMAP4+
* *
* Wait for the module IDLEST to be functional. If the idle state is in any * Wait for the module IDLEST to be functional. If the idle state is in any
* the non functional state (trans, idle or disabled), module and thus the * the non functional state (trans, idle or disabled), module and thus the
* sysconfig cannot be accessed and will probably lead to an "imprecise * sysconfig cannot be accessed and will probably lead to an "imprecise
* external abort" * external abort"
*/ */
int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, static int omap4_cminst_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
u16 clkctrl_offs) u8 bit_shift)
{ {
int i = 0; int i = 0;
if (!clkctrl_offs) if (!clkctrl_offs)
return 0; return 0;
omap_test_timeout(_is_module_ready(part, inst, cdoffs, clkctrl_offs), omap_test_timeout(_is_module_ready(part, inst, clkctrl_offs),
MAX_MODULE_READY_TIME, i); MAX_MODULE_READY_TIME, i);
return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
...@@ -294,21 +292,22 @@ int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, ...@@ -294,21 +292,22 @@ int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs,
* state * state
* @part: PRCM partition ID that the CM_CLKCTRL register exists in * @part: PRCM partition ID that the CM_CLKCTRL register exists in
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
* @bit_shift: Bit shift for the register, ignored for OMAP4+
* *
* Wait for the module IDLEST to be disabled. Some PRCM transition, * Wait for the module IDLEST to be disabled. Some PRCM transition,
* like reset assertion or parent clock de-activation must wait the * like reset assertion or parent clock de-activation must wait the
* module to be fully disabled. * module to be fully disabled.
*/ */
int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) static int omap4_cminst_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
u8 bit_shift)
{ {
int i = 0; int i = 0;
if (!clkctrl_offs) if (!clkctrl_offs)
return 0; return 0;
omap_test_timeout((_clkctrl_idlest(part, inst, cdoffs, clkctrl_offs) == omap_test_timeout((_clkctrl_idlest(part, inst, clkctrl_offs) ==
CLKCTRL_IDLEST_DISABLED), CLKCTRL_IDLEST_DISABLED),
MAX_MODULE_DISABLE_TIME, i); MAX_MODULE_DISABLE_TIME, i);
...@@ -320,13 +319,12 @@ int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_off ...@@ -320,13 +319,12 @@ int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_off
* @mode: Module mode (SW or HW) * @mode: Module mode (SW or HW)
* @part: PRCM partition ID that the CM_CLKCTRL register exists in * @part: PRCM partition ID that the CM_CLKCTRL register exists in
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
* *
* No return value. * No return value.
*/ */
void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, static void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst,
u16 clkctrl_offs) u16 clkctrl_offs)
{ {
u32 v; u32 v;
...@@ -340,13 +338,11 @@ void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, ...@@ -340,13 +338,11 @@ void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs,
* omap4_cminst_module_disable - Disable the module inside CLKCTRL * omap4_cminst_module_disable - Disable the module inside CLKCTRL
* @part: PRCM partition ID that the CM_CLKCTRL register exists in * @part: PRCM partition ID that the CM_CLKCTRL register exists in
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
* *
* No return value. * No return value.
*/ */
void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs, static void omap4_cminst_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
u16 clkctrl_offs)
{ {
u32 v; u32 v;
...@@ -510,3 +506,21 @@ struct clkdm_ops am43xx_clkdm_operations = { ...@@ -510,3 +506,21 @@ struct clkdm_ops am43xx_clkdm_operations = {
.clkdm_clk_enable = omap4_clkdm_clk_enable, .clkdm_clk_enable = omap4_clkdm_clk_enable,
.clkdm_clk_disable = omap4_clkdm_clk_disable, .clkdm_clk_disable = omap4_clkdm_clk_disable,
}; };
static struct cm_ll_data omap4xxx_cm_ll_data = {
.wait_module_ready = &omap4_cminst_wait_module_ready,
.wait_module_idle = &omap4_cminst_wait_module_idle,
.module_enable = &omap4_cminst_module_enable,
.module_disable = &omap4_cminst_module_disable,
};
int __init omap4_cm_init(void)
{
return cm_register(&omap4xxx_cm_ll_data);
}
static void __exit omap4_cm_exit(void)
{
cm_unregister(&omap4xxx_cm_ll_data);
}
__exitcall(omap4_cm_exit);
/*
* OMAP4 Clock Management (CM) function prototypes
*
* Copyright (C) 2010 Nokia Corporation
* Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ARCH_ASM_MACH_OMAP2_CMINST44XX_H
#define __ARCH_ASM_MACH_OMAP2_CMINST44XX_H
bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs);
void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs);
void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs);
void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs);
void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs);
extern int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs);
extern int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs,
u16 clkctrl_offs);
extern void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs,
u16 clkctrl_offs);
extern void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs,
u16 clkctrl_offs);
/*
* In an ideal world, we would not export these low-level functions,
* but this will probably take some time to fix properly
*/
u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx);
void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx);
u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part,
u16 inst, s16 idx);
u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst,
s16 idx);
u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst,
s16 idx);
extern u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx,
u32 mask);
extern void omap_cm_base_init(void);
#endif
...@@ -460,25 +460,24 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw) ...@@ -460,25 +460,24 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw)
/* Non-CORE DPLL rate set code */ /* Non-CORE DPLL rate set code */
/** /**
* omap3_noncore_dpll_set_rate - set non-core DPLL rate * omap3_noncore_dpll_determine_rate - determine rate for a DPLL
* @clk: struct clk * of DPLL to set * @hw: pointer to the clock to determine rate for
* @rate: rounded target rate * @rate: target rate for the DPLL
* @best_parent_rate: pointer for returning best parent rate
* @best_parent_clk: pointer for returning best parent clock
* *
* Set the DPLL CLKOUT to the target rate. If the DPLL can enter * Determines which DPLL mode to use for reaching a desired target rate.
* low-power bypass, and the target rate is the bypass source clock * Checks whether the DPLL shall be in bypass or locked mode, and if
* rate, then configure the DPLL for bypass. Otherwise, round the * locked, calculates the M,N values for the DPLL via round-rate.
* target rate if it hasn't been done already, then program and lock * Returns a positive clock rate with success, negative error value
* the DPLL. Returns -EINVAL upon error, or 0 upon success. * in failure.
*/ */
int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long *best_parent_rate,
struct clk **best_parent_clk)
{ {
struct clk_hw_omap *clk = to_clk_hw_omap(hw); struct clk_hw_omap *clk = to_clk_hw_omap(hw);
struct clk *new_parent = NULL;
unsigned long rrate;
u16 freqsel = 0;
struct dpll_data *dd; struct dpll_data *dd;
int ret;
if (!hw || !rate) if (!hw || !rate)
return -EINVAL; return -EINVAL;
...@@ -489,61 +488,121 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -489,61 +488,121 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
if (__clk_get_rate(dd->clk_bypass) == rate && if (__clk_get_rate(dd->clk_bypass) == rate &&
(dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
pr_debug("%s: %s: set rate: entering bypass.\n", *best_parent_clk = dd->clk_bypass;
__func__, __clk_get_name(hw->clk)); } else {
rate = omap2_dpll_round_rate(hw, rate, best_parent_rate);
*best_parent_clk = dd->clk_ref;
}
*best_parent_rate = rate;
return rate;
}
/**
* omap3_noncore_dpll_set_parent - set parent for a DPLL clock
* @hw: pointer to the clock to set parent for
* @index: parent index to select
*
* Sets parent for a DPLL clock. This sets the DPLL into bypass or
* locked mode. Returns 0 with success, negative error value otherwise.
*/
int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
int ret;
__clk_prepare(dd->clk_bypass); if (!hw)
clk_enable(dd->clk_bypass); return -EINVAL;
if (index)
ret = _omap3_noncore_dpll_bypass(clk); ret = _omap3_noncore_dpll_bypass(clk);
if (!ret) else
new_parent = dd->clk_bypass; ret = _omap3_noncore_dpll_lock(clk);
clk_disable(dd->clk_bypass);
__clk_unprepare(dd->clk_bypass);
} else {
__clk_prepare(dd->clk_ref);
clk_enable(dd->clk_ref);
/* XXX this check is probably pointless in the CCF context */
if (dd->last_rounded_rate != rate) {
rrate = __clk_round_rate(hw->clk, rate);
if (rrate != rate) {
pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n",
__func__, __clk_get_name(hw->clk),
rrate, rate);
rate = rrate;
}
}
if (dd->last_rounded_rate == 0) return ret;
return -EINVAL; }
/* Freqsel is available only on OMAP343X devices */ /**
if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) { * omap3_noncore_dpll_set_rate - set rate for a DPLL clock
freqsel = _omap3_dpll_compute_freqsel(clk, * @hw: pointer to the clock to set parent for
dd->last_rounded_n); * @rate: target rate for the clock
WARN_ON(!freqsel); * @parent_rate: rate of the parent clock
} *
* Sets rate for a DPLL clock. First checks if the clock parent is
* reference clock (in bypass mode, the rate of the clock can't be
* changed) and proceeds with the rate change operation. Returns 0
* with success, negative error value otherwise.
*/
int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
struct dpll_data *dd;
u16 freqsel = 0;
int ret;
if (!hw || !rate)
return -EINVAL;
dd = clk->dpll_data;
if (!dd)
return -EINVAL;
pr_debug("%s: %s: set rate: locking rate to %lu.\n", if (__clk_get_parent(hw->clk) != dd->clk_ref)
__func__, __clk_get_name(hw->clk), rate); return -EINVAL;
if (dd->last_rounded_rate == 0)
return -EINVAL;
ret = omap3_noncore_dpll_program(clk, freqsel); /* Freqsel is available only on OMAP343X devices */
if (!ret) if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) {
new_parent = dd->clk_ref; freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
clk_disable(dd->clk_ref); WARN_ON(!freqsel);
__clk_unprepare(dd->clk_ref);
} }
/*
* FIXME - this is all wrong. common code handles reparenting and
* migrating prepare/enable counts. dplls should be a multiplexer
* clock and this should be a set_parent operation so that all of that
* stuff is inherited for free
*/
if (!ret && clk_get_parent(hw->clk) != new_parent) pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__,
__clk_reparent(hw->clk, new_parent); __clk_get_name(hw->clk), rate);
return 0; ret = omap3_noncore_dpll_program(clk, freqsel);
return ret;
}
/**
* omap3_noncore_dpll_set_rate_and_parent - set rate and parent for a DPLL clock
* @hw: pointer to the clock to set rate and parent for
* @rate: target rate for the DPLL
* @parent_rate: clock rate of the DPLL parent
* @index: new parent index for the DPLL, 0 - reference, 1 - bypass
*
* Sets rate and parent for a DPLL clock. If new parent is the bypass
* clock, only selects the parent. Otherwise proceeds with a rate
* change, as this will effectively also change the parent as the
* DPLL is put into locked mode. Returns 0 with success, negative error
* value otherwise.
*/
int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate,
u8 index)
{
int ret;
if (!hw || !rate)
return -EINVAL;
/*
* clk-ref at index[0], in which case we only need to set rate,
* the parent will be changed automatically with the lock sequence.
* With clk-bypass case we only need to change parent.
*/
if (index)
ret = omap3_noncore_dpll_set_parent(hw, index);
else
ret = omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
return ret;
} }
/* DPLL autoidle read/set code */ /* DPLL autoidle read/set code */
......
...@@ -207,3 +207,44 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, ...@@ -207,3 +207,44 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
return dd->last_rounded_rate; return dd->last_rounded_rate;
} }
/**
* omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL
* @hw: pointer to the clock to determine rate for
* @rate: target rate for the DPLL
* @best_parent_rate: pointer for returning best parent rate
* @best_parent_clk: pointer for returning best parent clock
*
* Determines which DPLL mode to use for reaching a desired rate.
* Checks whether the DPLL shall be in bypass or locked mode, and if
* locked, calculates the M,N values for the DPLL via round-rate.
* Returns a positive clock rate with success, negative error value
* in failure.
*/
long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_clk)
{
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
struct dpll_data *dd;
if (!hw || !rate)
return -EINVAL;
dd = clk->dpll_data;
if (!dd)
return -EINVAL;
if (__clk_get_rate(dd->clk_bypass) == rate &&
(dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
*best_parent_clk = dd->clk_bypass;
} else {
rate = omap4_dpll_regm4xen_round_rate(hw, rate,
best_parent_rate);
*best_parent_clk = dd->clk_ref;
}
*best_parent_rate = rate;
return rate;
}
...@@ -45,13 +45,15 @@ ...@@ -45,13 +45,15 @@
#include "sram.h" #include "sram.h"
#include "cm2xxx.h" #include "cm2xxx.h"
#include "cm3xxx.h" #include "cm3xxx.h"
#include "cm33xx.h"
#include "cm44xx.h"
#include "prm.h" #include "prm.h"
#include "cm.h" #include "cm.h"
#include "prcm_mpu44xx.h" #include "prcm_mpu44xx.h"
#include "prminst44xx.h" #include "prminst44xx.h"
#include "cminst44xx.h"
#include "prm2xxx.h" #include "prm2xxx.h"
#include "prm3xxx.h" #include "prm3xxx.h"
#include "prm33xx.h"
#include "prm44xx.h" #include "prm44xx.h"
#include "opp2xxx.h" #include "opp2xxx.h"
...@@ -565,6 +567,8 @@ void __init am33xx_init_early(void) ...@@ -565,6 +567,8 @@ void __init am33xx_init_early(void)
omap2_set_globals_cm(AM33XX_L4_WK_IO_ADDRESS(AM33XX_PRCM_BASE), NULL); omap2_set_globals_cm(AM33XX_L4_WK_IO_ADDRESS(AM33XX_PRCM_BASE), NULL);
omap3xxx_check_revision(); omap3xxx_check_revision();
am33xx_check_features(); am33xx_check_features();
am33xx_prm_init();
am33xx_cm_init();
am33xx_powerdomains_init(); am33xx_powerdomains_init();
am33xx_clockdomains_init(); am33xx_clockdomains_init();
am33xx_hwmod_init(); am33xx_hwmod_init();
...@@ -591,6 +595,8 @@ void __init am43xx_init_early(void) ...@@ -591,6 +595,8 @@ void __init am43xx_init_early(void)
omap_cm_base_init(); omap_cm_base_init();
omap3xxx_check_revision(); omap3xxx_check_revision();
am33xx_check_features(); am33xx_check_features();
omap44xx_prm_init();
omap4_cm_init();
am43xx_powerdomains_init(); am43xx_powerdomains_init();
am43xx_clockdomains_init(); am43xx_clockdomains_init();
am43xx_hwmod_init(); am43xx_hwmod_init();
...@@ -620,6 +626,7 @@ void __init omap4430_init_early(void) ...@@ -620,6 +626,7 @@ void __init omap4430_init_early(void)
omap_cm_base_init(); omap_cm_base_init();
omap4xxx_check_revision(); omap4xxx_check_revision();
omap4xxx_check_features(); omap4xxx_check_features();
omap4_cm_init();
omap4_pm_init_early(); omap4_pm_init_early();
omap44xx_prm_init(); omap44xx_prm_init();
omap44xx_voltagedomains_init(); omap44xx_voltagedomains_init();
...@@ -655,6 +662,7 @@ void __init omap5_init_early(void) ...@@ -655,6 +662,7 @@ void __init omap5_init_early(void)
omap_cm_base_init(); omap_cm_base_init();
omap44xx_prm_init(); omap44xx_prm_init();
omap5xxx_check_revision(); omap5xxx_check_revision();
omap4_cm_init();
omap54xx_voltagedomains_init(); omap54xx_voltagedomains_init();
omap54xx_powerdomains_init(); omap54xx_powerdomains_init();
omap54xx_clockdomains_init(); omap54xx_clockdomains_init();
...@@ -686,6 +694,7 @@ void __init dra7xx_init_early(void) ...@@ -686,6 +694,7 @@ void __init dra7xx_init_early(void)
omap_cm_base_init(); omap_cm_base_init();
omap44xx_prm_init(); omap44xx_prm_init();
dra7xxx_check_revision(); dra7xxx_check_revision();
omap4_cm_init();
dra7xx_powerdomains_init(); dra7xx_powerdomains_init();
dra7xx_clockdomains_init(); dra7xx_clockdomains_init();
dra7xx_hwmod_init(); dra7xx_hwmod_init();
......
...@@ -227,7 +227,7 @@ static void __init save_l2x0_context(void) ...@@ -227,7 +227,7 @@ static void __init save_l2x0_context(void)
int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
{ {
struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
unsigned int save_state = 0; unsigned int save_state = 0, cpu_logic_state = PWRDM_POWER_RET;
unsigned int wakeup_cpu; unsigned int wakeup_cpu;
if (omap_rev() == OMAP4430_REV_ES1_0) if (omap_rev() == OMAP4430_REV_ES1_0)
...@@ -239,6 +239,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) ...@@ -239,6 +239,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
save_state = 0; save_state = 0;
break; break;
case PWRDM_POWER_OFF: case PWRDM_POWER_OFF:
cpu_logic_state = PWRDM_POWER_OFF;
save_state = 1; save_state = 1;
break; break;
case PWRDM_POWER_RET: case PWRDM_POWER_RET:
...@@ -270,6 +271,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) ...@@ -270,6 +271,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
cpu_clear_prev_logic_pwrst(cpu); cpu_clear_prev_logic_pwrst(cpu);
pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
pwrdm_set_logic_retst(pm_info->pwrdm, cpu_logic_state);
set_cpu_wakeup_addr(cpu, virt_to_phys(omap_pm_ops.resume)); set_cpu_wakeup_addr(cpu, virt_to_phys(omap_pm_ops.resume));
omap_pm_ops.scu_prepare(cpu, power_state); omap_pm_ops.scu_prepare(cpu, power_state);
l2x0_pwrst_prepare(cpu, save_state); l2x0_pwrst_prepare(cpu, save_state);
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include "soc.h" #include "soc.h"
#include "common.h" #include "common.h"
#include "prm2xxx.h" #include "prm.h"
/* /*
* reset_virt_prcm_set_ck, reset_sys_ck: pointers to the virt_prcm_set * reset_virt_prcm_set_ck, reset_sys_ck: pointers to the virt_prcm_set
...@@ -40,8 +40,7 @@ void omap2xxx_restart(enum reboot_mode mode, const char *cmd) ...@@ -40,8 +40,7 @@ void omap2xxx_restart(enum reboot_mode mode, const char *cmd)
/* XXX Should save the cmd argument for use after the reboot */ /* XXX Should save the cmd argument for use after the reboot */
omap2xxx_prm_dpll_reset(); /* never returns */ omap_prm_reset_system();
while (1);
} }
/** /**
......
...@@ -14,10 +14,8 @@ ...@@ -14,10 +14,8 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include "iomap.h"
#include "common.h"
#include "control.h" #include "control.h"
#include "prm3xxx.h" #include "prm.h"
/* Global address base setup code */ /* Global address base setup code */
...@@ -32,6 +30,5 @@ ...@@ -32,6 +30,5 @@
void omap3xxx_restart(enum reboot_mode mode, const char *cmd) void omap3xxx_restart(enum reboot_mode mode, const char *cmd)
{ {
omap3_ctrl_write_boot_mode((cmd ? (u8)*cmd : 0)); omap3_ctrl_write_boot_mode((cmd ? (u8)*cmd : 0));
omap3xxx_prm_dpll3_reset(); /* never returns */ omap_prm_reset_system();
while (1);
} }
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include "prminst44xx.h" #include "prm.h"
/** /**
* omap44xx_restart - trigger a software restart of the SoC * omap44xx_restart - trigger a software restart of the SoC
...@@ -22,7 +22,5 @@ ...@@ -22,7 +22,5 @@
void omap44xx_restart(enum reboot_mode mode, const char *cmd) void omap44xx_restart(enum reboot_mode mode, const char *cmd)
{ {
/* XXX Should save 'cmd' into scratchpad for use after reboot */ /* XXX Should save 'cmd' into scratchpad for use after reboot */
omap4_prminst_global_warm_sw_reset(); /* never returns */ omap_prm_reset_system();
while (1)
;
} }
...@@ -153,7 +153,6 @@ ...@@ -153,7 +153,6 @@
#include "powerdomain.h" #include "powerdomain.h"
#include "cm2xxx.h" #include "cm2xxx.h"
#include "cm3xxx.h" #include "cm3xxx.h"
#include "cminst44xx.h"
#include "cm33xx.h" #include "cm33xx.h"
#include "prm.h" #include "prm.h"
#include "prm3xxx.h" #include "prm3xxx.h"
...@@ -979,31 +978,9 @@ static void _omap4_enable_module(struct omap_hwmod *oh) ...@@ -979,31 +978,9 @@ static void _omap4_enable_module(struct omap_hwmod *oh)
pr_debug("omap_hwmod: %s: %s: %d\n", pr_debug("omap_hwmod: %s: %s: %d\n",
oh->name, __func__, oh->prcm.omap4.modulemode); oh->name, __func__, oh->prcm.omap4.modulemode);
omap4_cminst_module_enable(oh->prcm.omap4.modulemode, omap_cm_module_enable(oh->prcm.omap4.modulemode,
oh->clkdm->prcm_partition, oh->clkdm->prcm_partition,
oh->clkdm->cm_inst, oh->clkdm->cm_inst, oh->prcm.omap4.clkctrl_offs);
oh->clkdm->clkdm_offs,
oh->prcm.omap4.clkctrl_offs);
}
/**
* _am33xx_enable_module - enable CLKCTRL modulemode on AM33XX
* @oh: struct omap_hwmod *
*
* Enables the PRCM module mode related to the hwmod @oh.
* No return value.
*/
static void _am33xx_enable_module(struct omap_hwmod *oh)
{
if (!oh->clkdm || !oh->prcm.omap4.modulemode)
return;
pr_debug("omap_hwmod: %s: %s: %d\n",
oh->name, __func__, oh->prcm.omap4.modulemode);
am33xx_cm_module_enable(oh->prcm.omap4.modulemode, oh->clkdm->cm_inst,
oh->clkdm->clkdm_offs,
oh->prcm.omap4.clkctrl_offs);
} }
/** /**
...@@ -1026,35 +1003,9 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh) ...@@ -1026,35 +1003,9 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh)
if (oh->flags & HWMOD_NO_IDLEST) if (oh->flags & HWMOD_NO_IDLEST)
return 0; return 0;
return omap4_cminst_wait_module_idle(oh->clkdm->prcm_partition, return omap_cm_wait_module_idle(oh->clkdm->prcm_partition,
oh->clkdm->cm_inst, oh->clkdm->cm_inst,
oh->clkdm->clkdm_offs, oh->prcm.omap4.clkctrl_offs, 0);
oh->prcm.omap4.clkctrl_offs);
}
/**
* _am33xx_wait_target_disable - wait for a module to be disabled on AM33XX
* @oh: struct omap_hwmod *
*
* Wait for a module @oh to enter slave idle. Returns 0 if the module
* does not have an IDLEST bit or if the module successfully enters
* slave idle; otherwise, pass along the return value of the
* appropriate *_cm*_wait_module_idle() function.
*/
static int _am33xx_wait_target_disable(struct omap_hwmod *oh)
{
if (!oh)
return -EINVAL;
if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
return 0;
if (oh->flags & HWMOD_NO_IDLEST)
return 0;
return am33xx_cm_wait_module_idle(oh->clkdm->cm_inst,
oh->clkdm->clkdm_offs,
oh->prcm.omap4.clkctrl_offs);
} }
/** /**
...@@ -1859,10 +1810,8 @@ static int _omap4_disable_module(struct omap_hwmod *oh) ...@@ -1859,10 +1810,8 @@ static int _omap4_disable_module(struct omap_hwmod *oh)
pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
omap4_cminst_module_disable(oh->clkdm->prcm_partition, omap_cm_module_disable(oh->clkdm->prcm_partition, oh->clkdm->cm_inst,
oh->clkdm->cm_inst, oh->prcm.omap4.clkctrl_offs);
oh->clkdm->clkdm_offs,
oh->prcm.omap4.clkctrl_offs);
v = _omap4_wait_target_disable(oh); v = _omap4_wait_target_disable(oh);
if (v) if (v)
...@@ -1872,36 +1821,6 @@ static int _omap4_disable_module(struct omap_hwmod *oh) ...@@ -1872,36 +1821,6 @@ static int _omap4_disable_module(struct omap_hwmod *oh)
return 0; return 0;
} }
/**
* _am33xx_disable_module - enable CLKCTRL modulemode on AM33XX
* @oh: struct omap_hwmod *
*
* Disable the PRCM module mode related to the hwmod @oh.
* Return EINVAL if the modulemode is not supported and 0 in case of success.
*/
static int _am33xx_disable_module(struct omap_hwmod *oh)
{
int v;
if (!oh->clkdm || !oh->prcm.omap4.modulemode)
return -EINVAL;
pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
if (_are_any_hardreset_lines_asserted(oh))
return 0;
am33xx_cm_module_disable(oh->clkdm->cm_inst, oh->clkdm->clkdm_offs,
oh->prcm.omap4.clkctrl_offs);
v = _am33xx_wait_target_disable(oh);
if (v)
pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
oh->name);
return 0;
}
/** /**
* _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit
* @oh: struct omap_hwmod * * @oh: struct omap_hwmod *
...@@ -2065,10 +1984,7 @@ static void _reconfigure_io_chain(void) ...@@ -2065,10 +1984,7 @@ static void _reconfigure_io_chain(void)
spin_lock_irqsave(&io_chain_lock, flags); spin_lock_irqsave(&io_chain_lock, flags);
if (cpu_is_omap34xx()) omap_prm_reconfigure_io_chain();
omap3xxx_prm_reconfigure_io_chain();
else if (cpu_is_omap44xx())
omap44xx_prm_reconfigure_io_chain();
spin_unlock_irqrestore(&io_chain_lock, flags); spin_unlock_irqrestore(&io_chain_lock, flags);
} }
...@@ -2719,11 +2635,33 @@ static int __init _setup(struct omap_hwmod *oh, void *data) ...@@ -2719,11 +2635,33 @@ static int __init _setup(struct omap_hwmod *oh, void *data)
if (oh->_state != _HWMOD_STATE_INITIALIZED) if (oh->_state != _HWMOD_STATE_INITIALIZED)
return 0; return 0;
if (oh->parent_hwmod) {
int r;
r = _enable(oh->parent_hwmod);
WARN(r, "hwmod: %s: setup: failed to enable parent hwmod %s\n",
oh->name, oh->parent_hwmod->name);
}
_setup_iclk_autoidle(oh); _setup_iclk_autoidle(oh);
if (!_setup_reset(oh)) if (!_setup_reset(oh))
_setup_postsetup(oh); _setup_postsetup(oh);
if (oh->parent_hwmod) {
u8 postsetup_state;
postsetup_state = oh->parent_hwmod->_postsetup_state;
if (postsetup_state == _HWMOD_STATE_IDLE)
_idle(oh->parent_hwmod);
else if (postsetup_state == _HWMOD_STATE_DISABLED)
_shutdown(oh->parent_hwmod);
else if (postsetup_state != _HWMOD_STATE_ENABLED)
WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n",
oh->parent_hwmod->name, postsetup_state);
}
return 0; return 0;
} }
...@@ -2832,12 +2770,10 @@ static int __init _add_link(struct omap_hwmod_ocp_if *oi) ...@@ -2832,12 +2770,10 @@ static int __init _add_link(struct omap_hwmod_ocp_if *oi)
_alloc_links(&ml, &sl); _alloc_links(&ml, &sl);
ml->ocp_if = oi; ml->ocp_if = oi;
INIT_LIST_HEAD(&ml->node);
list_add(&ml->node, &oi->master->master_ports); list_add(&ml->node, &oi->master->master_ports);
oi->master->masters_cnt++; oi->master->masters_cnt++;
sl->ocp_if = oi; sl->ocp_if = oi;
INIT_LIST_HEAD(&sl->node);
list_add(&sl->node, &oi->slave->slave_ports); list_add(&sl->node, &oi->slave->slave_ports);
oi->slave->slaves_cnt++; oi->slave->slaves_cnt++;
...@@ -2927,34 +2863,7 @@ static int __init _alloc_linkspace(struct omap_hwmod_ocp_if **ois) ...@@ -2927,34 +2863,7 @@ static int __init _alloc_linkspace(struct omap_hwmod_ocp_if **ois)
/* Static functions intended only for use in soc_ops field function pointers */ /* Static functions intended only for use in soc_ops field function pointers */
/** /**
* _omap2xxx_wait_target_ready - wait for a module to leave slave idle * _omap2xxx_3xxx_wait_target_ready - wait for a module to leave slave idle
* @oh: struct omap_hwmod *
*
* Wait for a module @oh to leave slave idle. Returns 0 if the module
* does not have an IDLEST bit or if the module successfully leaves
* slave idle; otherwise, pass along the return value of the
* appropriate *_cm*_wait_module_ready() function.
*/
static int _omap2xxx_wait_target_ready(struct omap_hwmod *oh)
{
if (!oh)
return -EINVAL;
if (oh->flags & HWMOD_NO_IDLEST)
return 0;
if (!_find_mpu_rt_port(oh))
return 0;
/* XXX check module SIDLEMODE, hardreset status, enabled clocks */
return omap2xxx_cm_wait_module_ready(oh->prcm.omap2.module_offs,
oh->prcm.omap2.idlest_reg_id,
oh->prcm.omap2.idlest_idle_bit);
}
/**
* _omap3xxx_wait_target_ready - wait for a module to leave slave idle
* @oh: struct omap_hwmod * * @oh: struct omap_hwmod *
* *
* Wait for a module @oh to leave slave idle. Returns 0 if the module * Wait for a module @oh to leave slave idle. Returns 0 if the module
...@@ -2962,7 +2871,7 @@ static int _omap2xxx_wait_target_ready(struct omap_hwmod *oh) ...@@ -2962,7 +2871,7 @@ static int _omap2xxx_wait_target_ready(struct omap_hwmod *oh)
* slave idle; otherwise, pass along the return value of the * slave idle; otherwise, pass along the return value of the
* appropriate *_cm*_wait_module_ready() function. * appropriate *_cm*_wait_module_ready() function.
*/ */
static int _omap3xxx_wait_target_ready(struct omap_hwmod *oh) static int _omap2xxx_3xxx_wait_target_ready(struct omap_hwmod *oh)
{ {
if (!oh) if (!oh)
return -EINVAL; return -EINVAL;
...@@ -2975,9 +2884,9 @@ static int _omap3xxx_wait_target_ready(struct omap_hwmod *oh) ...@@ -2975,9 +2884,9 @@ static int _omap3xxx_wait_target_ready(struct omap_hwmod *oh)
/* XXX check module SIDLEMODE, hardreset status, enabled clocks */ /* XXX check module SIDLEMODE, hardreset status, enabled clocks */
return omap3xxx_cm_wait_module_ready(oh->prcm.omap2.module_offs, return omap_cm_wait_module_ready(0, oh->prcm.omap2.module_offs,
oh->prcm.omap2.idlest_reg_id, oh->prcm.omap2.idlest_reg_id,
oh->prcm.omap2.idlest_idle_bit); oh->prcm.omap2.idlest_idle_bit);
} }
/** /**
...@@ -3002,37 +2911,9 @@ static int _omap4_wait_target_ready(struct omap_hwmod *oh) ...@@ -3002,37 +2911,9 @@ static int _omap4_wait_target_ready(struct omap_hwmod *oh)
/* XXX check module SIDLEMODE, hardreset status */ /* XXX check module SIDLEMODE, hardreset status */
return omap4_cminst_wait_module_ready(oh->clkdm->prcm_partition, return omap_cm_wait_module_ready(oh->clkdm->prcm_partition,
oh->clkdm->cm_inst, oh->clkdm->cm_inst,
oh->clkdm->clkdm_offs, oh->prcm.omap4.clkctrl_offs, 0);
oh->prcm.omap4.clkctrl_offs);
}
/**
* _am33xx_wait_target_ready - wait for a module to leave slave idle
* @oh: struct omap_hwmod *
*
* Wait for a module @oh to leave slave idle. Returns 0 if the module
* does not have an IDLEST bit or if the module successfully leaves
* slave idle; otherwise, pass along the return value of the
* appropriate *_cm*_wait_module_ready() function.
*/
static int _am33xx_wait_target_ready(struct omap_hwmod *oh)
{
if (!oh || !oh->clkdm)
return -EINVAL;
if (oh->flags & HWMOD_NO_IDLEST)
return 0;
if (!_find_mpu_rt_port(oh))
return 0;
/* XXX check module SIDLEMODE, hardreset status */
return am33xx_cm_wait_module_ready(oh->clkdm->cm_inst,
oh->clkdm->clkdm_offs,
oh->prcm.omap4.clkctrl_offs);
} }
/** /**
...@@ -3049,8 +2930,8 @@ static int _am33xx_wait_target_ready(struct omap_hwmod *oh) ...@@ -3049,8 +2930,8 @@ static int _am33xx_wait_target_ready(struct omap_hwmod *oh)
static int _omap2_assert_hardreset(struct omap_hwmod *oh, static int _omap2_assert_hardreset(struct omap_hwmod *oh,
struct omap_hwmod_rst_info *ohri) struct omap_hwmod_rst_info *ohri)
{ {
return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs, return omap_prm_assert_hardreset(ohri->rst_shift, 0,
ohri->rst_shift); oh->prcm.omap2.module_offs, 0);
} }
/** /**
...@@ -3067,9 +2948,8 @@ static int _omap2_assert_hardreset(struct omap_hwmod *oh, ...@@ -3067,9 +2948,8 @@ static int _omap2_assert_hardreset(struct omap_hwmod *oh,
static int _omap2_deassert_hardreset(struct omap_hwmod *oh, static int _omap2_deassert_hardreset(struct omap_hwmod *oh,
struct omap_hwmod_rst_info *ohri) struct omap_hwmod_rst_info *ohri)
{ {
return omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs, return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0,
ohri->rst_shift, oh->prcm.omap2.module_offs, 0, 0);
ohri->st_shift);
} }
/** /**
...@@ -3087,8 +2967,8 @@ static int _omap2_deassert_hardreset(struct omap_hwmod *oh, ...@@ -3087,8 +2967,8 @@ static int _omap2_deassert_hardreset(struct omap_hwmod *oh,
static int _omap2_is_hardreset_asserted(struct omap_hwmod *oh, static int _omap2_is_hardreset_asserted(struct omap_hwmod *oh,
struct omap_hwmod_rst_info *ohri) struct omap_hwmod_rst_info *ohri)
{ {
return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs, return omap_prm_is_hardreset_asserted(ohri->st_shift, 0,
ohri->st_shift); oh->prcm.omap2.module_offs, 0);
} }
/** /**
...@@ -3109,10 +2989,10 @@ static int _omap4_assert_hardreset(struct omap_hwmod *oh, ...@@ -3109,10 +2989,10 @@ static int _omap4_assert_hardreset(struct omap_hwmod *oh,
if (!oh->clkdm) if (!oh->clkdm)
return -EINVAL; return -EINVAL;
return omap4_prminst_assert_hardreset(ohri->rst_shift, return omap_prm_assert_hardreset(ohri->rst_shift,
oh->clkdm->pwrdm.ptr->prcm_partition, oh->clkdm->pwrdm.ptr->prcm_partition,
oh->clkdm->pwrdm.ptr->prcm_offs, oh->clkdm->pwrdm.ptr->prcm_offs,
oh->prcm.omap4.rstctrl_offs); oh->prcm.omap4.rstctrl_offs);
} }
/** /**
...@@ -3136,10 +3016,10 @@ static int _omap4_deassert_hardreset(struct omap_hwmod *oh, ...@@ -3136,10 +3016,10 @@ static int _omap4_deassert_hardreset(struct omap_hwmod *oh,
if (ohri->st_shift) if (ohri->st_shift)
pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n", pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n",
oh->name, ohri->name); oh->name, ohri->name);
return omap4_prminst_deassert_hardreset(ohri->rst_shift, return omap_prm_deassert_hardreset(ohri->rst_shift, 0,
oh->clkdm->pwrdm.ptr->prcm_partition, oh->clkdm->pwrdm.ptr->prcm_partition,
oh->clkdm->pwrdm.ptr->prcm_offs, oh->clkdm->pwrdm.ptr->prcm_offs,
oh->prcm.omap4.rstctrl_offs); oh->prcm.omap4.rstctrl_offs, 0);
} }
/** /**
...@@ -3160,10 +3040,11 @@ static int _omap4_is_hardreset_asserted(struct omap_hwmod *oh, ...@@ -3160,10 +3040,11 @@ static int _omap4_is_hardreset_asserted(struct omap_hwmod *oh,
if (!oh->clkdm) if (!oh->clkdm)
return -EINVAL; return -EINVAL;
return omap4_prminst_is_hardreset_asserted(ohri->rst_shift, return omap_prm_is_hardreset_asserted(ohri->rst_shift,
oh->clkdm->pwrdm.ptr->prcm_partition, oh->clkdm->pwrdm.ptr->
oh->clkdm->pwrdm.ptr->prcm_offs, prcm_partition,
oh->prcm.omap4.rstctrl_offs); oh->clkdm->pwrdm.ptr->prcm_offs,
oh->prcm.omap4.rstctrl_offs);
} }
/** /**
...@@ -3182,9 +3063,9 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh, ...@@ -3182,9 +3063,9 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh,
struct omap_hwmod_rst_info *ohri) struct omap_hwmod_rst_info *ohri)
{ {
return am33xx_prm_assert_hardreset(ohri->rst_shift, return omap_prm_assert_hardreset(ohri->rst_shift, 0,
oh->clkdm->pwrdm.ptr->prcm_offs, oh->clkdm->pwrdm.ptr->prcm_offs,
oh->prcm.omap4.rstctrl_offs); oh->prcm.omap4.rstctrl_offs);
} }
/** /**
...@@ -3202,11 +3083,10 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh, ...@@ -3202,11 +3083,10 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh,
static int _am33xx_deassert_hardreset(struct omap_hwmod *oh, static int _am33xx_deassert_hardreset(struct omap_hwmod *oh,
struct omap_hwmod_rst_info *ohri) struct omap_hwmod_rst_info *ohri)
{ {
return am33xx_prm_deassert_hardreset(ohri->rst_shift, return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0,
ohri->st_shift, oh->clkdm->pwrdm.ptr->prcm_offs,
oh->clkdm->pwrdm.ptr->prcm_offs, oh->prcm.omap4.rstctrl_offs,
oh->prcm.omap4.rstctrl_offs, oh->prcm.omap4.rstst_offs);
oh->prcm.omap4.rstst_offs);
} }
/** /**
...@@ -3224,9 +3104,9 @@ static int _am33xx_deassert_hardreset(struct omap_hwmod *oh, ...@@ -3224,9 +3104,9 @@ static int _am33xx_deassert_hardreset(struct omap_hwmod *oh,
static int _am33xx_is_hardreset_asserted(struct omap_hwmod *oh, static int _am33xx_is_hardreset_asserted(struct omap_hwmod *oh,
struct omap_hwmod_rst_info *ohri) struct omap_hwmod_rst_info *ohri)
{ {
return am33xx_prm_is_hardreset_asserted(ohri->rst_shift, return omap_prm_is_hardreset_asserted(ohri->rst_shift, 0,
oh->clkdm->pwrdm.ptr->prcm_offs, oh->clkdm->pwrdm.ptr->prcm_offs,
oh->prcm.omap4.rstctrl_offs); oh->prcm.omap4.rstctrl_offs);
} }
/* Public functions */ /* Public functions */
...@@ -4234,12 +4114,12 @@ int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx) ...@@ -4234,12 +4114,12 @@ int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx)
void __init omap_hwmod_init(void) void __init omap_hwmod_init(void)
{ {
if (cpu_is_omap24xx()) { if (cpu_is_omap24xx()) {
soc_ops.wait_target_ready = _omap2xxx_wait_target_ready; soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready;
soc_ops.assert_hardreset = _omap2_assert_hardreset; soc_ops.assert_hardreset = _omap2_assert_hardreset;
soc_ops.deassert_hardreset = _omap2_deassert_hardreset; soc_ops.deassert_hardreset = _omap2_deassert_hardreset;
soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted; soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted;
} else if (cpu_is_omap34xx()) { } else if (cpu_is_omap34xx()) {
soc_ops.wait_target_ready = _omap3xxx_wait_target_ready; soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready;
soc_ops.assert_hardreset = _omap2_assert_hardreset; soc_ops.assert_hardreset = _omap2_assert_hardreset;
soc_ops.deassert_hardreset = _omap2_deassert_hardreset; soc_ops.deassert_hardreset = _omap2_deassert_hardreset;
soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted; soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted;
...@@ -4258,14 +4138,14 @@ void __init omap_hwmod_init(void) ...@@ -4258,14 +4138,14 @@ void __init omap_hwmod_init(void)
soc_ops.enable_module = _omap4_enable_module; soc_ops.enable_module = _omap4_enable_module;
soc_ops.disable_module = _omap4_disable_module; soc_ops.disable_module = _omap4_disable_module;
soc_ops.wait_target_ready = _omap4_wait_target_ready; soc_ops.wait_target_ready = _omap4_wait_target_ready;
soc_ops.assert_hardreset = _am33xx_assert_hardreset; soc_ops.assert_hardreset = _omap4_assert_hardreset;
soc_ops.deassert_hardreset = _am33xx_deassert_hardreset; soc_ops.deassert_hardreset = _omap4_deassert_hardreset;
soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted; soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted;
soc_ops.init_clkdm = _init_clkdm; soc_ops.init_clkdm = _init_clkdm;
} else if (soc_is_am33xx()) { } else if (soc_is_am33xx()) {
soc_ops.enable_module = _am33xx_enable_module; soc_ops.enable_module = _omap4_enable_module;
soc_ops.disable_module = _am33xx_disable_module; soc_ops.disable_module = _omap4_disable_module;
soc_ops.wait_target_ready = _am33xx_wait_target_ready; soc_ops.wait_target_ready = _omap4_wait_target_ready;
soc_ops.assert_hardreset = _am33xx_assert_hardreset; soc_ops.assert_hardreset = _am33xx_assert_hardreset;
soc_ops.deassert_hardreset = _am33xx_deassert_hardreset; soc_ops.deassert_hardreset = _am33xx_deassert_hardreset;
soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted; soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted;
......
...@@ -633,6 +633,7 @@ struct omap_hwmod_link { ...@@ -633,6 +633,7 @@ struct omap_hwmod_link {
* @flags: hwmod flags (documented below) * @flags: hwmod flags (documented below)
* @_lock: spinlock serializing operations on this hwmod * @_lock: spinlock serializing operations on this hwmod
* @node: list node for hwmod list (internal use) * @node: list node for hwmod list (internal use)
* @parent_hwmod: (temporary) a pointer to the hierarchical parent of this hwmod
* *
* @main_clk refers to this module's "main clock," which for our * @main_clk refers to this module's "main clock," which for our
* purposes is defined as "the functional clock needed for register * purposes is defined as "the functional clock needed for register
...@@ -643,6 +644,12 @@ struct omap_hwmod_link { ...@@ -643,6 +644,12 @@ struct omap_hwmod_link {
* the omap_hwmod code and should not be set during initialization. * the omap_hwmod code and should not be set during initialization.
* *
* @masters and @slaves are now deprecated. * @masters and @slaves are now deprecated.
*
* @parent_hwmod is temporary; there should be no need for it, as this
* information should already be expressed in the OCP interface
* structures. @parent_hwmod is present as a workaround until we improve
* handling for hwmods with multiple parents (e.g., OMAP4+ DSS with
* multiple register targets across different interconnects).
*/ */
struct omap_hwmod { struct omap_hwmod {
const char *name; const char *name;
...@@ -680,6 +687,7 @@ struct omap_hwmod { ...@@ -680,6 +687,7 @@ struct omap_hwmod {
u8 _int_flags; u8 _int_flags;
u8 _state; u8 _state;
u8 _postsetup_state; u8 _postsetup_state;
struct omap_hwmod *parent_hwmod;
}; };
struct omap_hwmod *omap_hwmod_lookup(const char *name); struct omap_hwmod *omap_hwmod_lookup(const char *name);
......
...@@ -417,6 +417,37 @@ static struct omap_hwmod am43xx_qspi_hwmod = { ...@@ -417,6 +417,37 @@ static struct omap_hwmod am43xx_qspi_hwmod = {
}, },
}; };
/*
* 'adc/tsc' class
* TouchScreen Controller (Analog-To-Digital Converter)
*/
static struct omap_hwmod_class_sysconfig am43xx_adc_tsc_sysc = {
.rev_offs = 0x00,
.sysc_offs = 0x10,
.sysc_flags = SYSC_HAS_SIDLEMODE,
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
SIDLE_SMART_WKUP),
.sysc_fields = &omap_hwmod_sysc_type2,
};
static struct omap_hwmod_class am43xx_adc_tsc_hwmod_class = {
.name = "adc_tsc",
.sysc = &am43xx_adc_tsc_sysc,
};
static struct omap_hwmod am43xx_adc_tsc_hwmod = {
.name = "adc_tsc",
.class = &am43xx_adc_tsc_hwmod_class,
.clkdm_name = "l3s_tsc_clkdm",
.main_clk = "adc_tsc_fck",
.prcm = {
.omap4 = {
.clkctrl_offs = AM43XX_CM_WKUP_ADC_TSC_CLKCTRL_OFFSET,
.modulemode = MODULEMODE_SWCTRL,
},
},
};
/* dss */ /* dss */
static struct omap_hwmod am43xx_dss_core_hwmod = { static struct omap_hwmod am43xx_dss_core_hwmod = {
...@@ -547,6 +578,13 @@ static struct omap_hwmod_ocp_if am43xx_l4_wkup__gpio0 = { ...@@ -547,6 +578,13 @@ static struct omap_hwmod_ocp_if am43xx_l4_wkup__gpio0 = {
.user = OCP_USER_MPU | OCP_USER_SDMA, .user = OCP_USER_MPU | OCP_USER_SDMA,
}; };
static struct omap_hwmod_ocp_if am43xx_l4_wkup__adc_tsc = {
.master = &am33xx_l4_wkup_hwmod,
.slave = &am43xx_adc_tsc_hwmod,
.clk = "dpll_core_m4_div2_ck",
.user = OCP_USER_MPU,
};
static struct omap_hwmod_ocp_if am43xx_l4_hs__cpgmac0 = { static struct omap_hwmod_ocp_if am43xx_l4_hs__cpgmac0 = {
.master = &am43xx_l4_hs_hwmod, .master = &am43xx_l4_hs_hwmod,
.slave = &am33xx_cpgmac0_hwmod, .slave = &am33xx_cpgmac0_hwmod,
...@@ -789,6 +827,7 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = { ...@@ -789,6 +827,7 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = {
&am43xx_l4_wkup__i2c1, &am43xx_l4_wkup__i2c1,
&am43xx_l4_wkup__gpio0, &am43xx_l4_wkup__gpio0,
&am43xx_l4_wkup__wd_timer1, &am43xx_l4_wkup__wd_timer1,
&am43xx_l4_wkup__adc_tsc,
&am43xx_l3_s__qspi, &am43xx_l3_s__qspi,
&am33xx_l4_per__dcan0, &am33xx_l4_per__dcan0,
&am33xx_l4_per__dcan1, &am33xx_l4_per__dcan1,
......
...@@ -589,6 +589,7 @@ static struct omap_hwmod omap44xx_dss_hwmod = { ...@@ -589,6 +589,7 @@ static struct omap_hwmod omap44xx_dss_hwmod = {
.omap4 = { .omap4 = {
.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET, .clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET, .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
.modulemode = MODULEMODE_SWCTRL,
}, },
}, },
.opt_clks = dss_opt_clks, .opt_clks = dss_opt_clks,
...@@ -647,7 +648,8 @@ static struct omap_hwmod omap44xx_dss_dispc_hwmod = { ...@@ -647,7 +648,8 @@ static struct omap_hwmod omap44xx_dss_dispc_hwmod = {
.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET, .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
}, },
}, },
.dev_attr = &omap44xx_dss_dispc_dev_attr .dev_attr = &omap44xx_dss_dispc_dev_attr,
.parent_hwmod = &omap44xx_dss_hwmod,
}; };
/* /*
...@@ -701,6 +703,7 @@ static struct omap_hwmod omap44xx_dss_dsi1_hwmod = { ...@@ -701,6 +703,7 @@ static struct omap_hwmod omap44xx_dss_dsi1_hwmod = {
}, },
.opt_clks = dss_dsi1_opt_clks, .opt_clks = dss_dsi1_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_dsi1_opt_clks), .opt_clks_cnt = ARRAY_SIZE(dss_dsi1_opt_clks),
.parent_hwmod = &omap44xx_dss_hwmod,
}; };
/* dss_dsi2 */ /* dss_dsi2 */
...@@ -733,6 +736,7 @@ static struct omap_hwmod omap44xx_dss_dsi2_hwmod = { ...@@ -733,6 +736,7 @@ static struct omap_hwmod omap44xx_dss_dsi2_hwmod = {
}, },
.opt_clks = dss_dsi2_opt_clks, .opt_clks = dss_dsi2_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_dsi2_opt_clks), .opt_clks_cnt = ARRAY_SIZE(dss_dsi2_opt_clks),
.parent_hwmod = &omap44xx_dss_hwmod,
}; };
/* /*
...@@ -790,6 +794,7 @@ static struct omap_hwmod omap44xx_dss_hdmi_hwmod = { ...@@ -790,6 +794,7 @@ static struct omap_hwmod omap44xx_dss_hdmi_hwmod = {
}, },
.opt_clks = dss_hdmi_opt_clks, .opt_clks = dss_hdmi_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_hdmi_opt_clks), .opt_clks_cnt = ARRAY_SIZE(dss_hdmi_opt_clks),
.parent_hwmod = &omap44xx_dss_hwmod,
}; };
/* /*
...@@ -819,7 +824,7 @@ static struct omap_hwmod_dma_info omap44xx_dss_rfbi_sdma_reqs[] = { ...@@ -819,7 +824,7 @@ static struct omap_hwmod_dma_info omap44xx_dss_rfbi_sdma_reqs[] = {
}; };
static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = { static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
{ .role = "ick", .clk = "dss_fck" }, { .role = "ick", .clk = "l3_div_ck" },
}; };
static struct omap_hwmod omap44xx_dss_rfbi_hwmod = { static struct omap_hwmod omap44xx_dss_rfbi_hwmod = {
...@@ -836,6 +841,7 @@ static struct omap_hwmod omap44xx_dss_rfbi_hwmod = { ...@@ -836,6 +841,7 @@ static struct omap_hwmod omap44xx_dss_rfbi_hwmod = {
}, },
.opt_clks = dss_rfbi_opt_clks, .opt_clks = dss_rfbi_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks), .opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks),
.parent_hwmod = &omap44xx_dss_hwmod,
}; };
/* /*
...@@ -859,6 +865,7 @@ static struct omap_hwmod omap44xx_dss_venc_hwmod = { ...@@ -859,6 +865,7 @@ static struct omap_hwmod omap44xx_dss_venc_hwmod = {
.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET, .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
}, },
}, },
.parent_hwmod = &omap44xx_dss_hwmod,
}; };
/* /*
...@@ -3671,7 +3678,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dma_addrs[] = { ...@@ -3671,7 +3678,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dma_addrs[] = {
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss = {
.master = &omap44xx_l3_main_2_hwmod, .master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_dss_hwmod, .slave = &omap44xx_dss_hwmod,
.clk = "dss_fck", .clk = "l3_div_ck",
.addr = omap44xx_dss_dma_addrs, .addr = omap44xx_dss_dma_addrs,
.user = OCP_USER_SDMA, .user = OCP_USER_SDMA,
}; };
...@@ -3707,7 +3714,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dispc_dma_addrs[] = { ...@@ -3707,7 +3714,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dispc_dma_addrs[] = {
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dispc = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dispc = {
.master = &omap44xx_l3_main_2_hwmod, .master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_dss_dispc_hwmod, .slave = &omap44xx_dss_dispc_hwmod,
.clk = "dss_fck", .clk = "l3_div_ck",
.addr = omap44xx_dss_dispc_dma_addrs, .addr = omap44xx_dss_dispc_dma_addrs,
.user = OCP_USER_SDMA, .user = OCP_USER_SDMA,
}; };
...@@ -3743,7 +3750,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dsi1_dma_addrs[] = { ...@@ -3743,7 +3750,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dsi1_dma_addrs[] = {
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi1 = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi1 = {
.master = &omap44xx_l3_main_2_hwmod, .master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_dss_dsi1_hwmod, .slave = &omap44xx_dss_dsi1_hwmod,
.clk = "dss_fck", .clk = "l3_div_ck",
.addr = omap44xx_dss_dsi1_dma_addrs, .addr = omap44xx_dss_dsi1_dma_addrs,
.user = OCP_USER_SDMA, .user = OCP_USER_SDMA,
}; };
...@@ -3779,7 +3786,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dsi2_dma_addrs[] = { ...@@ -3779,7 +3786,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dsi2_dma_addrs[] = {
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi2 = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi2 = {
.master = &omap44xx_l3_main_2_hwmod, .master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_dss_dsi2_hwmod, .slave = &omap44xx_dss_dsi2_hwmod,
.clk = "dss_fck", .clk = "l3_div_ck",
.addr = omap44xx_dss_dsi2_dma_addrs, .addr = omap44xx_dss_dsi2_dma_addrs,
.user = OCP_USER_SDMA, .user = OCP_USER_SDMA,
}; };
...@@ -3815,7 +3822,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_hdmi_dma_addrs[] = { ...@@ -3815,7 +3822,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_hdmi_dma_addrs[] = {
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_hdmi = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_hdmi = {
.master = &omap44xx_l3_main_2_hwmod, .master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_dss_hdmi_hwmod, .slave = &omap44xx_dss_hdmi_hwmod,
.clk = "dss_fck", .clk = "l3_div_ck",
.addr = omap44xx_dss_hdmi_dma_addrs, .addr = omap44xx_dss_hdmi_dma_addrs,
.user = OCP_USER_SDMA, .user = OCP_USER_SDMA,
}; };
...@@ -3851,7 +3858,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_rfbi_dma_addrs[] = { ...@@ -3851,7 +3858,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_rfbi_dma_addrs[] = {
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_rfbi = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_rfbi = {
.master = &omap44xx_l3_main_2_hwmod, .master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_dss_rfbi_hwmod, .slave = &omap44xx_dss_rfbi_hwmod,
.clk = "dss_fck", .clk = "l3_div_ck",
.addr = omap44xx_dss_rfbi_dma_addrs, .addr = omap44xx_dss_rfbi_dma_addrs,
.user = OCP_USER_SDMA, .user = OCP_USER_SDMA,
}; };
...@@ -3887,7 +3894,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_venc_dma_addrs[] = { ...@@ -3887,7 +3894,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_venc_dma_addrs[] = {
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_venc = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_venc = {
.master = &omap44xx_l3_main_2_hwmod, .master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_dss_venc_hwmod, .slave = &omap44xx_dss_venc_hwmod,
.clk = "dss_fck", .clk = "l3_div_ck",
.addr = omap44xx_dss_venc_dma_addrs, .addr = omap44xx_dss_venc_dma_addrs,
.user = OCP_USER_SDMA, .user = OCP_USER_SDMA,
}; };
......
...@@ -421,6 +421,7 @@ static struct omap_hwmod omap54xx_dss_dispc_hwmod = { ...@@ -421,6 +421,7 @@ static struct omap_hwmod omap54xx_dss_dispc_hwmod = {
.opt_clks = dss_dispc_opt_clks, .opt_clks = dss_dispc_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_dispc_opt_clks), .opt_clks_cnt = ARRAY_SIZE(dss_dispc_opt_clks),
.dev_attr = &dss_dispc_dev_attr, .dev_attr = &dss_dispc_dev_attr,
.parent_hwmod = &omap54xx_dss_hwmod,
}; };
/* /*
...@@ -462,6 +463,7 @@ static struct omap_hwmod omap54xx_dss_dsi1_a_hwmod = { ...@@ -462,6 +463,7 @@ static struct omap_hwmod omap54xx_dss_dsi1_a_hwmod = {
}, },
.opt_clks = dss_dsi1_a_opt_clks, .opt_clks = dss_dsi1_a_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_dsi1_a_opt_clks), .opt_clks_cnt = ARRAY_SIZE(dss_dsi1_a_opt_clks),
.parent_hwmod = &omap54xx_dss_hwmod,
}; };
/* dss_dsi1_c */ /* dss_dsi1_c */
...@@ -482,6 +484,7 @@ static struct omap_hwmod omap54xx_dss_dsi1_c_hwmod = { ...@@ -482,6 +484,7 @@ static struct omap_hwmod omap54xx_dss_dsi1_c_hwmod = {
}, },
.opt_clks = dss_dsi1_c_opt_clks, .opt_clks = dss_dsi1_c_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_dsi1_c_opt_clks), .opt_clks_cnt = ARRAY_SIZE(dss_dsi1_c_opt_clks),
.parent_hwmod = &omap54xx_dss_hwmod,
}; };
/* /*
...@@ -521,6 +524,7 @@ static struct omap_hwmod omap54xx_dss_hdmi_hwmod = { ...@@ -521,6 +524,7 @@ static struct omap_hwmod omap54xx_dss_hdmi_hwmod = {
}, },
.opt_clks = dss_hdmi_opt_clks, .opt_clks = dss_hdmi_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_hdmi_opt_clks), .opt_clks_cnt = ARRAY_SIZE(dss_hdmi_opt_clks),
.parent_hwmod = &omap54xx_dss_hwmod,
}; };
/* /*
...@@ -560,6 +564,7 @@ static struct omap_hwmod omap54xx_dss_rfbi_hwmod = { ...@@ -560,6 +564,7 @@ static struct omap_hwmod omap54xx_dss_rfbi_hwmod = {
}, },
.opt_clks = dss_rfbi_opt_clks, .opt_clks = dss_rfbi_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks), .opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks),
.parent_hwmod = &omap54xx_dss_hwmod,
}; };
/* /*
......
...@@ -2075,6 +2075,70 @@ static struct omap_hwmod dra7xx_uart6_hwmod = { ...@@ -2075,6 +2075,70 @@ static struct omap_hwmod dra7xx_uart6_hwmod = {
}, },
}; };
/* uart7 */
static struct omap_hwmod dra7xx_uart7_hwmod = {
.name = "uart7",
.class = &dra7xx_uart_hwmod_class,
.clkdm_name = "l4per2_clkdm",
.main_clk = "uart7_gfclk_mux",
.flags = HWMOD_SWSUP_SIDLE_ACT,
.prcm = {
.omap4 = {
.clkctrl_offs = DRA7XX_CM_L4PER2_UART7_CLKCTRL_OFFSET,
.context_offs = DRA7XX_RM_L4PER2_UART7_CONTEXT_OFFSET,
.modulemode = MODULEMODE_SWCTRL,
},
},
};
/* uart8 */
static struct omap_hwmod dra7xx_uart8_hwmod = {
.name = "uart8",
.class = &dra7xx_uart_hwmod_class,
.clkdm_name = "l4per2_clkdm",
.main_clk = "uart8_gfclk_mux",
.flags = HWMOD_SWSUP_SIDLE_ACT,
.prcm = {
.omap4 = {
.clkctrl_offs = DRA7XX_CM_L4PER2_UART8_CLKCTRL_OFFSET,
.context_offs = DRA7XX_RM_L4PER2_UART8_CONTEXT_OFFSET,
.modulemode = MODULEMODE_SWCTRL,
},
},
};
/* uart9 */
static struct omap_hwmod dra7xx_uart9_hwmod = {
.name = "uart9",
.class = &dra7xx_uart_hwmod_class,
.clkdm_name = "l4per2_clkdm",
.main_clk = "uart9_gfclk_mux",
.flags = HWMOD_SWSUP_SIDLE_ACT,
.prcm = {
.omap4 = {
.clkctrl_offs = DRA7XX_CM_L4PER2_UART9_CLKCTRL_OFFSET,
.context_offs = DRA7XX_RM_L4PER2_UART9_CONTEXT_OFFSET,
.modulemode = MODULEMODE_SWCTRL,
},
},
};
/* uart10 */
static struct omap_hwmod dra7xx_uart10_hwmod = {
.name = "uart10",
.class = &dra7xx_uart_hwmod_class,
.clkdm_name = "wkupaon_clkdm",
.main_clk = "uart10_gfclk_mux",
.flags = HWMOD_SWSUP_SIDLE_ACT,
.prcm = {
.omap4 = {
.clkctrl_offs = DRA7XX_CM_WKUPAON_UART10_CLKCTRL_OFFSET,
.context_offs = DRA7XX_RM_WKUPAON_UART10_CONTEXT_OFFSET,
.modulemode = MODULEMODE_SWCTRL,
},
},
};
/* /*
* 'usb_otg_ss' class * 'usb_otg_ss' class
* *
...@@ -3095,6 +3159,38 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart6 = { ...@@ -3095,6 +3159,38 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart6 = {
.user = OCP_USER_MPU | OCP_USER_SDMA, .user = OCP_USER_MPU | OCP_USER_SDMA,
}; };
/* l4_per2 -> uart7 */
static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart7 = {
.master = &dra7xx_l4_per2_hwmod,
.slave = &dra7xx_uart7_hwmod,
.clk = "l3_iclk_div",
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
/* l4_per2 -> uart8 */
static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart8 = {
.master = &dra7xx_l4_per2_hwmod,
.slave = &dra7xx_uart8_hwmod,
.clk = "l3_iclk_div",
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
/* l4_per2 -> uart9 */
static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart9 = {
.master = &dra7xx_l4_per2_hwmod,
.slave = &dra7xx_uart9_hwmod,
.clk = "l3_iclk_div",
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
/* l4_wkup -> uart10 */
static struct omap_hwmod_ocp_if dra7xx_l4_wkup__uart10 = {
.master = &dra7xx_l4_wkup_hwmod,
.slave = &dra7xx_uart10_hwmod,
.clk = "wkupaon_iclk_mux",
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
/* l4_per3 -> usb_otg_ss1 */ /* l4_per3 -> usb_otg_ss1 */
static struct omap_hwmod_ocp_if dra7xx_l4_per3__usb_otg_ss1 = { static struct omap_hwmod_ocp_if dra7xx_l4_per3__usb_otg_ss1 = {
.master = &dra7xx_l4_per3_hwmod, .master = &dra7xx_l4_per3_hwmod,
...@@ -3259,6 +3355,10 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = { ...@@ -3259,6 +3355,10 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
&dra7xx_l4_per1__uart4, &dra7xx_l4_per1__uart4,
&dra7xx_l4_per1__uart5, &dra7xx_l4_per1__uart5,
&dra7xx_l4_per1__uart6, &dra7xx_l4_per1__uart6,
&dra7xx_l4_per2__uart7,
&dra7xx_l4_per2__uart8,
&dra7xx_l4_per2__uart9,
&dra7xx_l4_wkup__uart10,
&dra7xx_l4_per3__usb_otg_ss1, &dra7xx_l4_per3__usb_otg_ss1,
&dra7xx_l4_per3__usb_otg_ss2, &dra7xx_l4_per3__usb_otg_ss2,
&dra7xx_l4_per3__usb_otg_ss3, &dra7xx_l4_per3__usb_otg_ss3,
......
...@@ -37,6 +37,16 @@ struct power_state { ...@@ -37,6 +37,16 @@ struct power_state {
struct list_head node; struct list_head node;
}; };
/**
* struct static_dep_map - Static dependency map
* @from: from clockdomain
* @to: to clockdomain
*/
struct static_dep_map {
const char *from;
const char *to;
};
static u32 cpu_suspend_state = PWRDM_POWER_OFF; static u32 cpu_suspend_state = PWRDM_POWER_OFF;
static LIST_HEAD(pwrst_list); static LIST_HEAD(pwrst_list);
...@@ -148,94 +158,61 @@ static void omap_default_idle(void) ...@@ -148,94 +158,61 @@ static void omap_default_idle(void)
omap_do_wfi(); omap_do_wfi();
} }
/** /*
* omap4_init_static_deps - Add OMAP4 static dependencies * The dynamic dependency between MPUSS -> MEMIF and
* * MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as
* Add needed static clockdomain dependencies on OMAP4 devices. * expected. The hardware recommendation is to enable static
* Return: 0 on success or 'err' on failures * dependencies for these to avoid system lock ups or random crashes.
* The L4 wakeup depedency is added to workaround the OCP sync hardware
* BUG with 32K synctimer which lead to incorrect timer value read
* from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which
* are part of L4 wakeup clockdomain.
*/ */
static inline int omap4_init_static_deps(void) static const struct static_dep_map omap4_static_dep_map[] = {
{ {.from = "mpuss_clkdm", .to = "l3_emif_clkdm"},
struct clockdomain *emif_clkdm, *mpuss_clkdm, *l3_1_clkdm; {.from = "mpuss_clkdm", .to = "l3_1_clkdm"},
struct clockdomain *ducati_clkdm, *l3_2_clkdm; {.from = "mpuss_clkdm", .to = "l3_2_clkdm"},
int ret = 0; {.from = "ducati_clkdm", .to = "l3_1_clkdm"},
{.from = "ducati_clkdm", .to = "l3_2_clkdm"},
if (omap_rev() == OMAP4430_REV_ES1_0) { {.from = NULL} /* TERMINATION */
WARN(1, "Power Management not supported on OMAP4430 ES1.0\n"); };
return -ENODEV;
}
pr_err("Power Management for TI OMAP4.\n");
/*
* OMAP4 chip PM currently works only with certain (newer)
* versions of bootloaders. This is due to missing code in the
* kernel to properly reset and initialize some devices.
* http://www.spinics.net/lists/arm-kernel/msg218641.html
*/
pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n");
ret = pwrdm_for_each(pwrdms_setup, NULL);
if (ret) {
pr_err("Failed to setup powerdomains\n");
return ret;
}
/*
* The dynamic dependency between MPUSS -> MEMIF and
* MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as
* expected. The hardware recommendation is to enable static
* dependencies for these to avoid system lock ups or random crashes.
* The L4 wakeup depedency is added to workaround the OCP sync hardware
* BUG with 32K synctimer which lead to incorrect timer value read
* from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which
* are part of L4 wakeup clockdomain.
*/
mpuss_clkdm = clkdm_lookup("mpuss_clkdm");
emif_clkdm = clkdm_lookup("l3_emif_clkdm");
l3_1_clkdm = clkdm_lookup("l3_1_clkdm");
l3_2_clkdm = clkdm_lookup("l3_2_clkdm");
ducati_clkdm = clkdm_lookup("ducati_clkdm");
if ((!mpuss_clkdm) || (!emif_clkdm) || (!l3_1_clkdm) ||
(!l3_2_clkdm) || (!ducati_clkdm))
return -EINVAL;
ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm);
ret |= clkdm_add_wkdep(mpuss_clkdm, l3_1_clkdm);
ret |= clkdm_add_wkdep(mpuss_clkdm, l3_2_clkdm);
ret |= clkdm_add_wkdep(ducati_clkdm, l3_1_clkdm);
ret |= clkdm_add_wkdep(ducati_clkdm, l3_2_clkdm);
if (ret) {
pr_err("Failed to add MPUSS -> L3/EMIF/L4PER, DUCATI -> L3 wakeup dependency\n");
return -EINVAL;
}
return ret; static const struct static_dep_map omap5_dra7_static_dep_map[] = {
} {.from = "mpu_clkdm", .to = "emif_clkdm"},
{.from = NULL} /* TERMINATION */
};
/** /**
* omap5_dra7_init_static_deps - Init static clkdm dependencies on OMAP5 and * omap4plus_init_static_deps() - Initialize a static dependency map
* DRA7 * @map: Mapping of clock domains
*
* The dynamic dependency between MPUSS -> EMIF is broken and has
* not worked as expected. The hardware recommendation is to
* enable static dependencies for these to avoid system
* lock ups or random crashes.
*/ */
static inline int omap5_dra7_init_static_deps(void) static inline int omap4plus_init_static_deps(const struct static_dep_map *map)
{ {
struct clockdomain *mpuss_clkdm, *emif_clkdm;
int ret; int ret;
struct clockdomain *from, *to;
if (!map)
return 0;
mpuss_clkdm = clkdm_lookup("mpu_clkdm"); while (map->from) {
emif_clkdm = clkdm_lookup("emif_clkdm"); from = clkdm_lookup(map->from);
if (!mpuss_clkdm || !emif_clkdm) to = clkdm_lookup(map->to);
return -EINVAL; if (!from || !to) {
pr_err("Failed lookup %s or %s for wakeup dependency\n",
map->from, map->to);
return -EINVAL;
}
ret = clkdm_add_wkdep(from, to);
if (ret) {
pr_err("Failed to add %s -> %s wakeup dependency(%d)\n",
map->from, map->to, ret);
return ret;
}
ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm); map++;
if (ret) };
pr_err("Failed to add MPUSS -> EMIF wakeup dependency\n");
return ret; return 0;
} }
/** /**
...@@ -272,6 +249,15 @@ int __init omap4_pm_init(void) ...@@ -272,6 +249,15 @@ int __init omap4_pm_init(void)
pr_info("Power Management for TI OMAP4+ devices.\n"); pr_info("Power Management for TI OMAP4+ devices.\n");
/*
* OMAP4 chip PM currently works only with certain (newer)
* versions of bootloaders. This is due to missing code in the
* kernel to properly reset and initialize some devices.
* http://www.spinics.net/lists/arm-kernel/msg218641.html
*/
if (cpu_is_omap44xx())
pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n");
ret = pwrdm_for_each(pwrdms_setup, NULL); ret = pwrdm_for_each(pwrdms_setup, NULL);
if (ret) { if (ret) {
pr_err("Failed to setup powerdomains.\n"); pr_err("Failed to setup powerdomains.\n");
...@@ -279,9 +265,9 @@ int __init omap4_pm_init(void) ...@@ -279,9 +265,9 @@ int __init omap4_pm_init(void)
} }
if (cpu_is_omap44xx()) if (cpu_is_omap44xx())
ret = omap4_init_static_deps(); ret = omap4plus_init_static_deps(omap4_static_dep_map);
else if (soc_is_omap54xx() || soc_is_dra7xx()) else if (soc_is_omap54xx() || soc_is_dra7xx())
ret = omap5_dra7_init_static_deps(); ret = omap4plus_init_static_deps(omap5_dra7_static_dep_map);
if (ret) { if (ret) {
pr_err("Failed to initialise static dependencies.\n"); pr_err("Failed to initialise static dependencies.\n");
......
...@@ -29,6 +29,7 @@ int of_prcm_init(void); ...@@ -29,6 +29,7 @@ int of_prcm_init(void);
* PRM_HAS_VOLTAGE: has voltage domains * PRM_HAS_VOLTAGE: has voltage domains
*/ */
#define PRM_HAS_IO_WAKEUP (1 << 0) #define PRM_HAS_IO_WAKEUP (1 << 0)
#define PRM_HAS_VOLTAGE (1 << 1)
/* /*
* MAX_MODULE_SOFTRESET_WAIT: Maximum microseconds to wait for OMAP * MAX_MODULE_SOFTRESET_WAIT: Maximum microseconds to wait for OMAP
...@@ -127,6 +128,8 @@ struct prm_reset_src_map { ...@@ -127,6 +128,8 @@ struct prm_reset_src_map {
* @was_any_context_lost_old: ptr to the SoC PRM context loss test fn * @was_any_context_lost_old: ptr to the SoC PRM context loss test fn
* @clear_context_loss_flags_old: ptr to the SoC PRM context loss flag clear fn * @clear_context_loss_flags_old: ptr to the SoC PRM context loss flag clear fn
* @late_init: ptr to the late init function * @late_init: ptr to the late init function
* @assert_hardreset: ptr to the SoC PRM hardreset assert impl
* @deassert_hardreset: ptr to the SoC PRM hardreset deassert impl
* *
* XXX @was_any_context_lost_old and @clear_context_loss_flags_old are * XXX @was_any_context_lost_old and @clear_context_loss_flags_old are
* deprecated. * deprecated.
...@@ -136,14 +139,27 @@ struct prm_ll_data { ...@@ -136,14 +139,27 @@ struct prm_ll_data {
bool (*was_any_context_lost_old)(u8 part, s16 inst, u16 idx); bool (*was_any_context_lost_old)(u8 part, s16 inst, u16 idx);
void (*clear_context_loss_flags_old)(u8 part, s16 inst, u16 idx); void (*clear_context_loss_flags_old)(u8 part, s16 inst, u16 idx);
int (*late_init)(void); int (*late_init)(void);
int (*assert_hardreset)(u8 shift, u8 part, s16 prm_mod, u16 offset);
int (*deassert_hardreset)(u8 shift, u8 st_shift, u8 part, s16 prm_mod,
u16 offset, u16 st_offset);
int (*is_hardreset_asserted)(u8 shift, u8 part, s16 prm_mod,
u16 offset);
void (*reset_system)(void);
}; };
extern int prm_register(struct prm_ll_data *pld); extern int prm_register(struct prm_ll_data *pld);
extern int prm_unregister(struct prm_ll_data *pld); extern int prm_unregister(struct prm_ll_data *pld);
int omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset);
int omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod,
u16 offset, u16 st_offset);
int omap_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset);
extern u32 prm_read_reset_sources(void); extern u32 prm_read_reset_sources(void);
extern bool prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx); extern bool prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx);
extern void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx); extern void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx);
void omap_prm_reset_system(void);
void omap_prm_reconfigure_io_chain(void);
#endif #endif
......
...@@ -106,7 +106,7 @@ static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst) ...@@ -106,7 +106,7 @@ static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst)
* Set the DPLL reset bit, which should reboot the SoC. This is the * Set the DPLL reset bit, which should reboot the SoC. This is the
* recommended way to restart the SoC. No return value. * recommended way to restart the SoC. No return value.
*/ */
void omap2xxx_prm_dpll_reset(void) static void omap2xxx_prm_dpll_reset(void)
{ {
omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD, omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD,
OMAP2_RM_RSTCTRL); OMAP2_RM_RSTCTRL);
...@@ -212,6 +212,10 @@ struct pwrdm_ops omap2_pwrdm_operations = { ...@@ -212,6 +212,10 @@ struct pwrdm_ops omap2_pwrdm_operations = {
static struct prm_ll_data omap2xxx_prm_ll_data = { static struct prm_ll_data omap2xxx_prm_ll_data = {
.read_reset_sources = &omap2xxx_prm_read_reset_sources, .read_reset_sources = &omap2xxx_prm_read_reset_sources,
.assert_hardreset = &omap2_prm_assert_hardreset,
.deassert_hardreset = &omap2_prm_deassert_hardreset,
.is_hardreset_asserted = &omap2_prm_is_hardreset_asserted,
.reset_system = &omap2xxx_prm_dpll_reset,
}; };
int __init omap2xxx_prm_init(void) int __init omap2xxx_prm_init(void)
......
...@@ -124,7 +124,6 @@ ...@@ -124,7 +124,6 @@
extern int omap2xxx_clkdm_sleep(struct clockdomain *clkdm); extern int omap2xxx_clkdm_sleep(struct clockdomain *clkdm);
extern int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm); extern int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm);
extern void omap2xxx_prm_dpll_reset(void);
void omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask); void omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask);
extern int __init omap2xxx_prm_init(void); extern int __init omap2xxx_prm_init(void);
......
...@@ -24,14 +24,16 @@ ...@@ -24,14 +24,16 @@
/** /**
* omap2_prm_is_hardreset_asserted - read the HW reset line state of * omap2_prm_is_hardreset_asserted - read the HW reset line state of
* submodules contained in the hwmod module * submodules contained in the hwmod module
* @prm_mod: PRM submodule base (e.g. CORE_MOD)
* @shift: register bit shift corresponding to the reset line to check * @shift: register bit shift corresponding to the reset line to check
* @part: PRM partition, ignored for OMAP2
* @prm_mod: PRM submodule base (e.g. CORE_MOD)
* @offset: register offset, ignored for OMAP2
* *
* Returns 1 if the (sub)module hardreset line is currently asserted, * Returns 1 if the (sub)module hardreset line is currently asserted,
* 0 if the (sub)module hardreset line is not currently asserted, or * 0 if the (sub)module hardreset line is not currently asserted, or
* -EINVAL if called while running on a non-OMAP2/3 chip. * -EINVAL if called while running on a non-OMAP2/3 chip.
*/ */
int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) int omap2_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset)
{ {
return omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, return omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL,
(1 << shift)); (1 << shift));
...@@ -39,8 +41,10 @@ int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) ...@@ -39,8 +41,10 @@ int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift)
/** /**
* omap2_prm_assert_hardreset - assert the HW reset line of a submodule * omap2_prm_assert_hardreset - assert the HW reset line of a submodule
* @prm_mod: PRM submodule base (e.g. CORE_MOD)
* @shift: register bit shift corresponding to the reset line to assert * @shift: register bit shift corresponding to the reset line to assert
* @part: PRM partition, ignored for OMAP2
* @prm_mod: PRM submodule base (e.g. CORE_MOD)
* @offset: register offset, ignored for OMAP2
* *
* Some IPs like dsp or iva contain processors that require an HW * Some IPs like dsp or iva contain processors that require an HW
* reset line to be asserted / deasserted in order to fully enable the * reset line to be asserted / deasserted in order to fully enable the
...@@ -49,7 +53,7 @@ int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) ...@@ -49,7 +53,7 @@ int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift)
* place the submodule into reset. Returns 0 upon success or -EINVAL * place the submodule into reset. Returns 0 upon success or -EINVAL
* upon an argument error. * upon an argument error.
*/ */
int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift) int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset)
{ {
u32 mask; u32 mask;
...@@ -64,6 +68,10 @@ int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift) ...@@ -64,6 +68,10 @@ int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift)
* @prm_mod: PRM submodule base (e.g. CORE_MOD) * @prm_mod: PRM submodule base (e.g. CORE_MOD)
* @rst_shift: register bit shift corresponding to the reset line to deassert * @rst_shift: register bit shift corresponding to the reset line to deassert
* @st_shift: register bit shift for the status of the deasserted submodule * @st_shift: register bit shift for the status of the deasserted submodule
* @part: PRM partition, not used for OMAP2
* @prm_mod: PRM submodule base (e.g. CORE_MOD)
* @rst_offset: reset register offset, not used for OMAP2
* @st_offset: reset status register offset, not used for OMAP2
* *
* Some IPs like dsp or iva contain processors that require an HW * Some IPs like dsp or iva contain processors that require an HW
* reset line to be asserted / deasserted in order to fully enable the * reset line to be asserted / deasserted in order to fully enable the
...@@ -74,7 +82,8 @@ int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift) ...@@ -74,7 +82,8 @@ int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift)
* -EINVAL upon an argument error, -EEXIST if the submodule was already out * -EINVAL upon an argument error, -EEXIST if the submodule was already out
* of reset, or -EBUSY if the submodule did not exit reset promptly. * of reset, or -EBUSY if the submodule did not exit reset promptly.
*/ */
int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift) int omap2_prm_deassert_hardreset(u8 rst_shift, u8 st_shift, u8 part,
s16 prm_mod, u16 rst_offset, u16 st_offset)
{ {
u32 rst, st; u32 rst, st;
int c; int c;
......
...@@ -100,9 +100,12 @@ static inline u32 omap2_prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx) ...@@ -100,9 +100,12 @@ static inline u32 omap2_prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx)
} }
/* These omap2_ PRM functions apply to both OMAP2 and 3 */ /* These omap2_ PRM functions apply to both OMAP2 and 3 */
extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift); int omap2_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset);
extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift); int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod,
extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift); u16 offset);
int omap2_prm_deassert_hardreset(u8 rst_shift, u8 st_shift, u8 part,
s16 prm_mod, u16 reset_offset,
u16 st_offset);
extern int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst); extern int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst);
extern int omap2_pwrdm_read_next_pwrst(struct powerdomain *pwrdm); extern int omap2_pwrdm_read_next_pwrst(struct powerdomain *pwrdm);
......
...@@ -23,20 +23,24 @@ ...@@ -23,20 +23,24 @@
#include "prm33xx.h" #include "prm33xx.h"
#include "prm-regbits-33xx.h" #include "prm-regbits-33xx.h"
#define AM33XX_PRM_RSTCTRL_OFFSET 0x0000
#define AM33XX_RST_GLOBAL_WARM_SW_MASK (1 << 0)
/* Read a register in a PRM instance */ /* Read a register in a PRM instance */
u32 am33xx_prm_read_reg(s16 inst, u16 idx) static u32 am33xx_prm_read_reg(s16 inst, u16 idx)
{ {
return readl_relaxed(prm_base + inst + idx); return readl_relaxed(prm_base + inst + idx);
} }
/* Write into a register in a PRM instance */ /* Write into a register in a PRM instance */
void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx) static void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx)
{ {
writel_relaxed(val, prm_base + inst + idx); writel_relaxed(val, prm_base + inst + idx);
} }
/* Read-modify-write a register in PRM. Caller must lock */ /* Read-modify-write a register in PRM. Caller must lock */
u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) static u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
{ {
u32 v; u32 v;
...@@ -52,6 +56,7 @@ u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) ...@@ -52,6 +56,7 @@ u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
* am33xx_prm_is_hardreset_asserted - read the HW reset line state of * am33xx_prm_is_hardreset_asserted - read the HW reset line state of
* submodules contained in the hwmod module * submodules contained in the hwmod module
* @shift: register bit shift corresponding to the reset line to check * @shift: register bit shift corresponding to the reset line to check
* @part: PRM partition, ignored for AM33xx
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @rstctrl_offs: RM_RSTCTRL register address offset for this module * @rstctrl_offs: RM_RSTCTRL register address offset for this module
* *
...@@ -59,7 +64,8 @@ u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) ...@@ -59,7 +64,8 @@ u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
* 0 if the (sub)module hardreset line is not currently asserted, or * 0 if the (sub)module hardreset line is not currently asserted, or
* -EINVAL upon parameter error. * -EINVAL upon parameter error.
*/ */
int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs) static int am33xx_prm_is_hardreset_asserted(u8 shift, u8 part, s16 inst,
u16 rstctrl_offs)
{ {
u32 v; u32 v;
...@@ -73,6 +79,7 @@ int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs) ...@@ -73,6 +79,7 @@ int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs)
/** /**
* am33xx_prm_assert_hardreset - assert the HW reset line of a submodule * am33xx_prm_assert_hardreset - assert the HW reset line of a submodule
* @shift: register bit shift corresponding to the reset line to assert * @shift: register bit shift corresponding to the reset line to assert
* @part: CM partition, ignored for AM33xx
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @rstctrl_reg: RM_RSTCTRL register address for this module * @rstctrl_reg: RM_RSTCTRL register address for this module
* *
...@@ -83,7 +90,8 @@ int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs) ...@@ -83,7 +90,8 @@ int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs)
* place the submodule into reset. Returns 0 upon success or -EINVAL * place the submodule into reset. Returns 0 upon success or -EINVAL
* upon an argument error. * upon an argument error.
*/ */
int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs) static int am33xx_prm_assert_hardreset(u8 shift, u8 part, s16 inst,
u16 rstctrl_offs)
{ {
u32 mask = 1 << shift; u32 mask = 1 << shift;
...@@ -96,6 +104,8 @@ int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs) ...@@ -96,6 +104,8 @@ int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs)
* am33xx_prm_deassert_hardreset - deassert a submodule hardreset line and * am33xx_prm_deassert_hardreset - deassert a submodule hardreset line and
* wait * wait
* @shift: register bit shift corresponding to the reset line to deassert * @shift: register bit shift corresponding to the reset line to deassert
* @st_shift: reset status register bit shift corresponding to the reset line
* @part: PRM partition, not used for AM33xx
* @inst: CM instance register offset (*_INST macro) * @inst: CM instance register offset (*_INST macro)
* @rstctrl_reg: RM_RSTCTRL register address for this module * @rstctrl_reg: RM_RSTCTRL register address for this module
* @rstst_reg: RM_RSTST register address for this module * @rstst_reg: RM_RSTST register address for this module
...@@ -109,14 +119,15 @@ int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs) ...@@ -109,14 +119,15 @@ int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs)
* -EINVAL upon an argument error, -EEXIST if the submodule was already out * -EINVAL upon an argument error, -EEXIST if the submodule was already out
* of reset, or -EBUSY if the submodule did not exit reset promptly. * of reset, or -EBUSY if the submodule did not exit reset promptly.
*/ */
int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst, static int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part,
u16 rstctrl_offs, u16 rstst_offs) s16 inst, u16 rstctrl_offs,
u16 rstst_offs)
{ {
int c; int c;
u32 mask = 1 << st_shift; u32 mask = 1 << st_shift;
/* Check the current status to avoid de-asserting the line twice */ /* Check the current status to avoid de-asserting the line twice */
if (am33xx_prm_is_hardreset_asserted(shift, inst, rstctrl_offs) == 0) if (am33xx_prm_is_hardreset_asserted(shift, 0, inst, rstctrl_offs) == 0)
return -EEXIST; return -EEXIST;
/* Clear the reset status by writing 1 to the status bit */ /* Clear the reset status by writing 1 to the status bit */
...@@ -128,7 +139,7 @@ int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst, ...@@ -128,7 +139,7 @@ int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst,
am33xx_prm_rmw_reg_bits(mask, 0, inst, rstctrl_offs); am33xx_prm_rmw_reg_bits(mask, 0, inst, rstctrl_offs);
/* wait the status to be set */ /* wait the status to be set */
omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, inst, omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, 0, inst,
rstst_offs), rstst_offs),
MAX_MODULE_HARDRESET_WAIT, c); MAX_MODULE_HARDRESET_WAIT, c);
...@@ -325,6 +336,23 @@ static int am33xx_check_vcvp(void) ...@@ -325,6 +336,23 @@ static int am33xx_check_vcvp(void)
return 0; return 0;
} }
/**
* am33xx_prm_global_warm_sw_reset - reboot the device via warm reset
*
* Immediately reboots the device through warm reset.
*/
static void am33xx_prm_global_warm_sw_reset(void)
{
am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK,
AM33XX_RST_GLOBAL_WARM_SW_MASK,
AM33XX_PRM_DEVICE_MOD,
AM33XX_PRM_RSTCTRL_OFFSET);
/* OCP barrier */
(void)am33xx_prm_read_reg(AM33XX_PRM_DEVICE_MOD,
AM33XX_PRM_RSTCTRL_OFFSET);
}
struct pwrdm_ops am33xx_pwrdm_operations = { struct pwrdm_ops am33xx_pwrdm_operations = {
.pwrdm_set_next_pwrst = am33xx_pwrdm_set_next_pwrst, .pwrdm_set_next_pwrst = am33xx_pwrdm_set_next_pwrst,
.pwrdm_read_next_pwrst = am33xx_pwrdm_read_next_pwrst, .pwrdm_read_next_pwrst = am33xx_pwrdm_read_next_pwrst,
...@@ -342,3 +370,21 @@ struct pwrdm_ops am33xx_pwrdm_operations = { ...@@ -342,3 +370,21 @@ struct pwrdm_ops am33xx_pwrdm_operations = {
.pwrdm_wait_transition = am33xx_pwrdm_wait_transition, .pwrdm_wait_transition = am33xx_pwrdm_wait_transition,
.pwrdm_has_voltdm = am33xx_check_vcvp, .pwrdm_has_voltdm = am33xx_check_vcvp,
}; };
static struct prm_ll_data am33xx_prm_ll_data = {
.assert_hardreset = am33xx_prm_assert_hardreset,
.deassert_hardreset = am33xx_prm_deassert_hardreset,
.is_hardreset_asserted = am33xx_prm_is_hardreset_asserted,
.reset_system = am33xx_prm_global_warm_sw_reset,
};
int __init am33xx_prm_init(void)
{
return prm_register(&am33xx_prm_ll_data);
}
static void __exit am33xx_prm_exit(void)
{
prm_unregister(&am33xx_prm_ll_data);
}
__exitcall(am33xx_prm_exit);
...@@ -118,14 +118,7 @@ ...@@ -118,14 +118,7 @@
#define AM33XX_PM_CEFUSE_PWRSTST AM33XX_PRM_REGADDR(AM33XX_PRM_CEFUSE_MOD, 0x0004) #define AM33XX_PM_CEFUSE_PWRSTST AM33XX_PRM_REGADDR(AM33XX_PRM_CEFUSE_MOD, 0x0004)
#ifndef __ASSEMBLER__ #ifndef __ASSEMBLER__
extern u32 am33xx_prm_read_reg(s16 inst, u16 idx); int am33xx_prm_init(void);
extern void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx);
extern u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx);
extern void am33xx_prm_global_warm_sw_reset(void);
extern int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst,
u16 rstctrl_offs);
extern int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs);
extern int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst,
u16 rstctrl_offs, u16 rstst_offs);
#endif /* ASSEMBLER */ #endif /* ASSEMBLER */
#endif #endif
...@@ -30,6 +30,11 @@ ...@@ -30,6 +30,11 @@
#include "cm3xxx.h" #include "cm3xxx.h"
#include "cm-regbits-34xx.h" #include "cm-regbits-34xx.h"
static void omap3xxx_prm_read_pending_irqs(unsigned long *events);
static void omap3xxx_prm_ocp_barrier(void);
static void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask);
static void omap3xxx_prm_restore_irqen(u32 *saved_mask);
static const struct omap_prcm_irq omap3_prcm_irqs[] = { static const struct omap_prcm_irq omap3_prcm_irqs[] = {
OMAP_PRCM_IRQ("wkup", 0, 0), OMAP_PRCM_IRQ("wkup", 0, 0),
OMAP_PRCM_IRQ("io", 9, 1), OMAP_PRCM_IRQ("io", 9, 1),
...@@ -131,7 +136,7 @@ u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset) ...@@ -131,7 +136,7 @@ u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset)
* recommended way to restart the SoC, considering Errata i520. No * recommended way to restart the SoC, considering Errata i520. No
* return value. * return value.
*/ */
void omap3xxx_prm_dpll3_reset(void) static void omap3xxx_prm_dpll3_reset(void)
{ {
omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, OMAP3430_GR_MOD, omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, OMAP3430_GR_MOD,
OMAP2_RM_RSTCTRL); OMAP2_RM_RSTCTRL);
...@@ -147,7 +152,7 @@ void omap3xxx_prm_dpll3_reset(void) ...@@ -147,7 +152,7 @@ void omap3xxx_prm_dpll3_reset(void)
* MPU IRQs, and store the result into the u32 pointed to by @events. * MPU IRQs, and store the result into the u32 pointed to by @events.
* No return value. * No return value.
*/ */
void omap3xxx_prm_read_pending_irqs(unsigned long *events) static void omap3xxx_prm_read_pending_irqs(unsigned long *events)
{ {
u32 mask, st; u32 mask, st;
...@@ -166,7 +171,7 @@ void omap3xxx_prm_read_pending_irqs(unsigned long *events) ...@@ -166,7 +171,7 @@ void omap3xxx_prm_read_pending_irqs(unsigned long *events)
* block, to avoid race conditions after acknowledging or clearing IRQ * block, to avoid race conditions after acknowledging or clearing IRQ
* bits. No return value. * bits. No return value.
*/ */
void omap3xxx_prm_ocp_barrier(void) static void omap3xxx_prm_ocp_barrier(void)
{ {
omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET); omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET);
} }
...@@ -182,7 +187,7 @@ void omap3xxx_prm_ocp_barrier(void) ...@@ -182,7 +187,7 @@ void omap3xxx_prm_ocp_barrier(void)
* returning; otherwise, spurious interrupts might occur. No return * returning; otherwise, spurious interrupts might occur. No return
* value. * value.
*/ */
void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask) static void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask)
{ {
saved_mask[0] = omap2_prm_read_mod_reg(OCP_MOD, saved_mask[0] = omap2_prm_read_mod_reg(OCP_MOD,
OMAP3_PRM_IRQENABLE_MPU_OFFSET); OMAP3_PRM_IRQENABLE_MPU_OFFSET);
...@@ -202,7 +207,7 @@ void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask) ...@@ -202,7 +207,7 @@ void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask)
* barrier should be needed here; any pending PRM interrupts will fire * barrier should be needed here; any pending PRM interrupts will fire
* once the writes reach the PRM. No return value. * once the writes reach the PRM. No return value.
*/ */
void omap3xxx_prm_restore_irqen(u32 *saved_mask) static void omap3xxx_prm_restore_irqen(u32 *saved_mask)
{ {
omap2_prm_write_mod_reg(saved_mask[0], OCP_MOD, omap2_prm_write_mod_reg(saved_mask[0], OCP_MOD,
OMAP3_PRM_IRQENABLE_MPU_OFFSET); OMAP3_PRM_IRQENABLE_MPU_OFFSET);
...@@ -375,7 +380,7 @@ void __init omap3_prm_init_pm(bool has_uart4, bool has_iva) ...@@ -375,7 +380,7 @@ void __init omap3_prm_init_pm(bool has_uart4, bool has_iva)
* The ST_IO_CHAIN bit does not exist in 3430 before es3.1. The only * The ST_IO_CHAIN bit does not exist in 3430 before es3.1. The only
* thing we can do is toggle EN_IO bit for earlier omaps. * thing we can do is toggle EN_IO bit for earlier omaps.
*/ */
void omap3430_pre_es3_1_reconfigure_io_chain(void) static void omap3430_pre_es3_1_reconfigure_io_chain(void)
{ {
omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD,
PM_WKEN); PM_WKEN);
...@@ -393,7 +398,7 @@ void omap3430_pre_es3_1_reconfigure_io_chain(void) ...@@ -393,7 +398,7 @@ void omap3430_pre_es3_1_reconfigure_io_chain(void)
* deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit. No * deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit. No
* return value. These registers are only available in 3430 es3.1 and later. * return value. These registers are only available in 3430 es3.1 and later.
*/ */
void omap3_prm_reconfigure_io_chain(void) static void omap3_prm_reconfigure_io_chain(void)
{ {
int i = 0; int i = 0;
...@@ -415,15 +420,6 @@ void omap3_prm_reconfigure_io_chain(void) ...@@ -415,15 +420,6 @@ void omap3_prm_reconfigure_io_chain(void)
omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST); omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST);
} }
/**
* omap3xxx_prm_reconfigure_io_chain - reconfigure I/O chain
*/
void omap3xxx_prm_reconfigure_io_chain(void)
{
if (omap3_prcm_irq_setup.reconfigure_io_chain)
omap3_prcm_irq_setup.reconfigure_io_chain();
}
/** /**
* omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches * omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches
* *
...@@ -664,6 +660,10 @@ static int omap3xxx_prm_late_init(void); ...@@ -664,6 +660,10 @@ static int omap3xxx_prm_late_init(void);
static struct prm_ll_data omap3xxx_prm_ll_data = { static struct prm_ll_data omap3xxx_prm_ll_data = {
.read_reset_sources = &omap3xxx_prm_read_reset_sources, .read_reset_sources = &omap3xxx_prm_read_reset_sources,
.late_init = &omap3xxx_prm_late_init, .late_init = &omap3xxx_prm_late_init,
.assert_hardreset = &omap2_prm_assert_hardreset,
.deassert_hardreset = &omap2_prm_deassert_hardreset,
.is_hardreset_asserted = &omap2_prm_is_hardreset_asserted,
.reset_system = &omap3xxx_prm_dpll3_reset,
}; };
int __init omap3xxx_prm_init(void) int __init omap3xxx_prm_init(void)
......
...@@ -144,22 +144,6 @@ extern u32 omap3_prm_vcvp_read(u8 offset); ...@@ -144,22 +144,6 @@ extern u32 omap3_prm_vcvp_read(u8 offset);
extern void omap3_prm_vcvp_write(u32 val, u8 offset); extern void omap3_prm_vcvp_write(u32 val, u8 offset);
extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
#ifdef CONFIG_ARCH_OMAP3
void omap3xxx_prm_reconfigure_io_chain(void);
#else
static inline void omap3xxx_prm_reconfigure_io_chain(void)
{
}
#endif
/* PRM interrupt-related functions */
extern void omap3xxx_prm_read_pending_irqs(unsigned long *events);
extern void omap3xxx_prm_ocp_barrier(void);
extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask);
extern void omap3xxx_prm_restore_irqen(u32 *saved_mask);
extern void omap3xxx_prm_dpll3_reset(void);
extern int __init omap3xxx_prm_init(void); extern int __init omap3xxx_prm_init(void);
extern u32 omap3xxx_prm_get_reset_sources(void); extern u32 omap3xxx_prm_get_reset_sources(void);
int omap3xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits); int omap3xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits);
......
...@@ -32,6 +32,12 @@ ...@@ -32,6 +32,12 @@
/* Static data */ /* Static data */
static void omap44xx_prm_read_pending_irqs(unsigned long *events);
static void omap44xx_prm_ocp_barrier(void);
static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask);
static void omap44xx_prm_restore_irqen(u32 *saved_mask);
static void omap44xx_prm_reconfigure_io_chain(void);
static const struct omap_prcm_irq omap4_prcm_irqs[] = { static const struct omap_prcm_irq omap4_prcm_irqs[] = {
OMAP_PRCM_IRQ("io", 9, 1), OMAP_PRCM_IRQ("io", 9, 1),
}; };
...@@ -80,19 +86,19 @@ static struct prm_reset_src_map omap44xx_prm_reset_src_map[] = { ...@@ -80,19 +86,19 @@ static struct prm_reset_src_map omap44xx_prm_reset_src_map[] = {
/* PRM low-level functions */ /* PRM low-level functions */
/* Read a register in a CM/PRM instance in the PRM module */ /* Read a register in a CM/PRM instance in the PRM module */
u32 omap4_prm_read_inst_reg(s16 inst, u16 reg) static u32 omap4_prm_read_inst_reg(s16 inst, u16 reg)
{ {
return readl_relaxed(prm_base + inst + reg); return readl_relaxed(prm_base + inst + reg);
} }
/* Write into a register in a CM/PRM instance in the PRM module */ /* Write into a register in a CM/PRM instance in the PRM module */
void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 reg) static void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 reg)
{ {
writel_relaxed(val, prm_base + inst + reg); writel_relaxed(val, prm_base + inst + reg);
} }
/* Read-modify-write a register in a PRM module. Caller must lock */ /* Read-modify-write a register in a PRM module. Caller must lock */
u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 reg) static u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 reg)
{ {
u32 v; u32 v;
...@@ -207,7 +213,7 @@ static inline u32 _read_pending_irq_reg(u16 irqen_offs, u16 irqst_offs) ...@@ -207,7 +213,7 @@ static inline u32 _read_pending_irq_reg(u16 irqen_offs, u16 irqst_offs)
* MPU IRQs, and store the result into the two u32s pointed to by @events. * MPU IRQs, and store the result into the two u32s pointed to by @events.
* No return value. * No return value.
*/ */
void omap44xx_prm_read_pending_irqs(unsigned long *events) static void omap44xx_prm_read_pending_irqs(unsigned long *events)
{ {
events[0] = _read_pending_irq_reg(OMAP4_PRM_IRQENABLE_MPU_OFFSET, events[0] = _read_pending_irq_reg(OMAP4_PRM_IRQENABLE_MPU_OFFSET,
OMAP4_PRM_IRQSTATUS_MPU_OFFSET); OMAP4_PRM_IRQSTATUS_MPU_OFFSET);
...@@ -224,7 +230,7 @@ void omap44xx_prm_read_pending_irqs(unsigned long *events) ...@@ -224,7 +230,7 @@ void omap44xx_prm_read_pending_irqs(unsigned long *events)
* block, to avoid race conditions after acknowledging or clearing IRQ * block, to avoid race conditions after acknowledging or clearing IRQ
* bits. No return value. * bits. No return value.
*/ */
void omap44xx_prm_ocp_barrier(void) static void omap44xx_prm_ocp_barrier(void)
{ {
omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
OMAP4_REVISION_PRM_OFFSET); OMAP4_REVISION_PRM_OFFSET);
...@@ -241,7 +247,7 @@ void omap44xx_prm_ocp_barrier(void) ...@@ -241,7 +247,7 @@ void omap44xx_prm_ocp_barrier(void)
* interrupts reaches the PRM before returning; otherwise, spurious * interrupts reaches the PRM before returning; otherwise, spurious
* interrupts might occur. No return value. * interrupts might occur. No return value.
*/ */
void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask) static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask)
{ {
saved_mask[0] = saved_mask[0] =
omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
...@@ -270,7 +276,7 @@ void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask) ...@@ -270,7 +276,7 @@ void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask)
* No OCP barrier should be needed here; any pending PRM interrupts will fire * No OCP barrier should be needed here; any pending PRM interrupts will fire
* once the writes reach the PRM. No return value. * once the writes reach the PRM. No return value.
*/ */
void omap44xx_prm_restore_irqen(u32 *saved_mask) static void omap44xx_prm_restore_irqen(u32 *saved_mask)
{ {
omap4_prm_write_inst_reg(saved_mask[0], OMAP4430_PRM_OCP_SOCKET_INST, omap4_prm_write_inst_reg(saved_mask[0], OMAP4430_PRM_OCP_SOCKET_INST,
OMAP4_PRM_IRQENABLE_MPU_OFFSET); OMAP4_PRM_IRQENABLE_MPU_OFFSET);
...@@ -287,7 +293,7 @@ void omap44xx_prm_restore_irqen(u32 *saved_mask) ...@@ -287,7 +293,7 @@ void omap44xx_prm_restore_irqen(u32 *saved_mask)
* deasserting WUCLKIN and waiting for WUCLKOUT to be deasserted. * deasserting WUCLKIN and waiting for WUCLKOUT to be deasserted.
* No return value. XXX Are the final two steps necessary? * No return value. XXX Are the final two steps necessary?
*/ */
void omap44xx_prm_reconfigure_io_chain(void) static void omap44xx_prm_reconfigure_io_chain(void)
{ {
int i = 0; int i = 0;
s32 inst = omap4_prmst_get_prm_dev_inst(); s32 inst = omap4_prmst_get_prm_dev_inst();
...@@ -652,11 +658,10 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm) ...@@ -652,11 +658,10 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm)
static int omap4_check_vcvp(void) static int omap4_check_vcvp(void)
{ {
/* No VC/VP on dra7xx devices */ if (prm_features & PRM_HAS_VOLTAGE)
if (soc_is_dra7xx()) return 1;
return 0;
return 1; return 0;
} }
struct pwrdm_ops omap4_pwrdm_operations = { struct pwrdm_ops omap4_pwrdm_operations = {
...@@ -689,6 +694,10 @@ static struct prm_ll_data omap44xx_prm_ll_data = { ...@@ -689,6 +694,10 @@ static struct prm_ll_data omap44xx_prm_ll_data = {
.was_any_context_lost_old = &omap44xx_prm_was_any_context_lost_old, .was_any_context_lost_old = &omap44xx_prm_was_any_context_lost_old,
.clear_context_loss_flags_old = &omap44xx_prm_clear_context_loss_flags_old, .clear_context_loss_flags_old = &omap44xx_prm_clear_context_loss_flags_old,
.late_init = &omap44xx_prm_late_init, .late_init = &omap44xx_prm_late_init,
.assert_hardreset = omap4_prminst_assert_hardreset,
.deassert_hardreset = omap4_prminst_deassert_hardreset,
.is_hardreset_asserted = omap4_prminst_is_hardreset_asserted,
.reset_system = omap4_prminst_global_warm_sw_reset,
}; };
int __init omap44xx_prm_init(void) int __init omap44xx_prm_init(void)
...@@ -696,6 +705,9 @@ int __init omap44xx_prm_init(void) ...@@ -696,6 +705,9 @@ int __init omap44xx_prm_init(void)
if (cpu_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx()) if (cpu_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx())
prm_features |= PRM_HAS_IO_WAKEUP; prm_features |= PRM_HAS_IO_WAKEUP;
if (!soc_is_dra7xx())
prm_features |= PRM_HAS_VOLTAGE;
return prm_register(&omap44xx_prm_ll_data); return prm_register(&omap44xx_prm_ll_data);
} }
......
...@@ -26,10 +26,6 @@ ...@@ -26,10 +26,6 @@
/* Function prototypes */ /* Function prototypes */
#ifndef __ASSEMBLER__ #ifndef __ASSEMBLER__
extern u32 omap4_prm_read_inst_reg(s16 inst, u16 idx);
extern void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 idx);
extern u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx);
/* OMAP4/OMAP5-specific VP functions */ /* OMAP4/OMAP5-specific VP functions */
u32 omap4_prm_vp_check_txdone(u8 vp_id); u32 omap4_prm_vp_check_txdone(u8 vp_id);
void omap4_prm_vp_clear_txdone(u8 vp_id); void omap4_prm_vp_clear_txdone(u8 vp_id);
...@@ -42,21 +38,6 @@ extern u32 omap4_prm_vcvp_read(u8 offset); ...@@ -42,21 +38,6 @@ extern u32 omap4_prm_vcvp_read(u8 offset);
extern void omap4_prm_vcvp_write(u32 val, u8 offset); extern void omap4_prm_vcvp_write(u32 val, u8 offset);
extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM43XX)
void omap44xx_prm_reconfigure_io_chain(void);
#else
static inline void omap44xx_prm_reconfigure_io_chain(void)
{
}
#endif
/* PRM interrupt-related functions */
extern void omap44xx_prm_read_pending_irqs(unsigned long *events);
extern void omap44xx_prm_ocp_barrier(void);
extern void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask);
extern void omap44xx_prm_restore_irqen(u32 *saved_mask);
extern int __init omap44xx_prm_init(void); extern int __init omap44xx_prm_init(void);
extern u32 omap44xx_prm_get_reset_sources(void); extern u32 omap44xx_prm_get_reset_sources(void);
......
...@@ -422,6 +422,105 @@ void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx) ...@@ -422,6 +422,105 @@ void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx)
__func__); __func__);
} }
/**
* omap_prm_assert_hardreset - assert hardreset for an IP block
* @shift: register bit shift corresponding to the reset line
* @part: PRM partition
* @prm_mod: PRM submodule base or instance offset
* @offset: register offset
*
* Asserts a hardware reset line for an IP block.
*/
int omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset)
{
if (!prm_ll_data->assert_hardreset) {
WARN_ONCE(1, "prm: %s: no mapping function defined\n",
__func__);
return -EINVAL;
}
return prm_ll_data->assert_hardreset(shift, part, prm_mod, offset);
}
/**
* omap_prm_deassert_hardreset - deassert hardreset for an IP block
* @shift: register bit shift corresponding to the reset line
* @st_shift: reset status bit shift corresponding to the reset line
* @part: PRM partition
* @prm_mod: PRM submodule base or instance offset
* @offset: register offset
* @st_offset: status register offset
*
* Deasserts a hardware reset line for an IP block.
*/
int omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod,
u16 offset, u16 st_offset)
{
if (!prm_ll_data->deassert_hardreset) {
WARN_ONCE(1, "prm: %s: no mapping function defined\n",
__func__);
return -EINVAL;
}
return prm_ll_data->deassert_hardreset(shift, st_shift, part, prm_mod,
offset, st_offset);
}
/**
* omap_prm_is_hardreset_asserted - check the hardreset status for an IP block
* @shift: register bit shift corresponding to the reset line
* @part: PRM partition
* @prm_mod: PRM submodule base or instance offset
* @offset: register offset
*
* Checks if a hardware reset line for an IP block is enabled or not.
*/
int omap_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset)
{
if (!prm_ll_data->is_hardreset_asserted) {
WARN_ONCE(1, "prm: %s: no mapping function defined\n",
__func__);
return -EINVAL;
}
return prm_ll_data->is_hardreset_asserted(shift, part, prm_mod, offset);
}
/**
* omap_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain
*
* Clear any previously-latched I/O wakeup events and ensure that the
* I/O wakeup gates are aligned with the current mux settings.
* Calls SoC specific I/O chain reconfigure function if available,
* otherwise does nothing.
*/
void omap_prm_reconfigure_io_chain(void)
{
if (!prcm_irq_setup || !prcm_irq_setup->reconfigure_io_chain)
return;
prcm_irq_setup->reconfigure_io_chain();
}
/**
* omap_prm_reset_system - trigger global SW reset
*
* Triggers SoC specific global warm reset to reboot the device.
*/
void omap_prm_reset_system(void)
{
if (!prm_ll_data->reset_system) {
WARN_ONCE(1, "prm: %s: no mapping function defined\n",
__func__);
return;
}
prm_ll_data->reset_system();
while (1)
cpu_relax();
}
/** /**
* prm_register - register per-SoC low-level data with the PRM * prm_register - register per-SoC low-level data with the PRM
* @pld: low-level per-SoC OMAP PRM data & function pointers to register * @pld: low-level per-SoC OMAP PRM data & function pointers to register
......
...@@ -148,8 +148,12 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, ...@@ -148,8 +148,12 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst,
/** /**
* omap4_prminst_deassert_hardreset - deassert a submodule hardreset line and * omap4_prminst_deassert_hardreset - deassert a submodule hardreset line and
* wait * wait
* @rstctrl_reg: RM_RSTCTRL register address for this module
* @shift: register bit shift corresponding to the reset line to deassert * @shift: register bit shift corresponding to the reset line to deassert
* @st_shift: status bit offset, not used for OMAP4+
* @part: PRM partition
* @inst: PRM instance offset
* @rstctrl_offs: reset register offset
* @st_offs: reset status register offset, not used for OMAP4+
* *
* Some IPs like dsp, ipu or iva contain processors that require an HW * Some IPs like dsp, ipu or iva contain processors that require an HW
* reset line to be asserted / deasserted in order to fully enable the * reset line to be asserted / deasserted in order to fully enable the
...@@ -160,8 +164,8 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, ...@@ -160,8 +164,8 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst,
* -EINVAL upon an argument error, -EEXIST if the submodule was already out * -EINVAL upon an argument error, -EEXIST if the submodule was already out
* of reset, or -EBUSY if the submodule did not exit reset promptly. * of reset, or -EBUSY if the submodule did not exit reset promptly.
*/ */
int omap4_prminst_deassert_hardreset(u8 shift, u8 part, s16 inst, int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 inst,
u16 rstctrl_offs) u16 rstctrl_offs, u16 st_offs)
{ {
int c; int c;
u32 mask = 1 << shift; u32 mask = 1 << shift;
......
...@@ -30,8 +30,9 @@ extern int omap4_prminst_is_hardreset_asserted(u8 shift, u8 part, s16 inst, ...@@ -30,8 +30,9 @@ extern int omap4_prminst_is_hardreset_asserted(u8 shift, u8 part, s16 inst,
u16 rstctrl_offs); u16 rstctrl_offs);
extern int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, extern int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst,
u16 rstctrl_offs); u16 rstctrl_offs);
extern int omap4_prminst_deassert_hardreset(u8 shift, u8 part, s16 inst, int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part,
u16 rstctrl_offs); s16 inst, u16 rstctrl_offs,
u16 rstst_offs);
extern void omap_prm_base_init(void); extern void omap_prm_base_init(void);
......
...@@ -4,6 +4,17 @@ menu "Intel PXA2xx/PXA3xx Implementations" ...@@ -4,6 +4,17 @@ menu "Intel PXA2xx/PXA3xx Implementations"
comment "Intel/Marvell Dev Platforms (sorted by hardware release time)" comment "Intel/Marvell Dev Platforms (sorted by hardware release time)"
config MACH_PXA27X_DT
bool "Support PXA27x platforms from device tree"
select CPU_PXA27x
select POWER_SUPPLY
select PXA27x
select USE_OF
help
Include support for Marvell PXA27x based platforms using
the device tree. Needn't select any other machine while
MACH_PXA27X_DT is enabled.
config MACH_PXA3XX_DT config MACH_PXA3XX_DT
bool "Support PXA3xx platforms from device tree" bool "Support PXA3xx platforms from device tree"
select CPU_PXA300 select CPU_PXA300
......
...@@ -21,6 +21,7 @@ obj-$(CONFIG_CPU_PXA930) += pxa930.o ...@@ -21,6 +21,7 @@ obj-$(CONFIG_CPU_PXA930) += pxa930.o
# Device Tree support # Device Tree support
obj-$(CONFIG_MACH_PXA3XX_DT) += pxa-dt.o obj-$(CONFIG_MACH_PXA3XX_DT) += pxa-dt.o
obj-$(CONFIG_MACH_PXA27X_DT) += pxa-dt.o
# Intel/Marvell Dev Platforms # Intel/Marvell Dev Platforms
obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
......
...@@ -378,7 +378,7 @@ static void __init em_x270_init_nand(void) ...@@ -378,7 +378,7 @@ static void __init em_x270_init_nand(void)
err = gpio_request(GPIO11_NAND_CS, "NAND CS"); err = gpio_request(GPIO11_NAND_CS, "NAND CS");
if (err) { if (err) {
pr_warning("EM-X270: failed to request NAND CS gpio\n"); pr_warn("EM-X270: failed to request NAND CS gpio\n");
return; return;
} }
...@@ -386,7 +386,7 @@ static void __init em_x270_init_nand(void) ...@@ -386,7 +386,7 @@ static void __init em_x270_init_nand(void)
err = gpio_request(nand_rb, "NAND R/B"); err = gpio_request(nand_rb, "NAND R/B");
if (err) { if (err) {
pr_warning("EM-X270: failed to request NAND R/B gpio\n"); pr_warn("EM-X270: failed to request NAND R/B gpio\n");
gpio_free(GPIO11_NAND_CS); gpio_free(GPIO11_NAND_CS);
return; return;
} }
......
...@@ -13,11 +13,11 @@ ...@@ -13,11 +13,11 @@
struct irq_data; struct irq_data;
extern void pxa_timer_init(void);
extern void __init pxa_map_io(void);
extern unsigned int get_clk_frequency_khz(int info); extern unsigned int get_clk_frequency_khz(int info);
extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *,
unsigned int));
extern void __init pxa_map_io(void);
extern void pxa_timer_init(void);
#define SET_BANK(__nr,__start,__size) \ #define SET_BANK(__nr,__start,__size) \
mi->bank[__nr].start = (__start), \ mi->bank[__nr].start = (__start), \
...@@ -25,6 +25,43 @@ extern unsigned int get_clk_frequency_khz(int info); ...@@ -25,6 +25,43 @@ extern unsigned int get_clk_frequency_khz(int info);
#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) #define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
#define pxa25x_handle_irq icip_handle_irq
extern void __init pxa25x_init_irq(void);
extern void __init pxa25x_map_io(void);
extern void __init pxa26x_init_irq(void);
#define pxa27x_handle_irq ichp_handle_irq
extern void __init pxa27x_dt_init_irq(void);
extern unsigned pxa27x_get_clk_frequency_khz(int);
extern void __init pxa27x_init_irq(void);
extern void __init pxa27x_map_io(void);
#define pxa3xx_handle_irq ichp_handle_irq
extern void __init pxa3xx_dt_init_irq(void);
extern void __init pxa3xx_init_irq(void);
extern void __init pxa3xx_map_io(void);
extern struct syscore_ops pxa_irq_syscore_ops;
extern struct syscore_ops pxa2xx_mfp_syscore_ops;
extern struct syscore_ops pxa3xx_mfp_syscore_ops;
void __init pxa_set_ffuart_info(void *info);
void __init pxa_set_btuart_info(void *info);
void __init pxa_set_stuart_info(void *info);
void __init pxa_set_hwuart_info(void *info);
void pxa_restart(enum reboot_mode, const char *);
#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x)
extern void pxa2xx_clear_reset_status(unsigned int);
#else
static inline void pxa2xx_clear_reset_status(unsigned int mask) {}
#endif
/*
* Once fully converted to the clock framework, all these functions should be
* removed, and replaced with a clk_get(NULL, "core").
*/
#ifdef CONFIG_PXA25x #ifdef CONFIG_PXA25x
extern unsigned pxa25x_get_clk_frequency_khz(int); extern unsigned pxa25x_get_clk_frequency_khz(int);
#else #else
...@@ -32,30 +69,12 @@ extern unsigned pxa25x_get_clk_frequency_khz(int); ...@@ -32,30 +69,12 @@ extern unsigned pxa25x_get_clk_frequency_khz(int);
#endif #endif
#ifdef CONFIG_PXA27x #ifdef CONFIG_PXA27x
extern unsigned pxa27x_get_clk_frequency_khz(int);
#else #else
#define pxa27x_get_clk_frequency_khz(x) (0) #define pxa27x_get_clk_frequency_khz(x) (0)
#endif #endif
#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x)
extern void pxa2xx_clear_reset_status(unsigned int);
#else
static inline void pxa2xx_clear_reset_status(unsigned int mask) {}
#endif
#ifdef CONFIG_PXA3xx #ifdef CONFIG_PXA3xx
extern unsigned pxa3xx_get_clk_frequency_khz(int); extern unsigned pxa3xx_get_clk_frequency_khz(int);
#else #else
#define pxa3xx_get_clk_frequency_khz(x) (0) #define pxa3xx_get_clk_frequency_khz(x) (0)
#endif #endif
extern struct syscore_ops pxa_irq_syscore_ops;
extern struct syscore_ops pxa2xx_mfp_syscore_ops;
extern struct syscore_ops pxa3xx_mfp_syscore_ops;
void __init pxa_set_ffuart_info(void *info);
void __init pxa_set_btuart_info(void *info);
void __init pxa_set_stuart_info(void *info);
void __init pxa_set_hwuart_info(void *info);
void pxa_restart(enum reboot_mode, const char *);
...@@ -140,8 +140,7 @@ static void gumstix_setup_bt_clock(void) ...@@ -140,8 +140,7 @@ static void gumstix_setup_bt_clock(void)
int timeout = 500; int timeout = 500;
if (!(OSCC & OSCC_OOK)) if (!(OSCC & OSCC_OOK))
pr_warning("32kHz clock was not on. Bootloader may need to " pr_warn("32kHz clock was not on. Bootloader may need to be updated\n");
"be updated\n");
else else
return; return;
......
...@@ -6,12 +6,4 @@ ...@@ -6,12 +6,4 @@
#include <mach/mfp-pxa25x.h> #include <mach/mfp-pxa25x.h>
#include <mach/irqs.h> #include <mach/irqs.h>
extern void __init pxa25x_map_io(void);
extern void __init pxa25x_init_irq(void);
#ifdef CONFIG_CPU_PXA26x
extern void __init pxa26x_init_irq(void);
#endif
#define pxa25x_handle_irq icip_handle_irq
#endif /* __MACH_PXA25x_H */ #endif /* __MACH_PXA25x_H */
...@@ -19,11 +19,7 @@ ...@@ -19,11 +19,7 @@
#define ARB_CORE_PARK (1<<24) /* Be parked with core when idle */ #define ARB_CORE_PARK (1<<24) /* Be parked with core when idle */
#define ARB_LOCK_FLAG (1<<23) /* Only Locking masters gain access to the bus */ #define ARB_LOCK_FLAG (1<<23) /* Only Locking masters gain access to the bus */
extern void __init pxa27x_map_io(void);
extern void __init pxa27x_init_irq(void);
extern int __init pxa27x_set_pwrmode(unsigned int mode); extern int __init pxa27x_set_pwrmode(unsigned int mode);
extern void pxa27x_cpu_pm_enter(suspend_state_t state); extern void pxa27x_cpu_pm_enter(suspend_state_t state);
#define pxa27x_handle_irq ichp_handle_irq
#endif /* __MACH_PXA27x_H */ #endif /* __MACH_PXA27x_H */
...@@ -5,9 +5,4 @@ ...@@ -5,9 +5,4 @@
#include <mach/pxa3xx-regs.h> #include <mach/pxa3xx-regs.h>
#include <mach/irqs.h> #include <mach/irqs.h>
extern void __init pxa3xx_map_io(void);
extern void __init pxa3xx_init_irq(void);
#define pxa3xx_handle_irq ichp_handle_irq
#endif /* __MACH_PXA3XX_H */ #endif /* __MACH_PXA3XX_H */
...@@ -93,8 +93,8 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c) ...@@ -93,8 +93,8 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c)
break; break;
default: default:
/* warning and fall through, treat as MFP_LPM_DEFAULT */ /* warning and fall through, treat as MFP_LPM_DEFAULT */
pr_warning("%s: GPIO%d: unsupported low power mode\n", pr_warn("%s: GPIO%d: unsupported low power mode\n",
__func__, gpio); __func__, gpio);
break; break;
} }
...@@ -107,14 +107,12 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c) ...@@ -107,14 +107,12 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c)
* configurations of those pins not able to wakeup * configurations of those pins not able to wakeup
*/ */
if ((c & MFP_LPM_CAN_WAKEUP) && !gpio_desc[gpio].can_wakeup) { if ((c & MFP_LPM_CAN_WAKEUP) && !gpio_desc[gpio].can_wakeup) {
pr_warning("%s: GPIO%d unable to wakeup\n", pr_warn("%s: GPIO%d unable to wakeup\n", __func__, gpio);
__func__, gpio);
return -EINVAL; return -EINVAL;
} }
if ((c & MFP_LPM_CAN_WAKEUP) && is_out) { if ((c & MFP_LPM_CAN_WAKEUP) && is_out) {
pr_warning("%s: output GPIO%d unable to wakeup\n", pr_warn("%s: output GPIO%d unable to wakeup\n", __func__, gpio);
__func__, gpio);
return -EINVAL; return -EINVAL;
} }
...@@ -126,7 +124,7 @@ static inline int __mfp_validate(int mfp) ...@@ -126,7 +124,7 @@ static inline int __mfp_validate(int mfp)
int gpio = mfp_to_gpio(mfp); int gpio = mfp_to_gpio(mfp);
if ((mfp > MFP_PIN_GPIO127) || !gpio_desc[gpio].valid) { if ((mfp > MFP_PIN_GPIO127) || !gpio_desc[gpio].valid) {
pr_warning("%s: GPIO%d is invalid pin\n", __func__, gpio); pr_warn("%s: GPIO%d is invalid pin\n", __func__, gpio);
return -1; return -1;
} }
......
...@@ -446,7 +446,7 @@ static void __init poodle_init(void) ...@@ -446,7 +446,7 @@ static void __init poodle_init(void)
ret = platform_add_devices(devices, ARRAY_SIZE(devices)); ret = platform_add_devices(devices, ARRAY_SIZE(devices));
if (ret) if (ret)
pr_warning("poodle: Unable to register LoCoMo device\n"); pr_warn("poodle: Unable to register LoCoMo device\n");
pxa_set_fb_info(&poodle_locomo_device.dev, &poodle_fb_info); pxa_set_fb_info(&poodle_locomo_device.dev, &poodle_fb_info);
pxa_set_udc_info(&udc_info); pxa_set_udc_info(&udc_info);
......
...@@ -15,13 +15,10 @@ ...@@ -15,13 +15,10 @@
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include <mach/irqs.h> #include <mach/irqs.h>
#include <mach/pxa3xx.h>
#include "generic.h" #include "generic.h"
#ifdef CONFIG_PXA3xx #ifdef CONFIG_PXA3xx
extern void __init pxa3xx_dt_init_irq(void);
static const struct of_dev_auxdata pxa3xx_auxdata_lookup[] __initconst = { static const struct of_dev_auxdata pxa3xx_auxdata_lookup[] __initconst = {
OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40100000, "pxa2xx-uart.0", NULL), OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40100000, "pxa2xx-uart.0", NULL),
OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40200000, "pxa2xx-uart.1", NULL), OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40200000, "pxa2xx-uart.1", NULL),
...@@ -61,3 +58,18 @@ DT_MACHINE_START(PXA_DT, "Marvell PXA3xx (Device Tree Support)") ...@@ -61,3 +58,18 @@ DT_MACHINE_START(PXA_DT, "Marvell PXA3xx (Device Tree Support)")
.dt_compat = pxa3xx_dt_board_compat, .dt_compat = pxa3xx_dt_board_compat,
MACHINE_END MACHINE_END
#endif #endif
#ifdef CONFIG_PXA27x
static const char * const pxa27x_dt_board_compat[] __initconst = {
"marvell,pxa270",
NULL,
};
DT_MACHINE_START(PXA27X_DT, "Marvell PXA2xx (Device Tree Support)")
.map_io = pxa27x_map_io,
.init_irq = pxa27x_dt_init_irq,
.handle_irq = pxa27x_handle_irq,
.restart = pxa_restart,
.dt_compat = pxa27x_dt_board_compat,
MACHINE_END
#endif
...@@ -398,6 +398,12 @@ void __init pxa27x_init_irq(void) ...@@ -398,6 +398,12 @@ void __init pxa27x_init_irq(void)
pxa_init_irq(34, pxa27x_set_wake); pxa_init_irq(34, pxa27x_set_wake);
} }
void __init pxa27x_dt_init_irq(void)
{
if (IS_ENABLED(CONFIG_OF))
pxa_dt_irq_init(pxa27x_set_wake);
}
static struct map_desc pxa27x_io_desc[] __initdata = { static struct map_desc pxa27x_io_desc[] __initdata = {
{ /* Mem Ctl */ { /* Mem Ctl */
.virtual = (unsigned long)SMEMC_VIRT, .virtual = (unsigned long)SMEMC_VIRT,
......
...@@ -74,7 +74,7 @@ static int pxa310_ulpi_poll(void) ...@@ -74,7 +74,7 @@ static int pxa310_ulpi_poll(void)
cpu_relax(); cpu_relax();
} }
pr_warning("%s: ULPI access timed out!\n", __func__); pr_warn("%s: ULPI access timed out!\n", __func__);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -84,7 +84,7 @@ static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg) ...@@ -84,7 +84,7 @@ static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg)
int err; int err;
if (pxa310_ulpi_get_phymode() != SYNCH) { if (pxa310_ulpi_get_phymode() != SYNCH) {
pr_warning("%s: PHY is not in SYNCH mode!\n", __func__); pr_warn("%s: PHY is not in SYNCH mode!\n", __func__);
return -EBUSY; return -EBUSY;
} }
...@@ -101,7 +101,7 @@ static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg) ...@@ -101,7 +101,7 @@ static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg)
static int pxa310_ulpi_write(struct usb_phy *otg, u32 val, u32 reg) static int pxa310_ulpi_write(struct usb_phy *otg, u32 val, u32 reg)
{ {
if (pxa310_ulpi_get_phymode() != SYNCH) { if (pxa310_ulpi_get_phymode() != SYNCH) {
pr_warning("%s: PHY is not in SYNCH mode!\n", __func__); pr_warn("%s: PHY is not in SYNCH mode!\n", __func__);
return -EBUSY; return -EBUSY;
} }
......
...@@ -521,7 +521,7 @@ static void __init raumfeld_w1_init(void) ...@@ -521,7 +521,7 @@ static void __init raumfeld_w1_init(void)
"W1 external pullup enable"); "W1 external pullup enable");
if (ret < 0) if (ret < 0)
pr_warning("Unable to request GPIO_W1_PULLUP_ENABLE\n"); pr_warn("Unable to request GPIO_W1_PULLUP_ENABLE\n");
else else
gpio_direction_output(GPIO_W1_PULLUP_ENABLE, 0); gpio_direction_output(GPIO_W1_PULLUP_ENABLE, 0);
...@@ -600,7 +600,7 @@ static void __init raumfeld_lcd_init(void) ...@@ -600,7 +600,7 @@ static void __init raumfeld_lcd_init(void)
ret = gpio_request(GPIO_TFT_VA_EN, "display VA enable"); ret = gpio_request(GPIO_TFT_VA_EN, "display VA enable");
if (ret < 0) if (ret < 0)
pr_warning("Unable to request GPIO_TFT_VA_EN\n"); pr_warn("Unable to request GPIO_TFT_VA_EN\n");
else else
gpio_direction_output(GPIO_TFT_VA_EN, 1); gpio_direction_output(GPIO_TFT_VA_EN, 1);
...@@ -608,7 +608,7 @@ static void __init raumfeld_lcd_init(void) ...@@ -608,7 +608,7 @@ static void __init raumfeld_lcd_init(void)
ret = gpio_request(GPIO_DISPLAY_ENABLE, "display enable"); ret = gpio_request(GPIO_DISPLAY_ENABLE, "display enable");
if (ret < 0) if (ret < 0)
pr_warning("Unable to request GPIO_DISPLAY_ENABLE\n"); pr_warn("Unable to request GPIO_DISPLAY_ENABLE\n");
else else
gpio_direction_output(GPIO_DISPLAY_ENABLE, 1); gpio_direction_output(GPIO_DISPLAY_ENABLE, 1);
...@@ -814,17 +814,17 @@ static void __init raumfeld_power_init(void) ...@@ -814,17 +814,17 @@ static void __init raumfeld_power_init(void)
/* Set PEN2 high to enable maximum charge current */ /* Set PEN2 high to enable maximum charge current */
ret = gpio_request(GPIO_CHRG_PEN2, "CHRG_PEN2"); ret = gpio_request(GPIO_CHRG_PEN2, "CHRG_PEN2");
if (ret < 0) if (ret < 0)
pr_warning("Unable to request GPIO_CHRG_PEN2\n"); pr_warn("Unable to request GPIO_CHRG_PEN2\n");
else else
gpio_direction_output(GPIO_CHRG_PEN2, 1); gpio_direction_output(GPIO_CHRG_PEN2, 1);
ret = gpio_request(GPIO_CHARGE_DC_OK, "CABLE_DC_OK"); ret = gpio_request(GPIO_CHARGE_DC_OK, "CABLE_DC_OK");
if (ret < 0) if (ret < 0)
pr_warning("Unable to request GPIO_CHARGE_DC_OK\n"); pr_warn("Unable to request GPIO_CHARGE_DC_OK\n");
ret = gpio_request(GPIO_CHARGE_USB_SUSP, "CHARGE_USB_SUSP"); ret = gpio_request(GPIO_CHARGE_USB_SUSP, "CHARGE_USB_SUSP");
if (ret < 0) if (ret < 0)
pr_warning("Unable to request GPIO_CHARGE_USB_SUSP\n"); pr_warn("Unable to request GPIO_CHARGE_USB_SUSP\n");
else else
gpio_direction_output(GPIO_CHARGE_USB_SUSP, 0); gpio_direction_output(GPIO_CHARGE_USB_SUSP, 0);
...@@ -976,19 +976,19 @@ static void __init raumfeld_audio_init(void) ...@@ -976,19 +976,19 @@ static void __init raumfeld_audio_init(void)
ret = gpio_request(GPIO_CODEC_RESET, "cs4270 reset"); ret = gpio_request(GPIO_CODEC_RESET, "cs4270 reset");
if (ret < 0) if (ret < 0)
pr_warning("unable to request GPIO_CODEC_RESET\n"); pr_warn("unable to request GPIO_CODEC_RESET\n");
else else
gpio_direction_output(GPIO_CODEC_RESET, 1); gpio_direction_output(GPIO_CODEC_RESET, 1);
ret = gpio_request(GPIO_SPDIF_RESET, "ak4104 s/pdif reset"); ret = gpio_request(GPIO_SPDIF_RESET, "ak4104 s/pdif reset");
if (ret < 0) if (ret < 0)
pr_warning("unable to request GPIO_SPDIF_RESET\n"); pr_warn("unable to request GPIO_SPDIF_RESET\n");
else else
gpio_direction_output(GPIO_SPDIF_RESET, 1); gpio_direction_output(GPIO_SPDIF_RESET, 1);
ret = gpio_request(GPIO_MCLK_RESET, "MCLK reset"); ret = gpio_request(GPIO_MCLK_RESET, "MCLK reset");
if (ret < 0) if (ret < 0)
pr_warning("unable to request GPIO_MCLK_RESET\n"); pr_warn("unable to request GPIO_MCLK_RESET\n");
else else
gpio_direction_output(GPIO_MCLK_RESET, 1); gpio_direction_output(GPIO_MCLK_RESET, 1);
...@@ -1019,20 +1019,20 @@ static void __init raumfeld_common_init(void) ...@@ -1019,20 +1019,20 @@ static void __init raumfeld_common_init(void)
ret = gpio_request(GPIO_W2W_RESET, "Wi2Wi reset"); ret = gpio_request(GPIO_W2W_RESET, "Wi2Wi reset");
if (ret < 0) if (ret < 0)
pr_warning("Unable to request GPIO_W2W_RESET\n"); pr_warn("Unable to request GPIO_W2W_RESET\n");
else else
gpio_direction_output(GPIO_W2W_RESET, 0); gpio_direction_output(GPIO_W2W_RESET, 0);
ret = gpio_request(GPIO_W2W_PDN, "Wi2Wi powerup"); ret = gpio_request(GPIO_W2W_PDN, "Wi2Wi powerup");
if (ret < 0) if (ret < 0)
pr_warning("Unable to request GPIO_W2W_PDN\n"); pr_warn("Unable to request GPIO_W2W_PDN\n");
else else
gpio_direction_output(GPIO_W2W_PDN, 0); gpio_direction_output(GPIO_W2W_PDN, 0);
/* this can be used to switch off the device */ /* this can be used to switch off the device */
ret = gpio_request(GPIO_SHUTDOWN_SUPPLY, "supply shutdown"); ret = gpio_request(GPIO_SHUTDOWN_SUPPLY, "supply shutdown");
if (ret < 0) if (ret < 0)
pr_warning("Unable to request GPIO_SHUTDOWN_SUPPLY\n"); pr_warn("Unable to request GPIO_SHUTDOWN_SUPPLY\n");
else else
gpio_direction_output(GPIO_SHUTDOWN_SUPPLY, 0); gpio_direction_output(GPIO_SHUTDOWN_SUPPLY, 0);
...@@ -1051,7 +1051,7 @@ static void __init raumfeld_controller_init(void) ...@@ -1051,7 +1051,7 @@ static void __init raumfeld_controller_init(void)
ret = gpio_request(GPIO_SHUTDOWN_BATT, "battery shutdown"); ret = gpio_request(GPIO_SHUTDOWN_BATT, "battery shutdown");
if (ret < 0) if (ret < 0)
pr_warning("Unable to request GPIO_SHUTDOWN_BATT\n"); pr_warn("Unable to request GPIO_SHUTDOWN_BATT\n");
else else
gpio_direction_output(GPIO_SHUTDOWN_BATT, 0); gpio_direction_output(GPIO_SHUTDOWN_BATT, 0);
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include <linux/gpio_keys.h> #include <linux/gpio_keys.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/pda_power.h> #include <linux/power/gpio-charger.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h> #include <linux/spi/pxa2xx_spi.h>
#include <linux/input/matrix_keypad.h> #include <linux/input/matrix_keypad.h>
...@@ -361,44 +361,17 @@ static struct pxaficp_platform_data tosa_ficp_platform_data = { ...@@ -361,44 +361,17 @@ static struct pxaficp_platform_data tosa_ficp_platform_data = {
/* /*
* Tosa AC IN * Tosa AC IN
*/ */
static int tosa_power_init(struct device *dev)
{
int ret = gpio_request(TOSA_GPIO_AC_IN, "ac in");
if (ret)
goto err_gpio_req;
ret = gpio_direction_input(TOSA_GPIO_AC_IN);
if (ret)
goto err_gpio_in;
return 0;
err_gpio_in:
gpio_free(TOSA_GPIO_AC_IN);
err_gpio_req:
return ret;
}
static void tosa_power_exit(struct device *dev)
{
gpio_free(TOSA_GPIO_AC_IN);
}
static int tosa_power_ac_online(void)
{
return gpio_get_value(TOSA_GPIO_AC_IN) == 0;
}
static char *tosa_ac_supplied_to[] = { static char *tosa_ac_supplied_to[] = {
"main-battery", "main-battery",
"backup-battery", "backup-battery",
"jacket-battery", "jacket-battery",
}; };
static struct pda_power_pdata tosa_power_data = { static struct gpio_charger_platform_data tosa_power_data = {
.init = tosa_power_init, .name = "charger",
.is_ac_online = tosa_power_ac_online, .type = POWER_SUPPLY_TYPE_MAINS,
.exit = tosa_power_exit, .gpio = TOSA_GPIO_AC_IN,
.gpio_active_low = 1,
.supplied_to = tosa_ac_supplied_to, .supplied_to = tosa_ac_supplied_to,
.num_supplicants = ARRAY_SIZE(tosa_ac_supplied_to), .num_supplicants = ARRAY_SIZE(tosa_ac_supplied_to),
}; };
...@@ -415,7 +388,7 @@ static struct resource tosa_power_resource[] = { ...@@ -415,7 +388,7 @@ static struct resource tosa_power_resource[] = {
}; };
static struct platform_device tosa_power_device = { static struct platform_device tosa_power_device = {
.name = "pda-power", .name = "gpio-charger",
.id = -1, .id = -1,
.dev.platform_data = &tosa_power_data, .dev.platform_data = &tosa_power_data,
.resource = tosa_power_resource, .resource = tosa_power_resource,
......
...@@ -16,7 +16,10 @@ ...@@ -16,7 +16,10 @@
#include <linux/init.h> #include <linux/init.h>
ENTRY(rockchip_secondary_startup) ENTRY(rockchip_secondary_startup)
bl v7_invalidate_l1 mrc p15, 0, r0, c0, c0, 0 @ read main ID register
ldr r1, =0x00000c09 @ Cortex-A9 primary part number
teq r0, r1
beq v7_invalidate_l1
b secondary_startup b secondary_startup
ENDPROC(rockchip_secondary_startup) ENDPROC(rockchip_secondary_startup)
......
...@@ -19,7 +19,11 @@ ...@@ -19,7 +19,11 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/reset.h>
#include <linux/cpu.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/cp15.h> #include <asm/cp15.h>
#include <asm/smp_scu.h> #include <asm/smp_scu.h>
...@@ -37,23 +41,78 @@ static int ncores; ...@@ -37,23 +41,78 @@ static int ncores;
#define PMU_PWRDN_SCU 4 #define PMU_PWRDN_SCU 4
static void __iomem *pmu_base_addr; static struct regmap *pmu;
static inline bool pmu_power_domain_is_on(int pd) static int pmu_power_domain_is_on(int pd)
{ {
return !(readl_relaxed(pmu_base_addr + PMU_PWRDN_ST) & BIT(pd)); u32 val;
int ret;
ret = regmap_read(pmu, PMU_PWRDN_ST, &val);
if (ret < 0)
return ret;
return !(val & BIT(pd));
} }
static void pmu_set_power_domain(int pd, bool on) struct reset_control *rockchip_get_core_reset(int cpu)
{ {
u32 val = readl_relaxed(pmu_base_addr + PMU_PWRDN_CON); struct device *dev = get_cpu_device(cpu);
if (on) struct device_node *np;
val &= ~BIT(pd);
/* The cpu device is only available after the initial core bringup */
if (dev)
np = dev->of_node;
else else
val |= BIT(pd); np = of_get_cpu_node(cpu, 0);
writel(val, pmu_base_addr + PMU_PWRDN_CON);
while (pmu_power_domain_is_on(pd) != on) { } return of_reset_control_get(np, NULL);
}
static int pmu_set_power_domain(int pd, bool on)
{
u32 val = (on) ? 0 : BIT(pd);
int ret;
/*
* We need to soft reset the cpu when we turn off the cpu power domain,
* or else the active processors might be stalled when the individual
* processor is powered down.
*/
if (read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) {
struct reset_control *rstc = rockchip_get_core_reset(pd);
if (IS_ERR(rstc)) {
pr_err("%s: could not get reset control for core %d\n",
__func__, pd);
return PTR_ERR(rstc);
}
if (on)
reset_control_deassert(rstc);
else
reset_control_assert(rstc);
reset_control_put(rstc);
}
ret = regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), val);
if (ret < 0) {
pr_err("%s: could not update power domain\n", __func__);
return ret;
}
ret = -1;
while (ret != on) {
ret = pmu_power_domain_is_on(pd);
if (ret < 0) {
pr_err("%s: could not read power domain state\n",
__func__);
return ret;
}
}
return 0;
} }
/* /*
...@@ -63,7 +122,9 @@ static void pmu_set_power_domain(int pd, bool on) ...@@ -63,7 +122,9 @@ static void pmu_set_power_domain(int pd, bool on)
static int __cpuinit rockchip_boot_secondary(unsigned int cpu, static int __cpuinit rockchip_boot_secondary(unsigned int cpu,
struct task_struct *idle) struct task_struct *idle)
{ {
if (!sram_base_addr || !pmu_base_addr) { int ret;
if (!sram_base_addr || !pmu) {
pr_err("%s: sram or pmu missing for cpu boot\n", __func__); pr_err("%s: sram or pmu missing for cpu boot\n", __func__);
return -ENXIO; return -ENXIO;
} }
...@@ -75,7 +136,24 @@ static int __cpuinit rockchip_boot_secondary(unsigned int cpu, ...@@ -75,7 +136,24 @@ static int __cpuinit rockchip_boot_secondary(unsigned int cpu,
} }
/* start the core */ /* start the core */
pmu_set_power_domain(0 + cpu, true); ret = pmu_set_power_domain(0 + cpu, true);
if (ret < 0)
return ret;
if (read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) {
/* We communicate with the bootrom to active the cpus other
* than cpu0, after a blob of initialize code, they will
* stay at wfe state, once they are actived, they will check
* the mailbox:
* sram_base_addr + 4: 0xdeadbeaf
* sram_base_addr + 8: start address for pc
* */
udelay(10);
writel(virt_to_phys(rockchip_secondary_startup),
sram_base_addr + 8);
writel(0xDEADBEAF, sram_base_addr + 4);
dsb_sev();
}
return 0; return 0;
} }
...@@ -110,8 +188,6 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node) ...@@ -110,8 +188,6 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node)
return -EINVAL; return -EINVAL;
} }
sram_base_addr = of_iomap(node, 0);
/* set the boot function for the sram code */ /* set the boot function for the sram code */
rockchip_boot_fn = virt_to_phys(rockchip_secondary_startup); rockchip_boot_fn = virt_to_phys(rockchip_secondary_startup);
...@@ -125,54 +201,115 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node) ...@@ -125,54 +201,115 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node)
return 0; return 0;
} }
static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) static struct regmap_config rockchip_pmu_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
};
static int __init rockchip_smp_prepare_pmu(void)
{ {
struct device_node *node; struct device_node *node;
unsigned int i; void __iomem *pmu_base;
node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); /*
* This function is only called via smp_ops->smp_prepare_cpu().
* That only happens if a "/cpus" device tree node exists
* and has an "enable-method" property that selects the SMP
* operations defined herein.
*/
node = of_find_node_by_path("/cpus");
pmu = syscon_regmap_lookup_by_phandle(node, "rockchip,pmu");
of_node_put(node);
if (!IS_ERR(pmu))
return 0;
pmu = syscon_regmap_lookup_by_compatible("rockchip,rk3066-pmu");
if (!IS_ERR(pmu))
return 0;
/* fallback, create our own regmap for the pmu area */
pmu = NULL;
node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-pmu");
if (!node) { if (!node) {
pr_err("%s: missing scu\n", __func__); pr_err("%s: could not find pmu dt node\n", __func__);
return; return -ENODEV;
} }
scu_base_addr = of_iomap(node, 0); pmu_base = of_iomap(node, 0);
if (!scu_base_addr) { if (!pmu_base) {
pr_err("%s: could not map scu registers\n", __func__); pr_err("%s: could not map pmu registers\n", __func__);
return; return -ENOMEM;
} }
node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-smp-sram"); pmu = regmap_init_mmio(NULL, pmu_base, &rockchip_pmu_regmap_config);
if (!node) { if (IS_ERR(pmu)) {
pr_err("%s: could not find sram dt node\n", __func__); int ret = PTR_ERR(pmu);
return;
iounmap(pmu_base);
pmu = NULL;
pr_err("%s: regmap init failed\n", __func__);
return ret;
} }
if (rockchip_smp_prepare_sram(node)) return 0;
return; }
node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-pmu"); static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)
{
struct device_node *node;
unsigned int i;
node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-smp-sram");
if (!node) { if (!node) {
pr_err("%s: could not find pmu dt node\n", __func__); pr_err("%s: could not find sram dt node\n", __func__);
return; return;
} }
pmu_base_addr = of_iomap(node, 0); sram_base_addr = of_iomap(node, 0);
if (!pmu_base_addr) { if (!sram_base_addr) {
pr_err("%s: could not map pmu registers\n", __func__); pr_err("%s: could not map sram registers\n", __func__);
return; return;
} }
/* enable the SCU power domain */ if (rockchip_smp_prepare_pmu())
pmu_set_power_domain(PMU_PWRDN_SCU, true); return;
/*
* While the number of cpus is gathered from dt, also get the number
* of cores from the scu to verify this value when booting the cores.
*/
ncores = scu_get_core_count(scu_base_addr);
scu_enable(scu_base_addr); if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
if (rockchip_smp_prepare_sram(node))
return;
/* enable the SCU power domain */
pmu_set_power_domain(PMU_PWRDN_SCU, true);
node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
if (!node) {
pr_err("%s: missing scu\n", __func__);
return;
}
scu_base_addr = of_iomap(node, 0);
if (!scu_base_addr) {
pr_err("%s: could not map scu registers\n", __func__);
return;
}
/*
* While the number of cpus is gathered from dt, also get the
* number of cores from the scu to verify this value when
* booting the cores.
*/
ncores = scu_get_core_count(scu_base_addr);
pr_err("%s: ncores %d\n", __func__, ncores);
scu_enable(scu_base_addr);
} else {
unsigned int l2ctlr;
asm ("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr));
ncores = ((l2ctlr >> 24) & 0x3) + 1;
}
/* Make sure that all cores except the first are really off */ /* Make sure that all cores except the first are really off */
for (i = 1; i < ncores; i++) for (i = 1; i < ncores; i++)
......
...@@ -24,6 +24,12 @@ ...@@ -24,6 +24,12 @@
#include <asm/hardware/cache-l2x0.h> #include <asm/hardware/cache-l2x0.h>
#include "core.h" #include "core.h"
static void __init rockchip_dt_init(void)
{
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
platform_device_register_simple("cpufreq-dt", 0, NULL, 0);
}
static const char * const rockchip_board_dt_compat[] = { static const char * const rockchip_board_dt_compat[] = {
"rockchip,rk2928", "rockchip,rk2928",
"rockchip,rk3066a", "rockchip,rk3066a",
...@@ -37,4 +43,5 @@ DT_MACHINE_START(ROCKCHIP_DT, "Rockchip Cortex-A9 (Device Tree)") ...@@ -37,4 +43,5 @@ DT_MACHINE_START(ROCKCHIP_DT, "Rockchip Cortex-A9 (Device Tree)")
.l2c_aux_val = 0, .l2c_aux_val = 0,
.l2c_aux_mask = ~0, .l2c_aux_mask = ~0,
.dt_compat = rockchip_board_dt_compat, .dt_compat = rockchip_board_dt_compat,
.init_machine = rockchip_dt_init,
MACHINE_END MACHINE_END
config ARCH_SHMOBILE config ARCH_SHMOBILE
bool bool
select ZONE_DMA if ARM_LPAE
config PM_RCAR config PM_RCAR
bool bool
...@@ -18,6 +19,7 @@ config ARCH_RCAR_GEN2 ...@@ -18,6 +19,7 @@ config ARCH_RCAR_GEN2
select PM_RCAR if PM || SMP select PM_RCAR if PM || SMP
select RENESAS_IRQC select RENESAS_IRQC
select SYS_SUPPORTS_SH_CMT select SYS_SUPPORTS_SH_CMT
select PCI_DOMAINS if PCI
config ARCH_RMOBILE config ARCH_RMOBILE
bool bool
......
...@@ -35,6 +35,7 @@ cpu-y := platsmp.o headsmp.o ...@@ -35,6 +35,7 @@ cpu-y := platsmp.o headsmp.o
# Shared SoC family objects # Shared SoC family objects
obj-$(CONFIG_ARCH_RCAR_GEN2) += setup-rcar-gen2.o platsmp-apmu.o $(cpu-y) obj-$(CONFIG_ARCH_RCAR_GEN2) += setup-rcar-gen2.o platsmp-apmu.o $(cpu-y)
CFLAGS_setup-rcar-gen2.o += -march=armv7-a
# SMP objects # SMP objects
smp-y := $(cpu-y) smp-y := $(cpu-y)
......
...@@ -1229,8 +1229,15 @@ static void __init eva_init(void) ...@@ -1229,8 +1229,15 @@ static void __init eva_init(void)
static struct pm_domain_device domain_devices[] __initdata = { static struct pm_domain_device domain_devices[] __initdata = {
{ "A4LC", &lcdc0_device }, { "A4LC", &lcdc0_device },
{ "A4LC", &hdmi_lcdc_device }, { "A4LC", &hdmi_lcdc_device },
{ "A4MP", &hdmi_device },
{ "A4MP", &fsi_device },
{ "A4R", &ceu0_device },
{ "A4S", &sh_eth_device },
{ "A3SP", &pwm_device },
{ "A3SP", &sdhi0_device },
{ "A3SP", &sh_mmcif_device },
}; };
struct platform_device *usb = NULL; struct platform_device *usb = NULL, *sdhi1 = NULL;
regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers, regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers,
ARRAY_SIZE(fixed3v3_power_consumers), 3300000); ARRAY_SIZE(fixed3v3_power_consumers), 3300000);
...@@ -1299,6 +1306,7 @@ static void __init eva_init(void) ...@@ -1299,6 +1306,7 @@ static void __init eva_init(void)
platform_device_register(&vcc_sdhi1); platform_device_register(&vcc_sdhi1);
platform_device_register(&sdhi1_device); platform_device_register(&sdhi1_device);
sdhi1 = &sdhi1_device;
} }
...@@ -1319,6 +1327,8 @@ static void __init eva_init(void) ...@@ -1319,6 +1327,8 @@ static void __init eva_init(void)
ARRAY_SIZE(domain_devices)); ARRAY_SIZE(domain_devices));
if (usb) if (usb)
rmobile_add_device_to_domain("A3SP", usb); rmobile_add_device_to_domain("A3SP", usb);
if (sdhi1)
rmobile_add_device_to_domain("A3SP", sdhi1);
r8a7740_pm_init(); r8a7740_pm_init();
} }
......
...@@ -39,6 +39,13 @@ static void __init kzm_init(void) ...@@ -39,6 +39,13 @@ static void __init kzm_init(void)
#endif #endif
} }
#define RESCNT2 IOMEM(0xe6188020)
static void kzm9g_restart(enum reboot_mode mode, const char *cmd)
{
/* Do soft power on reset */
writel((1 << 31), RESCNT2);
}
static const char *kzm9g_boards_compat_dt[] __initdata = { static const char *kzm9g_boards_compat_dt[] __initdata = {
"renesas,kzm9g-reference", "renesas,kzm9g-reference",
NULL, NULL,
...@@ -50,5 +57,6 @@ DT_MACHINE_START(KZM9G_DT, "kzm9g-reference") ...@@ -50,5 +57,6 @@ DT_MACHINE_START(KZM9G_DT, "kzm9g-reference")
.init_early = shmobile_init_delay, .init_early = shmobile_init_delay,
.init_machine = kzm_init, .init_machine = kzm_init,
.init_late = shmobile_init_late, .init_late = shmobile_init_late,
.restart = kzm9g_restart,
.dt_compat = kzm9g_boards_compat_dt, .dt_compat = kzm9g_boards_compat_dt,
MACHINE_END MACHINE_END
...@@ -19,11 +19,6 @@ extern void shmobile_boot_scu(void); ...@@ -19,11 +19,6 @@ extern void shmobile_boot_scu(void);
extern void shmobile_smp_scu_prepare_cpus(unsigned int max_cpus); extern void shmobile_smp_scu_prepare_cpus(unsigned int max_cpus);
extern void shmobile_smp_scu_cpu_die(unsigned int cpu); extern void shmobile_smp_scu_cpu_die(unsigned int cpu);
extern int shmobile_smp_scu_cpu_kill(unsigned int cpu); extern int shmobile_smp_scu_cpu_kill(unsigned int cpu);
extern void shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus);
extern int shmobile_smp_apmu_boot_secondary(unsigned int cpu,
struct task_struct *idle);
extern void shmobile_smp_apmu_cpu_die(unsigned int cpu);
extern int shmobile_smp_apmu_cpu_kill(unsigned int cpu);
struct clk; struct clk;
extern int shmobile_clk_init(void); extern int shmobile_clk_init(void);
extern void shmobile_handle_irq_intc(struct pt_regs *); extern void shmobile_handle_irq_intc(struct pt_regs *);
......
/* /*
* SMP support for SoCs with APMU * SMP support for SoCs with APMU
* *
* Copyright (C) 2014 Renesas Electronics Corporation
* Copyright (C) 2013 Magnus Damm * Copyright (C) 2013 Magnus Damm
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -22,6 +23,7 @@ ...@@ -22,6 +23,7 @@
#include <asm/smp_plat.h> #include <asm/smp_plat.h>
#include <asm/suspend.h> #include <asm/suspend.h>
#include "common.h" #include "common.h"
#include "platsmp-apmu.h"
static struct { static struct {
void __iomem *iomem; void __iomem *iomem;
...@@ -83,28 +85,15 @@ static void apmu_init_cpu(struct resource *res, int cpu, int bit) ...@@ -83,28 +85,15 @@ static void apmu_init_cpu(struct resource *res, int cpu, int bit)
pr_debug("apmu ioremap %d %d %pr\n", cpu, bit, res); pr_debug("apmu ioremap %d %d %pr\n", cpu, bit, res);
} }
static struct { static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit),
struct resource iomem; struct rcar_apmu_config *apmu_config, int num)
int cpus[4];
} apmu_config[] = {
{
.iomem = DEFINE_RES_MEM(0xe6152000, 0x88),
.cpus = { 0, 1, 2, 3 },
},
{
.iomem = DEFINE_RES_MEM(0xe6151000, 0x88),
.cpus = { 0x100, 0x101, 0x102, 0x103 },
}
};
static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit))
{ {
u32 id; u32 id;
int k; int k;
int bit, index; int bit, index;
bool is_allowed; bool is_allowed;
for (k = 0; k < ARRAY_SIZE(apmu_config); k++) { for (k = 0; k < num; k++) {
/* only enable the cluster that includes the boot CPU */ /* only enable the cluster that includes the boot CPU */
is_allowed = false; is_allowed = false;
for (bit = 0; bit < ARRAY_SIZE(apmu_config[k].cpus); bit++) { for (bit = 0; bit < ARRAY_SIZE(apmu_config[k].cpus); bit++) {
...@@ -128,14 +117,16 @@ static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit)) ...@@ -128,14 +117,16 @@ static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit))
} }
} }
void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus) void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus,
struct rcar_apmu_config *apmu_config,
int num)
{ {
/* install boot code shared by all CPUs */ /* install boot code shared by all CPUs */
shmobile_boot_fn = virt_to_phys(shmobile_smp_boot); shmobile_boot_fn = virt_to_phys(shmobile_smp_boot);
shmobile_boot_arg = MPIDR_HWID_BITMASK; shmobile_boot_arg = MPIDR_HWID_BITMASK;
/* perform per-cpu setup */ /* perform per-cpu setup */
apmu_parse_cfg(apmu_init_cpu); apmu_parse_cfg(apmu_init_cpu, apmu_config, num);
} }
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
......
/*
* rmobile apmu definition
*
* Copyright (C) 2014 Renesas Electronics Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef PLATSMP_APMU_H
#define PLATSMP_APMU_H
struct rcar_apmu_config {
struct resource iomem;
int cpus[4];
};
extern void shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus,
struct rcar_apmu_config *apmu_config,
int num);
extern int shmobile_smp_apmu_boot_secondary(unsigned int cpu,
struct task_struct *idle);
extern void shmobile_smp_apmu_cpu_die(unsigned int cpu);
extern int shmobile_smp_apmu_cpu_kill(unsigned int cpu);
#endif /* PLATSMP_APMU_H */
...@@ -14,10 +14,10 @@ ...@@ -14,10 +14,10 @@
#include "pm-rmobile.h" #include "pm-rmobile.h"
#if defined(CONFIG_PM) && !defined(CONFIG_ARCH_MULTIPLATFORM) #if defined(CONFIG_PM) && !defined(CONFIG_ARCH_MULTIPLATFORM)
static int r8a7740_pd_a4s_suspend(void) static int r8a7740_pd_a3sm_suspend(void)
{ {
/* /*
* The A4S domain contains the CPU core and therefore it should * The A3SM domain contains the CPU core and therefore it should
* only be turned off if the CPU is not in use. * only be turned off if the CPU is not in use.
*/ */
return -EBUSY; return -EBUSY;
...@@ -32,29 +32,65 @@ static int r8a7740_pd_a3sp_suspend(void) ...@@ -32,29 +32,65 @@ static int r8a7740_pd_a3sp_suspend(void)
return console_suspend_enabled ? 0 : -EBUSY; return console_suspend_enabled ? 0 : -EBUSY;
} }
static int r8a7740_pd_d4_suspend(void)
{
/*
* The D4 domain contains the Coresight-ETM hardware block and
* therefore it should only be turned off if the debug module is
* not in use.
*/
return -EBUSY;
}
static struct rmobile_pm_domain r8a7740_pm_domains[] = { static struct rmobile_pm_domain r8a7740_pm_domains[] = {
{ {
.genpd.name = "A4LC", .genpd.name = "A4LC",
.bit_shift = 1, .bit_shift = 1,
}, {
.genpd.name = "A4MP",
.bit_shift = 2,
}, {
.genpd.name = "D4",
.bit_shift = 3,
.gov = &pm_domain_always_on_gov,
.suspend = r8a7740_pd_d4_suspend,
}, {
.genpd.name = "A4R",
.bit_shift = 5,
}, {
.genpd.name = "A3RV",
.bit_shift = 6,
}, { }, {
.genpd.name = "A4S", .genpd.name = "A4S",
.bit_shift = 10, .bit_shift = 10,
.gov = &pm_domain_always_on_gov,
.no_debug = true, .no_debug = true,
.suspend = r8a7740_pd_a4s_suspend,
}, { }, {
.genpd.name = "A3SP", .genpd.name = "A3SP",
.bit_shift = 11, .bit_shift = 11,
.gov = &pm_domain_always_on_gov, .gov = &pm_domain_always_on_gov,
.no_debug = true, .no_debug = true,
.suspend = r8a7740_pd_a3sp_suspend, .suspend = r8a7740_pd_a3sp_suspend,
}, {
.genpd.name = "A3SM",
.bit_shift = 12,
.gov = &pm_domain_always_on_gov,
.suspend = r8a7740_pd_a3sm_suspend,
}, {
.genpd.name = "A3SG",
.bit_shift = 13,
}, {
.genpd.name = "A4SU",
.bit_shift = 20,
}, },
}; };
void __init r8a7740_init_pm_domains(void) void __init r8a7740_init_pm_domains(void)
{ {
rmobile_init_domains(r8a7740_pm_domains, ARRAY_SIZE(r8a7740_pm_domains)); rmobile_init_domains(r8a7740_pm_domains, ARRAY_SIZE(r8a7740_pm_domains));
pm_genpd_add_subdomain_names("A4R", "A3RV");
pm_genpd_add_subdomain_names("A4S", "A3SP"); pm_genpd_add_subdomain_names("A4S", "A3SP");
pm_genpd_add_subdomain_names("A4S", "A3SM");
pm_genpd_add_subdomain_names("A4S", "A3SG");
} }
#endif /* CONFIG_PM && !CONFIG_ARCH_MULTIPLATFORM */ #endif /* CONFIG_PM && !CONFIG_ARCH_MULTIPLATFORM */
......
...@@ -67,6 +67,7 @@ static struct map_desc r8a7740_io_desc[] __initdata = { ...@@ -67,6 +67,7 @@ static struct map_desc r8a7740_io_desc[] __initdata = {
void __init r8a7740_map_io(void) void __init r8a7740_map_io(void)
{ {
debug_ll_io_init();
iotable_init(r8a7740_io_desc, ARRAY_SIZE(r8a7740_io_desc)); iotable_init(r8a7740_io_desc, ARRAY_SIZE(r8a7740_io_desc));
} }
...@@ -742,6 +743,12 @@ static void r8a7740_i2c_workaround(struct platform_device *pdev) ...@@ -742,6 +743,12 @@ static void r8a7740_i2c_workaround(struct platform_device *pdev)
void __init r8a7740_add_standard_devices(void) void __init r8a7740_add_standard_devices(void)
{ {
static struct pm_domain_device domain_devices[] __initdata = { static struct pm_domain_device domain_devices[] __initdata = {
{ "A4R", &tmu0_device },
{ "A4R", &i2c0_device },
{ "A4S", &irqpin0_device },
{ "A4S", &irqpin1_device },
{ "A4S", &irqpin2_device },
{ "A4S", &irqpin3_device },
{ "A3SP", &scif0_device }, { "A3SP", &scif0_device },
{ "A3SP", &scif1_device }, { "A3SP", &scif1_device },
{ "A3SP", &scif2_device }, { "A3SP", &scif2_device },
...@@ -752,6 +759,11 @@ void __init r8a7740_add_standard_devices(void) ...@@ -752,6 +759,11 @@ void __init r8a7740_add_standard_devices(void)
{ "A3SP", &scif7_device }, { "A3SP", &scif7_device },
{ "A3SP", &scif8_device }, { "A3SP", &scif8_device },
{ "A3SP", &i2c1_device }, { "A3SP", &i2c1_device },
{ "A3SP", &ipmmu_device },
{ "A3SP", &dma0_device },
{ "A3SP", &dma1_device },
{ "A3SP", &dma2_device },
{ "A3SP", &usb_dma_device },
}; };
/* I2C work-around */ /* I2C work-around */
......
...@@ -66,6 +66,7 @@ static struct map_desc r8a7779_io_desc[] __initdata = { ...@@ -66,6 +66,7 @@ static struct map_desc r8a7779_io_desc[] __initdata = {
void __init r8a7779_map_io(void) void __init r8a7779_map_io(void)
{ {
debug_ll_io_init();
iotable_init(r8a7779_io_desc, ARRAY_SIZE(r8a7779_io_desc)); iotable_init(r8a7779_io_desc, ARRAY_SIZE(r8a7779_io_desc));
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* *
* Copyright (C) 2013 Renesas Solutions Corp. * Copyright (C) 2013 Renesas Solutions Corp.
* Copyright (C) 2013 Magnus Damm * Copyright (C) 2013 Magnus Damm
* Copyright (C) 2014 Ulrich Hecht
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -20,6 +21,7 @@ ...@@ -20,6 +21,7 @@
#include <linux/dma-contiguous.h> #include <linux/dma-contiguous.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_fdt.h> #include <linux/of_fdt.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include "common.h" #include "common.h"
...@@ -50,37 +52,61 @@ void __init rcar_gen2_timer_init(void) ...@@ -50,37 +52,61 @@ void __init rcar_gen2_timer_init(void)
{ {
#if defined(CONFIG_ARM_ARCH_TIMER) || defined(CONFIG_COMMON_CLK) #if defined(CONFIG_ARM_ARCH_TIMER) || defined(CONFIG_COMMON_CLK)
u32 mode = rcar_gen2_read_mode_pins(); u32 mode = rcar_gen2_read_mode_pins();
bool is_e2 = (bool)of_find_compatible_node(NULL, NULL,
"renesas,r8a7794");
#endif #endif
#ifdef CONFIG_ARM_ARCH_TIMER #ifdef CONFIG_ARM_ARCH_TIMER
void __iomem *base; void __iomem *base;
int extal_mhz = 0; int extal_mhz = 0;
u32 freq; u32 freq;
/* At Linux boot time the r8a7790 arch timer comes up if (is_e2) {
* with the counter disabled. Moreover, it may also report freq = 260000000 / 8; /* ZS / 8 */
* a potentially incorrect fixed 13 MHz frequency. To be /* CNTVOFF has to be initialized either from non-secure
* correct these registers need to be updated to use the * Hypervisor mode or secure Monitor mode with SCR.NS==1.
* frequency EXTAL / 2 which can be determined by the MD pins. * If TrustZone is enabled then it should be handled by the
*/ * secure code.
*/
switch (mode & (MD(14) | MD(13))) { asm volatile(
case 0: " cps 0x16\n"
extal_mhz = 15; " mrc p15, 0, r1, c1, c1, 0\n"
break; " orr r0, r1, #1\n"
case MD(13): " mcr p15, 0, r0, c1, c1, 0\n"
extal_mhz = 20; " isb\n"
break; " mov r0, #0\n"
case MD(14): " mcrr p15, 4, r0, r0, c14\n"
extal_mhz = 26; " isb\n"
break; " mcr p15, 0, r1, c1, c1, 0\n"
case MD(13) | MD(14): " isb\n"
extal_mhz = 30; " cps 0x13\n"
break; : : : "r0", "r1");
} else {
/* At Linux boot time the r8a7790 arch timer comes up
* with the counter disabled. Moreover, it may also report
* a potentially incorrect fixed 13 MHz frequency. To be
* correct these registers need to be updated to use the
* frequency EXTAL / 2 which can be determined by the MD pins.
*/
switch (mode & (MD(14) | MD(13))) {
case 0:
extal_mhz = 15;
break;
case MD(13):
extal_mhz = 20;
break;
case MD(14):
extal_mhz = 26;
break;
case MD(13) | MD(14):
extal_mhz = 30;
break;
}
/* The arch timer frequency equals EXTAL / 2 */
freq = extal_mhz * (1000000 / 2);
} }
/* The arch timer frequency equals EXTAL / 2 */
freq = extal_mhz * (1000000 / 2);
/* Remap "armgcnt address map" space */ /* Remap "armgcnt address map" space */
base = ioremap(0xe6080000, PAGE_SIZE); base = ioremap(0xe6080000, PAGE_SIZE);
......
...@@ -56,6 +56,7 @@ static struct map_desc sh7372_io_desc[] __initdata = { ...@@ -56,6 +56,7 @@ static struct map_desc sh7372_io_desc[] __initdata = {
void __init sh7372_map_io(void) void __init sh7372_map_io(void)
{ {
debug_ll_io_init();
iotable_init(sh7372_io_desc, ARRAY_SIZE(sh7372_io_desc)); iotable_init(sh7372_io_desc, ARRAY_SIZE(sh7372_io_desc));
} }
...@@ -1008,6 +1009,7 @@ DT_MACHINE_START(SH7372_DT, "Generic SH7372 (Flattened Device Tree)") ...@@ -1008,6 +1009,7 @@ DT_MACHINE_START(SH7372_DT, "Generic SH7372 (Flattened Device Tree)")
.init_irq = sh7372_init_irq, .init_irq = sh7372_init_irq,
.handle_irq = shmobile_handle_irq_intc, .handle_irq = shmobile_handle_irq_intc,
.init_machine = sh7372_add_standard_devices_dt, .init_machine = sh7372_add_standard_devices_dt,
.init_late = shmobile_init_late,
.dt_compat = sh7372_boards_compat_dt, .dt_compat = sh7372_boards_compat_dt,
MACHINE_END MACHINE_END
......
...@@ -55,6 +55,7 @@ static struct map_desc sh73a0_io_desc[] __initdata = { ...@@ -55,6 +55,7 @@ static struct map_desc sh73a0_io_desc[] __initdata = {
void __init sh73a0_map_io(void) void __init sh73a0_map_io(void)
{ {
debug_ll_io_init();
iotable_init(sh73a0_io_desc, ARRAY_SIZE(sh73a0_io_desc)); iotable_init(sh73a0_io_desc, ARRAY_SIZE(sh73a0_io_desc));
} }
...@@ -786,6 +787,13 @@ void __init sh73a0_add_standard_devices_dt(void) ...@@ -786,6 +787,13 @@ void __init sh73a0_add_standard_devices_dt(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
} }
#define RESCNT2 IOMEM(0xe6188020)
static void sh73a0_restart(enum reboot_mode mode, const char *cmd)
{
/* Do soft power on reset */
writel((1 << 31), RESCNT2);
}
static const char *sh73a0_boards_compat_dt[] __initdata = { static const char *sh73a0_boards_compat_dt[] __initdata = {
"renesas,sh73a0", "renesas,sh73a0",
NULL, NULL,
...@@ -797,6 +805,7 @@ DT_MACHINE_START(SH73A0_DT, "Generic SH73A0 (Flattened Device Tree)") ...@@ -797,6 +805,7 @@ DT_MACHINE_START(SH73A0_DT, "Generic SH73A0 (Flattened Device Tree)")
.init_early = shmobile_init_delay, .init_early = shmobile_init_delay,
.init_machine = sh73a0_add_standard_devices_dt, .init_machine = sh73a0_add_standard_devices_dt,
.init_late = shmobile_init_late, .init_late = shmobile_init_late,
.restart = sh73a0_restart,
.dt_compat = sh73a0_boards_compat_dt, .dt_compat = sh73a0_boards_compat_dt,
MACHINE_END MACHINE_END
#endif /* CONFIG_USE_OF */ #endif /* CONFIG_USE_OF */
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <asm/smp_plat.h> #include <asm/smp_plat.h>
#include "common.h" #include "common.h"
#include "platsmp-apmu.h"
#include "pm-rcar.h" #include "pm-rcar.h"
#include "r8a7790.h" #include "r8a7790.h"
...@@ -34,10 +35,23 @@ static struct rcar_sysc_ch r8a7790_ca7_scu = { ...@@ -34,10 +35,23 @@ static struct rcar_sysc_ch r8a7790_ca7_scu = {
.isr_bit = 21, /* CA7-SCU */ .isr_bit = 21, /* CA7-SCU */
}; };
static struct rcar_apmu_config r8a7790_apmu_config[] = {
{
.iomem = DEFINE_RES_MEM(0xe6152000, 0x88),
.cpus = { 0, 1, 2, 3 },
},
{
.iomem = DEFINE_RES_MEM(0xe6151000, 0x88),
.cpus = { 0x100, 0x0101, 0x102, 0x103 },
}
};
static void __init r8a7790_smp_prepare_cpus(unsigned int max_cpus) static void __init r8a7790_smp_prepare_cpus(unsigned int max_cpus)
{ {
/* let APMU code install data related to shmobile_boot_vector */ /* let APMU code install data related to shmobile_boot_vector */
shmobile_smp_apmu_prepare_cpus(max_cpus); shmobile_smp_apmu_prepare_cpus(max_cpus,
r8a7790_apmu_config,
ARRAY_SIZE(r8a7790_apmu_config));
/* turn on power to SCU */ /* turn on power to SCU */
r8a7790_pm_init(); r8a7790_pm_init();
......
...@@ -21,13 +21,23 @@ ...@@ -21,13 +21,23 @@
#include <asm/smp_plat.h> #include <asm/smp_plat.h>
#include "common.h" #include "common.h"
#include "platsmp-apmu.h"
#include "r8a7791.h" #include "r8a7791.h"
#include "rcar-gen2.h" #include "rcar-gen2.h"
static struct rcar_apmu_config r8a7791_apmu_config[] = {
{
.iomem = DEFINE_RES_MEM(0xe6152000, 0x88),
.cpus = { 0, 1 },
}
};
static void __init r8a7791_smp_prepare_cpus(unsigned int max_cpus) static void __init r8a7791_smp_prepare_cpus(unsigned int max_cpus)
{ {
/* let APMU code install data related to shmobile_boot_vector */ /* let APMU code install data related to shmobile_boot_vector */
shmobile_smp_apmu_prepare_cpus(max_cpus); shmobile_smp_apmu_prepare_cpus(max_cpus,
r8a7791_apmu_config,
ARRAY_SIZE(r8a7791_apmu_config));
r8a7791_pm_init(); r8a7791_pm_init();
} }
......
...@@ -40,6 +40,7 @@ void __init shmobile_init_delay(void) ...@@ -40,6 +40,7 @@ void __init shmobile_init_delay(void)
struct device_node *np, *cpus; struct device_node *np, *cpus;
bool is_a7_a8_a9 = false; bool is_a7_a8_a9 = false;
bool is_a15 = false; bool is_a15 = false;
bool has_arch_timer = false;
u32 max_freq = 0; u32 max_freq = 0;
cpus = of_find_node_by_path("/cpus"); cpus = of_find_node_by_path("/cpus");
...@@ -52,12 +53,16 @@ void __init shmobile_init_delay(void) ...@@ -52,12 +53,16 @@ void __init shmobile_init_delay(void)
if (!of_property_read_u32(np, "clock-frequency", &freq)) if (!of_property_read_u32(np, "clock-frequency", &freq))
max_freq = max(max_freq, freq); max_freq = max(max_freq, freq);
if (of_device_is_compatible(np, "arm,cortex-a7") || if (of_device_is_compatible(np, "arm,cortex-a8") ||
of_device_is_compatible(np, "arm,cortex-a8") || of_device_is_compatible(np, "arm,cortex-a9")) {
of_device_is_compatible(np, "arm,cortex-a9"))
is_a7_a8_a9 = true; is_a7_a8_a9 = true;
else if (of_device_is_compatible(np, "arm,cortex-a15")) } else if (of_device_is_compatible(np, "arm,cortex-a7")) {
is_a7_a8_a9 = true;
has_arch_timer = true;
} else if (of_device_is_compatible(np, "arm,cortex-a15")) {
is_a15 = true; is_a15 = true;
has_arch_timer = true;
}
} }
of_node_put(cpus); of_node_put(cpus);
...@@ -65,10 +70,12 @@ void __init shmobile_init_delay(void) ...@@ -65,10 +70,12 @@ void __init shmobile_init_delay(void)
if (!max_freq) if (!max_freq)
return; return;
if (is_a7_a8_a9) if (!has_arch_timer || !IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) {
shmobile_setup_delay_hz(max_freq, 1, 3); if (is_a7_a8_a9)
else if (is_a15 && !IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) shmobile_setup_delay_hz(max_freq, 1, 3);
shmobile_setup_delay_hz(max_freq, 2, 4); else if (is_a15)
shmobile_setup_delay_hz(max_freq, 2, 4);
}
} }
static void __init shmobile_late_time_init(void) static void __init shmobile_late_time_init(void)
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define __MACH_CORE_H #define __MACH_CORE_H
#define SOCFPGA_RSTMGR_CTRL 0x04 #define SOCFPGA_RSTMGR_CTRL 0x04
#define SOCFPGA_RSTMGR_MODMPURST 0x10
#define SOCFPGA_RSTMGR_MODPERRST 0x14 #define SOCFPGA_RSTMGR_MODPERRST 0x14
#define SOCFPGA_RSTMGR_BRGMODRST 0x1c #define SOCFPGA_RSTMGR_BRGMODRST 0x1c
...@@ -28,6 +29,8 @@ ...@@ -28,6 +29,8 @@
#define RSTMGR_CTRL_SWCOLDRSTREQ 0x1 /* Cold Reset */ #define RSTMGR_CTRL_SWCOLDRSTREQ 0x1 /* Cold Reset */
#define RSTMGR_CTRL_SWWARMRSTREQ 0x2 /* Warm Reset */ #define RSTMGR_CTRL_SWWARMRSTREQ 0x2 /* Warm Reset */
#define RSTMGR_MPUMODRST_CPU1 0x2 /* CPU1 Reset */
extern void socfpga_secondary_startup(void); extern void socfpga_secondary_startup(void);
extern void __iomem *socfpga_scu_base_addr; extern void __iomem *socfpga_scu_base_addr;
......
...@@ -34,17 +34,21 @@ static int socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle) ...@@ -34,17 +34,21 @@ static int socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle)
int trampoline_size = &secondary_trampoline_end - &secondary_trampoline; int trampoline_size = &secondary_trampoline_end - &secondary_trampoline;
if (socfpga_cpu1start_addr) { if (socfpga_cpu1start_addr) {
/* This will put CPU #1 into reset. */
writel(RSTMGR_MPUMODRST_CPU1,
rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST);
memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size); memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size);
__raw_writel(virt_to_phys(socfpga_secondary_startup), writel(virt_to_phys(socfpga_secondary_startup),
(sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff))); sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff));
flush_cache_all(); flush_cache_all();
smp_wmb(); smp_wmb();
outer_clean_range(0, trampoline_size); outer_clean_range(0, trampoline_size);
/* This will release CPU #1 out of reset.*/ /* This will release CPU #1 out of reset. */
__raw_writel(0, rst_manager_base_addr + 0x10); writel(0, rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST);
} }
return 0; return 0;
...@@ -86,10 +90,9 @@ static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus) ...@@ -86,10 +90,9 @@ static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus)
*/ */
static void socfpga_cpu_die(unsigned int cpu) static void socfpga_cpu_die(unsigned int cpu)
{ {
cpu_do_idle(); /* Do WFI. If we wake up early, go back into WFI */
while (1)
/* We should have never returned from idle */ cpu_do_idle();
panic("cpu %d unexpectedly exit from shutdown\n", cpu);
} }
struct smp_operations socfpga_smp_ops __initdata = { struct smp_operations socfpga_smp_ops __initdata = {
......
...@@ -42,4 +42,11 @@ config MACH_SUN8I ...@@ -42,4 +42,11 @@ config MACH_SUN8I
select MFD_SUN6I_PRCM select MFD_SUN6I_PRCM
select RESET_CONTROLLER select RESET_CONTROLLER
config MACH_SUN9I
bool "Allwinner (sun9i) SoCs support"
default ARCH_SUNXI
select ARCH_HAS_RESET_CONTROLLER
select ARM_GIC
select RESET_CONTROLLER
endif endif
...@@ -116,7 +116,7 @@ static int sun6i_smp_boot_secondary(unsigned int cpu, ...@@ -116,7 +116,7 @@ static int sun6i_smp_boot_secondary(unsigned int cpu,
return 0; return 0;
} }
struct smp_operations sun6i_smp_ops __initdata = { static struct smp_operations sun6i_smp_ops __initdata = {
.smp_prepare_cpus = sun6i_smp_prepare_cpus, .smp_prepare_cpus = sun6i_smp_prepare_cpus,
.smp_boot_secondary = sun6i_smp_boot_secondary, .smp_boot_secondary = sun6i_smp_boot_secondary,
}; };
......
...@@ -63,3 +63,12 @@ static const char * const sun8i_board_dt_compat[] = { ...@@ -63,3 +63,12 @@ static const char * const sun8i_board_dt_compat[] = {
DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i (A23) Family") DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i (A23) Family")
.dt_compat = sun8i_board_dt_compat, .dt_compat = sun8i_board_dt_compat,
MACHINE_END MACHINE_END
static const char * const sun9i_board_dt_compat[] = {
"allwinner,sun9i-a80",
NULL,
};
DT_MACHINE_START(SUN9I_DT, "Allwinner sun9i Family")
.dt_compat = sun9i_board_dt_compat,
MACHINE_END
...@@ -49,7 +49,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev, ...@@ -49,7 +49,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev,
call_firmware_op(prepare_idle); call_firmware_op(prepare_idle);
/* Do suspend by ourselves if the firmware does not implement it */ /* Do suspend by ourselves if the firmware does not implement it */
if (call_firmware_op(do_idle) == -ENOSYS) if (call_firmware_op(do_idle, 0) == -ENOSYS)
cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
......
...@@ -80,8 +80,8 @@ static ssize_t dummy_looptest(struct device *dev, ...@@ -80,8 +80,8 @@ static ssize_t dummy_looptest(struct device *dev,
"in 8bit mode\n"); "in 8bit mode\n");
status = spi_w8r8(spi, 0xAA); status = spi_w8r8(spi, 0xAA);
if (status < 0) if (status < 0)
pr_warning("Siple test 1: FAILURE: spi_write_then_read " pr_warn("Simple test 1: FAILURE: spi_write_then_read failed with status %d\n",
"failed with status %d\n", status); status);
else else
pr_info("Simple test 1: SUCCESS!\n"); pr_info("Simple test 1: SUCCESS!\n");
...@@ -89,8 +89,8 @@ static ssize_t dummy_looptest(struct device *dev, ...@@ -89,8 +89,8 @@ static ssize_t dummy_looptest(struct device *dev,
"in 8bit mode (full FIFO)\n"); "in 8bit mode (full FIFO)\n");
status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8); status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8);
if (status < 0) if (status < 0)
pr_warning("Simple test 2: FAILURE: spi_write_then_read() " pr_warn("Simple test 2: FAILURE: spi_write_then_read() failed with status %d\n",
"failed with status %d\n", status); status);
else else
pr_info("Simple test 2: SUCCESS!\n"); pr_info("Simple test 2: SUCCESS!\n");
...@@ -98,8 +98,8 @@ static ssize_t dummy_looptest(struct device *dev, ...@@ -98,8 +98,8 @@ static ssize_t dummy_looptest(struct device *dev,
"in 8bit mode (see if we overflow FIFO)\n"); "in 8bit mode (see if we overflow FIFO)\n");
status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14); status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14);
if (status < 0) if (status < 0)
pr_warning("Simple test 3: FAILURE: failed with status %d " pr_warn("Simple test 3: FAILURE: failed with status %d (probably FIFO overrun)\n",
"(probably FIFO overrun)\n", status); status);
else else
pr_info("Simple test 3: SUCCESS!\n"); pr_info("Simple test 3: SUCCESS!\n");
...@@ -107,14 +107,14 @@ static ssize_t dummy_looptest(struct device *dev, ...@@ -107,14 +107,14 @@ static ssize_t dummy_looptest(struct device *dev,
"bytes garbage with spi_read() in 8bit mode\n"); "bytes garbage with spi_read() in 8bit mode\n");
status = spi_write(spi, &txbuf[0], 8); status = spi_write(spi, &txbuf[0], 8);
if (status < 0) if (status < 0)
pr_warning("Simple test 4 step 1: FAILURE: spi_write() " pr_warn("Simple test 4 step 1: FAILURE: spi_write() failed with status %d\n",
"failed with status %d\n", status); status);
else else
pr_info("Simple test 4 step 1: SUCCESS!\n"); pr_info("Simple test 4 step 1: SUCCESS!\n");
status = spi_read(spi, &rxbuf[0], 8); status = spi_read(spi, &rxbuf[0], 8);
if (status < 0) if (status < 0)
pr_warning("Simple test 4 step 2: FAILURE: spi_read() " pr_warn("Simple test 4 step 2: FAILURE: spi_read() failed with status %d\n",
"failed with status %d\n", status); status);
else else
pr_info("Simple test 4 step 2: SUCCESS!\n"); pr_info("Simple test 4 step 2: SUCCESS!\n");
...@@ -122,16 +122,14 @@ static ssize_t dummy_looptest(struct device *dev, ...@@ -122,16 +122,14 @@ static ssize_t dummy_looptest(struct device *dev,
"14 bytes garbage with spi_read() in 8bit mode\n"); "14 bytes garbage with spi_read() in 8bit mode\n");
status = spi_write(spi, &txbuf[0], 14); status = spi_write(spi, &txbuf[0], 14);
if (status < 0) if (status < 0)
pr_warning("Simple test 5 step 1: FAILURE: spi_write() " pr_warn("Simple test 5 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n",
"failed with status %d (probably FIFO overrun)\n", status);
status);
else else
pr_info("Simple test 5 step 1: SUCCESS!\n"); pr_info("Simple test 5 step 1: SUCCESS!\n");
status = spi_read(spi, &rxbuf[0], 14); status = spi_read(spi, &rxbuf[0], 14);
if (status < 0) if (status < 0)
pr_warning("Simple test 5 step 2: FAILURE: spi_read() " pr_warn("Simple test 5 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n",
"failed with status %d (probably FIFO overrun)\n", status);
status);
else else
pr_info("Simple test 5: SUCCESS!\n"); pr_info("Simple test 5: SUCCESS!\n");
...@@ -140,16 +138,14 @@ static ssize_t dummy_looptest(struct device *dev, ...@@ -140,16 +138,14 @@ static ssize_t dummy_looptest(struct device *dev,
DMA_TEST_SIZE, DMA_TEST_SIZE); DMA_TEST_SIZE, DMA_TEST_SIZE);
status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE); status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE);
if (status < 0) if (status < 0)
pr_warning("Simple test 6 step 1: FAILURE: spi_write() " pr_warn("Simple test 6 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n",
"failed with status %d (probably FIFO overrun)\n", status);
status);
else else
pr_info("Simple test 6 step 1: SUCCESS!\n"); pr_info("Simple test 6 step 1: SUCCESS!\n");
status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE); status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE);
if (status < 0) if (status < 0)
pr_warning("Simple test 6 step 2: FAILURE: spi_read() " pr_warn("Simple test 6 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n",
"failed with status %d (probably FIFO overrun)\n", status);
status);
else else
pr_info("Simple test 6: SUCCESS!\n"); pr_info("Simple test 6: SUCCESS!\n");
...@@ -169,18 +165,17 @@ static ssize_t dummy_looptest(struct device *dev, ...@@ -169,18 +165,17 @@ static ssize_t dummy_looptest(struct device *dev,
pr_info("Simple test 7: SUCCESS! (expected failure with " pr_info("Simple test 7: SUCCESS! (expected failure with "
"status EIO)\n"); "status EIO)\n");
else if (status < 0) else if (status < 0)
pr_warning("Siple test 7: FAILURE: spi_write_then_read " pr_warn("Simple test 7: FAILURE: spi_write_then_read failed with status %d\n",
"failed with status %d\n", status); status);
else else
pr_warning("Siple test 7: FAILURE: spi_write_then_read " pr_warn("Simple test 7: FAILURE: spi_write_then_read succeeded but it was expected to fail!\n");
"succeeded but it was expected to fail!\n");
pr_info("Simple test 8: write 8 bytes, read back 8 bytes garbage " pr_info("Simple test 8: write 8 bytes, read back 8 bytes garbage "
"in 16bit mode (full FIFO)\n"); "in 16bit mode (full FIFO)\n");
status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8); status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8);
if (status < 0) if (status < 0)
pr_warning("Simple test 8: FAILURE: spi_write_then_read() " pr_warn("Simple test 8: FAILURE: spi_write_then_read() failed with status %d\n",
"failed with status %d\n", status); status);
else else
pr_info("Simple test 8: SUCCESS!\n"); pr_info("Simple test 8: SUCCESS!\n");
...@@ -188,8 +183,8 @@ static ssize_t dummy_looptest(struct device *dev, ...@@ -188,8 +183,8 @@ static ssize_t dummy_looptest(struct device *dev,
"in 16bit mode (see if we overflow FIFO)\n"); "in 16bit mode (see if we overflow FIFO)\n");
status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14); status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14);
if (status < 0) if (status < 0)
pr_warning("Simple test 9: FAILURE: failed with status %d " pr_warn("Simple test 9: FAILURE: failed with status %d (probably FIFO overrun)\n",
"(probably FIFO overrun)\n", status); status);
else else
pr_info("Simple test 9: SUCCESS!\n"); pr_info("Simple test 9: SUCCESS!\n");
...@@ -198,17 +193,15 @@ static ssize_t dummy_looptest(struct device *dev, ...@@ -198,17 +193,15 @@ static ssize_t dummy_looptest(struct device *dev,
DMA_TEST_SIZE, DMA_TEST_SIZE); DMA_TEST_SIZE, DMA_TEST_SIZE);
status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE); status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE);
if (status < 0) if (status < 0)
pr_warning("Simple test 10 step 1: FAILURE: spi_write() " pr_warn("Simple test 10 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n",
"failed with status %d (probably FIFO overrun)\n", status);
status);
else else
pr_info("Simple test 10 step 1: SUCCESS!\n"); pr_info("Simple test 10 step 1: SUCCESS!\n");
status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE); status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE);
if (status < 0) if (status < 0)
pr_warning("Simple test 10 step 2: FAILURE: spi_read() " pr_warn("Simple test 10 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n",
"failed with status %d (probably FIFO overrun)\n", status);
status);
else else
pr_info("Simple test 10: SUCCESS!\n"); pr_info("Simple test 10: SUCCESS!\n");
......
...@@ -32,6 +32,7 @@ config UX500_SOC_DB8500 ...@@ -32,6 +32,7 @@ config UX500_SOC_DB8500
select PINCTRL_AB8540 select PINCTRL_AB8540
select REGULATOR select REGULATOR
select REGULATOR_DB8500_PRCMU select REGULATOR_DB8500_PRCMU
select PM_GENERIC_DOMAINS if PM
config MACH_MOP500 config MACH_MOP500
bool "U8500 Development platform, MOP500 versions" bool "U8500 Development platform, MOP500 versions"
......
...@@ -9,5 +9,6 @@ obj-$(CONFIG_MACH_MOP500) += board-mop500-regulators.o \ ...@@ -9,5 +9,6 @@ obj-$(CONFIG_MACH_MOP500) += board-mop500-regulators.o \
board-mop500-audio.o board-mop500-audio.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o
CFLAGS_hotplug.o += -march=armv7-a CFLAGS_hotplug.o += -march=armv7-a
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/platform_data/arm-ux500-pm.h> #include <linux/platform_data/arm-ux500-pm.h>
#include "db8500-regs.h" #include "db8500-regs.h"
#include "pm_domains.h"
/* ARM WFI Standby signal register */ /* ARM WFI Standby signal register */
#define PRCM_ARM_WFI_STANDBY (prcmu_base + 0x130) #define PRCM_ARM_WFI_STANDBY (prcmu_base + 0x130)
...@@ -191,4 +192,7 @@ void __init ux500_pm_init(u32 phy_base, u32 size) ...@@ -191,4 +192,7 @@ void __init ux500_pm_init(u32 phy_base, u32 size)
/* Set up ux500 suspend callbacks. */ /* Set up ux500 suspend callbacks. */
suspend_set_ops(UX500_SUSPEND_OPS); suspend_set_ops(UX500_SUSPEND_OPS);
/* Initialize ux500 power domains */
ux500_pm_domains_init();
} }
/*
* Copyright (C) 2014 Linaro Ltd.
*
* Author: Ulf Hansson <ulf.hansson@linaro.org>
* License terms: GNU General Public License (GPL) version 2
*
* Implements PM domains using the generic PM domain for ux500.
*/
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/pm_domain.h>
#include <dt-bindings/arm/ux500_pm_domains.h>
#include "pm_domains.h"
static int pd_power_off(struct generic_pm_domain *domain)
{
/*
* Handle the gating of the PM domain regulator here.
*
* Drivers/subsystems handling devices in the PM domain needs to perform
* register context save/restore from their respective runtime PM
* callbacks, to be able to enable PM domain gating/ungating.
*/
return 0;
}
static int pd_power_on(struct generic_pm_domain *domain)
{
/*
* Handle the ungating of the PM domain regulator here.
*
* Drivers/subsystems handling devices in the PM domain needs to perform
* register context save/restore from their respective runtime PM
* callbacks, to be able to enable PM domain gating/ungating.
*/
return 0;
}
static struct generic_pm_domain ux500_pm_domain_vape = {
.name = "VAPE",
.power_off = pd_power_off,
.power_on = pd_power_on,
};
static struct generic_pm_domain *ux500_pm_domains[NR_DOMAINS] = {
[DOMAIN_VAPE] = &ux500_pm_domain_vape,
};
static struct of_device_id ux500_pm_domain_matches[] = {
{ .compatible = "stericsson,ux500-pm-domains", },
{ },
};
int __init ux500_pm_domains_init(void)
{
struct device_node *np;
struct genpd_onecell_data *genpd_data;
int i;
np = of_find_matching_node(NULL, ux500_pm_domain_matches);
if (!np)
return -ENODEV;
genpd_data = kzalloc(sizeof(*genpd_data), GFP_KERNEL);
if (!genpd_data)
return -ENOMEM;
genpd_data->domains = ux500_pm_domains;
genpd_data->num_domains = ARRAY_SIZE(ux500_pm_domains);
for (i = 0; i < ARRAY_SIZE(ux500_pm_domains); ++i)
pm_genpd_init(ux500_pm_domains[i], NULL, false);
of_genpd_add_provider_onecell(np, genpd_data);
return 0;
}
/*
* Copyright (C) 2014 Linaro Ltd.
*
* Author: Ulf Hansson <ulf.hansson@linaro.org>
* License terms: GNU General Public License (GPL) version 2
*/
#ifndef __MACH_UX500_PM_DOMAINS_H
#define __MACH_UX500_PM_DOMAINS_H
#ifdef CONFIG_PM_GENERIC_DOMAINS
extern int __init ux500_pm_domains_init(void);
#else
static inline int ux500_pm_domains_init(void) { return 0; }
#endif
#endif
...@@ -21,7 +21,7 @@ config CPU_ARM7TDMI ...@@ -21,7 +21,7 @@ config CPU_ARM7TDMI
# ARM720T # ARM720T
config CPU_ARM720T config CPU_ARM720T
bool "Support ARM720T processor" if ARCH_INTEGRATOR bool "Support ARM720T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
select CPU_32v4T select CPU_32v4T
select CPU_ABRT_LV4T select CPU_ABRT_LV4T
select CPU_CACHE_V4 select CPU_CACHE_V4
...@@ -39,7 +39,7 @@ config CPU_ARM720T ...@@ -39,7 +39,7 @@ config CPU_ARM720T
# ARM740T # ARM740T
config CPU_ARM740T config CPU_ARM740T
bool "Support ARM740T processor" if ARCH_INTEGRATOR bool "Support ARM740T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
depends on !MMU depends on !MMU
select CPU_32v4T select CPU_32v4T
select CPU_ABRT_LV4T select CPU_ABRT_LV4T
...@@ -71,7 +71,7 @@ config CPU_ARM9TDMI ...@@ -71,7 +71,7 @@ config CPU_ARM9TDMI
# ARM920T # ARM920T
config CPU_ARM920T config CPU_ARM920T
bool "Support ARM920T processor" if ARCH_INTEGRATOR bool "Support ARM920T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
select CPU_32v4T select CPU_32v4T
select CPU_ABRT_EV4T select CPU_ABRT_EV4T
select CPU_CACHE_V4WT select CPU_CACHE_V4WT
...@@ -89,7 +89,7 @@ config CPU_ARM920T ...@@ -89,7 +89,7 @@ config CPU_ARM920T
# ARM922T # ARM922T
config CPU_ARM922T config CPU_ARM922T
bool "Support ARM922T processor" if ARCH_INTEGRATOR bool "Support ARM922T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
select CPU_32v4T select CPU_32v4T
select CPU_ABRT_EV4T select CPU_ABRT_EV4T
select CPU_CACHE_V4WT select CPU_CACHE_V4WT
...@@ -127,7 +127,7 @@ config CPU_ARM925T ...@@ -127,7 +127,7 @@ config CPU_ARM925T
# ARM926T # ARM926T
config CPU_ARM926T config CPU_ARM926T
bool "Support ARM926T processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB bool "Support ARM926T processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V5) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB)
select CPU_32v5 select CPU_32v5
select CPU_ABRT_EV5TJ select CPU_ABRT_EV5TJ
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
...@@ -163,7 +163,7 @@ config CPU_FA526 ...@@ -163,7 +163,7 @@ config CPU_FA526
# ARM940T # ARM940T
config CPU_ARM940T config CPU_ARM940T
bool "Support ARM940T processor" if ARCH_INTEGRATOR bool "Support ARM940T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
depends on !MMU depends on !MMU
select CPU_32v4T select CPU_32v4T
select CPU_ABRT_NOMMU select CPU_ABRT_NOMMU
...@@ -181,7 +181,7 @@ config CPU_ARM940T ...@@ -181,7 +181,7 @@ config CPU_ARM940T
# ARM946E-S # ARM946E-S
config CPU_ARM946E config CPU_ARM946E
bool "Support ARM946E-S processor" if ARCH_INTEGRATOR bool "Support ARM946E-S processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
depends on !MMU depends on !MMU
select CPU_32v5 select CPU_32v5
select CPU_ABRT_NOMMU select CPU_ABRT_NOMMU
...@@ -198,7 +198,7 @@ config CPU_ARM946E ...@@ -198,7 +198,7 @@ config CPU_ARM946E
# ARM1020 - needs validating # ARM1020 - needs validating
config CPU_ARM1020 config CPU_ARM1020
bool "Support ARM1020T (rev 0) processor" if ARCH_INTEGRATOR bool "Support ARM1020T (rev 0) processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
select CPU_32v5 select CPU_32v5
select CPU_ABRT_EV4T select CPU_ABRT_EV4T
select CPU_CACHE_V4WT select CPU_CACHE_V4WT
...@@ -216,7 +216,7 @@ config CPU_ARM1020 ...@@ -216,7 +216,7 @@ config CPU_ARM1020
# ARM1020E - needs validating # ARM1020E - needs validating
config CPU_ARM1020E config CPU_ARM1020E
bool "Support ARM1020E processor" if ARCH_INTEGRATOR bool "Support ARM1020E processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
depends on n depends on n
select CPU_32v5 select CPU_32v5
select CPU_ABRT_EV4T select CPU_ABRT_EV4T
...@@ -229,7 +229,7 @@ config CPU_ARM1020E ...@@ -229,7 +229,7 @@ config CPU_ARM1020E
# ARM1022E # ARM1022E
config CPU_ARM1022 config CPU_ARM1022
bool "Support ARM1022E processor" if ARCH_INTEGRATOR bool "Support ARM1022E processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
select CPU_32v5 select CPU_32v5
select CPU_ABRT_EV4T select CPU_ABRT_EV4T
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
...@@ -247,7 +247,7 @@ config CPU_ARM1022 ...@@ -247,7 +247,7 @@ config CPU_ARM1022
# ARM1026EJ-S # ARM1026EJ-S
config CPU_ARM1026 config CPU_ARM1026
bool "Support ARM1026EJ-S processor" if ARCH_INTEGRATOR bool "Support ARM1026EJ-S processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
select CPU_32v5 select CPU_32v5
select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10 select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10
select CPU_CACHE_VIVT select CPU_CACHE_VIVT
...@@ -358,7 +358,7 @@ config CPU_PJ4B ...@@ -358,7 +358,7 @@ config CPU_PJ4B
# ARMv6 # ARMv6
config CPU_V6 config CPU_V6
bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX bool "Support ARM V6 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX)
select CPU_32v6 select CPU_32v6
select CPU_ABRT_EV6 select CPU_ABRT_EV6
select CPU_CACHE_V6 select CPU_CACHE_V6
...@@ -371,7 +371,7 @@ config CPU_V6 ...@@ -371,7 +371,7 @@ config CPU_V6
# ARMv6k # ARMv6k
config CPU_V6K config CPU_V6K
bool "Support ARM V6K processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX bool "Support ARM V6K processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX)
select CPU_32v6 select CPU_32v6
select CPU_32v6K select CPU_32v6K
select CPU_ABRT_EV6 select CPU_ABRT_EV6
...@@ -385,7 +385,7 @@ config CPU_V6K ...@@ -385,7 +385,7 @@ config CPU_V6K
# ARMv7 # ARMv7
config CPU_V7 config CPU_V7
bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX bool "Support ARM V7 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V7) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX)
select CPU_32v6K select CPU_32v6K
select CPU_32v7 select CPU_32v7
select CPU_ABRT_EV7 select CPU_ABRT_EV7
......
...@@ -35,6 +35,7 @@ obj-$(CONFIG_SAMSUNG_DMADEV) += dma-ops.o ...@@ -35,6 +35,7 @@ obj-$(CONFIG_SAMSUNG_DMADEV) += dma-ops.o
# PM support # PM support
obj-$(CONFIG_PM_SLEEP) += pm-common.o obj-$(CONFIG_PM_SLEEP) += pm-common.o
obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm-common.o
obj-$(CONFIG_SAMSUNG_PM) += pm.o obj-$(CONFIG_SAMSUNG_PM) += pm.o
obj-$(CONFIG_SAMSUNG_PM_GPIO) += pm-gpio.o obj-$(CONFIG_SAMSUNG_PM_GPIO) += pm-gpio.o
obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/pm.h>
#include <asm/bug.h> #include <asm/bug.h>
#include <asm/signal.h> #include <asm/signal.h>
...@@ -48,6 +49,7 @@ struct brcmstb_gisb_arb_device { ...@@ -48,6 +49,7 @@ struct brcmstb_gisb_arb_device {
struct list_head next; struct list_head next;
u32 valid_mask; u32 valid_mask;
const char *master_names[sizeof(u32) * BITS_PER_BYTE]; const char *master_names[sizeof(u32) * BITS_PER_BYTE];
u32 saved_timeout;
}; };
static LIST_HEAD(brcmstb_gisb_arb_device_list); static LIST_HEAD(brcmstb_gisb_arb_device_list);
...@@ -160,12 +162,6 @@ static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr, ...@@ -160,12 +162,6 @@ static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr,
return ret; return ret;
} }
void __init brcmstb_hook_fault_code(void)
{
hook_fault_code(22, brcmstb_bus_error_handler, SIGBUS, 0,
"imprecise external abort");
}
static irqreturn_t brcmstb_gisb_timeout_handler(int irq, void *dev_id) static irqreturn_t brcmstb_gisb_timeout_handler(int irq, void *dev_id)
{ {
brcmstb_gisb_arb_decode_addr(dev_id, "timeout"); brcmstb_gisb_arb_decode_addr(dev_id, "timeout");
...@@ -261,12 +257,48 @@ static int brcmstb_gisb_arb_probe(struct platform_device *pdev) ...@@ -261,12 +257,48 @@ static int brcmstb_gisb_arb_probe(struct platform_device *pdev)
list_add_tail(&gdev->next, &brcmstb_gisb_arb_device_list); list_add_tail(&gdev->next, &brcmstb_gisb_arb_device_list);
hook_fault_code(22, brcmstb_bus_error_handler, SIGBUS, 0,
"imprecise external abort");
dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n", dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n",
gdev->base, timeout_irq, tea_irq); gdev->base, timeout_irq, tea_irq);
return 0; return 0;
} }
#ifdef CONFIG_PM_SLEEP
static int brcmstb_gisb_arb_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev);
gdev->saved_timeout = ioread32(gdev->base + ARB_TIMER);
return 0;
}
/* Make sure we provide the same timeout value that was configured before, and
* do this before the GISB timeout interrupt handler has any chance to run.
*/
static int brcmstb_gisb_arb_resume_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev);
iowrite32(gdev->saved_timeout, gdev->base + ARB_TIMER);
return 0;
}
#else
#define brcmstb_gisb_arb_suspend NULL
#define brcmstb_gisb_arb_resume_noirq NULL
#endif
static const struct dev_pm_ops brcmstb_gisb_arb_pm_ops = {
.suspend = brcmstb_gisb_arb_suspend,
.resume_noirq = brcmstb_gisb_arb_resume_noirq,
};
static const struct of_device_id brcmstb_gisb_arb_of_match[] = { static const struct of_device_id brcmstb_gisb_arb_of_match[] = {
{ .compatible = "brcm,gisb-arb" }, { .compatible = "brcm,gisb-arb" },
{ }, { },
...@@ -278,6 +310,7 @@ static struct platform_driver brcmstb_gisb_arb_driver = { ...@@ -278,6 +310,7 @@ static struct platform_driver brcmstb_gisb_arb_driver = {
.name = "brcm-gisb-arb", .name = "brcm-gisb-arb",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = brcmstb_gisb_arb_of_match, .of_match_table = brcmstb_gisb_arb_of_match,
.pm = &brcmstb_gisb_arb_pm_ops,
}, },
}; };
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/syscore_ops.h>
/* /*
* DDR target is the same on all platforms. * DDR target is the same on all platforms.
...@@ -94,20 +95,42 @@ ...@@ -94,20 +95,42 @@
#define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4) #define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4)
/* Relative to mbusbridge_base */
#define MBUS_BRIDGE_CTRL_OFF 0x0
#define MBUS_BRIDGE_BASE_OFF 0x4
/* Maximum number of windows, for all known platforms */
#define MBUS_WINS_MAX 20
struct mvebu_mbus_state; struct mvebu_mbus_state;
struct mvebu_mbus_soc_data { struct mvebu_mbus_soc_data {
unsigned int num_wins; unsigned int num_wins;
unsigned int num_remappable_wins; unsigned int num_remappable_wins;
bool has_mbus_bridge;
unsigned int (*win_cfg_offset)(const int win); unsigned int (*win_cfg_offset)(const int win);
void (*setup_cpu_target)(struct mvebu_mbus_state *s); void (*setup_cpu_target)(struct mvebu_mbus_state *s);
int (*save_cpu_target)(struct mvebu_mbus_state *s,
u32 *store_addr);
int (*show_cpu_target)(struct mvebu_mbus_state *s, int (*show_cpu_target)(struct mvebu_mbus_state *s,
struct seq_file *seq, void *v); struct seq_file *seq, void *v);
}; };
/*
* Used to store the state of one MBus window accross suspend/resume.
*/
struct mvebu_mbus_win_data {
u32 ctrl;
u32 base;
u32 remap_lo;
u32 remap_hi;
};
struct mvebu_mbus_state { struct mvebu_mbus_state {
void __iomem *mbuswins_base; void __iomem *mbuswins_base;
void __iomem *sdramwins_base; void __iomem *sdramwins_base;
void __iomem *mbusbridge_base;
phys_addr_t sdramwins_phys_base;
struct dentry *debugfs_root; struct dentry *debugfs_root;
struct dentry *debugfs_sdram; struct dentry *debugfs_sdram;
struct dentry *debugfs_devs; struct dentry *debugfs_devs;
...@@ -115,6 +138,11 @@ struct mvebu_mbus_state { ...@@ -115,6 +138,11 @@ struct mvebu_mbus_state {
struct resource pcie_io_aperture; struct resource pcie_io_aperture;
const struct mvebu_mbus_soc_data *soc; const struct mvebu_mbus_soc_data *soc;
int hw_io_coherency; int hw_io_coherency;
/* Used during suspend/resume */
u32 mbus_bridge_ctrl;
u32 mbus_bridge_base;
struct mvebu_mbus_win_data wins[MBUS_WINS_MAX];
}; };
static struct mvebu_mbus_state mbus_state; static struct mvebu_mbus_state mbus_state;
...@@ -516,6 +544,28 @@ mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus) ...@@ -516,6 +544,28 @@ mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
mvebu_mbus_dram_info.num_cs = cs; mvebu_mbus_dram_info.num_cs = cs;
} }
static int
mvebu_mbus_default_save_cpu_target(struct mvebu_mbus_state *mbus,
u32 *store_addr)
{
int i;
for (i = 0; i < 4; i++) {
u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
writel(mbus->sdramwins_phys_base + DDR_BASE_CS_OFF(i),
store_addr++);
writel(base, store_addr++);
writel(mbus->sdramwins_phys_base + DDR_SIZE_CS_OFF(i),
store_addr++);
writel(size, store_addr++);
}
/* We've written 16 words to the store address */
return 16;
}
static void __init static void __init
mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus) mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus)
{ {
...@@ -546,10 +596,35 @@ mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus) ...@@ -546,10 +596,35 @@ mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus)
mvebu_mbus_dram_info.num_cs = cs; mvebu_mbus_dram_info.num_cs = cs;
} }
static int
mvebu_mbus_dove_save_cpu_target(struct mvebu_mbus_state *mbus,
u32 *store_addr)
{
int i;
for (i = 0; i < 2; i++) {
u32 map = readl(mbus->sdramwins_base + DOVE_DDR_BASE_CS_OFF(i));
writel(mbus->sdramwins_phys_base + DOVE_DDR_BASE_CS_OFF(i),
store_addr++);
writel(map, store_addr++);
}
/* We've written 4 words to the store address */
return 4;
}
int mvebu_mbus_save_cpu_target(u32 *store_addr)
{
return mbus_state.soc->save_cpu_target(&mbus_state, store_addr);
}
static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = { static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = {
.num_wins = 20, .num_wins = 20,
.num_remappable_wins = 8, .num_remappable_wins = 8,
.has_mbus_bridge = true,
.win_cfg_offset = armada_370_xp_mbus_win_offset, .win_cfg_offset = armada_370_xp_mbus_win_offset,
.save_cpu_target = mvebu_mbus_default_save_cpu_target,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion, .show_cpu_target = mvebu_sdram_debug_show_orion,
}; };
...@@ -558,6 +633,7 @@ static const struct mvebu_mbus_soc_data kirkwood_mbus_data = { ...@@ -558,6 +633,7 @@ static const struct mvebu_mbus_soc_data kirkwood_mbus_data = {
.num_wins = 8, .num_wins = 8,
.num_remappable_wins = 4, .num_remappable_wins = 4,
.win_cfg_offset = orion_mbus_win_offset, .win_cfg_offset = orion_mbus_win_offset,
.save_cpu_target = mvebu_mbus_default_save_cpu_target,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion, .show_cpu_target = mvebu_sdram_debug_show_orion,
}; };
...@@ -566,6 +642,7 @@ static const struct mvebu_mbus_soc_data dove_mbus_data = { ...@@ -566,6 +642,7 @@ static const struct mvebu_mbus_soc_data dove_mbus_data = {
.num_wins = 8, .num_wins = 8,
.num_remappable_wins = 4, .num_remappable_wins = 4,
.win_cfg_offset = orion_mbus_win_offset, .win_cfg_offset = orion_mbus_win_offset,
.save_cpu_target = mvebu_mbus_dove_save_cpu_target,
.setup_cpu_target = mvebu_mbus_dove_setup_cpu_target, .setup_cpu_target = mvebu_mbus_dove_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_dove, .show_cpu_target = mvebu_sdram_debug_show_dove,
}; };
...@@ -578,6 +655,7 @@ static const struct mvebu_mbus_soc_data orion5x_4win_mbus_data = { ...@@ -578,6 +655,7 @@ static const struct mvebu_mbus_soc_data orion5x_4win_mbus_data = {
.num_wins = 8, .num_wins = 8,
.num_remappable_wins = 4, .num_remappable_wins = 4,
.win_cfg_offset = orion_mbus_win_offset, .win_cfg_offset = orion_mbus_win_offset,
.save_cpu_target = mvebu_mbus_default_save_cpu_target,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion, .show_cpu_target = mvebu_sdram_debug_show_orion,
}; };
...@@ -586,6 +664,7 @@ static const struct mvebu_mbus_soc_data orion5x_2win_mbus_data = { ...@@ -586,6 +664,7 @@ static const struct mvebu_mbus_soc_data orion5x_2win_mbus_data = {
.num_wins = 8, .num_wins = 8,
.num_remappable_wins = 2, .num_remappable_wins = 2,
.win_cfg_offset = orion_mbus_win_offset, .win_cfg_offset = orion_mbus_win_offset,
.save_cpu_target = mvebu_mbus_default_save_cpu_target,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion, .show_cpu_target = mvebu_sdram_debug_show_orion,
}; };
...@@ -594,6 +673,7 @@ static const struct mvebu_mbus_soc_data mv78xx0_mbus_data = { ...@@ -594,6 +673,7 @@ static const struct mvebu_mbus_soc_data mv78xx0_mbus_data = {
.num_wins = 14, .num_wins = 14,
.num_remappable_wins = 8, .num_remappable_wins = 8,
.win_cfg_offset = mv78xx0_mbus_win_offset, .win_cfg_offset = mv78xx0_mbus_win_offset,
.save_cpu_target = mvebu_mbus_default_save_cpu_target,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion, .show_cpu_target = mvebu_sdram_debug_show_orion,
}; };
...@@ -698,11 +778,73 @@ static __init int mvebu_mbus_debugfs_init(void) ...@@ -698,11 +778,73 @@ static __init int mvebu_mbus_debugfs_init(void)
} }
fs_initcall(mvebu_mbus_debugfs_init); fs_initcall(mvebu_mbus_debugfs_init);
static int mvebu_mbus_suspend(void)
{
struct mvebu_mbus_state *s = &mbus_state;
int win;
if (!s->mbusbridge_base)
return -ENODEV;
for (win = 0; win < s->soc->num_wins; win++) {
void __iomem *addr = s->mbuswins_base +
s->soc->win_cfg_offset(win);
s->wins[win].base = readl(addr + WIN_BASE_OFF);
s->wins[win].ctrl = readl(addr + WIN_CTRL_OFF);
if (win >= s->soc->num_remappable_wins)
continue;
s->wins[win].remap_lo = readl(addr + WIN_REMAP_LO_OFF);
s->wins[win].remap_hi = readl(addr + WIN_REMAP_HI_OFF);
}
s->mbus_bridge_ctrl = readl(s->mbusbridge_base +
MBUS_BRIDGE_CTRL_OFF);
s->mbus_bridge_base = readl(s->mbusbridge_base +
MBUS_BRIDGE_BASE_OFF);
return 0;
}
static void mvebu_mbus_resume(void)
{
struct mvebu_mbus_state *s = &mbus_state;
int win;
writel(s->mbus_bridge_ctrl,
s->mbusbridge_base + MBUS_BRIDGE_CTRL_OFF);
writel(s->mbus_bridge_base,
s->mbusbridge_base + MBUS_BRIDGE_BASE_OFF);
for (win = 0; win < s->soc->num_wins; win++) {
void __iomem *addr = s->mbuswins_base +
s->soc->win_cfg_offset(win);
writel(s->wins[win].base, addr + WIN_BASE_OFF);
writel(s->wins[win].ctrl, addr + WIN_CTRL_OFF);
if (win >= s->soc->num_remappable_wins)
continue;
writel(s->wins[win].remap_lo, addr + WIN_REMAP_LO_OFF);
writel(s->wins[win].remap_hi, addr + WIN_REMAP_HI_OFF);
}
}
struct syscore_ops mvebu_mbus_syscore_ops = {
.suspend = mvebu_mbus_suspend,
.resume = mvebu_mbus_resume,
};
static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
phys_addr_t mbuswins_phys_base, phys_addr_t mbuswins_phys_base,
size_t mbuswins_size, size_t mbuswins_size,
phys_addr_t sdramwins_phys_base, phys_addr_t sdramwins_phys_base,
size_t sdramwins_size) size_t sdramwins_size,
phys_addr_t mbusbridge_phys_base,
size_t mbusbridge_size)
{ {
int win; int win;
...@@ -716,11 +858,26 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, ...@@ -716,11 +858,26 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
return -ENOMEM; return -ENOMEM;
} }
mbus->sdramwins_phys_base = sdramwins_phys_base;
if (mbusbridge_phys_base) {
mbus->mbusbridge_base = ioremap(mbusbridge_phys_base,
mbusbridge_size);
if (!mbus->mbusbridge_base) {
iounmap(mbus->sdramwins_base);
iounmap(mbus->mbuswins_base);
return -ENOMEM;
}
} else
mbus->mbusbridge_base = NULL;
for (win = 0; win < mbus->soc->num_wins; win++) for (win = 0; win < mbus->soc->num_wins; win++)
mvebu_mbus_disable_window(mbus, win); mvebu_mbus_disable_window(mbus, win);
mbus->soc->setup_cpu_target(mbus); mbus->soc->setup_cpu_target(mbus);
register_syscore_ops(&mvebu_mbus_syscore_ops);
return 0; return 0;
} }
...@@ -746,7 +903,7 @@ int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base, ...@@ -746,7 +903,7 @@ int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base,
mbuswins_phys_base, mbuswins_phys_base,
mbuswins_size, mbuswins_size,
sdramwins_phys_base, sdramwins_phys_base,
sdramwins_size); sdramwins_size, 0, 0);
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -887,7 +1044,7 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np, ...@@ -887,7 +1044,7 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np,
int __init mvebu_mbus_dt_init(bool is_coherent) int __init mvebu_mbus_dt_init(bool is_coherent)
{ {
struct resource mbuswins_res, sdramwins_res; struct resource mbuswins_res, sdramwins_res, mbusbridge_res;
struct device_node *np, *controller; struct device_node *np, *controller;
const struct of_device_id *of_id; const struct of_device_id *of_id;
const __be32 *prop; const __be32 *prop;
...@@ -923,6 +1080,19 @@ int __init mvebu_mbus_dt_init(bool is_coherent) ...@@ -923,6 +1080,19 @@ int __init mvebu_mbus_dt_init(bool is_coherent)
return -EINVAL; return -EINVAL;
} }
/*
* Set the resource to 0 so that it can be left unmapped by
* mvebu_mbus_common_init() if the DT doesn't carry the
* necessary information. This is needed to preserve backward
* compatibility.
*/
memset(&mbusbridge_res, 0, sizeof(mbusbridge_res));
if (mbus_state.soc->has_mbus_bridge) {
if (of_address_to_resource(controller, 2, &mbusbridge_res))
pr_warn(FW_WARN "deprecated mbus-mvebu Device Tree, suspend/resume will not work\n");
}
mbus_state.hw_io_coherency = is_coherent; mbus_state.hw_io_coherency = is_coherent;
/* Get optional pcie-{mem,io}-aperture properties */ /* Get optional pcie-{mem,io}-aperture properties */
...@@ -933,7 +1103,9 @@ int __init mvebu_mbus_dt_init(bool is_coherent) ...@@ -933,7 +1103,9 @@ int __init mvebu_mbus_dt_init(bool is_coherent)
mbuswins_res.start, mbuswins_res.start,
resource_size(&mbuswins_res), resource_size(&mbuswins_res),
sdramwins_res.start, sdramwins_res.start,
resource_size(&sdramwins_res)); resource_size(&sdramwins_res),
mbusbridge_res.start,
resource_size(&mbusbridge_res));
if (ret) if (ret)
return ret; return ret;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/syscore_ops.h>
#include "common.h" #include "common.h"
...@@ -177,14 +178,17 @@ struct clk_gating_ctrl { ...@@ -177,14 +178,17 @@ struct clk_gating_ctrl {
spinlock_t *lock; spinlock_t *lock;
struct clk **gates; struct clk **gates;
int num_gates; int num_gates;
void __iomem *base;
u32 saved_reg;
}; };
#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
static struct clk_gating_ctrl *ctrl;
static struct clk *clk_gating_get_src( static struct clk *clk_gating_get_src(
struct of_phandle_args *clkspec, void *data) struct of_phandle_args *clkspec, void *data)
{ {
struct clk_gating_ctrl *ctrl = (struct clk_gating_ctrl *)data;
int n; int n;
if (clkspec->args_count < 1) if (clkspec->args_count < 1)
...@@ -199,15 +203,35 @@ static struct clk *clk_gating_get_src( ...@@ -199,15 +203,35 @@ static struct clk *clk_gating_get_src(
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }
static int mvebu_clk_gating_suspend(void)
{
ctrl->saved_reg = readl(ctrl->base);
return 0;
}
static void mvebu_clk_gating_resume(void)
{
writel(ctrl->saved_reg, ctrl->base);
}
static struct syscore_ops clk_gate_syscore_ops = {
.suspend = mvebu_clk_gating_suspend,
.resume = mvebu_clk_gating_resume,
};
void __init mvebu_clk_gating_setup(struct device_node *np, void __init mvebu_clk_gating_setup(struct device_node *np,
const struct clk_gating_soc_desc *desc) const struct clk_gating_soc_desc *desc)
{ {
struct clk_gating_ctrl *ctrl;
struct clk *clk; struct clk *clk;
void __iomem *base; void __iomem *base;
const char *default_parent = NULL; const char *default_parent = NULL;
int n; int n;
if (ctrl) {
pr_err("mvebu-clk-gating: cannot instantiate more than one gatable clock device\n");
return;
}
base = of_iomap(np, 0); base = of_iomap(np, 0);
if (WARN_ON(!base)) if (WARN_ON(!base))
return; return;
...@@ -225,6 +249,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np, ...@@ -225,6 +249,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
/* lock must already be initialized */ /* lock must already be initialized */
ctrl->lock = &ctrl_gating_lock; ctrl->lock = &ctrl_gating_lock;
ctrl->base = base;
/* Count, allocate, and register clock gates */ /* Count, allocate, and register clock gates */
for (n = 0; desc[n].name;) for (n = 0; desc[n].name;)
n++; n++;
...@@ -246,6 +272,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np, ...@@ -246,6 +272,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
of_clk_add_provider(np, clk_gating_get_src, ctrl); of_clk_add_provider(np, clk_gating_get_src, ctrl);
register_syscore_ops(&clk_gate_syscore_ops);
return; return;
gates_out: gates_out:
kfree(ctrl); kfree(ctrl);
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include "clk.h" #include "clk.h"
#include "clk-pll.h" #include "clk-pll.h"
...@@ -23,6 +25,8 @@ ...@@ -23,6 +25,8 @@
#define CPU_CLK_STATUS 0xfc #define CPU_CLK_STATUS 0xfc
#define MISC_DOUT1 0x558 #define MISC_DOUT1 0x558
static void __iomem *reg_base;
/* parent clock name list */ /* parent clock name list */
PNAME(mout_armclk_p) = { "cplla", "cpllb" }; PNAME(mout_armclk_p) = { "cplla", "cpllb" };
PNAME(mout_spi_p) = { "div125", "div200" }; PNAME(mout_spi_p) = { "div125", "div200" };
...@@ -89,10 +93,30 @@ static const struct of_device_id ext_clk_match[] __initconst = { ...@@ -89,10 +93,30 @@ static const struct of_device_id ext_clk_match[] __initconst = {
{}, {},
}; };
static int exynos5440_clk_restart_notify(struct notifier_block *this,
unsigned long code, void *unused)
{
u32 val, status;
status = readl_relaxed(reg_base + 0xbc);
val = readl_relaxed(reg_base + 0xcc);
val = (val & 0xffff0000) | (status & 0xffff);
writel_relaxed(val, reg_base + 0xcc);
return NOTIFY_DONE;
}
/*
* Exynos5440 Clock restart notifier, handles restart functionality
*/
static struct notifier_block exynos5440_clk_restart_handler = {
.notifier_call = exynos5440_clk_restart_notify,
.priority = 128,
};
/* register exynos5440 clocks */ /* register exynos5440 clocks */
static void __init exynos5440_clk_init(struct device_node *np) static void __init exynos5440_clk_init(struct device_node *np)
{ {
void __iomem *reg_base;
struct samsung_clk_provider *ctx; struct samsung_clk_provider *ctx;
reg_base = of_iomap(np, 0); reg_base = of_iomap(np, 0);
...@@ -125,6 +149,9 @@ static void __init exynos5440_clk_init(struct device_node *np) ...@@ -125,6 +149,9 @@ static void __init exynos5440_clk_init(struct device_node *np)
samsung_clk_of_add_provider(np, ctx); samsung_clk_of_add_provider(np, ctx);
if (register_restart_handler(&exynos5440_clk_restart_handler))
pr_warn("exynos5440 clock can't register restart handler\n");
pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("arm_clk")); pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("arm_clk"));
pr_info("exynos5440 clock initialization complete\n"); pr_info("exynos5440 clock initialization complete\n");
} }
......
...@@ -33,6 +33,9 @@ static const struct clk_ops dpll_m4xen_ck_ops = { ...@@ -33,6 +33,9 @@ static const struct clk_ops dpll_m4xen_ck_ops = {
.recalc_rate = &omap4_dpll_regm4xen_recalc, .recalc_rate = &omap4_dpll_regm4xen_recalc,
.round_rate = &omap4_dpll_regm4xen_round_rate, .round_rate = &omap4_dpll_regm4xen_round_rate,
.set_rate = &omap3_noncore_dpll_set_rate, .set_rate = &omap3_noncore_dpll_set_rate,
.set_parent = &omap3_noncore_dpll_set_parent,
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
.determine_rate = &omap4_dpll_regm4xen_determine_rate,
.get_parent = &omap2_init_dpll_parent, .get_parent = &omap2_init_dpll_parent,
}; };
#else #else
...@@ -53,6 +56,9 @@ static const struct clk_ops dpll_ck_ops = { ...@@ -53,6 +56,9 @@ static const struct clk_ops dpll_ck_ops = {
.recalc_rate = &omap3_dpll_recalc, .recalc_rate = &omap3_dpll_recalc,
.round_rate = &omap2_dpll_round_rate, .round_rate = &omap2_dpll_round_rate,
.set_rate = &omap3_noncore_dpll_set_rate, .set_rate = &omap3_noncore_dpll_set_rate,
.set_parent = &omap3_noncore_dpll_set_parent,
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
.determine_rate = &omap3_noncore_dpll_determine_rate,
.get_parent = &omap2_init_dpll_parent, .get_parent = &omap2_init_dpll_parent,
}; };
...@@ -61,6 +67,9 @@ static const struct clk_ops dpll_no_gate_ck_ops = { ...@@ -61,6 +67,9 @@ static const struct clk_ops dpll_no_gate_ck_ops = {
.get_parent = &omap2_init_dpll_parent, .get_parent = &omap2_init_dpll_parent,
.round_rate = &omap2_dpll_round_rate, .round_rate = &omap2_dpll_round_rate,
.set_rate = &omap3_noncore_dpll_set_rate, .set_rate = &omap3_noncore_dpll_set_rate,
.set_parent = &omap3_noncore_dpll_set_parent,
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
.determine_rate = &omap3_noncore_dpll_determine_rate,
}; };
#else #else
static const struct clk_ops dpll_core_ck_ops = {}; static const struct clk_ops dpll_core_ck_ops = {};
...@@ -97,6 +106,9 @@ static const struct clk_ops omap3_dpll_ck_ops = { ...@@ -97,6 +106,9 @@ static const struct clk_ops omap3_dpll_ck_ops = {
.get_parent = &omap2_init_dpll_parent, .get_parent = &omap2_init_dpll_parent,
.recalc_rate = &omap3_dpll_recalc, .recalc_rate = &omap3_dpll_recalc,
.set_rate = &omap3_noncore_dpll_set_rate, .set_rate = &omap3_noncore_dpll_set_rate,
.set_parent = &omap3_noncore_dpll_set_parent,
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
.determine_rate = &omap3_noncore_dpll_determine_rate,
.round_rate = &omap2_dpll_round_rate, .round_rate = &omap2_dpll_round_rate,
}; };
...@@ -106,6 +118,9 @@ static const struct clk_ops omap3_dpll_per_ck_ops = { ...@@ -106,6 +118,9 @@ static const struct clk_ops omap3_dpll_per_ck_ops = {
.get_parent = &omap2_init_dpll_parent, .get_parent = &omap2_init_dpll_parent,
.recalc_rate = &omap3_dpll_recalc, .recalc_rate = &omap3_dpll_recalc,
.set_rate = &omap3_dpll4_set_rate, .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, .round_rate = &omap2_dpll_round_rate,
}; };
#endif #endif
......
...@@ -32,6 +32,7 @@ config ARMADA_370_XP_TIMER ...@@ -32,6 +32,7 @@ config ARMADA_370_XP_TIMER
config MESON6_TIMER config MESON6_TIMER
bool bool
select CLKSRC_MMIO
config ORION_TIMER config ORION_TIMER
select CLKSRC_OF select CLKSRC_OF
......
...@@ -45,4 +45,5 @@ obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o ...@@ -45,4 +45,5 @@ obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o
obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o
obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/sched_clock.h> #include <linux/sched_clock.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/syscore_ops.h>
/* /*
* Timer block registers. * Timer block registers.
...@@ -223,6 +224,28 @@ static struct notifier_block armada_370_xp_timer_cpu_nb = { ...@@ -223,6 +224,28 @@ static struct notifier_block armada_370_xp_timer_cpu_nb = {
.notifier_call = armada_370_xp_timer_cpu_notify, .notifier_call = armada_370_xp_timer_cpu_notify,
}; };
static u32 timer0_ctrl_reg, timer0_local_ctrl_reg;
static int armada_370_xp_timer_suspend(void)
{
timer0_ctrl_reg = readl(timer_base + TIMER_CTRL_OFF);
timer0_local_ctrl_reg = readl(local_base + TIMER_CTRL_OFF);
return 0;
}
static void armada_370_xp_timer_resume(void)
{
writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
writel(timer0_ctrl_reg, timer_base + TIMER_CTRL_OFF);
writel(timer0_local_ctrl_reg, local_base + TIMER_CTRL_OFF);
}
struct syscore_ops armada_370_xp_timer_syscore_ops = {
.suspend = armada_370_xp_timer_suspend,
.resume = armada_370_xp_timer_resume,
};
static void __init armada_370_xp_timer_common_init(struct device_node *np) static void __init armada_370_xp_timer_common_init(struct device_node *np)
{ {
u32 clr = 0, set = 0; u32 clr = 0, set = 0;
...@@ -285,6 +308,8 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np) ...@@ -285,6 +308,8 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
/* Immediately configure the timer on the boot CPU */ /* Immediately configure the timer on the boot CPU */
if (!res) if (!res)
armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
register_syscore_ops(&armada_370_xp_timer_syscore_ops);
} }
static void __init armada_xp_timer_init(struct device_node *np) static void __init armada_xp_timer_init(struct device_node *np)
......
/*
* Integrator/AP timer driver
* Copyright (C) 2000-2003 Deep Blue Solutions Ltd
* Copyright (c) 2014, Linaro Limited
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/clk.h>
#include <linux/clocksource.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/sched_clock.h>
#include <asm/hardware/arm_timer.h>
static void __iomem * sched_clk_base;
static u64 notrace integrator_read_sched_clock(void)
{
return -readl(sched_clk_base + TIMER_VALUE);
}
static void integrator_clocksource_init(unsigned long inrate,
void __iomem *base)
{
u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
unsigned long rate = inrate;
if (rate >= 1500000) {
rate /= 16;
ctrl |= TIMER_CTRL_DIV16;
}
writel(0xffff, base + TIMER_LOAD);
writel(ctrl, base + TIMER_CTRL);
clocksource_mmio_init(base + TIMER_VALUE, "timer2",
rate, 200, 16, clocksource_mmio_readl_down);
sched_clk_base = base;
sched_clock_register(integrator_read_sched_clock, 16, rate);
}
static unsigned long timer_reload;
static void __iomem * clkevt_base;
/*
* IRQ handler for the timer
*/
static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = dev_id;
/* clear the interrupt */
writel(1, clkevt_base + TIMER_INTCLR);
evt->event_handler(evt);
return IRQ_HANDLED;
}
static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
{
u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
/* Disable timer */
writel(ctrl, clkevt_base + TIMER_CTRL);
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
/* Enable the timer and start the periodic tick */
writel(timer_reload, clkevt_base + TIMER_LOAD);
ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
writel(ctrl, clkevt_base + TIMER_CTRL);
break;
case CLOCK_EVT_MODE_ONESHOT:
/* Leave the timer disabled, .set_next_event will enable it */
ctrl &= ~TIMER_CTRL_PERIODIC;
writel(ctrl, clkevt_base + TIMER_CTRL);
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_RESUME:
default:
/* Just leave in disabled state */
break;
}
}
static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
{
unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
writel(next, clkevt_base + TIMER_LOAD);
writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
return 0;
}
static struct clock_event_device integrator_clockevent = {
.name = "timer1",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = clkevt_set_mode,
.set_next_event = clkevt_set_next_event,
.rating = 300,
};
static struct irqaction integrator_timer_irq = {
.name = "timer",
.flags = IRQF_TIMER | IRQF_IRQPOLL,
.handler = integrator_timer_interrupt,
.dev_id = &integrator_clockevent,
};
static void integrator_clockevent_init(unsigned long inrate,
void __iomem *base, int irq)
{
unsigned long rate = inrate;
unsigned int ctrl = 0;
clkevt_base = base;
/* Calculate and program a divisor */
if (rate > 0x100000 * HZ) {
rate /= 256;
ctrl |= TIMER_CTRL_DIV256;
} else if (rate > 0x10000 * HZ) {
rate /= 16;
ctrl |= TIMER_CTRL_DIV16;
}
timer_reload = rate / HZ;
writel(ctrl, clkevt_base + TIMER_CTRL);
setup_irq(irq, &integrator_timer_irq);
clockevents_config_and_register(&integrator_clockevent,
rate,
1,
0xffffU);
}
static void __init integrator_ap_timer_init_of(struct device_node *node)
{
const char *path;
void __iomem *base;
int err;
int irq;
struct clk *clk;
unsigned long rate;
struct device_node *pri_node;
struct device_node *sec_node;
base = of_io_request_and_map(node, 0, "integrator-timer");
if (!base)
return;
clk = of_clk_get(node, 0);
if (IS_ERR(clk)) {
pr_err("No clock for %s\n", node->name);
return;
}
clk_prepare_enable(clk);
rate = clk_get_rate(clk);
writel(0, base + TIMER_CTRL);
err = of_property_read_string(of_aliases,
"arm,timer-primary", &path);
if (WARN_ON(err))
return;
pri_node = of_find_node_by_path(path);
err = of_property_read_string(of_aliases,
"arm,timer-secondary", &path);
if (WARN_ON(err))
return;
sec_node = of_find_node_by_path(path);
if (node == pri_node) {
/* The primary timer lacks IRQ, use as clocksource */
integrator_clocksource_init(rate, base);
return;
}
if (node == sec_node) {
/* The secondary timer will drive the clock event */
irq = irq_of_parse_and_map(node, 0);
integrator_clockevent_init(rate, base, irq);
return;
}
pr_info("Timer @%p unused\n", base);
clk_disable_unprepare(clk);
}
CLOCKSOURCE_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer",
integrator_ap_timer_init_of);
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/of_pci.h> #include <linux/of_pci.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/syscore_ops.h>
#include <linux/msi.h> #include <linux/msi.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/exception.h> #include <asm/exception.h>
...@@ -67,6 +68,7 @@ ...@@ -67,6 +68,7 @@
static void __iomem *per_cpu_int_base; static void __iomem *per_cpu_int_base;
static void __iomem *main_int_base; static void __iomem *main_int_base;
static struct irq_domain *armada_370_xp_mpic_domain; static struct irq_domain *armada_370_xp_mpic_domain;
static u32 doorbell_mask_reg;
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
static struct irq_domain *armada_370_xp_msi_domain; static struct irq_domain *armada_370_xp_msi_domain;
static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR); static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
...@@ -485,6 +487,54 @@ armada_370_xp_handle_irq(struct pt_regs *regs) ...@@ -485,6 +487,54 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
} while (1); } while (1);
} }
static int armada_370_xp_mpic_suspend(void)
{
doorbell_mask_reg = readl(per_cpu_int_base +
ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
return 0;
}
static void armada_370_xp_mpic_resume(void)
{
int nirqs;
irq_hw_number_t irq;
/* Re-enable interrupts */
nirqs = (readl(main_int_base + ARMADA_370_XP_INT_CONTROL) >> 2) & 0x3ff;
for (irq = 0; irq < nirqs; irq++) {
struct irq_data *data;
int virq;
virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq);
if (virq == 0)
continue;
if (irq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ)
writel(irq, per_cpu_int_base +
ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
else
writel(irq, main_int_base +
ARMADA_370_XP_INT_SET_ENABLE_OFFS);
data = irq_get_irq_data(virq);
if (!irqd_irq_disabled(data))
armada_370_xp_irq_unmask(data);
}
/* Reconfigure doorbells for IPIs and MSIs */
writel(doorbell_mask_reg,
per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
if (doorbell_mask_reg & IPI_DOORBELL_MASK)
writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK)
writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
}
struct syscore_ops armada_370_xp_mpic_syscore_ops = {
.suspend = armada_370_xp_mpic_suspend,
.resume = armada_370_xp_mpic_resume,
};
static int __init armada_370_xp_mpic_of_init(struct device_node *node, static int __init armada_370_xp_mpic_of_init(struct device_node *node,
struct device_node *parent) struct device_node *parent)
{ {
...@@ -541,6 +591,8 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node, ...@@ -541,6 +591,8 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
armada_370_xp_mpic_handle_cascade_irq); armada_370_xp_mpic_handle_cascade_irq);
} }
register_syscore_ops(&armada_370_xp_mpic_syscore_ops);
return 0; return 0;
} }
......
...@@ -71,6 +71,15 @@ config POWER_RESET_HISI ...@@ -71,6 +71,15 @@ config POWER_RESET_HISI
help help
Reboot support for Hisilicon boards. Reboot support for Hisilicon boards.
config POWER_RESET_IMX
bool "IMX6 power-off driver"
depends on POWER_RESET && SOC_IMX6
help
This driver support power off external PMIC by PMIC_ON_REQ on i.mx6
boards.If you want to use other pin to control external power,please
say N here or disable in dts to make sure pm_power_off never be
overwrote wrongly by this driver.
config POWER_RESET_MSM config POWER_RESET_MSM
bool "Qualcomm MSM power-off driver" bool "Qualcomm MSM power-off driver"
depends on ARCH_QCOM depends on ARCH_QCOM
......
...@@ -6,6 +6,7 @@ obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o ...@@ -6,6 +6,7 @@ obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o
obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
obj-$(CONFIG_POWER_RESET_IMX) += imx-snvs-poweroff.o
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
......
/* Power off driver for i.mx6
* Copyright (c) 2014, FREESCALE CORPORATION. All rights reserved.
*
* based on msm-poweroff.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
static void __iomem *snvs_base;
static void do_imx_poweroff(void)
{
u32 value = readl(snvs_base);
/* set TOP and DP_EN bit */
writel(value | 0x60, snvs_base);
}
static int imx_poweroff_probe(struct platform_device *pdev)
{
snvs_base = of_iomap(pdev->dev.of_node, 0);
if (!snvs_base) {
dev_err(&pdev->dev, "failed to get memory\n");
return -ENODEV;
}
pm_power_off = do_imx_poweroff;
return 0;
}
static const struct of_device_id of_imx_poweroff_match[] = {
{ .compatible = "fsl,sec-v4.0-poweroff", },
{},
};
MODULE_DEVICE_TABLE(of, of_imx_poweroff_match);
static struct platform_driver imx_poweroff_driver = {
.probe = imx_poweroff_probe,
.driver = {
.name = "imx-snvs-poweroff",
.of_match_table = of_match_ptr(of_imx_poweroff_match),
},
};
static int __init imx_poweroff_init(void)
{
return platform_driver_register(&imx_poweroff_driver);
}
device_initcall(imx_poweroff_init);
# #
# ARM Versatile SoC drivers # ARM Versatile SoC drivers
# #
config SOC_INTEGRATOR_CM
bool "SoC bus device for the ARM Integrator platform core modules"
depends on ARCH_INTEGRATOR
select SOC_BUS
help
Include support for the SoC bus on the ARM Integrator platform
core modules providing some sysfs information about the ASIC
variant.
config SOC_REALVIEW config SOC_REALVIEW
bool "SoC bus device for the ARM RealView platforms" bool "SoC bus device for the ARM RealView platforms"
depends on ARCH_REALVIEW depends on ARCH_REALVIEW
......
obj-$(CONFIG_SOC_INTEGRATOR_CM) += soc-integrator.o
obj-$(CONFIG_SOC_REALVIEW) += soc-realview.o obj-$(CONFIG_SOC_REALVIEW) += soc-realview.o
/*
* Copyright (C) 2014 Linaro Ltd.
*
* Author: Linus Walleij <linus.walleij@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
*/
#include <linux/init.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/sys_soc.h>
#include <linux/platform_device.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/of.h>
#define INTEGRATOR_HDR_ID_OFFSET 0x00
static u32 integrator_coreid;
static const struct of_device_id integrator_cm_match[] = {
{ .compatible = "arm,core-module-integrator", },
{ }
};
static const char *integrator_arch_str(u32 id)
{
switch ((id >> 16) & 0xff) {
case 0x00:
return "ASB little-endian";
case 0x01:
return "AHB little-endian";
case 0x03:
return "AHB-Lite system bus, bi-endian";
case 0x04:
return "AHB";
case 0x08:
return "AHB system bus, ASB processor bus";
default:
return "Unknown";
}
}
static const char *integrator_fpga_str(u32 id)
{
switch ((id >> 12) & 0xf) {
case 0x01:
return "XC4062";
case 0x02:
return "XC4085";
case 0x03:
return "XVC600";
case 0x04:
return "EPM7256AE (Altera PLD)";
default:
return "Unknown";
}
}
static ssize_t integrator_get_manf(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%02x\n", integrator_coreid >> 24);
}
static struct device_attribute integrator_manf_attr =
__ATTR(manufacturer, S_IRUGO, integrator_get_manf, NULL);
static ssize_t integrator_get_arch(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n", integrator_arch_str(integrator_coreid));
}
static struct device_attribute integrator_arch_attr =
__ATTR(arch, S_IRUGO, integrator_get_arch, NULL);
static ssize_t integrator_get_fpga(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n", integrator_fpga_str(integrator_coreid));
}
static struct device_attribute integrator_fpga_attr =
__ATTR(fpga, S_IRUGO, integrator_get_fpga, NULL);
static ssize_t integrator_get_build(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%02x\n", (integrator_coreid >> 4) & 0xFF);
}
static struct device_attribute integrator_build_attr =
__ATTR(build, S_IRUGO, integrator_get_build, NULL);
static int __init integrator_soc_init(void)
{
static struct regmap *syscon_regmap;
struct soc_device *soc_dev;
struct soc_device_attribute *soc_dev_attr;
struct device_node *np;
struct device *dev;
u32 val;
int ret;
np = of_find_matching_node(NULL, integrator_cm_match);
if (!np)
return -ENODEV;
syscon_regmap = syscon_node_to_regmap(np);
if (IS_ERR(syscon_regmap))
return PTR_ERR(syscon_regmap);
ret = regmap_read(syscon_regmap, INTEGRATOR_HDR_ID_OFFSET,
&val);
if (ret)
return -ENODEV;
integrator_coreid = val;
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
if (!soc_dev_attr)
return -ENOMEM;
soc_dev_attr->soc_id = "Integrator";
soc_dev_attr->machine = "Integrator";
soc_dev_attr->family = "Versatile";
soc_dev = soc_device_register(soc_dev_attr);
if (IS_ERR(soc_dev)) {
kfree(soc_dev_attr);
return -ENODEV;
}
dev = soc_device_to_device(soc_dev);
device_create_file(dev, &integrator_manf_attr);
device_create_file(dev, &integrator_arch_attr);
device_create_file(dev, &integrator_fpga_attr);
device_create_file(dev, &integrator_build_attr);
dev_info(dev, "Detected ARM core module:\n");
dev_info(dev, " Manufacturer: %02x\n", (val >> 24));
dev_info(dev, " Architecture: %s\n", integrator_arch_str(val));
dev_info(dev, " FPGA: %s\n", integrator_fpga_str(val));
dev_info(dev, " Build: %02x\n", (val >> 4) & 0xFF);
dev_info(dev, " Rev: %c\n", ('A' + (val & 0x03)));
return 0;
}
device_initcall(integrator_soc_init);
/*
* Copyright (C) 2014 Linaro Ltd.
*
* Author: Ulf Hansson <ulf.hansson@linaro.org>
* License terms: GNU General Public License (GPL) version 2
*/
#ifndef _DT_BINDINGS_ARM_UX500_PM_DOMAINS_H
#define _DT_BINDINGS_ARM_UX500_PM_DOMAINS_H
#define DOMAIN_VAPE 0
/* Number of PM domains. */
#define NR_DOMAINS (DOMAIN_VAPE + 1)
#endif
...@@ -198,6 +198,9 @@ ...@@ -198,6 +198,9 @@
#define IMX5_CLK_OCRAM 186 #define IMX5_CLK_OCRAM 186
#define IMX5_CLK_SAHARA_IPG_GATE 187 #define IMX5_CLK_SAHARA_IPG_GATE 187
#define IMX5_CLK_SATA_REF 188 #define IMX5_CLK_SATA_REF 188
#define IMX5_CLK_END 189 #define IMX5_CLK_STEP_SEL 189
#define IMX5_CLK_CPU_PODF_SEL 190
#define IMX5_CLK_ARM 191
#define IMX5_CLK_END 192
#endif /* __DT_BINDINGS_CLOCK_IMX5_H */ #endif /* __DT_BINDINGS_CLOCK_IMX5_H */
...@@ -254,13 +254,26 @@ extern const struct clk_ops ti_clk_mux_ops; ...@@ -254,13 +254,26 @@ extern const struct clk_ops ti_clk_mux_ops;
void omap2_init_clk_hw_omap_clocks(struct clk *clk); void omap2_init_clk_hw_omap_clocks(struct clk *clk);
int omap3_noncore_dpll_enable(struct clk_hw *hw); int omap3_noncore_dpll_enable(struct clk_hw *hw);
void omap3_noncore_dpll_disable(struct clk_hw *hw); void omap3_noncore_dpll_disable(struct clk_hw *hw);
int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index);
int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate); unsigned long parent_rate);
int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate,
u8 index);
long omap3_noncore_dpll_determine_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_clk);
unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
unsigned long parent_rate); unsigned long parent_rate);
long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
unsigned long target_rate, unsigned long target_rate,
unsigned long *parent_rate); unsigned long *parent_rate);
long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_clk);
u8 omap2_init_dpll_parent(struct clk_hw *hw); u8 omap2_init_dpll_parent(struct clk_hw *hw);
unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate);
long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
...@@ -278,6 +291,8 @@ int omap2_clk_disable_autoidle_all(void); ...@@ -278,6 +291,8 @@ int omap2_clk_disable_autoidle_all(void);
void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks);
int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate,
unsigned long parent_rate); unsigned long parent_rate);
int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate, u8 index);
int omap2_dflt_clk_enable(struct clk_hw *hw); int omap2_dflt_clk_enable(struct clk_hw *hw);
void omap2_dflt_clk_disable(struct clk_hw *hw); void omap2_dflt_clk_disable(struct clk_hw *hw);
int omap2_dflt_clk_is_enabled(struct clk_hw *hw); int omap2_dflt_clk_is_enabled(struct clk_hw *hw);
......
...@@ -61,6 +61,7 @@ static inline const struct mbus_dram_target_info *mv_mbus_dram_info(void) ...@@ -61,6 +61,7 @@ static inline const struct mbus_dram_target_info *mv_mbus_dram_info(void)
} }
#endif #endif
int mvebu_mbus_save_cpu_target(u32 *store_addr);
void mvebu_mbus_get_pcie_mem_aperture(struct resource *res); void mvebu_mbus_get_pcie_mem_aperture(struct resource *res);
void mvebu_mbus_get_pcie_io_aperture(struct resource *res); void mvebu_mbus_get_pcie_io_aperture(struct resource *res);
int mvebu_mbus_add_window_remap_by_id(unsigned int target, int mvebu_mbus_add_window_remap_by_id(unsigned int target,
......
...@@ -395,4 +395,43 @@ ...@@ -395,4 +395,43 @@
#define IMX6SL_GPR1_FEC_CLOCK_MUX1_SEL_MASK (0x3 << 17) #define IMX6SL_GPR1_FEC_CLOCK_MUX1_SEL_MASK (0x3 << 17)
#define IMX6SL_GPR1_FEC_CLOCK_MUX2_SEL_MASK (0x1 << 14) #define IMX6SL_GPR1_FEC_CLOCK_MUX2_SEL_MASK (0x1 << 14)
/* For imx6sx iomux gpr register field define */
#define IMX6SX_GPR1_VDEC_SW_RST_MASK (0x1 << 20)
#define IMX6SX_GPR1_VDEC_SW_RST_RESET (0x1 << 20)
#define IMX6SX_GPR1_VDEC_SW_RST_RELEASE (0x0 << 20)
#define IMX6SX_GPR1_VADC_SW_RST_MASK (0x1 << 19)
#define IMX6SX_GPR1_VADC_SW_RST_RESET (0x1 << 19)
#define IMX6SX_GPR1_VADC_SW_RST_RELEASE (0x0 << 19)
#define IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_MASK (0x3 << 13)
#define IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK (0x3 << 17)
#define IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_EXT (0x3 << 13)
#define IMX6SX_GPR4_FEC_ENET1_STOP_REQ (0x1 << 3)
#define IMX6SX_GPR4_FEC_ENET2_STOP_REQ (0x1 << 4)
#define IMX6SX_GPR5_DISP_MUX_LDB_CTRL_MASK (0x1 << 3)
#define IMX6SX_GPR5_DISP_MUX_LDB_CTRL_LCDIF1 (0x0 << 3)
#define IMX6SX_GPR5_DISP_MUX_LDB_CTRL_LCDIF2 (0x1 << 3)
#define IMX6SX_GPR5_CSI2_MUX_CTRL_MASK (0x3 << 27)
#define IMX6SX_GPR5_CSI2_MUX_CTRL_EXT_PIN (0x0 << 27)
#define IMX6SX_GPR5_CSI2_MUX_CTRL_CVD (0x1 << 27)
#define IMX6SX_GPR5_CSI2_MUX_CTRL_VDAC_TO_CSI (0x2 << 27)
#define IMX6SX_GPR5_CSI2_MUX_CTRL_GND (0x3 << 27)
#define IMX6SX_GPR5_VADC_TO_CSI_CAPTURE_EN_MASK (0x1 << 26)
#define IMX6SX_GPR5_VADC_TO_CSI_CAPTURE_EN_ENABLE (0x1 << 26)
#define IMX6SX_GPR5_VADC_TO_CSI_CAPTURE_EN_DISABLE (0x0 << 26)
#define IMX6SX_GPR5_CSI1_MUX_CTRL_MASK (0x3 << 4)
#define IMX6SX_GPR5_CSI1_MUX_CTRL_EXT_PIN (0x0 << 4)
#define IMX6SX_GPR5_CSI1_MUX_CTRL_CVD (0x1 << 4)
#define IMX6SX_GPR5_CSI1_MUX_CTRL_VDAC_TO_CSI (0x2 << 4)
#define IMX6SX_GPR5_CSI1_MUX_CTRL_GND (0x3 << 4)
#define IMX6SX_GPR5_DISP_MUX_DCIC2_LCDIF2 (0x0 << 2)
#define IMX6SX_GPR5_DISP_MUX_DCIC2_LVDS (0x1 << 2)
#define IMX6SX_GPR5_DISP_MUX_DCIC2_MASK (0x1 << 2)
#define IMX6SX_GPR5_DISP_MUX_DCIC1_LCDIF1 (0x0 << 1)
#define IMX6SX_GPR5_DISP_MUX_DCIC1_LVDS (0x1 << 1)
#define IMX6SX_GPR5_DISP_MUX_DCIC1_MASK (0x1 << 1)
#endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */ #endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册