Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
3ad06d1a
Commit
3ad06d1a
authored
Feb 11, 2013
by
Olof Johansson
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'depends/rmk-psci' into next/virt
parents
4f5c1c04
2bdd424f
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
338 additions
and
0 deletions
+338
-0
Documentation/devicetree/bindings/arm/psci.txt
Documentation/devicetree/bindings/arm/psci.txt
+55
-0
arch/arm/Kconfig
arch/arm/Kconfig
+10
-0
arch/arm/include/asm/opcodes-sec.h
arch/arm/include/asm/opcodes-sec.h
+24
-0
arch/arm/include/asm/opcodes.h
arch/arm/include/asm/opcodes.h
+1
-0
arch/arm/include/asm/psci.h
arch/arm/include/asm/psci.h
+36
-0
arch/arm/kernel/Makefile
arch/arm/kernel/Makefile
+1
-0
arch/arm/kernel/psci.c
arch/arm/kernel/psci.c
+211
-0
No files found.
Documentation/devicetree/bindings/arm/psci.txt
0 → 100644
View file @
3ad06d1a
* Power State Coordination Interface (PSCI)
Firmware implementing the PSCI functions described in ARM document number
ARM DEN 0022A ("Power State Coordination Interface System Software on ARM
processors") can be used by Linux to initiate various CPU-centric power
operations.
Issue A of the specification describes functions for CPU suspend, hotplug
and migration of secure software.
Functions are invoked by trapping to the privilege level of the PSCI
firmware (specified as part of the binding below) and passing arguments
in a manner similar to that specified by AAPCS:
r0 => 32-bit Function ID / return value
{r1 - r3} => Parameters
Note that the immediate field of the trapping instruction must be set
to #0.
Main node required properties:
- compatible : Must be "arm,psci"
- method : The method of calling the PSCI firmware. Permitted
values are:
"smc" : SMC #0, with the register assignments specified
in this binding.
"hvc" : HVC #0, with the register assignments specified
in this binding.
Main node optional properties:
- cpu_suspend : Function ID for CPU_SUSPEND operation
- cpu_off : Function ID for CPU_OFF operation
- cpu_on : Function ID for CPU_ON operation
- migrate : Function ID for MIGRATE operation
Example:
psci {
compatible = "arm,psci";
method = "smc";
cpu_suspend = <0x95c10000>;
cpu_off = <0x95c10001>;
cpu_on = <0x95c10002>;
migrate = <0x95c10003>;
};
arch/arm/Kconfig
View file @
3ad06d1a
...
...
@@ -1622,6 +1622,16 @@ config HOTPLUG_CPU
Say Y here to experiment with turning CPUs off and on. CPUs
can be controlled through /sys/devices/system/cpu.
config ARM_PSCI
bool "Support for the ARM Power State Coordination Interface (PSCI)"
depends on CPU_V7
help
Say Y here if you want Linux to communicate with system firmware
implementing the PSCI specification for CPU-centric power
management operations described in ARM document number ARM DEN
0022A ("Power State Coordination Interface System Software on
ARM processors").
config LOCAL_TIMERS
bool "Use local timer interrupts"
depends on SMP
...
...
arch/arm/include/asm/opcodes-sec.h
0 → 100644
View file @
3ad06d1a
/*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Copyright (C) 2012 ARM Limited
*/
#ifndef __ASM_ARM_OPCODES_SEC_H
#define __ASM_ARM_OPCODES_SEC_H
#include <asm/opcodes.h>
#define __SMC(imm4) __inst_arm_thumb32( \
0xE1600070 | (((imm4) & 0xF) << 0), \
0xF7F08000 | (((imm4) & 0xF) << 16) \
)
#endif
/* __ASM_ARM_OPCODES_SEC_H */
arch/arm/include/asm/opcodes.h
View file @
3ad06d1a
...
...
@@ -10,6 +10,7 @@
#define __ASM_ARM_OPCODES_H
#ifndef __ASSEMBLY__
#include <linux/linkage.h>
extern
asmlinkage
unsigned
int
arm_check_condition
(
u32
opcode
,
u32
psr
);
#endif
...
...
arch/arm/include/asm/psci.h
0 → 100644
View file @
3ad06d1a
/*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Copyright (C) 2012 ARM Limited
*/
#ifndef __ASM_ARM_PSCI_H
#define __ASM_ARM_PSCI_H
#define PSCI_POWER_STATE_TYPE_STANDBY 0
#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1
struct
psci_power_state
{
u16
id
;
u8
type
;
u8
affinity_level
;
};
struct
psci_operations
{
int
(
*
cpu_suspend
)(
struct
psci_power_state
state
,
unsigned
long
entry_point
);
int
(
*
cpu_off
)(
struct
psci_power_state
state
);
int
(
*
cpu_on
)(
unsigned
long
cpuid
,
unsigned
long
entry_point
);
int
(
*
migrate
)(
unsigned
long
cpuid
);
};
extern
struct
psci_operations
psci_ops
;
#endif
/* __ASM_ARM_PSCI_H */
arch/arm/kernel/Makefile
View file @
3ad06d1a
...
...
@@ -82,5 +82,6 @@ obj-$(CONFIG_DEBUG_LL) += debug.o
obj-$(CONFIG_EARLY_PRINTK)
+=
early_printk.o
obj-$(CONFIG_ARM_VIRT_EXT)
+=
hyp-stub.o
obj-$(CONFIG_ARM_PSCI)
+=
psci.o
extra-y
:=
$
(
head-y
)
vmlinux.lds
arch/arm/kernel/psci.c
0 → 100644
View file @
3ad06d1a
/*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Copyright (C) 2012 ARM Limited
*
* Author: Will Deacon <will.deacon@arm.com>
*/
#define pr_fmt(fmt) "psci: " fmt
#include <linux/init.h>
#include <linux/of.h>
#include <asm/compiler.h>
#include <asm/errno.h>
#include <asm/opcodes-sec.h>
#include <asm/opcodes-virt.h>
#include <asm/psci.h>
struct
psci_operations
psci_ops
;
static
int
(
*
invoke_psci_fn
)(
u32
,
u32
,
u32
,
u32
);
enum
psci_function
{
PSCI_FN_CPU_SUSPEND
,
PSCI_FN_CPU_ON
,
PSCI_FN_CPU_OFF
,
PSCI_FN_MIGRATE
,
PSCI_FN_MAX
,
};
static
u32
psci_function_id
[
PSCI_FN_MAX
];
#define PSCI_RET_SUCCESS 0
#define PSCI_RET_EOPNOTSUPP -1
#define PSCI_RET_EINVAL -2
#define PSCI_RET_EPERM -3
static
int
psci_to_linux_errno
(
int
errno
)
{
switch
(
errno
)
{
case
PSCI_RET_SUCCESS
:
return
0
;
case
PSCI_RET_EOPNOTSUPP
:
return
-
EOPNOTSUPP
;
case
PSCI_RET_EINVAL
:
return
-
EINVAL
;
case
PSCI_RET_EPERM
:
return
-
EPERM
;
};
return
-
EINVAL
;
}
#define PSCI_POWER_STATE_ID_MASK 0xffff
#define PSCI_POWER_STATE_ID_SHIFT 0
#define PSCI_POWER_STATE_TYPE_MASK 0x1
#define PSCI_POWER_STATE_TYPE_SHIFT 16
#define PSCI_POWER_STATE_AFFL_MASK 0x3
#define PSCI_POWER_STATE_AFFL_SHIFT 24
static
u32
psci_power_state_pack
(
struct
psci_power_state
state
)
{
return
((
state
.
id
&
PSCI_POWER_STATE_ID_MASK
)
<<
PSCI_POWER_STATE_ID_SHIFT
)
|
((
state
.
type
&
PSCI_POWER_STATE_TYPE_MASK
)
<<
PSCI_POWER_STATE_TYPE_SHIFT
)
|
((
state
.
affinity_level
&
PSCI_POWER_STATE_AFFL_MASK
)
<<
PSCI_POWER_STATE_AFFL_SHIFT
);
}
/*
* The following two functions are invoked via the invoke_psci_fn pointer
* and will not be inlined, allowing us to piggyback on the AAPCS.
*/
static
noinline
int
__invoke_psci_fn_hvc
(
u32
function_id
,
u32
arg0
,
u32
arg1
,
u32
arg2
)
{
asm
volatile
(
__asmeq
(
"%0"
,
"r0"
)
__asmeq
(
"%1"
,
"r1"
)
__asmeq
(
"%2"
,
"r2"
)
__asmeq
(
"%3"
,
"r3"
)
__HVC
(
0
)
:
"+r"
(
function_id
)
:
"r"
(
arg0
),
"r"
(
arg1
),
"r"
(
arg2
));
return
function_id
;
}
static
noinline
int
__invoke_psci_fn_smc
(
u32
function_id
,
u32
arg0
,
u32
arg1
,
u32
arg2
)
{
asm
volatile
(
__asmeq
(
"%0"
,
"r0"
)
__asmeq
(
"%1"
,
"r1"
)
__asmeq
(
"%2"
,
"r2"
)
__asmeq
(
"%3"
,
"r3"
)
__SMC
(
0
)
:
"+r"
(
function_id
)
:
"r"
(
arg0
),
"r"
(
arg1
),
"r"
(
arg2
));
return
function_id
;
}
static
int
psci_cpu_suspend
(
struct
psci_power_state
state
,
unsigned
long
entry_point
)
{
int
err
;
u32
fn
,
power_state
;
fn
=
psci_function_id
[
PSCI_FN_CPU_SUSPEND
];
power_state
=
psci_power_state_pack
(
state
);
err
=
invoke_psci_fn
(
fn
,
power_state
,
entry_point
,
0
);
return
psci_to_linux_errno
(
err
);
}
static
int
psci_cpu_off
(
struct
psci_power_state
state
)
{
int
err
;
u32
fn
,
power_state
;
fn
=
psci_function_id
[
PSCI_FN_CPU_OFF
];
power_state
=
psci_power_state_pack
(
state
);
err
=
invoke_psci_fn
(
fn
,
power_state
,
0
,
0
);
return
psci_to_linux_errno
(
err
);
}
static
int
psci_cpu_on
(
unsigned
long
cpuid
,
unsigned
long
entry_point
)
{
int
err
;
u32
fn
;
fn
=
psci_function_id
[
PSCI_FN_CPU_ON
];
err
=
invoke_psci_fn
(
fn
,
cpuid
,
entry_point
,
0
);
return
psci_to_linux_errno
(
err
);
}
static
int
psci_migrate
(
unsigned
long
cpuid
)
{
int
err
;
u32
fn
;
fn
=
psci_function_id
[
PSCI_FN_MIGRATE
];
err
=
invoke_psci_fn
(
fn
,
cpuid
,
0
,
0
);
return
psci_to_linux_errno
(
err
);
}
static
const
struct
of_device_id
psci_of_match
[]
__initconst
=
{
{
.
compatible
=
"arm,psci"
,
},
{},
};
static
int
__init
psci_init
(
void
)
{
struct
device_node
*
np
;
const
char
*
method
;
u32
id
;
np
=
of_find_matching_node
(
NULL
,
psci_of_match
);
if
(
!
np
)
return
0
;
pr_info
(
"probing function IDs from device-tree
\n
"
);
if
(
of_property_read_string
(
np
,
"method"
,
&
method
))
{
pr_warning
(
"missing
\"
method
\"
property
\n
"
);
goto
out_put_node
;
}
if
(
!
strcmp
(
"hvc"
,
method
))
{
invoke_psci_fn
=
__invoke_psci_fn_hvc
;
}
else
if
(
!
strcmp
(
"smc"
,
method
))
{
invoke_psci_fn
=
__invoke_psci_fn_smc
;
}
else
{
pr_warning
(
"invalid
\"
method
\"
property: %s
\n
"
,
method
);
goto
out_put_node
;
}
if
(
!
of_property_read_u32
(
np
,
"cpu_suspend"
,
&
id
))
{
psci_function_id
[
PSCI_FN_CPU_SUSPEND
]
=
id
;
psci_ops
.
cpu_suspend
=
psci_cpu_suspend
;
}
if
(
!
of_property_read_u32
(
np
,
"cpu_off"
,
&
id
))
{
psci_function_id
[
PSCI_FN_CPU_OFF
]
=
id
;
psci_ops
.
cpu_off
=
psci_cpu_off
;
}
if
(
!
of_property_read_u32
(
np
,
"cpu_on"
,
&
id
))
{
psci_function_id
[
PSCI_FN_CPU_ON
]
=
id
;
psci_ops
.
cpu_on
=
psci_cpu_on
;
}
if
(
!
of_property_read_u32
(
np
,
"migrate"
,
&
id
))
{
psci_function_id
[
PSCI_FN_MIGRATE
]
=
id
;
psci_ops
.
migrate
=
psci_migrate
;
}
out_put_node:
of_node_put
(
np
);
return
0
;
}
early_initcall
(
psci_init
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment