diff mbox

[Xen-devel,v6] xen/arm : emulation of arm's PSCI v0.2 standard

Message ID 1406317971-8479-1-git-send-email-parth.dixit@linaro.org
State New
Headers show

Commit Message

Parth Dixit July 25, 2014, 7:52 p.m. UTC
Arm based virtual machines dom0/guest will request power related functionality
from xen through PSCI interface. This patch implements version 0.2 of
PSCI standard specified by arm for 64bit and 32 bit arm machines.

- removed arm_psci_fn_t
- implemented psci_cpu_on with additional error conditions
- added switch-case in do_trap_psci function
- added PSCI v0.2 macros in psci.h
- removed tables for PSCI v0.1 and v0.2
- implemented affinity_info
- moved do_common_cpu up in vpsci.c removed declaration
- removed PSCI_ARGS macro
- added new macro for 32 bit arguments
- added new function psci_mode_check
- modified cpu_suspend to return context_id
- added macros for checking powe_state

Signed-off-by: Parth Dixit <parth.dixit@linaro.org>
---
Changelog v6
- fixed indentation
- removed casting from error codes
- modified cpu_suspend to check power_state
- ignoring context_id in case of standby
- added comments for ignoring affinity
- added macro for checking power_state

Changelog v5
- removed PSCI_ARGS macro
- preload error value for calls that do not return
- added new macro for 32 bit arguments
- casting return calls to appropriate types
- added new function psci_mode_check
- added error checks for PSCI v0.2 function id's

Changelog v4
- added target_affinity_mask[] to local variable
- removed AFF3 masking for 64 bit cpu
- added do_common_cpu_on for PSCI v0.1 and v0.2
- moved cpu_on decision based on entry point
- removed vpsci_ver introduced in v3
- removed psci tables
- added new macro for selecting arguments
- do_trap_psci is now switch case based instead of tables

Changelog v3
- moved wfi helper to seperate patch
- replaced new wfi function in traps.c
- removed defining power_state variable using value directly
- added new line between declaration
- merged PSCI v0.1 and v0.2 cpu_on function to avoid duplication
- removed spurious change
- renamed PSCI return values to reflect v0.2 moved them to top
- removed PSCI v0.1 version declaration for now, will introduce it when needed
- removed hard tabs in the code lifted from linux
- removed PSCI_0_1_MAX
- did not retained copyright header from linux as most of functions are removed
- added two function tables for PSCI v0.1 and PSCI v0.2
- added compatibility string to libxl_arm to expose new functionality
- refactored affinity_info code
- added table for masking function
- removed definitions of unused PSCI v0.2 functions
- removed function id's of unused PSCI v0.2 functions
- renamed constant PSCI_0_2_TOS_MP ( multicore aware) as per spec

 tools/libxl/libxl_arm.c         |   2 +-
 xen/arch/arm/domain_build.c     |   5 +-
 xen/arch/arm/traps.c            | 127 +++++++++++++++++++++++++++----------
 xen/arch/arm/vpsci.c            | 137 ++++++++++++++++++++++++++++++++++++++--
 xen/include/asm-arm/processor.h |   3 +
 xen/include/asm-arm/psci.h      |  83 +++++++++++++++++++++---
 6 files changed, 309 insertions(+), 48 deletions(-)

Comments

Ian Campbell July 30, 2014, 11:14 a.m. UTC | #1
On Sat, 2014-07-26 at 01:22 +0530, Parth Dixit wrote:
> +    case PSCI_cpu_off:
> +        {
> +            uint32_t pstate = PSCI_ARG32(regs,1);
> +            PSCI_RESULT_REG(regs) = (int32_t) do_psci_cpu_off(pstate);

do_psci_cpu_off returns int32_t, so no need for this cast. The same is
true of all of the helpers, I think. Except perhaps MIGRATE_INFO_UP_CPU
which differs between 32- and 64-bit.

IOW I think this...

> +    case PSCI_0_2_FN_MIGRATE_INFO_UP_CPU:
> +        if ( psci_mode_check(current->domain, fid) )
> +            PSCI_RESULT_REG(regs) =
> +               (uint32_t) do_psci_0_2_migrate_info_up_cpu();

... is the only cast which might need to remain, and even there I'm not
sure.

do_psci_0_2_migrate_info_up_cpu() returns a register_t, which given the
currently trivial implementation I think is likely to be sufficient
without the cast.

> +register_t do_psci_0_2_cpu_suspend(uint32_t power_state, register_t entry_point,
> +                            register_t context_id)
> +{
> +    struct vcpu *v = current;
> +
> +    /* affinity values are ignored in this implementation as
> +     * at present xen does not supports affinity level greater
> +     * than 0, for all  affinity values passed we power down/ standby
> +     * the current core */
> +
> +    vcpu_block_unless_event_pending(v);
> +
> +    /* if power down is requested context_id must be returned in x0/r0
> +     * as the function return will be written in x0/r0 we return context_id
> +     * instead os success value */

The spec isn't clear on this, but I don't think this can be correct.

I expect the requirement is that you either return PSCI_SUCCESS to the
instruction after the smc or you return to entry_point with
x0==context_id. I don't think it makes sense to return after the smc
with the x0==context_id. This is implied by section 5.4.2 bullet #4
which talks about handling PSCI return codes.

I'm going to ask ARM for clarification, please stand by.

Ian.
Ian Campbell July 30, 2014, 1:25 p.m. UTC | #2
On Wed, 2014-07-30 at 12:14 +0100, Ian Campbell wrote:
> > +register_t do_psci_0_2_cpu_suspend(uint32_t power_state, register_t entry_point,
> > +                            register_t context_id)
> > +{
> > +    struct vcpu *v = current;
> > +
> > +    /* affinity values are ignored in this implementation as
> > +     * at present xen does not supports affinity level greater
> > +     * than 0, for all  affinity values passed we power down/ standby
> > +     * the current core */
> > +
> > +    vcpu_block_unless_event_pending(v);
> > +
> > +    /* if power down is requested context_id must be returned in x0/r0
> > +     * as the function return will be written in x0/r0 we return context_id
> > +     * instead os success value */
> 
> The spec isn't clear on this, but I don't think this can be correct.
> 
> I expect the requirement is that you either return PSCI_SUCCESS to the
> instruction after the smc or you return to entry_point with
> x0==context_id. I don't think it makes sense to return after the smc
> with the x0==context_id. This is implied by section 5.4.2 bullet #4
> which talks about handling PSCI return codes.
> 
> I'm going to ask ARM for clarification, please stand by.

ARM have confirmed. If you are returning to the instruction after the
smc then you should return a PSCI error code in x0, not context_id.

Ian.
diff mbox

Patch

diff --git a/tools/libxl/libxl_arm.c b/tools/libxl/libxl_arm.c
index 4f0f0e2..e8bcd05 100644
--- a/tools/libxl/libxl_arm.c
+++ b/tools/libxl/libxl_arm.c
@@ -237,7 +237,7 @@  static int make_psci_node(libxl__gc *gc, void *fdt)
     res = fdt_begin_node(fdt, "psci");
     if (res) return res;
 
-    res = fdt_property_compat(gc, fdt, 1, "arm,psci");
+    res = fdt_property_compat(gc, fdt, 2, "arm,psci-0.2","arm,psci");
     if (res) return res;
 
     res = fdt_property_string(fdt, "method", "hvc");
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index c424793..ebd4170 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -388,6 +388,9 @@  static int make_hypervisor_node(struct domain *d,
 static int make_psci_node(void *fdt, const struct dt_device_node *parent)
 {
     int res;
+    const char compat[] =
+        "arm,psci-0.2""\0"
+        "arm,psci";
 
     DPRINT("Create PSCI node\n");
 
@@ -396,7 +399,7 @@  static int make_psci_node(void *fdt, const struct dt_device_node *parent)
     if ( res )
         return res;
 
-    res = fdt_property_string(fdt, "compatible", "arm,psci");
+    res = fdt_property(fdt, "compatible", compat, sizeof(compat));
     if ( res )
         return res;
 
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 8102540..6d6da1e 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -1030,24 +1030,6 @@  static arm_hypercall_t arm_hypercall_table[] = {
     HYPERCALL_ARM(vcpu_op, 3),
 };
 
-typedef int (*arm_psci_fn_t)(uint32_t, register_t);
-
-typedef struct {
-    arm_psci_fn_t fn;
-    int nr_args;
-} arm_psci_t;
-
-#define PSCI(_name, _nr_args)                                  \
-    [ PSCI_ ## _name ] =  {                                    \
-        .fn = (arm_psci_fn_t) &do_psci_ ## _name,              \
-        .nr_args = _nr_args,                                   \
-    }
-
-static arm_psci_t arm_psci_table[] = {
-    PSCI(cpu_off, 1),
-    PSCI(cpu_on, 2),
-};
-
 #ifndef NDEBUG
 static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code)
 {
@@ -1080,33 +1062,112 @@  static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code)
 #endif
 
 #ifdef CONFIG_ARM_64
-#define PSCI_OP_REG(r) (r)->x0
 #define PSCI_RESULT_REG(r) (r)->x0
-#define PSCI_ARGS(r) (r)->x1, (r)->x2
+#define PSCI_ARG(r,n) (r)->x##n
+#define PSCI_ARG32(r,n) (uint32_t)( (r)->x##n & 0x00000000FFFFFFFF )
 #else
-#define PSCI_OP_REG(r) (r)->r0
 #define PSCI_RESULT_REG(r) (r)->r0
-#define PSCI_ARGS(r) (r)->r1, (r)->r2
+#define PSCI_ARG(r,n) (r)->r##n
+#define PSCI_ARG32(r,n) PSCI_ARG(r,n)
 #endif
 
-static void do_trap_psci(struct cpu_user_regs *regs)
+/* helper function for checking arm mode 32/64 bit */
+static inline int psci_mode_check(struct domain *d, register_t fid)
 {
-    arm_psci_fn_t psci_call = NULL;
+        return !( is_64bit_domain(d)^( (fid & PSCI_0_2_64BIT) >> 30 ) );
+}
 
-    if ( PSCI_OP_REG(regs) >= ARRAY_SIZE(arm_psci_table) )
-    {
-        domain_crash_synchronous();
-        return;
-    }
+static void do_trap_psci(struct cpu_user_regs *regs)
+{
+    register_t fid = PSCI_ARG(regs,0);
 
-    psci_call = arm_psci_table[PSCI_OP_REG(regs)].fn;
-    if ( psci_call == NULL )
+    /* preloading in case psci_mode_check fails */
+    PSCI_RESULT_REG(regs) = PSCI_INVALID_PARAMETERS;
+    switch( fid )
     {
+    case PSCI_cpu_off:
+        {
+            uint32_t pstate = PSCI_ARG32(regs,1);
+            PSCI_RESULT_REG(regs) = (int32_t) do_psci_cpu_off(pstate);
+        }
+        break;
+    case PSCI_cpu_on:
+        {
+            uint32_t vcpuid = PSCI_ARG32(regs,1);
+            register_t epoint = PSCI_ARG(regs,2);
+            PSCI_RESULT_REG(regs) = (int32_t) do_psci_cpu_on(vcpuid, epoint);
+        }
+        break;
+    case PSCI_0_2_FN_PSCI_VERSION:
+        PSCI_RESULT_REG(regs) = (uint32_t) do_psci_0_2_version();
+        break;
+    case PSCI_0_2_FN_CPU_OFF:
+        PSCI_RESULT_REG(regs) = (int32_t) do_psci_0_2_cpu_off();
+        break;
+    case PSCI_0_2_FN_MIGRATE_INFO_TYPE:
+        PSCI_RESULT_REG(regs) = (uint32_t) do_psci_0_2_migrate_info_type();
+        break;
+    case PSCI_0_2_FN_MIGRATE_INFO_UP_CPU:
+        if ( psci_mode_check(current->domain, fid) )
+            PSCI_RESULT_REG(regs) =
+               (uint32_t) do_psci_0_2_migrate_info_up_cpu();
+        break;
+    case PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU:
+        if ( psci_mode_check(current->domain, fid) )
+            PSCI_RESULT_REG(regs) = do_psci_0_2_migrate_info_up_cpu();
+        break;
+    case PSCI_0_2_FN_SYSTEM_OFF:
+        do_psci_0_2_system_off();
+        PSCI_RESULT_REG(regs) = PSCI_INTERNAL_FAILURE;
+        break;
+    case PSCI_0_2_FN_SYSTEM_RESET:
+        do_psci_0_2_system_reset();
+        PSCI_RESULT_REG(regs) = PSCI_INTERNAL_FAILURE;
+        break;
+    case PSCI_0_2_FN_CPU_ON:
+    case PSCI_0_2_FN64_CPU_ON:
+        if ( psci_mode_check(current->domain, fid) )
+        {
+            register_t vcpuid = PSCI_ARG(regs,1);
+            register_t epoint = PSCI_ARG(regs,2);
+            register_t cid = PSCI_ARG(regs,3);
+            PSCI_RESULT_REG(regs) =
+                (int32_t) do_psci_0_2_cpu_on(vcpuid, epoint, cid);
+        }
+        break;
+    case PSCI_0_2_FN_CPU_SUSPEND:
+    case PSCI_0_2_FN64_CPU_SUSPEND:
+        if ( psci_mode_check(current->domain, fid) )
+        {
+            uint32_t pstate = PSCI_ARG32(regs,1);
+            register_t epoint = PSCI_ARG(regs,2);
+            register_t cid = PSCI_ARG(regs,3);
+            PSCI_RESULT_REG(regs) =
+                do_psci_0_2_cpu_suspend(pstate, epoint, cid);
+        }
+        break;
+    case PSCI_0_2_FN_AFFINITY_INFO:
+    case PSCI_0_2_FN64_AFFINITY_INFO:
+        if ( psci_mode_check(current->domain, fid) )
+        {
+            register_t taff = PSCI_ARG(regs,1);
+            uint32_t laff = PSCI_ARG32(regs,2);
+            PSCI_RESULT_REG(regs) =
+                (int32_t) do_psci_0_2_affinity_info(taff, laff);
+        }
+        break;
+    case PSCI_0_2_FN_MIGRATE:
+    case PSCI_0_2_FN64_MIGRATE:
+        if ( psci_mode_check(current->domain, fid) )
+        {
+            uint32_t tcpu = PSCI_ARG32(regs,1);
+            PSCI_RESULT_REG(regs) = (int32_t) do_psci_0_2_migrate(tcpu);
+        }
+        break;
+    default:
         domain_crash_synchronous();
         return;
     }
-
-    PSCI_RESULT_REG(regs) = psci_call(PSCI_ARGS(regs));
 }
 
 #ifdef CONFIG_ARM_64
diff --git a/xen/arch/arm/vpsci.c b/xen/arch/arm/vpsci.c
index 1ceb8cb..fc8f02e 100644
--- a/xen/arch/arm/vpsci.c
+++ b/xen/arch/arm/vpsci.c
@@ -17,24 +17,37 @@ 
 #include <asm/current.h>
 #include <asm/gic.h>
 #include <asm/psci.h>
+#include <public/sched.h>
+#include <asm-arm/event.h>
 
-int do_psci_cpu_on(uint32_t vcpuid, register_t entry_point)
+static int do_common_cpu_on(register_t target_cpu, register_t entry_point,
+                       register_t context_id,int ver)
 {
     struct vcpu *v;
     struct domain *d = current->domain;
     struct vcpu_guest_context *ctxt;
     int rc;
     int is_thumb = entry_point & 1;
+    register_t vcpuid;
+
+    if( ver == XEN_PSCI_V_0_2 )
+        vcpuid = (target_cpu & MPIDR_HWID_MASK);
+    else
+        vcpuid = target_cpu;
 
     if ( (vcpuid < 0) || (vcpuid >= MAX_VIRT_CPUS) )
-        return PSCI_EINVAL;
+        return PSCI_INVALID_PARAMETERS;
 
     if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL )
-        return PSCI_EINVAL;
+        return PSCI_INVALID_PARAMETERS;
 
     /* THUMB set is not allowed with 64-bit domain */
     if ( is_64bit_domain(d) && is_thumb )
-        return PSCI_EINVAL;
+        return PSCI_INVALID_PARAMETERS;
+
+    if( ( ver == XEN_PSCI_V_0_2 ) &&
+            ( !test_bit(_VPF_down, &v->pause_flags) ) )
+        return PSCI_ALREADY_ON;
 
     if ( (ctxt = alloc_vcpu_guest_context()) == NULL )
         return PSCI_DENIED;
@@ -48,10 +61,18 @@  int do_psci_cpu_on(uint32_t vcpuid, register_t entry_point)
     ctxt->ttbr1 = 0;
     ctxt->ttbcr = 0; /* Defined Reset Value */
     if ( is_32bit_domain(d) )
+    {
         ctxt->user_regs.cpsr = PSR_GUEST32_INIT;
+        if( ver == XEN_PSCI_V_0_2 )
+            ctxt->user_regs.r0_usr = context_id;
+    }
 #ifdef CONFIG_ARM_64
     else
+    {
         ctxt->user_regs.cpsr = PSR_GUEST64_INIT;
+        if( ver == XEN_PSCI_V_0_2 )
+            ctxt->user_regs.x0 = context_id;
+    }
 #endif
 
     /* Start the VCPU with THUMB set if it's requested by the kernel */
@@ -75,7 +96,12 @@  int do_psci_cpu_on(uint32_t vcpuid, register_t entry_point)
     return PSCI_SUCCESS;
 }
 
-int do_psci_cpu_off(uint32_t power_state)
+int32_t do_psci_cpu_on(uint32_t vcpuid, register_t entry_point)
+{
+    return do_common_cpu_on(vcpuid,entry_point,0,XEN_PSCI_V_0_1);
+}
+
+int32_t do_psci_cpu_off(uint32_t power_state)
 {
     struct vcpu *v = current;
     if ( !test_and_set_bit(_VPF_down, &v->pause_flags) )
@@ -83,6 +109,107 @@  int do_psci_cpu_off(uint32_t power_state)
     return PSCI_SUCCESS;
 }
 
+uint32_t do_psci_0_2_version(void)
+{
+    return XEN_PSCI_V_0_2;
+}
+
+register_t do_psci_0_2_cpu_suspend(uint32_t power_state, register_t entry_point,
+                            register_t context_id)
+{
+    struct vcpu *v = current;
+
+    /* affinity values are ignored in this implementation as
+     * at present xen does not supports affinity level greater
+     * than 0, for all  affinity values passed we power down/ standby
+     * the current core */
+
+    vcpu_block_unless_event_pending(v);
+
+    /* if power down is requested context_id must be returned in x0/r0
+     * as the function return will be written in x0/r0 we return context_id
+     * instead os success value */
+    if( power_state & PSCI_0_2_POWER_STATE_TYPE_MASK )
+        return context_id;
+    else
+        return PSCI_SUCCESS;
+}
+
+int32_t do_psci_0_2_cpu_off(void)
+{
+    return do_psci_cpu_off(0);
+}
+
+int32_t do_psci_0_2_cpu_on(register_t target_cpu, register_t entry_point,
+                       register_t context_id)
+{
+    return do_common_cpu_on(target_cpu,entry_point,context_id,XEN_PSCI_V_0_2);
+}
+
+static const unsigned long target_affinity_mask[] = {
+    ( MPIDR_HWID_MASK & AFFINITY_MASK( 0 ) ),
+    ( MPIDR_HWID_MASK & AFFINITY_MASK( 1 ) ),
+    ( MPIDR_HWID_MASK & AFFINITY_MASK( 2 ) )
+#ifdef CONFIG_ARM_64
+    ,( MPIDR_HWID_MASK & AFFINITY_MASK( 3 ) )
+#endif
+};
+
+int32_t do_psci_0_2_affinity_info(register_t target_affinity,
+                              uint32_t lowest_affinity_level)
+{
+    struct domain *d = current->domain;
+    struct vcpu *v;
+    uint32_t vcpuid;
+    unsigned long tmask;
+
+    if ( lowest_affinity_level < ARRAY_SIZE(target_affinity_mask) )
+    {
+        tmask = target_affinity_mask[lowest_affinity_level];
+        target_affinity &= tmask;
+    }
+    else
+        return PSCI_INVALID_PARAMETERS;
+
+    for ( vcpuid = 0; vcpuid < d->max_vcpus; vcpuid++ )
+    {
+        v = d->vcpu[vcpuid];
+
+        if ( ( ( v->arch.vmpidr & tmask ) == target_affinity )
+                && ( !test_bit(_VPF_down, &v->pause_flags) ) )
+            return PSCI_0_2_AFFINITY_LEVEL_ON;
+    }
+
+    return PSCI_0_2_AFFINITY_LEVEL_OFF;
+}
+
+int32_t do_psci_0_2_migrate(uint32_t target_cpu)
+{
+    return PSCI_NOT_SUPPORTED;
+}
+
+uint32_t do_psci_0_2_migrate_info_type(void)
+{
+    return PSCI_0_2_TOS_MP_OR_NOT_PRESENT;
+}
+
+register_t do_psci_0_2_migrate_info_up_cpu(void)
+{
+    return PSCI_NOT_SUPPORTED;
+}
+
+void do_psci_0_2_system_off( void )
+{
+    struct domain *d = current->domain;
+    domain_shutdown(d,SHUTDOWN_poweroff);
+}
+
+void do_psci_0_2_system_reset(void)
+{
+    struct domain *d = current->domain;
+    domain_shutdown(d,SHUTDOWN_reboot);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h
index 9267c1b..8a237c4 100644
--- a/xen/include/asm-arm/processor.h
+++ b/xen/include/asm-arm/processor.h
@@ -16,6 +16,9 @@ 
 #define MPIDR_AFF0_MASK     (_AC(0xff,U) << MPIDR_AFF0_SHIFT)
 #define MPIDR_HWID_MASK     _AC(0xffffff,U)
 #define MPIDR_INVALID       (~MPIDR_HWID_MASK)
+#define MPIDR_LEVEL_BITS    (8)
+#define AFFINITY_MASK(level)    ~((_AC(0x1,U) << ((level) * MPIDR_LEVEL_BITS)) - 1)
+
 
 /* TTBCR Translation Table Base Control Register */
 #define TTBCR_EAE    _AC(0x80000000,U)
diff --git a/xen/include/asm-arm/psci.h b/xen/include/asm-arm/psci.h
index 189964b..9777c03 100644
--- a/xen/include/asm-arm/psci.h
+++ b/xen/include/asm-arm/psci.h
@@ -1,10 +1,16 @@ 
 #ifndef __ASM_PSCI_H__
 #define __ASM_PSCI_H__
 
-#define PSCI_SUCCESS  0
-#define PSCI_ENOSYS  -1
-#define PSCI_EINVAL  -2
-#define PSCI_DENIED  -3
+/* PSCI return values (inclusive of all PSCI versions) */
+#define PSCI_SUCCESS                 0
+#define PSCI_NOT_SUPPORTED          -1
+#define PSCI_INVALID_PARAMETERS     -2
+#define PSCI_DENIED                 -3
+#define PSCI_ALREADY_ON             -4
+#define PSCI_ON_PENDING             -5
+#define PSCI_INTERNAL_FAILURE       -6
+#define PSCI_NOT_PRESENT            -7
+#define PSCI_DISABLED               -8
 
 /* availability of PSCI on the host for SMP bringup */
 extern bool_t psci_available;
@@ -13,10 +19,71 @@  int psci_init(void);
 int call_psci_cpu_on(int cpu);
 
 /* functions to handle guest PSCI requests */
-int do_psci_cpu_on(uint32_t vcpuid, register_t entry_point);
-int do_psci_cpu_off(uint32_t power_state);
-int do_psci_cpu_suspend(uint32_t power_state, register_t entry_point);
-int do_psci_migrate(uint32_t vcpuid);
+int32_t do_psci_cpu_on(uint32_t vcpuid, register_t entry_point);
+int32_t do_psci_cpu_off(uint32_t power_state);
+int32_t do_psci_cpu_suspend(uint32_t power_state, register_t entry_point);
+int32_t do_psci_migrate(uint32_t vcpuid);
+
+/* PSCI 0.2 functions to handle guest PSCI requests */
+uint32_t do_psci_0_2_version(void);
+register_t do_psci_0_2_cpu_suspend(uint32_t power_state, register_t entry_point,
+                            register_t context_id);
+int32_t do_psci_0_2_cpu_off(void);
+int32_t do_psci_0_2_cpu_on(register_t target_cpu, register_t entry_point,
+                       register_t context_id);
+int32_t do_psci_0_2_affinity_info(register_t target_affinity,
+                              uint32_t lowest_affinity_level);
+int32_t do_psci_0_2_migrate(uint32_t target_cpu);
+uint32_t do_psci_0_2_migrate_info_type(void);
+register_t do_psci_0_2_migrate_info_up_cpu(void);
+void do_psci_0_2_system_off(void);
+void do_psci_0_2_system_reset(void);
+
+/* PSCI version */
+#define XEN_PSCI_V_0_1 1
+#define XEN_PSCI_V_0_2 2
+
+/* PSCI v0.2 interface */
+#define PSCI_0_2_FN_BASE        0x84000000
+#define PSCI_0_2_FN(n)          (PSCI_0_2_FN_BASE + (n))
+#define PSCI_0_2_64BIT          0x40000000
+#define PSCI_0_2_FN64_BASE      \
+                        (PSCI_0_2_FN_BASE + PSCI_0_2_64BIT)
+#define PSCI_0_2_FN64(n)        (PSCI_0_2_FN64_BASE + (n))
+
+#define PSCI_0_2_FN_PSCI_VERSION        PSCI_0_2_FN(0)
+#define PSCI_0_2_FN_CPU_SUSPEND         PSCI_0_2_FN(1)
+#define PSCI_0_2_FN_CPU_OFF             PSCI_0_2_FN(2)
+#define PSCI_0_2_FN_CPU_ON              PSCI_0_2_FN(3)
+#define PSCI_0_2_FN_AFFINITY_INFO       PSCI_0_2_FN(4)
+#define PSCI_0_2_FN_MIGRATE             PSCI_0_2_FN(5)
+#define PSCI_0_2_FN_MIGRATE_INFO_TYPE   PSCI_0_2_FN(6)
+#define PSCI_0_2_FN_MIGRATE_INFO_UP_CPU PSCI_0_2_FN(7)
+#define PSCI_0_2_FN_SYSTEM_OFF          PSCI_0_2_FN(8)
+#define PSCI_0_2_FN_SYSTEM_RESET        PSCI_0_2_FN(9)
+
+#define PSCI_0_2_FN64_CPU_SUSPEND       PSCI_0_2_FN64(1)
+#define PSCI_0_2_FN64_CPU_ON            PSCI_0_2_FN64(3)
+#define PSCI_0_2_FN64_AFFINITY_INFO     PSCI_0_2_FN64(4)
+#define PSCI_0_2_FN64_MIGRATE           PSCI_0_2_FN64(5)
+#define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU   PSCI_0_2_FN64(7)
+
+/* PSCI v0.2 affinity level state returned by AFFINITY_INFO */
+#define PSCI_0_2_AFFINITY_LEVEL_ON      0
+#define PSCI_0_2_AFFINITY_LEVEL_OFF     1
+#define PSCI_0_2_AFFINITY_LEVEL_ON_PENDING  2
+
+/* PSCI v0.2 multicore support in Trusted OS returned by MIGRATE_INFO_TYPE */
+#define PSCI_0_2_TOS_UP_MIGRATE_CAPABLE          0
+#define PSCI_0_2_TOS_UP_NOT_MIGRATE_CAPABLE      1
+#define PSCI_0_2_TOS_MP_OR_NOT_PRESENT           2
+
+/* PSCI v0.2 power state encoding for CPU_SUSPEND function */
+#define PSCI_0_2_POWER_STATE_ID_MASK        0xffff
+#define PSCI_0_2_POWER_STATE_ID_SHIFT       0
+#define PSCI_0_2_POWER_STATE_TYPE_SHIFT     16
+#define PSCI_0_2_POWER_STATE_TYPE_MASK      \
+                    (0x1 << PSCI_0_2_POWER_STATE_TYPE_SHIFT)
 
 #endif /* __ASM_PSCI_H__ */