diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-26 14:34:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-26 14:34:35 -0400 |
commit | 4aa705b18bf17c4ff33ff7bbcd3f0c596443fa81 (patch) | |
tree | 3b166bff290d123ccaa88598ad2d45be67f5b358 /arch/arm/mach-socfpga | |
parent | c11d716218910c3aa2bac1bb641e6086ad649555 (diff) | |
parent | 2879e43f09122f8b3ef5456e3d7e48716b086e60 (diff) |
Merge tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC platform support updates from Kevin Hilman:
"Our SoC branch usually contains expanded support for new SoCs and
other core platform code. Some highlights from this round:
- sunxi: SMP support for A23 SoC
- socpga: big-endian support
- pxa: conversion to common clock framework
- bcm: SMP support for BCM63138
- imx: support new I.MX7D SoC
- zte: basic support for ZX296702 SoC"
* tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (134 commits)
ARM: zx: Add basic defconfig support for ZX296702
ARM: dts: zx: add an initial zx296702 dts and doc
clk: zx: add clock support to zx296702
dt-bindings: Add #defines for ZTE ZX296702 clocks
ARM: socfpga: fix build error due to secondary_startup
MAINTAINERS: ARM64: EXYNOS: Extend entry for ARM64 DTS
ARM: ep93xx: simone: support for SPI-based MMC/SD cards
MAINTAINERS: update Shawn's email to use kernel.org one
ARM: socfpga: support suspend to ram
ARM: socfpga: add CPU_METHOD_OF_DECLARE for Arria 10
ARM: socfpga: use CPU_METHOD_OF_DECLARE for socfpga_cyclone5
ARM: EXYNOS: register power domain driver from core_initcall
ARM: EXYNOS: use PS_HOLD based poweroff for all supported SoCs
ARM: SAMSUNG: Constify platform_device_id
ARM: EXYNOS: Constify irq_domain_ops
ARM: EXYNOS: add coupled cpuidle support for Exynos3250
ARM: EXYNOS: add exynos_get_boot_addr() helper
ARM: EXYNOS: add exynos_set_boot_addr() helper
ARM: EXYNOS: make exynos_core_restart() less verbose
ARM: EXYNOS: fix exynos_boot_secondary() return value on timeout
...
Diffstat (limited to 'arch/arm/mach-socfpga')
-rw-r--r-- | arch/arm/mach-socfpga/Kconfig | 11 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/core.h | 11 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/headsmp.S | 5 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/platsmp.c | 57 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/pm.c | 149 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/self-refresh.S | 136 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/socfpga.c | 41 |
8 files changed, 351 insertions, 60 deletions
diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig index b5f8d75d51a0..90efdeb56be5 100644 --- a/arch/arm/mach-socfpga/Kconfig +++ b/arch/arm/mach-socfpga/Kconfig | |||
@@ -1,5 +1,6 @@ | |||
1 | config ARCH_SOCFPGA | 1 | menuconfig ARCH_SOCFPGA |
2 | bool "Altera SOCFPGA family" if ARCH_MULTI_V7 | 2 | bool "Altera SOCFPGA family" if ARCH_MULTI_V7 |
3 | select ARCH_SUPPORTS_BIG_ENDIAN | ||
3 | select ARM_AMBA | 4 | select ARM_AMBA |
4 | select ARM_GIC | 5 | select ARM_GIC |
5 | select CACHE_L2X0 | 6 | select CACHE_L2X0 |
@@ -8,3 +9,11 @@ config ARCH_SOCFPGA | |||
8 | select HAVE_ARM_SCU | 9 | select HAVE_ARM_SCU |
9 | select HAVE_ARM_TWD if SMP | 10 | select HAVE_ARM_TWD if SMP |
10 | select MFD_SYSCON | 11 | select MFD_SYSCON |
12 | |||
13 | if ARCH_SOCFPGA | ||
14 | config SOCFPGA_SUSPEND | ||
15 | bool "Suspend to RAM on SOCFPGA" | ||
16 | help | ||
17 | Select this if you want to enable Suspend-to-RAM on SOCFPGA | ||
18 | platforms. | ||
19 | endif | ||
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile index 6dd7a93a90fe..b8f9e238e4ab 100644 --- a/arch/arm/mach-socfpga/Makefile +++ b/arch/arm/mach-socfpga/Makefile | |||
@@ -4,3 +4,4 @@ | |||
4 | 4 | ||
5 | obj-y := socfpga.o | 5 | obj-y := socfpga.o |
6 | obj-$(CONFIG_SMP) += headsmp.o platsmp.o | 6 | obj-$(CONFIG_SMP) += headsmp.o platsmp.o |
7 | obj-$(CONFIG_SOCFPGA_SUSPEND) += pm.o self-refresh.o | ||
diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h index 767c09e954a0..7259c3732702 100644 --- a/arch/arm/mach-socfpga/core.h +++ b/arch/arm/mach-socfpga/core.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2012 Pavel Machek <pavel@denx.de> | 2 | * Copyright 2012 Pavel Machek <pavel@denx.de> |
3 | * Copyright (C) 2012 Altera Corporation | 3 | * Copyright (C) 2012-2015 Altera Corporation |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -25,21 +25,24 @@ | |||
25 | #define SOCFPGA_RSTMGR_MODPERRST 0x14 | 25 | #define SOCFPGA_RSTMGR_MODPERRST 0x14 |
26 | #define SOCFPGA_RSTMGR_BRGMODRST 0x1c | 26 | #define SOCFPGA_RSTMGR_BRGMODRST 0x1c |
27 | 27 | ||
28 | #define SOCFPGA_A10_RSTMGR_MODMPURST 0x20 | ||
29 | |||
28 | /* System Manager bits */ | 30 | /* System Manager bits */ |
29 | #define RSTMGR_CTRL_SWCOLDRSTREQ 0x1 /* Cold Reset */ | 31 | #define RSTMGR_CTRL_SWCOLDRSTREQ 0x1 /* Cold Reset */ |
30 | #define RSTMGR_CTRL_SWWARMRSTREQ 0x2 /* Warm Reset */ | 32 | #define RSTMGR_CTRL_SWWARMRSTREQ 0x2 /* Warm Reset */ |
31 | 33 | ||
32 | #define RSTMGR_MPUMODRST_CPU1 0x2 /* CPU1 Reset */ | 34 | #define RSTMGR_MPUMODRST_CPU1 0x2 /* CPU1 Reset */ |
33 | 35 | ||
34 | extern void __iomem *socfpga_scu_base_addr; | ||
35 | |||
36 | extern void socfpga_init_clocks(void); | 36 | extern void socfpga_init_clocks(void); |
37 | extern void socfpga_sysmgr_init(void); | 37 | extern void socfpga_sysmgr_init(void); |
38 | 38 | ||
39 | extern void __iomem *sys_manager_base_addr; | 39 | extern void __iomem *sys_manager_base_addr; |
40 | extern void __iomem *rst_manager_base_addr; | 40 | extern void __iomem *rst_manager_base_addr; |
41 | extern void __iomem *sdr_ctl_base_addr; | ||
42 | |||
43 | u32 socfpga_sdram_self_refresh(u32 sdr_base); | ||
44 | extern unsigned int socfpga_sdram_self_refresh_sz; | ||
41 | 45 | ||
42 | extern struct smp_operations socfpga_smp_ops; | ||
43 | extern char secondary_trampoline, secondary_trampoline_end; | 46 | extern char secondary_trampoline, secondary_trampoline_end; |
44 | 47 | ||
45 | extern unsigned long socfpga_cpu1start_addr; | 48 | extern unsigned long socfpga_cpu1start_addr; |
diff --git a/arch/arm/mach-socfpga/headsmp.S b/arch/arm/mach-socfpga/headsmp.S index 5bb016427107..5d94b7a2fb10 100644 --- a/arch/arm/mach-socfpga/headsmp.S +++ b/arch/arm/mach-socfpga/headsmp.S | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/linkage.h> | 10 | #include <linux/linkage.h> |
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <asm/memory.h> | 12 | #include <asm/memory.h> |
13 | #include <asm/assembler.h> | ||
13 | 14 | ||
14 | .arch armv7-a | 15 | .arch armv7-a |
15 | 16 | ||
@@ -18,12 +19,14 @@ ENTRY(secondary_trampoline) | |||
18 | * Thus, we can just subtract the PAGE_OFFSET to get the physical | 19 | * Thus, we can just subtract the PAGE_OFFSET to get the physical |
19 | * address of &cpu1start_addr. This would not work for platforms | 20 | * address of &cpu1start_addr. This would not work for platforms |
20 | * where the physical memory does not start at 0x0. | 21 | * where the physical memory does not start at 0x0. |
21 | */ | 22 | */ |
23 | ARM_BE8(setend be) | ||
22 | adr r0, 1f | 24 | adr r0, 1f |
23 | ldmia r0, {r1, r2} | 25 | ldmia r0, {r1, r2} |
24 | sub r2, r2, #PAGE_OFFSET | 26 | sub r2, r2, #PAGE_OFFSET |
25 | ldr r3, [r2] | 27 | ldr r3, [r2] |
26 | ldr r4, [r3] | 28 | ldr r4, [r3] |
29 | ARM_BE8(rev r4, r4) | ||
27 | bx r4 | 30 | bx r4 |
28 | 31 | ||
29 | .align | 32 | .align |
diff --git a/arch/arm/mach-socfpga/platsmp.c b/arch/arm/mach-socfpga/platsmp.c index 79c5336c569f..c6f1df89f9af 100644 --- a/arch/arm/mach-socfpga/platsmp.c +++ b/arch/arm/mach-socfpga/platsmp.c | |||
@@ -54,32 +54,43 @@ static int socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle) | |||
54 | return 0; | 54 | return 0; |
55 | } | 55 | } |
56 | 56 | ||
57 | /* | 57 | static int socfpga_a10_boot_secondary(unsigned int cpu, struct task_struct *idle) |
58 | * Initialise the CPU possible map early - this describes the CPUs | ||
59 | * which may be present or become present in the system. | ||
60 | */ | ||
61 | static void __init socfpga_smp_init_cpus(void) | ||
62 | { | 58 | { |
63 | unsigned int i, ncores; | 59 | int trampoline_size = &secondary_trampoline_end - &secondary_trampoline; |
64 | 60 | ||
65 | ncores = scu_get_core_count(socfpga_scu_base_addr); | 61 | if (socfpga_cpu1start_addr) { |
62 | writel(RSTMGR_MPUMODRST_CPU1, rst_manager_base_addr + | ||
63 | SOCFPGA_A10_RSTMGR_MODMPURST); | ||
64 | memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size); | ||
66 | 65 | ||
67 | for (i = 0; i < ncores; i++) | 66 | writel(virt_to_phys(secondary_startup), |
68 | set_cpu_possible(i, true); | 67 | sys_manager_base_addr + (socfpga_cpu1start_addr & 0x00000fff)); |
69 | 68 | ||
70 | /* sanity check */ | 69 | flush_cache_all(); |
71 | if (ncores > num_possible_cpus()) { | 70 | smp_wmb(); |
72 | pr_warn("socfpga: no. of cores (%d) greater than configured" | 71 | outer_clean_range(0, trampoline_size); |
73 | "maximum of %d - clipping\n", ncores, num_possible_cpus()); | 72 | |
74 | ncores = num_possible_cpus(); | 73 | /* This will release CPU #1 out of reset. */ |
74 | writel(0, rst_manager_base_addr + SOCFPGA_A10_RSTMGR_MODMPURST); | ||
75 | } | 75 | } |
76 | 76 | ||
77 | for (i = 0; i < ncores; i++) | 77 | return 0; |
78 | set_cpu_possible(i, true); | ||
79 | } | 78 | } |
80 | 79 | ||
81 | static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus) | 80 | static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus) |
82 | { | 81 | { |
82 | struct device_node *np; | ||
83 | void __iomem *socfpga_scu_base_addr; | ||
84 | |||
85 | np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); | ||
86 | if (!np) { | ||
87 | pr_err("%s: missing scu\n", __func__); | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | socfpga_scu_base_addr = of_iomap(np, 0); | ||
92 | if (!socfpga_scu_base_addr) | ||
93 | return; | ||
83 | scu_enable(socfpga_scu_base_addr); | 94 | scu_enable(socfpga_scu_base_addr); |
84 | } | 95 | } |
85 | 96 | ||
@@ -95,11 +106,21 @@ static void socfpga_cpu_die(unsigned int cpu) | |||
95 | cpu_do_idle(); | 106 | cpu_do_idle(); |
96 | } | 107 | } |
97 | 108 | ||
98 | struct smp_operations socfpga_smp_ops __initdata = { | 109 | static struct smp_operations socfpga_smp_ops __initdata = { |
99 | .smp_init_cpus = socfpga_smp_init_cpus, | ||
100 | .smp_prepare_cpus = socfpga_smp_prepare_cpus, | 110 | .smp_prepare_cpus = socfpga_smp_prepare_cpus, |
101 | .smp_boot_secondary = socfpga_boot_secondary, | 111 | .smp_boot_secondary = socfpga_boot_secondary, |
102 | #ifdef CONFIG_HOTPLUG_CPU | 112 | #ifdef CONFIG_HOTPLUG_CPU |
103 | .cpu_die = socfpga_cpu_die, | 113 | .cpu_die = socfpga_cpu_die, |
104 | #endif | 114 | #endif |
105 | }; | 115 | }; |
116 | |||
117 | static struct smp_operations socfpga_a10_smp_ops __initdata = { | ||
118 | .smp_prepare_cpus = socfpga_smp_prepare_cpus, | ||
119 | .smp_boot_secondary = socfpga_a10_boot_secondary, | ||
120 | #ifdef CONFIG_HOTPLUG_CPU | ||
121 | .cpu_die = socfpga_cpu_die, | ||
122 | #endif | ||
123 | }; | ||
124 | |||
125 | CPU_METHOD_OF_DECLARE(socfpga_smp, "altr,socfpga-smp", &socfpga_smp_ops); | ||
126 | CPU_METHOD_OF_DECLARE(socfpga_a10_smp, "altr,socfpga-a10-smp", &socfpga_a10_smp_ops); | ||
diff --git a/arch/arm/mach-socfpga/pm.c b/arch/arm/mach-socfpga/pm.c new file mode 100644 index 000000000000..1ed89fc2b7a8 --- /dev/null +++ b/arch/arm/mach-socfpga/pm.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-socfpga/pm.c | ||
3 | * | ||
4 | * Copyright (C) 2014-2015 Altera Corporation. All rights reserved. | ||
5 | * | ||
6 | * with code from pm-imx6.c | ||
7 | * Copyright 2011-2014 Freescale Semiconductor, Inc. | ||
8 | * Copyright 2011 Linaro Ltd. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms and conditions of the GNU General Public License, | ||
12 | * version 2, as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along with | ||
20 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
21 | */ | ||
22 | |||
23 | #include <linux/bitops.h> | ||
24 | #include <linux/genalloc.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/of_platform.h> | ||
28 | #include <linux/suspend.h> | ||
29 | #include <asm/suspend.h> | ||
30 | #include <asm/fncpy.h> | ||
31 | #include "core.h" | ||
32 | |||
33 | /* Pointer to function copied to ocram */ | ||
34 | static u32 (*socfpga_sdram_self_refresh_in_ocram)(u32 sdr_base); | ||
35 | |||
36 | static int socfpga_setup_ocram_self_refresh(void) | ||
37 | { | ||
38 | struct platform_device *pdev; | ||
39 | phys_addr_t ocram_pbase; | ||
40 | struct device_node *np; | ||
41 | struct gen_pool *ocram_pool; | ||
42 | unsigned long ocram_base; | ||
43 | void __iomem *suspend_ocram_base; | ||
44 | int ret = 0; | ||
45 | |||
46 | np = of_find_compatible_node(NULL, NULL, "mmio-sram"); | ||
47 | if (!np) { | ||
48 | pr_err("%s: Unable to find mmio-sram in dtb\n", __func__); | ||
49 | return -ENODEV; | ||
50 | } | ||
51 | |||
52 | pdev = of_find_device_by_node(np); | ||
53 | if (!pdev) { | ||
54 | pr_warn("%s: failed to find ocram device!\n", __func__); | ||
55 | ret = -ENODEV; | ||
56 | goto put_node; | ||
57 | } | ||
58 | |||
59 | ocram_pool = dev_get_gen_pool(&pdev->dev); | ||
60 | if (!ocram_pool) { | ||
61 | pr_warn("%s: ocram pool unavailable!\n", __func__); | ||
62 | ret = -ENODEV; | ||
63 | goto put_node; | ||
64 | } | ||
65 | |||
66 | ocram_base = gen_pool_alloc(ocram_pool, socfpga_sdram_self_refresh_sz); | ||
67 | if (!ocram_base) { | ||
68 | pr_warn("%s: unable to alloc ocram!\n", __func__); | ||
69 | ret = -ENOMEM; | ||
70 | goto put_node; | ||
71 | } | ||
72 | |||
73 | ocram_pbase = gen_pool_virt_to_phys(ocram_pool, ocram_base); | ||
74 | |||
75 | suspend_ocram_base = __arm_ioremap_exec(ocram_pbase, | ||
76 | socfpga_sdram_self_refresh_sz, | ||
77 | false); | ||
78 | if (!suspend_ocram_base) { | ||
79 | pr_warn("%s: __arm_ioremap_exec failed!\n", __func__); | ||
80 | ret = -ENOMEM; | ||
81 | goto put_node; | ||
82 | } | ||
83 | |||
84 | /* Copy the code that puts DDR in self refresh to ocram */ | ||
85 | socfpga_sdram_self_refresh_in_ocram = | ||
86 | (void *)fncpy(suspend_ocram_base, | ||
87 | &socfpga_sdram_self_refresh, | ||
88 | socfpga_sdram_self_refresh_sz); | ||
89 | |||
90 | WARN(!socfpga_sdram_self_refresh_in_ocram, | ||
91 | "could not copy function to ocram"); | ||
92 | if (!socfpga_sdram_self_refresh_in_ocram) | ||
93 | ret = -EFAULT; | ||
94 | |||
95 | put_node: | ||
96 | of_node_put(np); | ||
97 | |||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | static int socfpga_pm_suspend(unsigned long arg) | ||
102 | { | ||
103 | u32 ret; | ||
104 | |||
105 | if (!sdr_ctl_base_addr) | ||
106 | return -EFAULT; | ||
107 | |||
108 | ret = socfpga_sdram_self_refresh_in_ocram((u32)sdr_ctl_base_addr); | ||
109 | |||
110 | pr_debug("%s self-refresh loops request=%d exit=%d\n", __func__, | ||
111 | ret & 0xffff, (ret >> 16) & 0xffff); | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int socfpga_pm_enter(suspend_state_t state) | ||
117 | { | ||
118 | switch (state) { | ||
119 | case PM_SUSPEND_STANDBY: | ||
120 | case PM_SUSPEND_MEM: | ||
121 | outer_disable(); | ||
122 | cpu_suspend(0, socfpga_pm_suspend); | ||
123 | outer_resume(); | ||
124 | break; | ||
125 | default: | ||
126 | return -EINVAL; | ||
127 | } | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static const struct platform_suspend_ops socfpga_pm_ops = { | ||
132 | .valid = suspend_valid_only_mem, | ||
133 | .enter = socfpga_pm_enter, | ||
134 | }; | ||
135 | |||
136 | static int __init socfpga_pm_init(void) | ||
137 | { | ||
138 | int ret; | ||
139 | |||
140 | ret = socfpga_setup_ocram_self_refresh(); | ||
141 | if (ret) | ||
142 | return ret; | ||
143 | |||
144 | suspend_set_ops(&socfpga_pm_ops); | ||
145 | pr_info("SoCFPGA initialized for DDR self-refresh during suspend.\n"); | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | arch_initcall(socfpga_pm_init); | ||
diff --git a/arch/arm/mach-socfpga/self-refresh.S b/arch/arm/mach-socfpga/self-refresh.S new file mode 100644 index 000000000000..f2d7f883e33d --- /dev/null +++ b/arch/arm/mach-socfpga/self-refresh.S | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2015 Altera Corporation. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | #include <linux/linkage.h> | ||
17 | #include <asm/assembler.h> | ||
18 | |||
19 | #define MAX_LOOP_COUNT 1000 | ||
20 | |||
21 | /* Register offset */ | ||
22 | #define SDR_CTRLGRP_LOWPWREQ_ADDR 0x54 | ||
23 | #define SDR_CTRLGRP_LOWPWRACK_ADDR 0x58 | ||
24 | |||
25 | /* Bitfield positions */ | ||
26 | #define SELFRSHREQ_POS 3 | ||
27 | #define SELFRSHREQ_MASK 0x8 | ||
28 | |||
29 | #define SELFRFSHACK_POS 1 | ||
30 | #define SELFRFSHACK_MASK 0x2 | ||
31 | |||
32 | /* | ||
33 | * This code assumes that when the bootloader configured | ||
34 | * the sdram controller for the DDR on the board it | ||
35 | * configured the following fields depending on the DDR | ||
36 | * vendor/configuration: | ||
37 | * | ||
38 | * sdr.ctrlcfg.lowpwreq.selfrfshmask | ||
39 | * sdr.ctrlcfg.lowpwrtiming.clkdisablecycles | ||
40 | * sdr.ctrlcfg.dramtiming4.selfrfshexit | ||
41 | */ | ||
42 | |||
43 | .arch armv7-a | ||
44 | .text | ||
45 | .align 3 | ||
46 | |||
47 | /* | ||
48 | * socfpga_sdram_self_refresh | ||
49 | * | ||
50 | * r0 : sdr_ctl_base_addr | ||
51 | * r1 : temp storage of return value | ||
52 | * r2 : temp storage of register values | ||
53 | * r3 : loop counter | ||
54 | * | ||
55 | * return value: lower 16 bits: loop count going into self refresh | ||
56 | * upper 16 bits: loop count exiting self refresh | ||
57 | */ | ||
58 | ENTRY(socfpga_sdram_self_refresh) | ||
59 | /* Enable dynamic clock gating in the Power Control Register. */ | ||
60 | mrc p15, 0, r2, c15, c0, 0 | ||
61 | orr r2, r2, #1 | ||
62 | mcr p15, 0, r2, c15, c0, 0 | ||
63 | |||
64 | /* Enable self refresh: set sdr.ctrlgrp.lowpwreq.selfrshreq = 1 */ | ||
65 | ldr r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR] | ||
66 | orr r2, r2, #SELFRSHREQ_MASK | ||
67 | str r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR] | ||
68 | |||
69 | /* Poll until sdr.ctrlgrp.lowpwrack.selfrfshack == 1 or hit max loops */ | ||
70 | mov r3, #0 | ||
71 | while_ack_0: | ||
72 | ldr r2, [r0, #SDR_CTRLGRP_LOWPWRACK_ADDR] | ||
73 | and r2, r2, #SELFRFSHACK_MASK | ||
74 | cmp r2, #SELFRFSHACK_MASK | ||
75 | beq ack_1 | ||
76 | |||
77 | add r3, #1 | ||
78 | cmp r3, #MAX_LOOP_COUNT | ||
79 | bne while_ack_0 | ||
80 | |||
81 | ack_1: | ||
82 | mov r1, r3 | ||
83 | |||
84 | /* | ||
85 | * Execute an ISB instruction to ensure that all of the | ||
86 | * CP15 register changes have been committed. | ||
87 | */ | ||
88 | isb | ||
89 | |||
90 | /* | ||
91 | * Execute a barrier instruction to ensure that all cache, | ||
92 | * TLB and branch predictor maintenance operations issued | ||
93 | * by any CPU in the cluster have completed. | ||
94 | */ | ||
95 | dsb | ||
96 | dmb | ||
97 | |||
98 | wfi | ||
99 | |||
100 | /* Disable self-refresh: set sdr.ctrlgrp.lowpwreq.selfrshreq = 0 */ | ||
101 | ldr r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR] | ||
102 | bic r2, r2, #SELFRSHREQ_MASK | ||
103 | str r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR] | ||
104 | |||
105 | /* Poll until sdr.ctrlgrp.lowpwrack.selfrfshack == 0 or hit max loops */ | ||
106 | mov r3, #0 | ||
107 | while_ack_1: | ||
108 | ldr r2, [r0, #SDR_CTRLGRP_LOWPWRACK_ADDR] | ||
109 | and r2, r2, #SELFRFSHACK_MASK | ||
110 | cmp r2, #SELFRFSHACK_MASK | ||
111 | bne ack_0 | ||
112 | |||
113 | add r3, #1 | ||
114 | cmp r3, #MAX_LOOP_COUNT | ||
115 | bne while_ack_1 | ||
116 | |||
117 | ack_0: | ||
118 | /* | ||
119 | * Prepare return value: | ||
120 | * Shift loop count for exiting self refresh into upper 16 bits. | ||
121 | * Leave loop count for requesting self refresh in lower 16 bits. | ||
122 | */ | ||
123 | mov r3, r3, lsl #16 | ||
124 | add r1, r1, r3 | ||
125 | |||
126 | /* Disable dynamic clock gating in the Power Control Register. */ | ||
127 | mrc p15, 0, r2, c15, c0, 0 | ||
128 | bic r2, r2, #1 | ||
129 | mcr p15, 0, r2, c15, c0, 0 | ||
130 | |||
131 | mov r0, r1 @ return value | ||
132 | bx lr @ return | ||
133 | |||
134 | ENDPROC(socfpga_sdram_self_refresh) | ||
135 | ENTRY(socfpga_sdram_self_refresh_sz) | ||
136 | .word . - socfpga_sdram_self_refresh | ||
diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c index f5e597c207b9..19643a756c48 100644 --- a/arch/arm/mach-socfpga/socfpga.c +++ b/arch/arm/mach-socfpga/socfpga.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2012 Altera Corporation | 2 | * Copyright (C) 2012-2015 Altera Corporation |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | 5 | * it under the terms of the GNU General Public License as published by |
@@ -27,43 +27,11 @@ | |||
27 | 27 | ||
28 | #include "core.h" | 28 | #include "core.h" |
29 | 29 | ||
30 | void __iomem *socfpga_scu_base_addr = ((void __iomem *)(SOCFPGA_SCU_VIRT_BASE)); | ||
31 | void __iomem *sys_manager_base_addr; | 30 | void __iomem *sys_manager_base_addr; |
32 | void __iomem *rst_manager_base_addr; | 31 | void __iomem *rst_manager_base_addr; |
32 | void __iomem *sdr_ctl_base_addr; | ||
33 | unsigned long socfpga_cpu1start_addr; | 33 | unsigned long socfpga_cpu1start_addr; |
34 | 34 | ||
35 | static struct map_desc scu_io_desc __initdata = { | ||
36 | .virtual = SOCFPGA_SCU_VIRT_BASE, | ||
37 | .pfn = 0, /* run-time */ | ||
38 | .length = SZ_8K, | ||
39 | .type = MT_DEVICE, | ||
40 | }; | ||
41 | |||
42 | static struct map_desc uart_io_desc __initdata = { | ||
43 | .virtual = 0xfec02000, | ||
44 | .pfn = __phys_to_pfn(0xffc02000), | ||
45 | .length = SZ_8K, | ||
46 | .type = MT_DEVICE, | ||
47 | }; | ||
48 | |||
49 | static void __init socfpga_scu_map_io(void) | ||
50 | { | ||
51 | unsigned long base; | ||
52 | |||
53 | /* Get SCU base */ | ||
54 | asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base)); | ||
55 | |||
56 | scu_io_desc.pfn = __phys_to_pfn(base); | ||
57 | iotable_init(&scu_io_desc, 1); | ||
58 | } | ||
59 | |||
60 | static void __init socfpga_map_io(void) | ||
61 | { | ||
62 | socfpga_scu_map_io(); | ||
63 | iotable_init(&uart_io_desc, 1); | ||
64 | early_printk("Early printk initialized\n"); | ||
65 | } | ||
66 | |||
67 | void __init socfpga_sysmgr_init(void) | 35 | void __init socfpga_sysmgr_init(void) |
68 | { | 36 | { |
69 | struct device_node *np; | 37 | struct device_node *np; |
@@ -82,6 +50,9 @@ void __init socfpga_sysmgr_init(void) | |||
82 | 50 | ||
83 | np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr"); | 51 | np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr"); |
84 | rst_manager_base_addr = of_iomap(np, 0); | 52 | rst_manager_base_addr = of_iomap(np, 0); |
53 | |||
54 | np = of_find_compatible_node(NULL, NULL, "altr,sdr-ctl"); | ||
55 | sdr_ctl_base_addr = of_iomap(np, 0); | ||
85 | } | 56 | } |
86 | 57 | ||
87 | static void __init socfpga_init_irq(void) | 58 | static void __init socfpga_init_irq(void) |
@@ -111,8 +82,6 @@ static const char *altera_dt_match[] = { | |||
111 | DT_MACHINE_START(SOCFPGA, "Altera SOCFPGA") | 82 | DT_MACHINE_START(SOCFPGA, "Altera SOCFPGA") |
112 | .l2c_aux_val = 0, | 83 | .l2c_aux_val = 0, |
113 | .l2c_aux_mask = ~0, | 84 | .l2c_aux_mask = ~0, |
114 | .smp = smp_ops(socfpga_smp_ops), | ||
115 | .map_io = socfpga_map_io, | ||
116 | .init_irq = socfpga_init_irq, | 85 | .init_irq = socfpga_init_irq, |
117 | .restart = socfpga_cyclone5_restart, | 86 | .restart = socfpga_cyclone5_restart, |
118 | .dt_compat = altera_dt_match, | 87 | .dt_compat = altera_dt_match, |