diff options
Diffstat (limited to 'arch/arm/mach-exynos/mcpm-exynos.c')
| -rw-r--r-- | arch/arm/mach-exynos/mcpm-exynos.c | 66 |
1 files changed, 31 insertions, 35 deletions
diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c index 13a210865c6f..9315ba91c1fb 100644 --- a/arch/arm/mach-exynos/mcpm-exynos.c +++ b/arch/arm/mach-exynos/mcpm-exynos.c | |||
| @@ -26,6 +26,10 @@ | |||
| 26 | #define EXYNOS5420_CPUS_PER_CLUSTER 4 | 26 | #define EXYNOS5420_CPUS_PER_CLUSTER 4 |
| 27 | #define EXYNOS5420_NR_CLUSTERS 2 | 27 | #define EXYNOS5420_NR_CLUSTERS 2 |
| 28 | 28 | ||
| 29 | #define EXYNOS5420_ENABLE_AUTOMATIC_CORE_DOWN BIT(9) | ||
| 30 | #define EXYNOS5420_USE_ARM_CORE_DOWN_STATE BIT(29) | ||
| 31 | #define EXYNOS5420_USE_L2_COMMON_UP_STATE BIT(30) | ||
| 32 | |||
| 29 | /* | 33 | /* |
| 30 | * The common v7_exit_coherency_flush API could not be used because of the | 34 | * The common v7_exit_coherency_flush API could not be used because of the |
| 31 | * Erratum 799270 workaround. This macro is the same as the common one (in | 35 | * Erratum 799270 workaround. This macro is the same as the common one (in |
| @@ -73,36 +77,9 @@ cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS]; | |||
| 73 | 77 | ||
| 74 | #define exynos_cluster_unused(cluster) !exynos_cluster_usecnt(cluster) | 78 | #define exynos_cluster_unused(cluster) !exynos_cluster_usecnt(cluster) |
| 75 | 79 | ||
| 76 | static int exynos_cluster_power_control(unsigned int cluster, int enable) | ||
| 77 | { | ||
| 78 | unsigned int tries = 100; | ||
| 79 | unsigned int val; | ||
| 80 | |||
| 81 | if (enable) { | ||
| 82 | exynos_cluster_power_up(cluster); | ||
| 83 | val = S5P_CORE_LOCAL_PWR_EN; | ||
| 84 | } else { | ||
| 85 | exynos_cluster_power_down(cluster); | ||
| 86 | val = 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | /* Wait until cluster power control is applied */ | ||
| 90 | while (tries--) { | ||
| 91 | if (exynos_cluster_power_state(cluster) == val) | ||
| 92 | return 0; | ||
| 93 | |||
| 94 | cpu_relax(); | ||
| 95 | } | ||
| 96 | pr_debug("timed out waiting for cluster %u to power %s\n", cluster, | ||
| 97 | enable ? "on" : "off"); | ||
| 98 | |||
| 99 | return -ETIMEDOUT; | ||
| 100 | } | ||
| 101 | |||
| 102 | static int exynos_power_up(unsigned int cpu, unsigned int cluster) | 80 | static int exynos_power_up(unsigned int cpu, unsigned int cluster) |
| 103 | { | 81 | { |
| 104 | unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER); | 82 | unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER); |
| 105 | int err = 0; | ||
| 106 | 83 | ||
| 107 | pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); | 84 | pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); |
| 108 | if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER || | 85 | if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER || |
| @@ -126,12 +103,9 @@ static int exynos_power_up(unsigned int cpu, unsigned int cluster) | |||
| 126 | * cores. | 103 | * cores. |
| 127 | */ | 104 | */ |
| 128 | if (was_cluster_down) | 105 | if (was_cluster_down) |
| 129 | err = exynos_cluster_power_control(cluster, 1); | 106 | exynos_cluster_power_up(cluster); |
| 130 | 107 | ||
| 131 | if (!err) | 108 | exynos_cpu_power_up(cpunr); |
| 132 | exynos_cpu_power_up(cpunr); | ||
| 133 | else | ||
| 134 | exynos_cluster_power_control(cluster, 0); | ||
| 135 | } else if (cpu_use_count[cpu][cluster] != 2) { | 109 | } else if (cpu_use_count[cpu][cluster] != 2) { |
| 136 | /* | 110 | /* |
| 137 | * The only possible values are: | 111 | * The only possible values are: |
| @@ -147,7 +121,7 @@ static int exynos_power_up(unsigned int cpu, unsigned int cluster) | |||
| 147 | arch_spin_unlock(&exynos_mcpm_lock); | 121 | arch_spin_unlock(&exynos_mcpm_lock); |
| 148 | local_irq_enable(); | 122 | local_irq_enable(); |
| 149 | 123 | ||
| 150 | return err; | 124 | return 0; |
| 151 | } | 125 | } |
| 152 | 126 | ||
| 153 | /* | 127 | /* |
| @@ -178,9 +152,10 @@ static void exynos_power_down(void) | |||
| 178 | if (cpu_use_count[cpu][cluster] == 0) { | 152 | if (cpu_use_count[cpu][cluster] == 0) { |
| 179 | exynos_cpu_power_down(cpunr); | 153 | exynos_cpu_power_down(cpunr); |
| 180 | 154 | ||
| 181 | if (exynos_cluster_unused(cluster)) | 155 | if (exynos_cluster_unused(cluster)) { |
| 182 | /* TODO: Turn off the cluster here to save power. */ | 156 | exynos_cluster_power_down(cluster); |
| 183 | last_man = true; | 157 | last_man = true; |
| 158 | } | ||
| 184 | } else if (cpu_use_count[cpu][cluster] == 1) { | 159 | } else if (cpu_use_count[cpu][cluster] == 1) { |
| 185 | /* | 160 | /* |
| 186 | * A power_up request went ahead of us. | 161 | * A power_up request went ahead of us. |
| @@ -335,6 +310,7 @@ static int __init exynos_mcpm_init(void) | |||
| 335 | { | 310 | { |
| 336 | struct device_node *node; | 311 | struct device_node *node; |
| 337 | void __iomem *ns_sram_base_addr; | 312 | void __iomem *ns_sram_base_addr; |
| 313 | unsigned int value, i; | ||
| 338 | int ret; | 314 | int ret; |
| 339 | 315 | ||
| 340 | node = of_find_matching_node(NULL, exynos_dt_mcpm_match); | 316 | node = of_find_matching_node(NULL, exynos_dt_mcpm_match); |
| @@ -378,6 +354,26 @@ static int __init exynos_mcpm_init(void) | |||
| 378 | pr_info("Exynos MCPM support installed\n"); | 354 | pr_info("Exynos MCPM support installed\n"); |
| 379 | 355 | ||
| 380 | /* | 356 | /* |
| 357 | * On Exynos5420/5800 for the A15 and A7 clusters: | ||
| 358 | * | ||
| 359 | * EXYNOS5420_ENABLE_AUTOMATIC_CORE_DOWN ensures that all the cores | ||
| 360 | * in a cluster are turned off before turning off the cluster L2. | ||
| 361 | * | ||
| 362 | * EXYNOS5420_USE_ARM_CORE_DOWN_STATE ensures that a cores is powered | ||
| 363 | * off before waking it up. | ||
| 364 | * | ||
| 365 | * EXYNOS5420_USE_L2_COMMON_UP_STATE ensures that cluster L2 will be | ||
| 366 | * turned on before the first man is powered up. | ||
| 367 | */ | ||
| 368 | for (i = 0; i < EXYNOS5420_NR_CLUSTERS; i++) { | ||
| 369 | value = __raw_readl(EXYNOS_COMMON_OPTION(i)); | ||
| 370 | value |= EXYNOS5420_ENABLE_AUTOMATIC_CORE_DOWN | | ||
| 371 | EXYNOS5420_USE_ARM_CORE_DOWN_STATE | | ||
| 372 | EXYNOS5420_USE_L2_COMMON_UP_STATE; | ||
| 373 | __raw_writel(value, EXYNOS_COMMON_OPTION(i)); | ||
| 374 | } | ||
| 375 | |||
| 376 | /* | ||
| 381 | * U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr | 377 | * U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr |
| 382 | * as part of secondary_cpu_start(). Let's redirect it to the | 378 | * as part of secondary_cpu_start(). Let's redirect it to the |
| 383 | * mcpm_entry_point(). | 379 | * mcpm_entry_point(). |
