[linux-yocto] [PATCH 13/35] arch/arm/mach-axxia: Support for CPU Hotplug
Bruce Ashfield
bruce.ashfield at windriver.com
Sun Nov 16 20:43:04 PST 2014
On 2014-11-13, 12:19 PM, Daniel Dragomir wrote:
> From: John Jacques <john.jacques at lsi.com>
>
> This includes powering down a cluster when all four cores are
> off and powering up the cluster when one of the cores gets
> re-enabled.
This is a fairly sizeable patch. Isn't that power management change
doing more than adding cpu hotplug support ?
Bruce
>
> Signed-off-by: John Jacques <john.jacques at lsi.com>
> ---
> arch/arm/mach-axxia/Makefile | 2 +-
> arch/arm/mach-axxia/axxia-gic.c | 10 +-
> arch/arm/mach-axxia/axxia.h | 1 +
> arch/arm/mach-axxia/hotplug.c | 76 +-
> arch/arm/mach-axxia/lsi_power_management.c | 1522 ++++++++++++++++++++++++++++
> arch/arm/mach-axxia/lsi_power_management.h | 183 ++++
> arch/arm/mach-axxia/platsmp.c | 44 +-
> 7 files changed, 1778 insertions(+), 60 deletions(-)
> create mode 100644 arch/arm/mach-axxia/lsi_power_management.c
> create mode 100644 arch/arm/mach-axxia/lsi_power_management.h
>
> diff --git a/arch/arm/mach-axxia/Makefile b/arch/arm/mach-axxia/Makefile
> index a4ecf4e..720857b 100644
> --- a/arch/arm/mach-axxia/Makefile
> +++ b/arch/arm/mach-axxia/Makefile
> @@ -12,5 +12,5 @@ obj-y += ddr_retention.o ddr_shutdown.o
> obj-$(CONFIG_I2C) += i2c.o
> obj-$(CONFIG_SMP) += platsmp.o headsmp.o
> obj-$(CONFIG_ARCH_AXXIA_GIC) += axxia-gic.o
> -obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
> +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o lsi_power_management.o
> obj-$(CONFIG_AXXIA_RIO) += rapidio.o
> diff --git a/arch/arm/mach-axxia/axxia-gic.c b/arch/arm/mach-axxia/axxia-gic.c
> index 53e525a..c670f3d 100644
> --- a/arch/arm/mach-axxia/axxia-gic.c
> +++ b/arch/arm/mach-axxia/axxia-gic.c
> @@ -45,6 +45,7 @@
> #include <asm/mach/irq.h>
>
> #include <mach/axxia-gic.h>
> +#include "lsi_power_management.h"
>
> #define MAX_GIC_INTERRUPTS 1020
> #define MAX_NUM_CLUSTERS 4
> @@ -1057,9 +1058,10 @@ static void __cpuinit gic_dist_init(struct gic_chip_data *gic)
> u32 enablemask;
> u32 enableoff;
> u32 val;
> + u32 this_cluster = get_cluster_id();
>
> /* Initialize the distributor interface once per CPU cluster */
> - if (test_and_set_bit(get_cluster_id(), &gic->dist_init_done))
> + if ((test_and_set_bit(get_cluster_id(), &gic->dist_init_done)) && (!cluster_power_up[this_cluster]))
> return;
>
> cpumask = 1 << cpu;
> @@ -1362,6 +1364,12 @@ void __cpuinit axxia_gic_secondary_init(void)
> gic_cpu_init(&gic_data);
> }
>
> +void __cpuinit axxia_hotplug_gic_secondary_init(void)
> +{
> + struct gic_chip_data *gic = &gic_data;
> + gic_cpu_init(&gic_data);
> +}
> +
> #ifdef CONFIG_OF
>
> int __init axxia_gic_of_init(struct device_node *node,
> diff --git a/arch/arm/mach-axxia/axxia.h b/arch/arm/mach-axxia/axxia.h
> index 156c6e0..000adc8 100644
> --- a/arch/arm/mach-axxia/axxia.h
> +++ b/arch/arm/mach-axxia/axxia.h
> @@ -3,6 +3,7 @@
> void axxia_init_clocks(int is_sim);
> void axxia_ddr_retention_init(void);
> void axxia_platform_cpu_die(unsigned int cpu);
> +int axxia_platform_cpu_kill(unsigned int cpu);
>
> extern struct smp_operations axxia_smp_ops;
>
> diff --git a/arch/arm/mach-axxia/hotplug.c b/arch/arm/mach-axxia/hotplug.c
> index fb5ec90..9e82bdc 100644
> --- a/arch/arm/mach-axxia/hotplug.c
> +++ b/arch/arm/mach-axxia/hotplug.c
> @@ -15,6 +15,8 @@
> #include <asm/cacheflush.h>
> #include <asm/smp_plat.h>
> #include <asm/cp15.h>
> +#include "lsi_power_management.h"
> +
>
> extern volatile int pen_release;
>
> @@ -63,49 +65,10 @@ static inline void cpu_leave_lowpower(void)
> : "cc");
> }
>
> -static void __ref platform_do_lowpower(unsigned int cpu, int *spurious)
> -{
> - int phys_cpu, cluster;
>
> - /*
> - * there is no power-control hardware on this platform, so all
> - * we can do is put the core into WFI; this is safe as the calling
> - * code will have already disabled interrupts
> - */
> - for (;;) {
> - wfi();
> -
> - /*
> - * Convert the "cpu" variable to be compatible with the
> - * ARM MPIDR register format (CLUSTERID and CPUID):
> - *
> - * Bits: |11 10 9 8|7 6 5 4 3 2|1 0
> - * | CLUSTER | Reserved |CPU
> - */
> - phys_cpu = cpu_logical_map(cpu);
> - cluster = (phys_cpu / 4) << 8;
> - phys_cpu = cluster + (phys_cpu % 4);
> -
> - if (pen_release == phys_cpu) {
> - /*
> - * OK, proper wakeup, we're done
> - */
> - break;
> - }
> -
> - /*
> - * Getting here, means that we have come out of WFI without
> - * having been woken up - this shouldn't happen
> - *
> - * Just note it happening - when we're woken, we can report
> - * its occurrence.
> - */
> - (*spurious)++;
> - }
> -}
> -
> -int platform_cpu_kill(unsigned int cpu)
> +int axxia_platform_cpu_kill(unsigned int cpu)
> {
> + pm_cpu_shutdown(cpu);
> return 1;
> }
>
> @@ -114,24 +77,29 @@ int platform_cpu_kill(unsigned int cpu)
> *
> * Called with IRQs disabled
> */
> +
> void axxia_platform_cpu_die(unsigned int cpu)
> {
> - int spurious = 0;
>
> - /*
> - * we're ready for shutdown now, so do it
> - */
> - cpu_enter_lowpower_a15();
> - platform_do_lowpower(cpu, &spurious);
> + pm_data pm_request;
> + int rVal = 0;
> + bool lastCpu;
>
> - /*
> - * bring this CPU back into the world of cache
> - * coherency, and then restore interrupts
> - */
> - cpu_leave_lowpower();
> + pm_request.cpu = cpu;
> + pm_request.cluster = 0;
> +
> +
> + lastCpu = pm_cpu_last_of_cluster(cpu);
> + if (lastCpu)
> + rVal = pm_cpul2_logical_die(&pm_request);
> + else
> + rVal = pm_cpu_logical_die(&pm_request);
> + if (rVal)
> + pr_err("CPU %d failed to die\n", cpu);
> +
> + for (;;)
> + wfi();
>
> - if (spurious)
> - pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
> }
>
> int platform_cpu_disable(unsigned int cpu)
> diff --git a/arch/arm/mach-axxia/lsi_power_management.c b/arch/arm/mach-axxia/lsi_power_management.c
> new file mode 100644
> index 0000000..9723054
> --- /dev/null
> +++ b/arch/arm/mach-axxia/lsi_power_management.c
> @@ -0,0 +1,1522 @@
> +/*
> + * linux/arch/arm/mach-axxia/lsi_power_management.c
> + *
> + * C * Created on: Jun 19, 2014
> + * Author: z8cpaul
> + * opyright (C) 2002 ARM Ltd.
> + * All Rights Reserved
> + *
> + * 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.
> + *
> + * Created on: Jun 19, 2014
> + * Author: z8cpaul
> + */
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/smp.h>
> +#include <linux/delay.h>
> +#include <asm/exception.h>
> +#include <asm/cacheflush.h>
> +#include <asm/smp_plat.h>
> +#include <asm/cp15.h>
> +
> +#include "axxia.h"
> +#include "lsi_power_management.h"
> +
> +#undef DEBUG_CPU_PM
> +
> +#define SYSCON_PHYS_ADDR 0x002010030000ULL
> +#define DICKENS_PHYS_ADDR 0x2000000000
> +
> +#define PM_WAIT_TIME (10000)
> +#define MAX_CLUSTER (4)
> +
> +#define CHECK_BIT(var, pos) ((var) & (1 << (pos)))
> +
> +bool pm_in_progress[16];
> +bool cluster_power_up[4];
> +
> +static const u32 cluster_to_node[MAX_CLUSTER] = { DKN_CLUSTER0_NODE,
> +DKN_CLUSTER1_NODE,
> +DKN_CLUSTER2_NODE,
> +DKN_CLUSTER3_NODE };
> +
> +static const u32 cluster_to_poreset[MAX_CLUSTER] = {
> +PORESET_CLUSTER0,
> +PORESET_CLUSTER1,
> +PORESET_CLUSTER2,
> +PORESET_CLUSTER3 };
> +
> +static u32 pm_cpu_powered_down;
> +
> +/*======================= LOCAL FUNCTIONS ==============================*/
> +static void pm_set_bits_syscon_register(void __iomem *syscon, u32 reg, u32 data);
> +static void pm_clear_bits_syscon_register(void __iomem *syscon, u32 reg, u32 data);
> +static bool pm_test_for_bit_with_timeout(void __iomem *syscon, u32 reg, u32 bit);
> +static bool pm_wait_for_bit_clear_with_timeout(void __iomem *syscon, u32 reg,
> + u32 bit);
> +static void pm_dickens_logical_shutdown(u32 cluster);
> +static int pm_dickens_logical_powerup(u32 cluster);
> +static int pm_cpu_physical_isolation_and_power_down(int cpu);
> +static void pm_L2_isolation_and_power_down(int cluster);
> +static void __pm_cpu_shutdown(void *data);
> +static int pm_cpu_physical_connection_and_power_up(int cpu);
> +static int pm_L2_physical_connection_and_power_up(u32 cluster);
> +static int pm_L2_logical_powerup(u32 cluster, u32 cpu);
> +
> +static bool pm_first_cpu_of_cluster(u32 cpu)
> +{
> + u32 count = 0;
> + switch (cpu) {
> + case (0):
> + case (1):
> + case (2):
> + case (3):
> + /* This will never happen because cpu 0 will never be turned off */
> + break;
> + case (4):
> + case (5):
> + case (6):
> + case (7):
> + if (pm_cpu_powered_down & (1 << 4))
> + count++;
> + if (pm_cpu_powered_down & (1 << 5))
> + count++;
> + if (pm_cpu_powered_down & (1 << 6))
> + count++;
> + if (pm_cpu_powered_down & (1 << 7))
> + count++;
> + if (count == 4)
> + return true;
> + break;
> + case (8):
> + case (9):
> + case (10):
> + case (11):
> + if (pm_cpu_powered_down & (1 << 8))
> + count++;
> + if (pm_cpu_powered_down & (1 << 9))
> + count++;
> + if (pm_cpu_powered_down & (1 << 10))
> + count++;
> + if (pm_cpu_powered_down & (1 << 11))
> + count++;
> + if (count == 4)
> + return true;
> + break;
> + case (12):
> + case (13):
> + case (14):
> + case (15):
> + if (pm_cpu_powered_down & (1 << 12))
> + count++;
> + if (pm_cpu_powered_down & (1 << 13))
> + count++;
> + if (pm_cpu_powered_down & (1 << 14))
> + count++;
> + if (pm_cpu_powered_down & (1 << 15))
> + count++;
> + if (count == 4)
> + return true;
> + break;
> + default:
> + pr_err("ERROR: the cpu does not exist: %d - %s:%d\n", cpu, __FILE__,
> + __LINE__);
> + break;
> + }
> + return false;
> +}
> +
> +bool pm_cpu_last_of_cluster(u32 cpu)
> +{
> + u32 count = 0;
> + switch (cpu) {
> + case (0):
> + case (1):
> + case (2):
> + case (3):
> + /* This will never happen because cpu 0 will never be turned off */
> + break;
> + case (4):
> + case (5):
> + case (6):
> + case (7):
> + if (pm_cpu_powered_down & (1 << 4))
> + count++;
> + if (pm_cpu_powered_down & (1 << 5))
> + count++;
> + if (pm_cpu_powered_down & (1 << 6))
> + count++;
> + if (pm_cpu_powered_down & (1 << 7))
> + count++;
> + if (count == 3)
> + return true;
> + break;
> + case (8):
> + case (9):
> + case (10):
> + case (11):
> + if (pm_cpu_powered_down & (1 << 8))
> + count++;
> + if (pm_cpu_powered_down & (1 << 9))
> + count++;
> + if (pm_cpu_powered_down & (1 << 10))
> + count++;
> + if (pm_cpu_powered_down & (1 << 11))
> + count++;
> + if (count == 3)
> + return true;
> + break;
> + case (12):
> + case (13):
> + case (14):
> + case (15):
> + if (pm_cpu_powered_down & (1 << 12))
> + count++;
> + if (pm_cpu_powered_down & (1 << 13))
> + count++;
> + if (pm_cpu_powered_down & (1 << 14))
> + count++;
> + if (pm_cpu_powered_down & (1 << 15))
> + count++;
> + if (count == 3)
> + return true;
> + break;
> + default:
> + pr_err("ERROR: the cpu does not exist: %d - %s:%d\n", cpu, __FILE__,
> + __LINE__);
> + break;
> + }
> + return false;
> +}
> +
> +static void pm_set_bits_syscon_register(void __iomem *syscon, u32 reg, u32 data)
> +{
> + u32 tmp;
> +
> + tmp = readl(syscon + reg);
> + tmp |= data;
> + writel(tmp, syscon + reg);
> +}
> +
> +static void pm_clear_bits_syscon_register(void __iomem *syscon, u32 reg, u32 data)
> +{
> + u32 tmp;
> +
> + tmp = readl(syscon + reg);
> + tmp &= ~(data);
> + writel(tmp, syscon + reg);
> +}
> +
> +static bool pm_test_for_bit_with_timeout(void __iomem *syscon, u32 reg, u32 bit)
> +{
> +
> + u32 tmp = 0;
> + u32 cnt = 0;
> +
> + while (cnt < PM_WAIT_TIME) {
> + tmp = readl(syscon + reg);
> + if (CHECK_BIT(tmp, bit))
> + break;
> + cnt++;
> + }
> + if (cnt == PM_WAIT_TIME) {
> + pr_err("reg=0x%x tmp:=0x%x\n", reg, tmp);
> + return false;
> + }
> + return true;
> +}
> +
> +static bool pm_wait_for_bit_clear_with_timeout(void __iomem *syscon, u32 reg,
> + u32 bit)
> +{
> + u32 cnt = 0;
> + u32 tmp = 0;
> +
> + while (cnt < PM_WAIT_TIME) {
> + tmp = readl(syscon + reg);
> + if (!(CHECK_BIT(tmp, bit)))
> + break;
> + cnt++;
> + }
> + if (cnt == PM_WAIT_TIME) {
> + pr_err("reg=0x%x tmp:=0x%x\n", reg, tmp);
> + return false;
> + }
> +
> + return true;
> +}
> +static void pm_dickens_logical_shutdown(u32 cluster)
> +{
> + int i;
> + int status;
> + u32 bit;
> + u32 bit_pos;
> + int retries;
> + void __iomem *dickens;
> +
> + dickens = ioremap(DICKENS_PHYS_ADDR, SZ_4M);
> + if (dickens == NULL) {
> + pr_err("DICKENS: Failed to map the dickens registers\n");
> + return;
> + }
> +
> + bit = (0x01 << cluster_to_node[cluster]);
> + bit_pos = cluster_to_node[cluster];
> +
> + for (i = 0; i < DKN_HNF_TOTAL_NODES; ++i) {
> + writel(bit,
> + dickens + (0x10000 * (DKN_HNF_NODE_ID + i))
> + + DKN_HNF_SNOOP_DOMAIN_CTL_CLR);
> +
> + retries = PM_WAIT_TIME;
> +
> + do {
> + status = readl(
> + dickens + (0x10000 * (DKN_HNF_NODE_ID + i))
> + + DKN_HNF_SNOOP_DOMAIN_CTL);
> + udelay(1);
> + } while ((0 < --retries) && CHECK_BIT(status, bit_pos));
> +
> + if (0 == retries) {
> + pr_err("DICKENS: Failed to clear the SNOOP main control. LOOP:%d reg: 0x%x\n", i, status);
> + goto dickens_power_down;
> +
> + }
> +
> + }
> + /* Clear the domain cluster */
> + writel(bit, dickens + (0x10000 * DKN_DVM_DOMAIN_OFFSET) + DKN_MN_DVM_DOMAIN_CTL_CLR);
> +
> + /* Check for complete */
> + retries = PM_WAIT_TIME;
> +
> + do {
> + status = readl(
> + dickens + (0x10000 * DKN_DVM_DOMAIN_OFFSET)
> + + DKN_MN_DVM_DOMAIN_CTL);
> + udelay(1);
> + } while ((0 < --retries) && CHECK_BIT(status, bit_pos));
> +
> + if (0 == retries) {
> + pr_err("DICKENS: failed to set DOMAIN OFFSET Reg=0x%x\n", status);
> + goto dickens_power_down;
> +
> + }
> +
> +dickens_power_down:
> + iounmap(dickens);
> +
> + return;
> +}
> +
> +static int pm_dickens_logical_powerup(u32 cluster)
> +{
> + int i;
> + u32 status;
> + u32 bit;
> + u32 bit_pos;
> + int retries;
> + int rval = 0;
> +
> + void __iomem *dickens = ioremap(DICKENS_PHYS_ADDR, SZ_4M);
> + if (dickens == NULL) {
> + pr_err("Failed to map dickens registers\n");
> + return -EINVAL;
> + }
> +
> + bit = (0x01 << cluster_to_node[cluster]);
> + bit_pos = cluster_to_node[cluster];
> +
> + for (i = 0; i < DKN_HNF_TOTAL_NODES; ++i) {
> + writel(bit,
> + dickens + (0x10000 * (DKN_HNF_NODE_ID + i))
> + + DKN_HNF_SNOOP_DOMAIN_CTL_SET);
> +
> + retries = PM_WAIT_TIME;
> +
> + do {
> + status = readl(
> + dickens + (0x10000 * (DKN_HNF_NODE_ID + i))
> + + DKN_HNF_SNOOP_DOMAIN_CTL);
> + udelay(1);
> + } while ((0 < --retries) && !CHECK_BIT(status, bit_pos));
> +
> + if (0 == retries) {
> + pr_err("DICKENS: Failed on the SNOOP DONAIN\n");
> + rval = -EINVAL;
> + goto dickens_power_up;
> + }
> +
> + }
> +
> + /* Clear the domain cluster */
> + writel(bit, dickens + (0x10000 * DKN_DVM_DOMAIN_OFFSET) + DKN_MN_DVM_DOMAIN_CTL_SET);
> +
> + /* Check for complete */
> + retries = PM_WAIT_TIME;
> +
> + do {
> + status = readl(
> + dickens + (0x10000 * DKN_DVM_DOMAIN_OFFSET)
> + + DKN_MN_DVM_DOMAIN_CTL);
> + udelay(1);
> + } while ((0 < --retries) && !CHECK_BIT(status, bit_pos));
> +
> + if (0 == retries) {
> + pr_err("DICKENS: Failed on the SNOOP DONAIN\n");
> + rval = -EINVAL;
> + goto dickens_power_up;
> + }
> +
> +dickens_power_up:
> + iounmap(dickens);
> +
> + return rval;
> +}
> +
> +static void __pm_cpu_shutdown(void *data)
> +{
> +
> + pm_data *pm_request = (pm_data *)data;
> + void __iomem *syscon;
> + bool success;
> + u32 cluster_mask = (0x01 << pm_request->cluster);
> + bool last_cpu;
> + int rval = 0;
> +
> + /*
> + * Is this the last cpu of a cluster then turn off the L2 cache
> + * along with the CPU.
> + */
> + last_cpu = pm_cpu_last_of_cluster(pm_request->cpu);
> + if (last_cpu) {
> +
> + /* Remove the cluster from the Dickens coherency domain */
> + pm_dickens_logical_shutdown(pm_request->cluster);
> +
> + /* Power down the cpu */
> + pm_cpu_physical_isolation_and_power_down(pm_request->cpu);
> +
> + syscon = ioremap(SYSCON_PHYS_ADDR, SZ_64K);
> + if (WARN_ON(!syscon))
> + return;
> +
> +#if 0
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_CSYSREQ_TS, cluster_mask);
> + success = pm_wait_for_bit_clear_with_timeout(syscon, NCP_SYSCON_PWR_CACTIVE_TS, pm_request->cluster);
> + if (!success) {
> + pr_err(
> + "Failed to keep other cluster TS going on cluster %d: %s-%d\n",
> + pm_request->cluster, __FILE__, __LINE__);
> + iounmap(syscon);
> + return;
> + }
> +
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_CSYSREQ_ATB, cluster_mask);
> + success = pm_wait_for_bit_clear_with_timeout(syscon, NCP_SYSCON_PWR_CACTIVE_ATB, pm_request->cluster);
> + if (!success) {
> + pr_err(
> + "Failed to keep other cluster ATB going on cluster %d: %s-%d\n",
> + pm_request->cluster, __FILE__, __LINE__);
> + iounmap(syscon);
> + return;
> + }
> +
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_CSYSREQ_APB, cluster_mask);
> + success = pm_wait_for_bit_clear_with_timeout(syscon, NCP_SYSCON_PWR_CACTIVE_APB, pm_request->cluster);
> + if (!success) {
> + pr_err(
> + "Failed to keep other cluster APB going on cluster %d: %s-%d\n",
> + pm_request->cluster, __FILE__, __LINE__);
> + iounmap(syscon);
> + return;
> + }
> +#endif
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_CSYSREQ_CNT, cluster_mask);
> + success = pm_wait_for_bit_clear_with_timeout(syscon, NCP_SYSCON_PWR_CACTIVE_CNT, pm_request->cluster);
> + if (!success) {
> + pr_err(
> + "Failed to keep other cluster count going on cluster %d: %s-%d\n",
> + pm_request->cluster, __FILE__, __LINE__);
> + iounmap(syscon);
> + return;
> + }
> +
> + /* Turn off the ACE */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_ACEPWRDNRQ, cluster_mask);
> +
> + /* Wait for ACE to complete power off */
> + success = pm_wait_for_bit_clear_with_timeout(syscon, NCP_SYSCON_PWR_NACEPWRDNACK, pm_request->cluster);
> + if (!success) {
> + pr_err("Failed to power off ACE on cluster %d: %s-%d\n",
> + pm_request->cluster, __FILE__, __LINE__);
> + iounmap(syscon);
> + return;
> + }
> +
> + /* Isolate the cluster */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_ISOLATEL2MISC, cluster_mask);
> +
> + /* Wait for WFI L2 to go to standby */
> + success = pm_test_for_bit_with_timeout(syscon, NCP_SYSCON_PWR_STANDBYWFIL2, pm_request->cluster);
> + if (!success) {
> + pr_err("Failed to enter L2 WFI on cluster %d: %s-%d\n",
> + pm_request->cluster, __FILE__, __LINE__);
> + iounmap(syscon);
> + return;
> + }
> +
> + iounmap(syscon);
> +
> + /* Power off the L2 */
> + pm_L2_isolation_and_power_down(pm_request->cluster);
> + if (rval == 0) {
> + pr_info("CPU %d is powered down with cluster: %d\n", pm_request->cpu, pm_request->cluster);
> + pm_cpu_powered_down |= (1 << pm_request->cpu);
> + } else
> + pr_err("CPU %d failed to power down\n", pm_request->cpu);
> +
> +
> + } else {
> +
> + rval = pm_cpu_physical_isolation_and_power_down(pm_request->cpu);
> + if (rval == 0)
> + pm_cpu_powered_down |= (1 << pm_request->cpu);
> + else
> + pr_err("CPU %d failed to power down\n", pm_request->cpu);
> + }
> +
> + return;
> +}
> +
> +
> +int pm_cpu_logical_die(pm_data *pm_request)
> +{
> + void __iomem *syscon;
> + bool success;
> +
> + smp_call_function_single(pm_request->cpu, pm_cpu_logical_shutdown, (void *)pm_request, 1);
> +
> + syscon = ioremap(SYSCON_PHYS_ADDR, SZ_64K);
> + if (WARN_ON(!syscon))
> + return -EINVAL;
> +
> + /* Wait for the cpu to enter wfi */
> + success = pm_test_for_bit_with_timeout(syscon, NCP_SYSCON_PWR_STANDBYWFI, pm_request->cpu);
> + if (!success) {
> + pr_err("Failed to enter WFI mode on cpu %d: %s-%d\n",
> + pm_request->cpu, __FILE__, __LINE__);
> + iounmap(syscon);
> + return -EINVAL;
> + }
> +
> + iounmap(syscon);
> + return 0;
> +}
> +
> +int pm_cpul2_logical_die(pm_data *pm_request)
> +{
> + void __iomem *syscon;
> + bool success;
> +
> + smp_call_function_single(pm_request->cpu, pm_L2_logical_shutdown, (void *)pm_request, 1);
> +
> + syscon = ioremap(SYSCON_PHYS_ADDR, SZ_64K);
> + if (WARN_ON(!syscon))
> + return -EINVAL;
> +
> + /* Wait for the cpu to enter wfi */
> + success = pm_test_for_bit_with_timeout(syscon, NCP_SYSCON_PWR_STANDBYWFI, pm_request->cpu);
> + if (!success) {
> + pr_err("Failed to enter WFI mode on cpu %d: %s-%d\n",
> + pm_request->cpu, __FILE__, __LINE__);
> + iounmap(syscon);
> + return -EINVAL;
> + }
> +
> + iounmap(syscon);
> + return 0;
> +}
> +
> +void pm_cpu_shutdown(u32 cpu)
> +{
> +
> + pm_data pm_request;
> +
> + u32 pcpu = cpu_logical_map(smp_processor_id());
> + u32 rcpu = cpumask_any_and(cpu_present_mask, cpu_online_mask);
> + u32 reqcpu = cpu_logical_map(cpu);
> +
> + /* Check to see if the cpu is powered up */
> + if (pm_cpu_powered_down & (1 << cpu)) {
> + pr_err("CPU %d is already powered off - %s:%d\n", cpu, __FILE__, __LINE__);
> + return;
> + }
> + /*
> + * Is this the last cpu to be powered off, then don't
> + * allow the power to be shut off.
> + */
> + if (cpu == 0) {
> + pr_err("Cannot turn off cpu 0 - %s:%d\n", __FILE__, __LINE__);
> + return;
> + }
> +
> + /*
> + * Is this process on the requested cpu to power down
> + * then send it to another cpu for processing
> + */
> + pm_request.cpu = cpu;
> + pm_request.cluster = reqcpu / CORES_PER_CLUSTER;
> +
> + if (pcpu == cpu)
> + smp_call_function_single(rcpu, __pm_cpu_shutdown, (void *)&pm_request, 0);
> + else
> + __pm_cpu_shutdown(&pm_request);
> +
> +}
> +
> +int pm_cpu_powerup(u32 cpu)
> +{
> +
> + bool first_cpu;
> + int rval = 0;
> + void __iomem *syscon = NULL;
> + u32 cpu_mask = (0x01 << cpu);
> +
> + u32 reqcpu = cpu_logical_map(cpu);
> + u32 cluster = reqcpu / CORES_PER_CLUSTER;
> +
> + /* Hold the CPU in reset */
> + syscon = ioremap(SYSCON_PHYS_ADDR, SZ_64K);
> + if (WARN_ON(!syscon))
> + return -EINVAL;
> +
> + /*
> + * The key value has to be written before the CPU RST can be written.
> + */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_KEY, VALID_KEY_VALUE);
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWRUP_CPU_RST, cpu_mask);
> +
> + iounmap(syscon);
> +
> + /*
> + * Is this the first cpu of a cluster to come back on?
> + * Then power up the L2 cache.
> + */
> + first_cpu = pm_first_cpu_of_cluster(cpu);
> + if (first_cpu) {
> +
> +
> + rval = pm_L2_logical_powerup(cluster, cpu);
> + if (rval) {
> + pr_err("CPU: Failed the logical L2 power up\n");
> + return rval;
> + }
> + cluster_power_up[cluster] = true;
> +
> + }
> +
> +
> + /*
> + * Power up the CPU
> + */
> + rval = pm_cpu_physical_connection_and_power_up(cpu);
> + if (rval) {
> + pr_err("Failed to power up physical connection of cpu: %d\n", cpu);
> + goto pm_power_up;
> + }
> +
> + udelay(16);
> +
> + /* Clear the CPU from reset and let it go */
> + syscon = ioremap(SYSCON_PHYS_ADDR, SZ_64K);
> + if (WARN_ON(!syscon))
> + return -EINVAL;
> +
> + /*
> + * The key value must be written before the CPU RST can be written.
> + */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_KEY, VALID_KEY_VALUE);
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWRUP_CPU_RST, cpu_mask);
> +
> + /*
> + * The key value must be written before HOLD CPU can be written.
> + */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_KEY, VALID_KEY_VALUE);
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_HOLD_CPU, cpu_mask);
> +
> + /*
> + * Clear the powered down mask
> + */
> + pm_cpu_powered_down &= ~(1 << cpu);
> +
> +
> +pm_power_up:
> + iounmap(syscon);
> + return rval;
> +}
> +
> +unsigned long pm_get_powered_down_cpu(void)
> +{
> + return pm_cpu_powered_down;
> +}
> +
> +void pm_cpu_logical_shutdown(void *data)
> +{
> + u32 val;
> +
> + asm volatile(
> + " mrc p15, 1, %0, c9, c0, 2\n"
> + : "=&r" (val)
> + : "Ir" (0x1)
> + : "cc");
> +
> + asm volatile(
> + " mrc p15, 0, %0, c1, c0, 0\n"
> + " bic %0, %0, %1\n"
> + " mcr p15, 0, %0, c1, c0, 0\n"
> + : "=&r" (val)
> + : "Ir" (CR_C)
> + : "cc");
> +
> + /* Clear and invalidate all date from L1 data cache */
> + flush_cache_all();
> +
> + /* Switch the processor over to AMP mode out of SMP */
> + asm volatile(
> + " mrc p15, 0, %0, c1, c0, 1\n"
> + " bic %0, %0, %1\n"
> + " mcr p15, 0, %0, c1, c0, 1\n"
> + : "=&r" (val)
> + : "Ir" (0x40)
> + : "cc");
> +
> + isb();
> + dsb();
> +
> + wfi();
> +
> + return;
> +
> +}
> +
> +void pm_cpu_logical_powerup(void)
> +{
> + unsigned int v;
> +
> + asm volatile(
> + " mrc p15, 0, %0, c1, c0, 0\n"
> + " orr %0, %0, %1\n"
> + " mcr p15, 0, %0, c1, c0, 0\n"
> + " mrc p15, 0, %0, c1, c0, 0\n"
> + " orr %0, %0, %2\n"
> + " mcr p15, 0, %0, c1, c0, 0\n"
> + " mrc p15, 0, %0, c1, c0, 1\n"
> + " orr %0, %0, %3\n"
> + " mcr p15, 0, %0, c1, c0, 1\n"
> + : "=&r" (v)
> + : "Ir" (CR_C), "Ir" (CR_I), "Ir" (0x40)
> + : "cc");
> +
> + asm volatile(
> + " mrc p15, 1, %0, c9, c0, 2\n"
> + : "=&r" (v)
> + : "Ir" (0x1)
> + : "cc");
> +
> +}
> +
> +static int pm_cpu_physical_isolation_and_power_down(int cpu)
> +{
> + void __iomem *syscon;
> + int rval = 0;
> +
> + bool success;
> + u32 mask = (0x01 << cpu);
> +
> + syscon = ioremap(SYSCON_PHYS_ADDR, SZ_64K);
> + if (WARN_ON(!syscon))
> + return -EINVAL;
> +
> + /* Initiate power down of the CPU's HS Rams */
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPCPURAM, mask);
> +
> + /* Wait until the RAM power down is complete */
> + success = pm_test_for_bit_with_timeout(syscon, NCP_SYSCON_PWR_NPWRUPCPURAM_ACK, cpu);
> + if (!success) {
> + rval = -EINVAL;
> + pr_err("CPU: Failed to power down CPU RAM\n");
> + goto power_down_cleanup;
> + }
> +
> + /* Activate the CPU's isolation clamps */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_ISOLATECPU, mask);
> +
> + /* Initiate power down of the CPU logic */
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPCPUSTG2, mask);
> +
> + udelay(10);
> +
> + /* Continue power down of the CPU logic */
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPCPUSTG1, mask);
> +
> + success = pm_test_for_bit_with_timeout(syscon, NCP_SYSCON_PWR_NPWRUPCPUSTG1_ACK, cpu);
> + if (!success) {
> + rval = -EINVAL;
> + pr_err("CPU: Failed to power down stage 1 cpu\n");
> + goto power_down_cleanup;
> + }
> +
> +power_down_cleanup:
> + iounmap(syscon);
> + return rval;
> +}
> +
> +static int pm_cpu_physical_connection_and_power_up(int cpu)
> +{
> + int rval = 0;
> + void __iomem *syscon;
> + bool success;
> + u32 mask = (0x01 << cpu);
> +
> + syscon = ioremap(SYSCON_PHYS_ADDR, SZ_64K);
> + if (WARN_ON(!syscon))
> + return -EINVAL;
> +
> + /* Initiate power up of the CPU */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPCPUSTG1, mask);
> +
> + /* Wait until CPU logic power is compete */
> + success = pm_wait_for_bit_clear_with_timeout(syscon, NCP_SYSCON_PWR_NPWRUPCPUSTG1_ACK, cpu);
> + if (!success) {
> + rval = -EINVAL;
> + pr_err("CPU: Failed to get ACK from power down stage 1\n");
> + goto power_up_cleanup;
> + }
> +
> + /* Continue stage 2 power up of the CPU*/
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPCPUSTG2, mask);
> +
> + udelay(10);
> +
> + /* Initiate power up of HS Rams */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPCPURAM, mask);
> +
> + /* Wait until the RAM power up is complete */
> + success = pm_wait_for_bit_clear_with_timeout(syscon, NCP_SYSCON_PWR_NPWRUPCPURAM_ACK, cpu);
> + if (!success) {
> + rval = -EINVAL;
> + pr_err("CPU: Failed to get ACK of power power up\n");
> + goto power_up_cleanup;
> + }
> +
> + /* Release the CPU's isolation clamps */
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_ISOLATECPU, mask);
> +
> +power_up_cleanup:
> + iounmap(syscon);
> +
> + return rval;
> +
> +}
> +/*========================================== L2 FUNCTIONS ========================================*/
> +
> +void pm_L2_logical_shutdown(void *data)
> +{
> + u32 val;
> +
> +
> + asm volatile(
> + " mrc p15, 0, %0, c1, c0, 0\n"
> + " bic %0, %0, %1\n"
> + " mcr p15, 0, %0, c1, c0, 0\n"
> + : "=&r" (val)
> + : "Ir" (CR_C)
> + : "cc");
> +
> +
> + asm volatile(
> + /*
> + * Disable L2 prefetch
> + */
> + " mrc p15, 1, %0, c15, c0, 3\n"
> + " orr %0, %0, %1\n"
> + " mcr p15, 1, %0, c15, c0, 3\n"
> + : "=&r" (val)
> + : "Ir" (0x400)
> + : "cc");
> +
> + isb();
> + dsb();
> +
> + /* Clear and invalidate all L1 and L2 data cache */
> + flush_cache_all();
> +
> +
> + /* Turn the DBG Double Lock quiet */
> + asm volatile(
> + /*
> + * Turn Off the DBGOSDLR.DLK bit
> + */
> + " mrc p14, 0, %0, c1, c3, 4\n"
> + " orr %0, %0, %1\n"
> + " mcr p14, 0, %0, c1, c3, 4\n"
> + : "=&r" (val)
> + : "Ir" (0x1)
> + : "cc");
> +
> + /* Switch the processor over to AMP mode out of SMP */
> + asm volatile(
> + " mrc p15, 0, %0, c1, c0, 1\n"
> + " bic %0, %0, %1\n"
> + " mcr p15, 0, %0, c1, c0, 1\n"
> + : "=&r" (val)
> + : "Ir" (0x40)
> + : "cc");
> +
> + isb();
> + dsb();
> +
> + wfi();
> + return;
> +}
> +
> +static void pm_L2_isolation_and_power_down(int cluster)
> +{
> + void __iomem *syscon;
> + u32 mask = (0x1 << cluster);
> +
> +
> + syscon = ioremap(SYSCON_PHYS_ADDR, SZ_64K);
> + if (WARN_ON(!syscon))
> + return;
> +
> + /* Enable the chip select for the cluster */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_CHIPSELECTEN, mask);
> +
> + /* Disable the hsram */
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL2HSRAM, mask);
> +
> + switch (cluster) {
> + case (0):
> +
> +#ifdef PM_POWER_OFF_ONLY_DATARAM
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM1, RAM_BANK0_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM1, RAM_BANK1_LS_MASK);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM2, RAM_BANK1_MS_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM2, RAM_BANK2_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM2, RAM_BANK3_MASK);
> + udelay(20);
> +#else
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM2, RAM_ALL_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM1, RAM_ALL_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM0, RAM_ALL_MASK);
> + udelay(20);
> +
> +#endif
> + break;
> + case (1):
> +
> +#ifdef PM_POWER_OFF_ONLY_DATARAM
> +
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM1, RAM_BANK0_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM1, RAM_BANK1_LS_MASK);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM2, RAM_BANK1_MS_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM2, RAM_BANK2_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM2, RAM_BANK3_MASK);
> + udelay(20);
> +#else
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM2, RAM_ALL_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM1, RAM_ALL_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM0, RAM_ALL_MASK);
> + udelay(20);
> +#endif
> + break;
> + case (2):
> +
> +#ifdef PM_POWER_OFF_ONLY_DATARAM
> +
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM1, RAM_BANK0_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM1, RAM_BANK1_LS_MASK);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM2, RAM_BANK1_MS_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM2, RAM_BANK2_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM2, RAM_BANK3_MASK);
> + udelay(20);
> +#else
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM2, RAM_ALL_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM1, RAM_ALL_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM0, RAM_ALL_MASK);
> + udelay(20);
> +#endif
> + break;
> + case (3):
> +
> +#ifdef PM_POWER_OFF_ONLY_DATARAM
> +
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM1, RAM_BANK0_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM1, RAM_BANK1_LS_MASK);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM2, RAM_BANK1_MS_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM2, RAM_BANK2_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM2, RAM_BANK3_MASK);
> + udelay(20);
> +#else
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM2, RAM_ALL_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM1, RAM_ALL_MASK);
> + udelay(20);
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM0, RAM_ALL_MASK);
> + udelay(20);
> +#endif
> + break;
> + default:
> + pr_err("Illegal cluster: %d > 3\n", cluster);
> + break;
> + }
> +
> + /* Power down stage 2 */
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL2LGCSTG2, mask);
> +
> + /* Power down stage 1 */
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL2LGCSTG1, mask);
> +
> +
> + iounmap(syscon);
> +}
> +
> +static int pm_L2_physical_connection_and_power_up(u32 cluster)
> +{
> + void __iomem *syscon;
> + bool success;
> + u32 mask = (0x1 << cluster);
> + int rval = 0;
> +
> + syscon = ioremap(SYSCON_PHYS_ADDR, SZ_64K);
> + if (WARN_ON(!syscon))
> + return -EINVAL;
> +
> + /* Power up stage 1 */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL2LGCSTG1, mask);
> +
> + /* Wait for the stage 1 power up to complete */
> + success = pm_wait_for_bit_clear_with_timeout(syscon, NCP_SYSCON_PWR_NPWRUPL2LGCSTG1_ACK, cluster);
> + if (!success) {
> + pr_err("CPU: Failed to ack the L2 Stage 1 Power up\n");
> + rval = -EINVAL;
> + goto power_up_l2_cleanup;
> + }
> +
> + /* Power on stage 2 */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL2LGCSTG2, mask);
> +
> + /* Set the chip select */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_CHIPSELECTEN, mask);
> +
> + /* Power up the snoop ramram */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL2HSRAM, mask);
> +
> + /* Wait for the stage 1 power up to complete */
> + success = pm_wait_for_bit_clear_with_timeout(syscon, NCP_SYSCON_PWR_NPWRUPL2HSRAM_ACK, cluster);
> + if (!success) {
> + pr_err("CPU: failed to get the HSRAM power up ACK\n");
> + rval = -EINVAL;
> + goto power_up_l2_cleanup;
> + }
> +
> + switch (cluster) {
> + case (0):
> +
> +#ifdef PM_POWER_OFF_ONLY_DATARAM
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM1, RAM_BANK0_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM1, RAM_BANK1_LS_MASK);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM2, RAM_BANK1_MS_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM2, RAM_BANK2_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM2, RAM_BANK3_MASK);
> + udelay(20);
> +#else
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM2, RAM_ALL_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM1, RAM_ALL_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM0, RAM_ALL_MASK);
> + udelay(20);
> +
> +#endif
> + break;
> + case (1):
> +
> +#ifdef PM_POWER_OFF_ONLY_DATARAM
> +
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM1, RAM_BANK0_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM1, RAM_BANK1_LS_MASK);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM2, RAM_BANK1_MS_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM2, RAM_BANK2_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM2, RAM_BANK3_MASK);
> + udelay(20);
> +#else
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM2, RAM_ALL_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM1, RAM_ALL_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM0, RAM_ALL_MASK);
> + udelay(20);
> +#endif
> + break;
> + case (2):
> +
> +#ifdef PM_POWER_OFF_ONLY_DATARAM
> +
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM1, RAM_BANK0_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM1, RAM_BANK1_LS_MASK);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM2, RAM_BANK1_MS_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM2, RAM_BANK2_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM2, RAM_BANK3_MASK);
> + udelay(20);
> +#else
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM2, RAM_ALL_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM1, RAM_ALL_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM0, RAM_ALL_MASK);
> + udelay(20);
> +#endif
> + break;
> + case (3):
> +
> +#ifdef PM_POWER_OFF_ONLY_DATARAM
> +
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM1, RAM_BANK0_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM1, RAM_BANK1_LS_MASK);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM2, RAM_BANK1_MS_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM2, RAM_BANK2_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon,
> + NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM2, RAM_BANK3_MASK);
> + udelay(20);
> +#else
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM2, RAM_ALL_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM1, RAM_ALL_MASK);
> + udelay(20);
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM0, RAM_ALL_MASK);
> + udelay(20);
> +#endif
> + break;
> + default:
> + pr_err("Illegal cluster: %d > 3\n", cluster);
> + break;
> + }
> +
> + /* Clear the chip select */
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_CHIPSELECTEN, mask);
> +
> + /* Release the isolation clamps */
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_ISOLATEL2MISC, mask);
> +
> + /* Turn the ACE bridge power on*/
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_ACEPWRDNRQ, mask);
> +
> +power_up_l2_cleanup:
> +
> + iounmap(syscon);
> +
> + return rval;
> +}
> +
> +static int pm_L2_logical_powerup(u32 cluster, u32 cpu)
> +{
> +
> + void __iomem *syscon;
> + u32 mask = (0x1 << cluster);
> + u32 cpu_mask = (0x1 << cpu);
> + int rval = 0;
> +
> + syscon = ioremap(SYSCON_PHYS_ADDR, SZ_64K);
> + if (WARN_ON(!syscon))
> + return -EINVAL;
> +
> + /* put the cluster into a cpu hold */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_RESET_AXIS,
> + cluster_to_poreset[cluster]);
> +
> + /*
> + * Write the key so the reset cpu register can be written to.
> + */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_KEY, VALID_KEY_VALUE);
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWRUP_CPU_RST, cpu_mask);
> +
> + /* Hold the chip debug cluster */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_KEY, VALID_KEY_VALUE);
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_HOLD_DBG, mask);
> +
> + /* Hold the L2 cluster */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_KEY, VALID_KEY_VALUE);
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_HOLD_L2, mask);
> +
> + iounmap(syscon);
> +
> + /* Cluster physical power up */
> + rval = pm_L2_physical_connection_and_power_up(cluster);
> +
> + udelay(16);
> +
> + syscon = ioremap(SYSCON_PHYS_ADDR, SZ_64K);
> + if (WARN_ON(!syscon))
> + return -EINVAL;
> +
> + /* take the cluster out of a cpu hold */
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_RESET_AXIS,
> + cluster_to_poreset[cluster]);
> +
> + udelay(64);
> +
> + /* Enable the system counter */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_PWR_CSYSREQ_CNT, mask);
> +
> + /* Release the L2 cluster */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_KEY, VALID_KEY_VALUE);
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_HOLD_L2, mask);
> +
> + /* Release the chip debug cluster */
> + pm_set_bits_syscon_register(syscon, NCP_SYSCON_KEY, VALID_KEY_VALUE);
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_HOLD_DBG, mask);
> +
> +
> + rval = pm_dickens_logical_powerup(cluster);
> +
> + /* start L2 */
> + pm_clear_bits_syscon_register(syscon, NCP_SYSCON_PWR_ACINACTM, mask);
> +
> + iounmap(syscon);
> +
> + return rval;
> +
> +}
> +
> +#ifdef DEBUG_CPU_PM
> +
> +void pm_debug_read_pwr_registers(void)
> +{
> + u32 reg;
> +
> + void __iomem *syscon;
> +
> + syscon = ioremap(SYSCON_PHYS_ADDR, SZ_64K);
> + if (WARN_ON(!syscon))
> + return;
> +
> + reg = readl(syscon + 0x1400);
> + pr_err("NCP_SYSCON_PWR_CLKEN: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_PWR_ACINACTM);
> + pr_err("NCP_SYSCON_PWR_ACINACTM: 0x%x\n", reg);
> + reg = readl(syscon + 0x140c);
> + pr_err("NCP_SYSCON_PWR_CHIPSELECTEN: 0x%x\n", reg);
> + reg = readl(syscon + 0x1410);
> + pr_err("NCP_SYSCON_PWR_CSYSREQ_TS: 0x%x\n", reg);
> + reg = readl(syscon + 0x1414);
> + pr_err("NCP_SYSCON_PWR_CSYSREQ_CNT: 0x%x\n", reg);
> + reg = readl(syscon + 0x1418);
> + pr_err("NCP_SYSCON_PWR_CSYSREQ_ATB: 0x%x\n", reg);
> + reg = readl(syscon + 0x141c);
> + pr_err("NCP_SYSCON_PWR_CSYSREQ_APB: 0x%x\n", reg);
> + reg = readl(syscon + 0x1420);
> + pr_err("NCP_SYSCON_PWR_PWRUPL2LGCSTG1: 0x%x\n", reg);
> + reg = readl(syscon + 0x1424);
> + pr_err("NCP_SYSCON_PWR_PWRUPL2LGCSTG2: 0x%x\n", reg);
> + reg = readl(syscon + 0x1428);
> + pr_err("NCP_SYSCON_PWR_PWRUPL2HSRAM: 0x%x\n", reg);
> + reg = readl(syscon + 0x142c);
> + pr_err("NCP_SYSCON_PWR_ACEPWRDNRQ: 0x%x\n", reg);
> + reg = readl(syscon + 0x1430);
> + pr_err("NCP_SYSCON_PWR_ISOLATEL2MIS: 0x%x\n", reg);
> + reg = readl(syscon + 0x1438);
> + pr_err("NCP_SYSCON_PWR_NPWRUPL2LGCSTG1_ACK: 0x%x\n", reg);
> + reg = readl(syscon + 0x143c);
> + pr_err("NCP_SYSCON_PWR_NPWRUPL2HSRAM_ACK: 0x%x\n", reg);
> + reg = readl(syscon + 0x1440);
> + pr_err("NCP_SYSCON_PWR_STANDBYWFIL2: 0x%x\n", reg);
> + reg = readl(syscon + 0x1444);
> + pr_err("NCP_SYSCON_PWR_CSYSACK_TS: 0x%x\n", reg);
> + reg = readl(syscon + 0x1448);
> + pr_err("NCP_SYSCON_PWR_CACTIVE_TS: 0x%x\n", reg);
> + reg = readl(syscon + 0x144c);
> + pr_err("NCP_SYSCON_PWR_CSYSACK_CNT: 0x%x\n", reg);
> + reg = readl(syscon + 0x1450);
> + pr_err("NCP_SYSCON_PWR_CACTIVE_CNT: 0x%x\n", reg);
> + reg = readl(syscon + 0x1454);
> + pr_err("NCP_SYSCON_PWR_CSYSACK_ATB: 0x%x\n", reg);
> + reg = readl(syscon + 0x1458);
> + pr_err("NCP_SYSCON_PWR_CACTIVE_ATB: 0x%x\n", reg);
> + reg = readl(syscon + 0x145c);
> + pr_err("NCP_SYSCON_PWR_CSYSACK_APB: 0x%x\n", reg);
> + reg = readl(syscon + 0x1460);
> + pr_err("NCP_SYSCON_PWR_CACTIVE_APB: 0x%x\n", reg);
> + reg = readl(syscon + 0x1464);
> + pr_err("NCP_SYSCON_PWR_NACEPWRDNACK: 0x%x\n", reg);
> + reg = readl(syscon + 0x1468);
> + pr_err("NCP_SYSCON_PWR_CACTIVEM_EAGM: 0x%x\n", reg);
> + reg = readl(syscon + 0x146c);
> + pr_err("NCP_SYSCON_PWR_CACTIVEM_EAGS: 0x%x\n", reg);
> + reg = readl(syscon + 0x1470);
> + pr_err("NCP_SYSCON_PWR_CACTIVES_EAGM: 0x%x\n", reg);
> + reg = readl(syscon + 0x1474);
> + pr_err("NCP_SYSCON_PWR_CACTIVES_EAGS: 0x%x\n", reg);
> + reg = readl(syscon + 0x1480);
> + pr_err("NCP_SYSCON_PWR_PWRUPCPUSTG1: 0x%x\n", reg);
> + reg = readl(syscon + 0x1484);
> + pr_err("NCP_SYSCON_PWR_PWRUPCPUSTG2: 0x%x\n", reg);
> + reg = readl(syscon + 0x1488);
> + pr_err("NCP_SYSCON_PWR_PWRUPCPURAM: 0x%x\n", reg);
> + reg = readl(syscon + 0x148c);
> + pr_err("NCP_SYSCON_PWR_ISOLATECPU: 0x%x\n", reg);
> + reg = readl(syscon + 0x1490);
> + pr_err("NCP_SYSCON_PWR_NPWRUPCPUSTG1_ACK: 0x%x\n", reg);
> + reg = readl(syscon + 0x1494);
> + pr_err("NCP_SYSCON_PWR_NPWRUPCPURAM_ACK: 0x%x\n", reg);
> + reg = readl(syscon + 0x1498);
> + pr_err("NCP_SYSCON_PWR_QACTIVE: 0x%x\n", reg);
> + reg = readl(syscon + 0x149C);
> + pr_err("NCP_SYSCON_PWR_STANDBYWFI: 0x%x\n", reg);
> + reg = readl(syscon + 0x14A0);
> + pr_err("NCP_SYSCON_PWR_STANDBYWFE: 0x%x\n", reg);
> + reg = readl(syscon + 0x14A4);
> + pr_err("NCP_SYSCON_PWR_DBGNOPWRDWN: 0x%x\n", reg);
> + reg = readl(syscon + 0x14A8);
> + pr_err("NCP_SYSCON_PWR_DBGPWRUPREQ: 0x%x\n", reg);
> + reg = readl(syscon + 0x1040);
> + pr_err("NCP_SYSCON_RESET_AXIS: 0x%x\n", reg);
> + reg = readl(syscon + 0x1044);
> + pr_err("NCP_SYSCON_RESET_AXIS-WORD1: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_RESET_CPU);
> + pr_err("NCP_SYSCON_RESET_CPU: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_HOLD_DBG);
> + pr_err("NCP_SYSCON_HOLD_DBG: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_HOLD_L2);
> + pr_err("NCP_SYSCON_HOLD_L2: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_HOLD_CPU);
> + pr_err("NCP_SYSCON_HOLD_CPU: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_PWRUP_CPU_RST);
> + pr_err("NCP_SYSCON_PWRUP_CPU_RST: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_RESET_STATUS);
> + pr_err("NCP_SYSCON_RESET_STATUS: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_RESET_CORE_STATUS);
> + pr_err("NCP_SYSCON_RESET_CORE_STATUS: 0x%x\n", reg);
> +
> +
> +#if 0
> + reg = readl(syscon + NCP_SYSCON_MCG_CSW_CPU);
> + pr_err("NCP_SYSCON_MCG_CSW_CPU: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MCG_CSW_SYS);
> + pr_err("NCP_SYSCON_MCG_CSW_SYS: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MCG_DIV_CPU);
> + pr_err("NCP_SYSCON_MCG_DIV_CPU: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MCG_DIV_SYS);
> + pr_err("NCP_SYSCON_MCG_DIV_SYS: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_CLKDEBUG);
> + pr_err("NCP_SYSCON_CLKDEBUG: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_EVENT_ENB);
> + pr_err("NCP_SYSCON_EVENT_ENB: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_CPU_FAST_INT);
> + pr_err("NCP_SYSCON_CPU_FAST_INT: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_GIC_DISABLE);
> + pr_err("NCP_SYSCON_GIC_DISABLE: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_CP15SDISABLE);
> + pr_err("NCP_SYSCON_CP15SDISABLE: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_LDO_CTL);
> + pr_err("NCP_SYSCON_LDO_CTL: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_SHWK_QOS);
> + pr_err("NCP_SYSCON_SHWK_QOS: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_FUSE_RTO);
> + pr_err("NCP_SYSCON_FUSE_RTO: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_PFUSE);
> + pr_err("NCP_SYSCON_PFUSE: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_FUSE_STAT);
> + pr_err("NCP_SYSCON_FUSE_STAT: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_SCRATCH);
> + pr_err("NCP_SYSCON_SCRATCH: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI0);
> + pr_err("NCP_SYSCON_MASK_IPI0: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI1);
> + pr_err("NCP_SYSCON_MASK_IPI1: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI2);
> + pr_err("NCP_SYSCON_MASK_IPI2: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI3);
> + pr_err("NCP_SYSCON_MASK_IPI3: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI4);
> + pr_err("NCP_SYSCON_MASK_IPI4: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI5);
> + pr_err("NCP_SYSCON_MASK_IPI5: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI6);
> + pr_err("NCP_SYSCON_MASK_IPI6: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI7);
> + pr_err("NCP_SYSCON_MASK_IPI7: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI8);
> + pr_err("NCP_SYSCON_MASK_IPI8: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI9);
> + pr_err("NCP_SYSCON_MASK_IPI9: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI10);
> + pr_err("NCP_SYSCON_MASK_IPI10: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI11);
> + pr_err("NCP_SYSCON_MASK_IPI11: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI12);
> + pr_err("NCP_SYSCON_MASK_IPI12: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI13);
> + pr_err("NCP_SYSCON_MASK_IPI13: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI14);
> + pr_err("NCP_SYSCON_MASK_IPI14: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_MASK_IPI15);
> + pr_err("NCP_SYSCON_MASK_IPI15: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_SPARE0);
> + pr_err("NCP_SYSCON_SPARE0: 0x%x\n", reg);
> + reg = readl(syscon + NCP_SYSCON_STOP_CLK_CPU);
> + pr_err("NCP_SYSCON_STOP_CLK_CPU: 0x%x\n", reg);
> +#endif
> +
> +
> + iounmap(syscon);
> +}
> +
> +
> +void pm_dump_L2_registers(void)
> +{
> + u32 reg;
> +
> + void __iomem *syscon;
> +
> + syscon = ioremap(SYSCON_PHYS_ADDR, SZ_64K);
> + if (WARN_ON(!syscon))
> + return;
> + reg = readl(syscon + 0x1580);
> + pr_err("NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM2: 0x%x\n", reg);
> + reg = readl(syscon + 0x1584);
> + pr_err("NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM1: 0x%x\n", reg);
> + reg = readl(syscon + 0x1588);
> + pr_err("NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM0: 0x%x\n", reg);
> + reg = readl(syscon + 0x158c);
> + pr_err("NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM2: 0x%x\n", reg);
> + reg = readl(syscon + 0x1590);
> + pr_err("NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM1: 0x%x\n", reg);
> + reg = readl(syscon + 0x1594);
> + pr_err("NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM0: 0x%x\n", reg);
> + reg = readl(syscon + 0x1598);
> + pr_err("NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM2: 0x%x\n", reg);
> + reg = readl(syscon + 0x159c);
> + pr_err("NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM1: 0x%x\n", reg);
> + reg = readl(syscon + 0x15a0);
> + pr_err("NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM0: 0x%x\n", reg);
> + reg = readl(syscon + 0x15a4);
> + pr_err("NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM2: 0x%x\n", reg);
> + reg = readl(syscon + 0x15a8);
> + pr_err("NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM1: 0x%x\n", reg);
> + reg = readl(syscon + 0x15ac);
> + pr_err("NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM0: 0x%x\n", reg);
> +
> + iounmap(syscon);
> +}
> +
> +
> +void pm_dump_dickens(void)
> +{
> +
> + void __iomem *dickens;
> + u32 status;
> + u32 i;
> +
> + dickens = ioremap(DICKENS_PHYS_ADDR, SZ_4M);
> + if (dickens == NULL) {
> + pr_err("DICKENS: Failed to map the dickens registers\n");
> + return;
> + }
> +
> + for (i = 0; i < DKN_HNF_TOTAL_NODES; ++i) {
> + status = readl(
> + dickens + (0x10000 * (DKN_HNF_NODE_ID + i))
> + + DKN_HNF_SNOOP_DOMAIN_CTL);
> + udelay(1);
> + pr_err("DKN_HNF_SNOOP_DOMAIN_CTL[%d]: 0x%x\n", i, status);
> + }
> +
> + status = readl(
> + dickens + (0x10000 * DKN_DVM_DOMAIN_OFFSET)
> + + DKN_MN_DVM_DOMAIN_CTL);
> +
> + pr_err("DKN_MN_DVM_DOMAIN_CTL: 0x%x\n", status);
> +
> +
> + iounmap(dickens);
> +
> +
> +}
> +
> +#endif
> diff --git a/arch/arm/mach-axxia/lsi_power_management.h b/arch/arm/mach-axxia/lsi_power_management.h
> new file mode 100644
> index 0000000..4cb6d1f
> --- /dev/null
> +++ b/arch/arm/mach-axxia/lsi_power_management.h
> @@ -0,0 +1,183 @@
> +/*
> + * lsi_power_management.h
> + *
> + * Created on: Jun 23, 2014
> + * Author: z8cpaul
> + */
> +
> +#ifndef LSI_POWER_MANAGEMENT_H_
> +#define LSI_POWER_MANAGEMENT_H_
> +
> +
> +#define NCP_SYSCON_MCG_CSW_CPU (0x00000000)
> +#define NCP_SYSCON_MCG_CSW_SYS (0x00000004)
> +#define NCP_SYSCON_MCG_DIV_CPU (0x00000008)
> +#define NCP_SYSCON_MCG_DIV_SYS (0x0000000c)
> +#define NCP_SYSCON_CLKDEBUG (0x00000010)
> +#define NCP_SYSCON_EVENT_ENB (0x00000014)
> +#define NCP_SYSCON_CPU_FAST_INT (0x00000018)
> +#define NCP_SYSCON_GIC_DISABLE (0x0000001c)
> +#define NCP_SYSCON_CP15SDISABLE (0x00000020)
> +#define NCP_SYSCON_LRSTDISABLE (0x00000024)
> +#define NCP_SYSCON_LDO_CTL (0x00000028)
> +#define NCP_SYSCON_SHWK_QOS (0x0000002c)
> +#define NCP_SYSCON_FUSE_RTO (0x00000030)
> +#define NCP_SYSCON_PFUSE (0x00000034)
> +#define NCP_SYSCON_FUSE_STAT (0x00000038)
> +#define NCP_SYSCON_SCRATCH (0x0000003c)
> +#define NCP_SYSCON_MASK_IPI0 (0x00000040)
> +#define NCP_SYSCON_MASK_IPI1 (0x00000044)
> +#define NCP_SYSCON_MASK_IPI2 (0x00000048)
> +#define NCP_SYSCON_MASK_IPI3 (0x0000004c)
> +#define NCP_SYSCON_MASK_IPI4 (0x00000050)
> +#define NCP_SYSCON_MASK_IPI5 (0x00000054)
> +#define NCP_SYSCON_MASK_IPI6 (0x00000058)
> +#define NCP_SYSCON_MASK_IPI7 (0x0000005c)
> +#define NCP_SYSCON_MASK_IPI8 (0x00000060)
> +#define NCP_SYSCON_MASK_IPI9 (0x00000064)
> +#define NCP_SYSCON_MASK_IPI10 (0x00000068)
> +#define NCP_SYSCON_MASK_IPI11 (0x0000006c)
> +#define NCP_SYSCON_MASK_IPI12 (0x00000070)
> +#define NCP_SYSCON_MASK_IPI13 (0x00000074)
> +#define NCP_SYSCON_MASK_IPI14 (0x00000078)
> +#define NCP_SYSCON_MASK_IPI15 (0x0000007c)
> +#define NCP_SYSCON_MASK_IPI16 (0x00000080)
> +#define NCP_SYSCON_MASK_IPI17 (0x00000084)
> +#define NCP_SYSCON_MASK_IPI18 (0x00000088)
> +#define NCP_SYSCON_SPARE0 (0x0000008c)
> +#define NCP_SYSCON_STOP_CLK_CPU (0x00000090)
> +
> +
> +#define NCP_SYSCON_RESET_STATUS (0x00000100)
> +#define NCP_SYSCON_RESET_CORE_STATUS (0x00000108)
> +
> +#define NCP_SYSCON_KEY (0x00001000)
> +#define NCP_SYSCON_RESET_CTL (0x00001008)
> +#define NCP_SYSCON_RESET_CPU (0x0000100c)
> +#define NCP_SYSCON_HOLD_CPU (0x00001010)
> +#define NCP_SYSCON_HOLD_PTM (0x00001014)
> +#define NCP_SYSCON_HOLD_L2 (0x00001018)
> +#define NCP_SYSCON_HOLD_DBG (0x0000101c)
> +
> +#define NCP_SYSCON_PWRUP_CPU_RST (0x00001030)
> +
> +#define NCP_SYSCON_RESET_AXIS (0x00001040)
> +#define NCP_SYSCON_RESET_AXIS_ACCESS_SIZE (0x00000008)
> +
> +#define NCP_SYSCON_PWR_CLKEN (0x00001400)
> +#define NCP_SYSCON_ENABLE_CLKEN_SET (0x00001404)
> +#define NCP_SYSCON_PWR_ACINACTM (0x00001408)
> +#define NCP_SYSCON_PWR_CHIPSELECTEN (0x0000140c)
> +#define NCP_SYSCON_PWR_CSYSREQ_TS (0x00001410)
> +#define NCP_SYSCON_PWR_CSYSREQ_CNT (0x00001414)
> +#define NCP_SYSCON_PWR_CSYSREQ_ATB (0x00001418)
> +#define NCP_SYSCON_PWR_CSYSREQ_APB (0x0000141c)
> +#define NCP_SYSCON_PWR_PWRUPL2LGCSTG1 (0x00001420)
> +#define NCP_SYSCON_PWR_PWRUPL2LGCSTG2 (0x00001424)
> +#define NCP_SYSCON_PWR_PWRUPL2HSRAM (0x00001428)
> +#define NCP_SYSCON_PWR_ACEPWRDNRQ (0x0000142c)
> +#define NCP_SYSCON_PWR_ISOLATEL2MISC (0x00001430)
> +#define NCP_SYSCON_PWR_NPWRUPL2LGCSTG1_ACK (0x00001438)
> +#define NCP_SYSCON_PWR_NPWRUPL2HSRAM_ACK (0x0000143c)
> +#define NCP_SYSCON_PWR_STANDBYWFIL2 (0x00001440)
> +#define NCP_SYSCON_PWR_CSYSACK_TS (0x00001444)
> +#define NCP_SYSCON_PWR_CACTIVE_TS (0x00001448)
> +#define NCP_SYSCON_PWR_CSYSACK_CNT (0x0000144c)
> +#define NCP_SYSCON_PWR_CACTIVE_CNT (0x00001450)
> +#define NCP_SYSCON_PWR_CSYSACK_ATB (0x00001454)
> +#define NCP_SYSCON_PWR_CACTIVE_ATB (0x00001458)
> +#define NCP_SYSCON_PWR_CSYSACK_APB (0x0000145c)
> +#define NCP_SYSCON_PWR_CACTIVE_APB (0x00001460)
> +#define NCP_SYSCON_PWR_NACEPWRDNACK (0x00001464)
> +#define NCP_SYSCON_PWR_CACTIVEM_EAGM (0x00001468)
> +#define NCP_SYSCON_PWR_CACTIVEM_EAGS (0x0000146c)
> +#define NCP_SYSCON_PWR_CACTIVES_EAGM (0x00001470)
> +#define NCP_SYSCON_PWR_CACTIVES_EAGS (0x00001474)
> +#define NCP_SYSCON_PWR_PWRUPCPUSTG1 (0x00001480)
> +#define NCP_SYSCON_PWR_PWRUPCPUSTG2 (0x00001484)
> +#define NCP_SYSCON_PWR_PWRUPCPURAM (0x00001488)
> +#define NCP_SYSCON_PWR_ISOLATECPU (0x0000148c)
> +#define NCP_SYSCON_PWR_NPWRUPCPUSTG1_ACK (0x00001490)
> +#define NCP_SYSCON_PWR_NPWRUPCPURAM_ACK (0x00001494)
> +#define NCP_SYSCON_PWR_QACTIVE (0x00001498)
> +#define NCP_SYSCON_PWR_STANDBYWFI (0x0000149c)
> +#define NCP_SYSCON_PWR_STANDBYWFE (0x000014a0)
> +#define NCP_SYSCON_PWR_DBGNOPWRDWN (0x000014a4)
> +#define NCP_SYSCON_PWR_DBGPWRUPREQ (0x000014a8)
> +#define NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM2 (0x00001580)
> +#define NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM1 (0x00001584)
> +#define NCP_SYSCON_PWR_PWRUPL20RAM_PWRUPL2RAM0 (0x00001588)
> +#define NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM2 (0x0000158c)
> +#define NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM1 (0x00001590)
> +#define NCP_SYSCON_PWR_PWRUPL21RAM_PWRUPL2RAM0 (0x00001594)
> +#define NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM2 (0x00001598)
> +#define NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM1 (0x0000159c)
> +#define NCP_SYSCON_PWR_PWRUPL22RAM_PWRUPL2RAM0 (0x000015a0)
> +#define NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM2 (0x000015a4)
> +#define NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM1 (0x000015a8)
> +#define NCP_SYSCON_PWR_PWRUPL23RAM_PWRUPL2RAM0 (0x000015ac)
> +
> +#define RAM_BANK0_MASK (0x0FFF0000)
> +#define RAM_BANK1_LS_MASK (0xF0000000)
> +#define RAM_BANK1_MS_MASK (0x000000FF)
> +#define RAM_BANK2_MASK (0x000FFF00)
> +#define RAM_BANK3_MASK (0xFFF00000)
> +#define RAM_ALL_MASK (0xFFFFFFFF)
> +
> +/* DICKENS REGISTERS (Miscelaneous Node) */
> +#define DKN_MN_NODE_ID (0x0)
> +#define DKN_DVM_DOMAIN_OFFSET (0x0)
> +#define DKN_MN_DVM_DOMAIN_CTL (0x200)
> +#define DKN_MN_DVM_DOMAIN_CTL_SET (0x210)
> +#define DKN_MN_DVM_DOMAIN_CTL_CLR (0x220)
> +
> +/* DICKENS HN-F (Fully-coherent Home Node) */
> +#define DKN_HNF_NODE_ID (0x20)
> +#define DKN_HNF_TOTAL_NODES (0x8)
> +#define DKN_HNF_SNOOP_DOMAIN_CTL (0x200)
> +#define DKN_HNF_SNOOP_DOMAIN_CTL_SET (0x210)
> +#define DKN_HNF_SNOOP_DOMAIN_CTL_CLR (0x220)
> +
> +/* DICKENS clustid to Node */
> +#define DKN_CLUSTER0_NODE (1)
> +#define DKN_CLUSTER1_NODE (9)
> +#define DKN_CLUSTER2_NODE (11)
> +#define DKN_CLUSTER3_NODE (19)
> +
> +/* PO RESET cluster id to bit */
> +#define PORESET_CLUSTER0 (0x10000)
> +#define PORESET_CLUSTER1 (0x20000)
> +#define PORESET_CLUSTER2 (0x40000)
> +#define PORESET_CLUSTER3 (0x80000)
> +
> +/* SYSCON KEY Value */
> +#define VALID_KEY_VALUE (0xAB)
> +
> +#define MAX_NUM_CLUSTERS (4)
> +#define CORES_PER_CLUSTER (4)
> +
> +typedef struct {
> + u32 cpu;
> + u32 cluster;
> +} pm_data;
> +
> +
> +void pm_cpu_shutdown(u32 cpu);
> +int pm_cpu_powerup(u32 cpu);
> +void pm_debug_read_pwr_registers(void);
> +void pm_dump_L2_registers(void);
> +void pm_cpu_logical_shutdown(void *data);
> +int pm_cpu_logical_die(pm_data *pm_request);
> +int pm_cpul2_logical_die(pm_data *pm_request);
> +unsigned long pm_get_powered_down_cpu(void);
> +bool pm_cpu_last_of_cluster(u32 cpu);
> +void pm_L2_logical_shutdown(void *data);
> +void pm_dump_dickens(void);
> +void pm_init_cpu(u32 cpu);
> +void pm_cpu_logical_powerup(void);
> +
> +extern bool pm_in_progress[];
> +extern bool cluster_power_up[];
> +
> +
> +#endif /* LSI_POWER_MANAGEMENT_H_ */
> diff --git a/arch/arm/mach-axxia/platsmp.c b/arch/arm/mach-axxia/platsmp.c
> index 44cde07..2d4d0e9 100644
> --- a/arch/arm/mach-axxia/platsmp.c
> +++ b/arch/arm/mach-axxia/platsmp.c
> @@ -23,6 +23,7 @@
> #include <asm/virt.h>
>
> #include "axxia.h"
> +#include "lsi_power_management.h"
> #include <mach/axxia-gic.h>
>
> extern void axxia_secondary_startup(void);
> @@ -88,10 +89,25 @@ static DEFINE_RAW_SPINLOCK(boot_lock);
>
> void __cpuinit axxia_secondary_init(unsigned int cpu)
> {
> - /* Fixup for cross-cluster SEV */
> - do_fixup_sev();
> + int phys_cpu, cluster;
> +
> + phys_cpu = cpu_logical_map(cpu);
> + cluster = (phys_cpu / 4) << 8;
>
> - axxia_gic_secondary_init();
> + /*
> + * Only execute this when powering up a cpu for hotplug.
> + */
> + if (!pm_in_progress[cpu]) {
> + /* Fixup for cross-cluster SEV */
> + do_fixup_sev();
> +
> + axxia_gic_secondary_init();
> + } else {
> + axxia_gic_secondary_init();
> + pm_cpu_logical_powerup();
> + pm_in_progress[cpu] = false;
> + cluster_power_up[cluster] = false;
> + }
>
> /*
> * Let the primary processor know we're out of the
> @@ -108,8 +124,12 @@ void __cpuinit axxia_secondary_init(unsigned int cpu)
>
> int __cpuinit axxia_boot_secondary(unsigned int cpu, struct task_struct *idle)
> {
> - unsigned long timeout;
> +
> int phys_cpu, cluster;
> + unsigned long timeout;
> + unsigned long powered_down_cpu;
> + int rVal = 0;
> +
>
> /*
> * Set synchronisation state between this boot processor
> @@ -117,6 +137,21 @@ int __cpuinit axxia_boot_secondary(unsigned int cpu, struct task_struct *idle)
> */
> _raw_spin_lock(&boot_lock);
>
> + phys_cpu = cpu_logical_map(cpu);
> +
> + powered_down_cpu = pm_get_powered_down_cpu();
> +
> + if (powered_down_cpu & (1 << phys_cpu)) {
> + pm_in_progress[cpu] = true;
> +
> + rVal = pm_cpu_powerup(phys_cpu);
> + if (rVal) {
> + _raw_spin_unlock(&boot_lock);
> + return rVal;
> + }
> +
> + }
> +
> /*
> * In the Axxia, the bootloader does not put the secondary cores
> * into a wait-for-event (wfe) or wait-for-interrupt (wfi) state
> @@ -260,6 +295,7 @@ struct smp_operations axxia_smp_ops __initdata = {
> .smp_boot_secondary = axxia_boot_secondary,
> #ifdef CONFIG_HOTPLUG_CPU
> .cpu_die = axxia_platform_cpu_die,
> + .cpu_kill = axxia_platform_cpu_kill,
> #endif
>
> };
>
More information about the linux-yocto
mailing list