Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Arm Trusted Firmware
Commits
b32e6b2b
Commit
b32e6b2b
authored
Jun 05, 2017
by
danh-arm
Committed by
GitHub
Jun 05, 2017
Browse files
Merge pull request #963 from soby-mathew/sm/scmi_dev
Add SCMI power domain and system power protocol support
parents
c66f4ade
40111d44
Changes
13
Show whitespace changes
Inline
Side-by-side
docs/user-guide.md
View file @
b32e6b2b
...
@@ -622,6 +622,10 @@ map is explained in the [Firmware Design].
...
@@ -622,6 +622,10 @@ map is explained in the [Firmware Design].
SCP_BL2U to the FIP and FWU_FIP respectively, and enables them to be loaded
SCP_BL2U to the FIP and FWU_FIP respectively, and enables them to be loaded
during boot. Default is 1.
during boot. Default is 1.
*
`CSS_USE_SCMI_DRIVER`
: Boolean flag which selects SCMI driver instead of
SCPI driver for communicating with the SCP during power management operations.
If this option is set to 1, then SCMI driver will be used. Default is 0.
#### ARM FVP platform specific build options
#### ARM FVP platform specific build options
*
`FVP_CLUSTER_COUNT`
: Configures the cluster count to be used to
*
`FVP_CLUSTER_COUNT`
: Configures the cluster count to be used to
...
...
include/plat/arm/common/plat_arm.h
View file @
b32e6b2b
...
@@ -46,7 +46,7 @@ void arm_setup_page_tables(uintptr_t total_base,
...
@@ -46,7 +46,7 @@ void arm_setup_page_tables(uintptr_t total_base,
* arm_lock_xxx() macros
* arm_lock_xxx() macros
*/
*/
#define ARM_INSTANTIATE_LOCK DEFINE_BAKERY_LOCK(arm_lock);
#define ARM_INSTANTIATE_LOCK DEFINE_BAKERY_LOCK(arm_lock);
#define ARM_LOCK_GET_INSTANCE (&arm_lock)
/*
/*
* These are wrapper macros to the Coherent Memory Bakery Lock API.
* These are wrapper macros to the Coherent Memory Bakery Lock API.
*/
*/
...
@@ -60,6 +60,7 @@ void arm_setup_page_tables(uintptr_t total_base,
...
@@ -60,6 +60,7 @@ void arm_setup_page_tables(uintptr_t total_base,
* Empty macros for all other BL stages other than BL31 and BL32
* Empty macros for all other BL stages other than BL31 and BL32
*/
*/
#define ARM_INSTANTIATE_LOCK
#define ARM_INSTANTIATE_LOCK
#define ARM_LOCK_GET_INSTANCE 0
#define arm_lock_init()
#define arm_lock_init()
#define arm_lock_get()
#define arm_lock_get()
#define arm_lock_release()
#define arm_lock_release()
...
...
include/plat/arm/css/common/css_def.h
View file @
b32e6b2b
/*
/*
* Copyright (c) 2015-201
6
, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2015-201
7
, ARM Limited and Contributors. All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: BSD-3-Clause
*/
*/
...
@@ -47,6 +47,17 @@
...
@@ -47,6 +47,17 @@
CSS_IRQ_TZ_WDOG, \
CSS_IRQ_TZ_WDOG, \
CSS_IRQ_SEC_SYS_TIMER
CSS_IRQ_SEC_SYS_TIMER
/*
* The lower Non-secure MHU channel is being used for SCMI for ARM Trusted
* Firmware.
* TODO: Move SCMI to Secure channel once the migration to SCMI in SCP is
* complete.
*/
#define MHU_CPU_INTR_L_SET_OFFSET 0x108
#define MHU_CPU_INTR_H_SET_OFFSET 0x128
#define CSS_SCMI_PAYLOAD_BASE (NSRAM_BASE + 0x500)
#define CSS_SCMI_MHU_DB_REG_OFF MHU_CPU_INTR_L_SET_OFFSET
/*
/*
* SCP <=> AP boot configuration
* SCP <=> AP boot configuration
*
*
...
@@ -63,6 +74,11 @@
...
@@ -63,6 +74,11 @@
CSS_DEVICE_SIZE, \
CSS_DEVICE_SIZE, \
MT_DEVICE | MT_RW | MT_SECURE)
MT_DEVICE | MT_RW | MT_SECURE)
#define CSS_MAP_NSRAM MAP_REGION_FLAT( \
NSRAM_BASE, \
NSRAM_SIZE, \
MT_DEVICE | MT_RW | MT_SECURE)
/* Platform ID address */
/* Platform ID address */
#define SSC_VERSION_OFFSET 0x040
#define SSC_VERSION_OFFSET 0x040
...
...
plat/arm/board/common/board_css_common.c
View file @
b32e6b2b
...
@@ -49,6 +49,15 @@ const mmap_region_t plat_arm_mmap[] = {
...
@@ -49,6 +49,15 @@ const mmap_region_t plat_arm_mmap[] = {
ARM_MAP_SHARED_RAM
,
ARM_MAP_SHARED_RAM
,
V2M_MAP_IOFPGA
,
V2M_MAP_IOFPGA
,
CSS_MAP_DEVICE
,
CSS_MAP_DEVICE
,
#if CSS_USE_SCMI_DRIVER
/*
* The SCMI payload area is currently in the Non Secure SRAM. This is
* a potential security risk but this will be resolved once SCP
* completely replaces SCPI with SCMI as the only communication
* protocol.
*/
CSS_MAP_NSRAM
,
#endif
SOC_CSS_MAP_DEVICE
,
SOC_CSS_MAP_DEVICE
,
{
0
}
{
0
}
};
};
...
...
plat/arm/board/juno/include/platform_def.h
View file @
b32e6b2b
...
@@ -74,8 +74,13 @@
...
@@ -74,8 +74,13 @@
#endif
#endif
#ifdef IMAGE_BL31
#ifdef IMAGE_BL31
# if CSS_USE_SCMI_DRIVER
# define PLAT_ARM_MMAP_ENTRIES 6
# define MAX_XLAT_TABLES 3
# else
# define PLAT_ARM_MMAP_ENTRIES 5
# define PLAT_ARM_MMAP_ENTRIES 5
# define MAX_XLAT_TABLES 2
# define MAX_XLAT_TABLES 2
# endif
#endif
#endif
#ifdef IMAGE_BL32
#ifdef IMAGE_BL32
...
...
plat/arm/board/juno/juno_topology.c
View file @
b32e6b2b
...
@@ -51,3 +51,10 @@ unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr)
...
@@ -51,3 +51,10 @@ unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr)
return
(((
mpidr
)
&
0x100
)
?
JUNO_CLUSTER1_CORE_COUNT
:
\
return
(((
mpidr
)
&
0x100
)
?
JUNO_CLUSTER1_CORE_COUNT
:
\
JUNO_CLUSTER0_CORE_COUNT
);
JUNO_CLUSTER0_CORE_COUNT
);
}
}
/*
* The array mapping platform core position (implemented by plat_my_core_pos())
* to the SCMI power domain ID implemented by SCP.
*/
const
uint32_t
plat_css_core_pos_to_scmi_dmn_id_map
[
PLATFORM_CORE_COUNT
]
=
{
2
,
3
,
4
,
5
,
0
,
1
};
plat/arm/css/common/css_common.mk
View file @
b32e6b2b
#
#
# Copyright (c) 2015-201
6
, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2015-201
7
, ARM Limited and Contributors. All rights reserved.
#
#
# SPDX-License-Identifier: BSD-3-Clause
# SPDX-License-Identifier: BSD-3-Clause
#
#
...
@@ -8,6 +8,9 @@
...
@@ -8,6 +8,9 @@
# By default, SCP images are needed by CSS platforms.
# By default, SCP images are needed by CSS platforms.
CSS_LOAD_SCP_IMAGES
?=
1
CSS_LOAD_SCP_IMAGES
?=
1
# By default, SCMI driver is disabled for CSS platforms
CSS_USE_SCMI_DRIVER
?=
0
PLAT_INCLUDES
+=
-Iinclude
/plat/arm/css/common
\
PLAT_INCLUDES
+=
-Iinclude
/plat/arm/css/common
\
-Iinclude
/plat/arm/css/common/aarch64
-Iinclude
/plat/arm/css/common/aarch64
...
@@ -25,10 +28,18 @@ BL2U_SOURCES += plat/arm/css/common/css_bl2u_setup.c \
...
@@ -25,10 +28,18 @@ BL2U_SOURCES += plat/arm/css/common/css_bl2u_setup.c \
plat/arm/css/drivers/scpi/css_scpi.c
plat/arm/css/drivers/scpi/css_scpi.c
BL31_SOURCES
+=
plat/arm/css/common/css_pm.c
\
BL31_SOURCES
+=
plat/arm/css/common/css_pm.c
\
plat/arm/css/common/css_topology.c
\
plat/arm/css/common/css_topology.c
plat/arm/css/drivers/scp/css_pm_scpi.c
\
ifeq
(${CSS_USE_SCMI_DRIVER},0)
BL31_SOURCES
+=
plat/arm/css/drivers/scp/css_pm_scpi.c
\
plat/arm/css/drivers/scpi/css_mhu.c
\
plat/arm/css/drivers/scpi/css_mhu.c
\
plat/arm/css/drivers/scpi/css_scpi.c
plat/arm/css/drivers/scpi/css_scpi.c
else
BL31_SOURCES
+=
plat/arm/css/drivers/scp/css_pm_scmi.c
\
plat/arm/css/drivers/scmi/scmi_common.c
\
plat/arm/css/drivers/scmi/scmi_pwr_dmn_proto.c
\
plat/arm/css/drivers/scmi/scmi_sys_pwr_proto.c
endif
ifneq
(${RESET_TO_BL31},0)
ifneq
(${RESET_TO_BL31},0)
$(error
"Using
BL31
as
the
reset
vector
is
not
supported
on
CSS
platforms.
\
$(error
"Using
BL31
as
the
reset
vector
is
not
supported
on
CSS
platforms.
\
...
@@ -56,3 +67,8 @@ CSS_DETECT_PRE_1_7_0_SCP := 1
...
@@ -56,3 +67,8 @@ CSS_DETECT_PRE_1_7_0_SCP := 1
# Process CSS_DETECT_PRE_1_7_0_SCP flag
# Process CSS_DETECT_PRE_1_7_0_SCP flag
$(eval
$(call
assert_boolean,CSS_DETECT_PRE_1_7_0_SCP))
$(eval
$(call
assert_boolean,CSS_DETECT_PRE_1_7_0_SCP))
$(eval
$(call
add_define,CSS_DETECT_PRE_1_7_0_SCP))
$(eval
$(call
add_define,CSS_DETECT_PRE_1_7_0_SCP))
# Process CSS_USE_SCMI_DRIVER flag
$(eval
$(call
assert_boolean,CSS_USE_SCMI_DRIVER))
$(eval
$(call
add_define,CSS_USE_SCMI_DRIVER))
plat/arm/css/drivers/scmi/scmi.h
0 → 100644
View file @
b32e6b2b
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __CSS_SCMI_H__
#define __CSS_SCMI_H__
#include <bakery_lock.h>
#include <stddef.h>
#include <stdint.h>
/* Supported SCMI Protocol Versions */
#define SCMI_PWR_DMN_PROTO_VER MAKE_SCMI_VERSION(1, 0)
#define SCMI_SYS_PWR_PROTO_VER MAKE_SCMI_VERSION(1, 0)
#define GET_SCMI_MAJOR_VER(ver) (((ver) >> 16) & 0xffff)
#define GET_SCMI_MINOR_VER(ver) ((ver) & 0xffff)
#define MAKE_SCMI_VERSION(maj, min) \
((((maj) & 0xffff) << 16) | ((min) & 0xffff))
/* Macro to check if the driver is compatible with the SCMI version reported */
#define is_scmi_version_compatible(drv, scmi) \
((GET_SCMI_MAJOR_VER(drv) == GET_SCMI_MAJOR_VER(scmi)) && \
(GET_SCMI_MINOR_VER(drv) <= GET_SCMI_MINOR_VER(scmi)))
/* SCMI Protocol identifiers */
#define SCMI_PWR_DMN_PROTO_ID 0x11
#define SCMI_SYS_PWR_PROTO_ID 0x12
/* Mandatory messages IDs for all SCMI protocols */
#define SCMI_PROTO_VERSION_MSG 0x0
#define SCMI_PROTO_ATTR_MSG 0x1
#define SCMI_PROTO_MSG_ATTR_MSG 0x2
/* SCMI power domain management protocol message IDs */
#define SCMI_PWR_STATE_SET_MSG 0x4
#define SCMI_PWR_STATE_GET_MSG 0x5
/* SCMI system power management protocol message IDs */
#define SCMI_SYS_PWR_STATE_SET_MSG 0x3
#define SCMI_SYS_PWR_STATE_GET_MSG 0x4
/* Helper macros for system power management protocol commands */
/*
* Macros to describe the bit-fields of the `attribute` of system power domain
* protocol PROTOCOL_MSG_ATTRIBUTE message.
*/
#define SYS_PWR_ATTR_WARM_RESET_SHIFT 31
#define SCMI_SYS_PWR_WARM_RESET_SUPPORTED (1U << SYS_PWR_ATTR_WARM_RESET_SHIFT)
#define SYS_PWR_ATTR_SUSPEND_SHIFT 30
#define SCMI_SYS_PWR_SUSPEND_SUPPORTED (1 << SYS_PWR_ATTR_SUSPEND_SHIFT)
/*
* Macros to describe the bit-fields of the `flags` parameter of system power
* domain protocol SYSTEM_POWER_STATE_SET message.
*/
#define SYS_PWR_SET_GRACEFUL_REQ_SHIFT 0
#define SCMI_SYS_PWR_GRACEFUL_REQ (1 << SYS_PWR_SET_GRACEFUL_REQ_SHIFT)
#define SCMI_SYS_PWR_FORCEFUL_REQ (0 << SYS_PWR_SET_GRACEFUL_REQ_SHIFT)
/*
* Macros to describe the `system_state` parameter of system power
* domain protocol SYSTEM_POWER_STATE_SET message.
*/
#define SCMI_SYS_PWR_SHUTDOWN 0x0
#define SCMI_SYS_PWR_COLD_RESET 0x1
#define SCMI_SYS_PWR_WARM_RESET 0x2
#define SCMI_SYS_PWR_POWER_UP 0x3
#define SCMI_SYS_PWR_SUSPEND 0x4
/* SCMI Error code definitions */
#define SCMI_E_QUEUED 1
#define SCMI_E_SUCCESS 0
#define SCMI_E_NOT_SUPPORTED -1
#define SCMI_E_INVALID_PARAM -2
#define SCMI_E_DENIED -3
#define SCMI_E_NOT_FOUND -4
#define SCMI_E_OUT_OF_RANGE -5
#define SCMI_E_BUSY -6
/*
* SCMI driver platform information. The details of the doorbell mechanism
* can be found in the SCMI specification.
*/
typedef
struct
scmi_channel_plat_info
{
/* SCMI mailbox memory */
uintptr_t
scmi_mbx_mem
;
/* The door bell register address */
uintptr_t
db_reg_addr
;
/* The bit mask that need to be preserved when ringing doorbell */
uint32_t
db_preserve_mask
;
/* The bit mask that need to be set to ring doorbell */
uint32_t
db_modify_mask
;
}
scmi_channel_plat_info_t
;
/*
* Structure to represent an SCMI channel.
*/
typedef
struct
scmi_channel
{
scmi_channel_plat_info_t
*
info
;
/* The lock for channel access */
bakery_lock_t
*
lock
;
/* Indicate whether the channel is initialized */
int
is_initialized
;
}
scmi_channel_t
;
/* External Common API */
void
*
scmi_init
(
scmi_channel_t
*
ch
);
int
scmi_proto_msg_attr
(
void
*
p
,
uint32_t
proto_id
,
uint32_t
command_id
,
uint32_t
*
attr
);
int
scmi_proto_version
(
void
*
p
,
uint32_t
proto_id
,
uint32_t
*
version
);
/*
* Power domain protocol commands. Refer to the SCMI specification for more
* details on these commands.
*/
int
scmi_pwr_state_set
(
void
*
p
,
uint32_t
domain_id
,
uint32_t
scmi_pwr_state
);
int
scmi_pwr_state_get
(
void
*
p
,
uint32_t
domain_id
,
uint32_t
*
scmi_pwr_state
);
/*
* System power management protocol commands. Refer SCMI specification for more
* details on these commands.
*/
int
scmi_sys_pwr_state_set
(
void
*
p
,
uint32_t
flags
,
uint32_t
system_state
);
int
scmi_sys_pwr_state_get
(
void
*
p
,
uint32_t
*
system_state
);
#endif
/* __CSS_SCMI_H__ */
plat/arm/css/drivers/scmi/scmi_common.c
0 → 100644
View file @
b32e6b2b
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <debug.h>
#include "scmi.h"
#include "scmi_private.h"
/*
* Private helper function to get exclusive access to SCMI channel.
*/
void
scmi_get_channel
(
scmi_channel_t
*
ch
)
{
assert
(
ch
->
lock
);
bakery_lock_get
(
ch
->
lock
);
/* Make sure any previous command has finished */
assert
(
SCMI_IS_CHANNEL_FREE
(
((
mailbox_mem_t
*
)(
ch
->
info
->
scmi_mbx_mem
))
->
status
));
}
/*
* Private helper function to transfer ownership of channel from AP to SCP.
*/
void
scmi_send_sync_command
(
scmi_channel_t
*
ch
)
{
mailbox_mem_t
*
mbx_mem
=
(
mailbox_mem_t
*
)(
ch
->
info
->
scmi_mbx_mem
);
SCMI_MARK_CHANNEL_BUSY
(
mbx_mem
->
status
);
/*
* Ensure that any write to the SCMI payload area is seen by SCP before
* we write to the doorbell register. If these 2 writes were reordered
* by the CPU then SCP would read stale payload data
*/
dmbst
();
SCMI_RING_DOORBELL
(
ch
->
info
->
db_reg_addr
,
ch
->
info
->
db_modify_mask
,
ch
->
info
->
db_preserve_mask
);
/*
* Ensure that the write to the doorbell register is ordered prior to
* checking whether the channel is free.
*/
dmbsy
();
/* Wait for channel to be free */
while
(
!
SCMI_IS_CHANNEL_FREE
(
mbx_mem
->
status
))
;
/*
* Ensure that any read to the SCMI payload area is done after reading
* mailbox status. If these 2 reads were reordered then the CPU would
* read invalid payload data
*/
dmbld
();
}
/*
* Private helper function to release exclusive access to SCMI channel.
*/
void
scmi_put_channel
(
scmi_channel_t
*
ch
)
{
/* Make sure any previous command has finished */
assert
(
SCMI_IS_CHANNEL_FREE
(
((
mailbox_mem_t
*
)(
ch
->
info
->
scmi_mbx_mem
))
->
status
));
assert
(
ch
->
lock
);
bakery_lock_release
(
ch
->
lock
);
}
/*
* API to query the SCMI protocol version.
*/
int
scmi_proto_version
(
void
*
p
,
uint32_t
proto_id
,
uint32_t
*
version
)
{
mailbox_mem_t
*
mbx_mem
;
int
token
=
0
,
ret
;
scmi_channel_t
*
ch
=
(
scmi_channel_t
*
)
p
;
validate_scmi_channel
(
ch
);
scmi_get_channel
(
ch
);
mbx_mem
=
(
mailbox_mem_t
*
)(
ch
->
info
->
scmi_mbx_mem
);
mbx_mem
->
msg_header
=
SCMI_MSG_CREATE
(
proto_id
,
SCMI_PROTO_VERSION_MSG
,
token
);
mbx_mem
->
len
=
SCMI_PROTO_VERSION_MSG_LEN
;
mbx_mem
->
flags
=
SCMI_FLAG_RESP_POLL
;
scmi_send_sync_command
(
ch
);
/* Get the return values */
SCMI_PAYLOAD_RET_VAL2
(
mbx_mem
->
payload
,
ret
,
*
version
);
assert
(
mbx_mem
->
len
==
SCMI_PROTO_VERSION_RESP_LEN
);
assert
(
token
==
SCMI_MSG_GET_TOKEN
(
mbx_mem
->
msg_header
));
scmi_put_channel
(
ch
);
return
ret
;
}
/*
* API to query the protocol message attributes for a SCMI protocol.
*/
int
scmi_proto_msg_attr
(
void
*
p
,
uint32_t
proto_id
,
uint32_t
command_id
,
uint32_t
*
attr
)
{
mailbox_mem_t
*
mbx_mem
;
int
token
=
0
,
ret
;
scmi_channel_t
*
ch
=
(
scmi_channel_t
*
)
p
;
validate_scmi_channel
(
ch
);
scmi_get_channel
(
ch
);
mbx_mem
=
(
mailbox_mem_t
*
)(
ch
->
info
->
scmi_mbx_mem
);
mbx_mem
->
msg_header
=
SCMI_MSG_CREATE
(
proto_id
,
SCMI_PROTO_MSG_ATTR_MSG
,
token
);
mbx_mem
->
len
=
SCMI_PROTO_MSG_ATTR_MSG_LEN
;
mbx_mem
->
flags
=
SCMI_FLAG_RESP_POLL
;
SCMI_PAYLOAD_ARG1
(
mbx_mem
->
payload
,
command_id
);
scmi_send_sync_command
(
ch
);
/* Get the return values */
SCMI_PAYLOAD_RET_VAL2
(
mbx_mem
->
payload
,
ret
,
*
attr
);
assert
(
mbx_mem
->
len
==
SCMI_PROTO_MSG_ATTR_RESP_LEN
);
assert
(
token
==
SCMI_MSG_GET_TOKEN
(
mbx_mem
->
msg_header
));
scmi_put_channel
(
ch
);
return
ret
;
}
/*
* SCMI Driver initialization API. Returns initialized channel on success
* or NULL on error. The return type is an opaque void pointer.
*/
void
*
scmi_init
(
scmi_channel_t
*
ch
)
{
uint32_t
version
;
int
ret
;
assert
(
ch
&&
ch
->
info
);
assert
(
ch
->
info
->
db_reg_addr
);
assert
(
ch
->
info
->
db_modify_mask
);
assert
(
ch
->
info
->
db_preserve_mask
);
assert
(
ch
->
lock
);
bakery_lock_init
(
ch
->
lock
);
ch
->
is_initialized
=
1
;
ret
=
scmi_proto_version
(
ch
,
SCMI_PWR_DMN_PROTO_ID
,
&
version
);
if
(
ret
!=
SCMI_E_SUCCESS
)
{
WARN
(
"SCMI power domain protocol version message failed"
);
goto
error
;
}
if
(
!
is_scmi_version_compatible
(
SCMI_PWR_DMN_PROTO_VER
,
version
))
{
WARN
(
"SCMI power domain protocol version 0x%x incompatible with driver version 0x%x"
,
version
,
SCMI_PWR_DMN_PROTO_VER
);
goto
error
;
}
VERBOSE
(
"SCMI power domain protocol version 0x%x detected
\n
"
,
version
);
ret
=
scmi_proto_version
(
ch
,
SCMI_SYS_PWR_PROTO_ID
,
&
version
);
if
((
ret
!=
SCMI_E_SUCCESS
))
{
WARN
(
"SCMI system power protocol version message failed"
);
goto
error
;
}
if
(
!
is_scmi_version_compatible
(
SCMI_SYS_PWR_PROTO_VER
,
version
))
{
WARN
(
"SCMI system power management protocol version 0x%x incompatible with driver version 0x%x"
,
version
,
SCMI_SYS_PWR_PROTO_VER
);
goto
error
;
}
VERBOSE
(
"SCMI system power management protocol version 0x%x detected
\n
"
,
version
);
INFO
(
"SCMI driver initialized
\n
"
);
return
(
void
*
)
ch
;
error:
ch
->
is_initialized
=
0
;
return
NULL
;
}
plat/arm/css/drivers/scmi/scmi_private.h
0 → 100644
View file @
b32e6b2b
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __CSS_SCMI_PRIVATE_H__
#define __CSS_SCMI_PRIVATE_H__
/*
* SCMI power domain management protocol message and response lengths. It is
* calculated as sum of length in bytes of the message header (4) and payload
* area (the number of bytes of parameters or return values in the payload).
*/
#define SCMI_PROTO_VERSION_MSG_LEN 4
#define SCMI_PROTO_VERSION_RESP_LEN 12
#define SCMI_PROTO_MSG_ATTR_MSG_LEN 8
#define SCMI_PROTO_MSG_ATTR_RESP_LEN 12
#define SCMI_PWR_STATE_SET_MSG_LEN 16
#define SCMI_PWR_STATE_SET_RESP_LEN 8
#define SCMI_PWR_STATE_GET_MSG_LEN 8
#define SCMI_PWR_STATE_GET_RESP_LEN 12
#define SCMI_SYS_PWR_STATE_SET_MSG_LEN 12
#define SCMI_SYS_PWR_STATE_SET_RESP_LEN 8
#define SCMI_SYS_PWR_STATE_GET_MSG_LEN 4
#define SCMI_SYS_PWR_STATE_GET_RESP_LEN 12
/* SCMI message header format bit field */
#define SCMI_MSG_ID_SHIFT 0
#define SCMI_MSG_ID_WIDTH 8
#define SCMI_MSG_ID_MASK ((1 << SCMI_MSG_ID_WIDTH) - 1)
#define SCMI_MSG_TYPE_SHIFT 8
#define SCMI_MSG_TYPE_WIDTH 2
#define SCMI_MSG_TYPE_MASK ((1 << SCMI_MSG_TYPE_WIDTH) - 1)
#define SCMI_MSG_PROTO_ID_SHIFT 10
#define SCMI_MSG_PROTO_ID_WIDTH 8
#define SCMI_MSG_PROTO_ID_MASK ((1 << SCMI_MSG_PROTO_ID_WIDTH) - 1)
#define SCMI_MSG_TOKEN_SHIFT 18
#define SCMI_MSG_TOKEN_WIDTH 10
#define SCMI_MSG_TOKEN_MASK ((1 << SCMI_MSG_TOKEN_WIDTH) - 1)
/* SCMI mailbox flags */
#define SCMI_FLAG_RESP_POLL 0
#define SCMI_FLAG_RESP_INT 1
/* SCMI power domain protocol `POWER_STATE_SET` message flags */
#define SCMI_PWR_STATE_SET_FLAG_SYNC 0
#define SCMI_PWR_STATE_SET_FLAG_ASYNC 1
/*
* Helper macro to create an SCMI message header given protocol, message id
* and token.
*/
#define SCMI_MSG_CREATE(protocol, msg_id, token) \
((((protocol) & SCMI_MSG_PROTO_ID_MASK) << SCMI_MSG_PROTO_ID_SHIFT) | \
(((msg_id) & SCMI_MSG_ID_MASK) << SCMI_MSG_ID_SHIFT) | \
(((token) & SCMI_MSG_TOKEN_MASK) << SCMI_MSG_TOKEN_SHIFT))
/* Helper macro to get the token from a SCMI message header */
#define SCMI_MSG_GET_TOKEN(msg) \
(((msg) >> SCMI_MSG_TOKEN_SHIFT) & SCMI_MSG_TOKEN_MASK)
/* SCMI Channel Status bit fields */
#define SCMI_CH_STATUS_RES0_MASK 0xFFFFFFFE
#define SCMI_CH_STATUS_FREE_SHIFT 0
#define SCMI_CH_STATUS_FREE_WIDTH 1
#define SCMI_CH_STATUS_FREE_MASK ((1 << SCMI_CH_STATUS_FREE_WIDTH) - 1)
/* Helper macros to check and write the channel status */
#define SCMI_IS_CHANNEL_FREE(status) \
(!!(((status) >> SCMI_CH_STATUS_FREE_SHIFT) & SCMI_CH_STATUS_FREE_MASK))
#define SCMI_MARK_CHANNEL_BUSY(status) do { \
assert(SCMI_IS_CHANNEL_FREE(status)); \
(status) &= ~(SCMI_CH_STATUS_FREE_MASK << \
SCMI_CH_STATUS_FREE_SHIFT); \
} while (0)
/* Helper macros to copy arguments to the mailbox payload */
#define SCMI_PAYLOAD_ARG1(payld_arr, arg1) \
mmio_write_32((uintptr_t)&payld_arr[0], arg1)
#define SCMI_PAYLOAD_ARG2(payld_arr, arg1, arg2) do { \
SCMI_PAYLOAD_ARG1(payld_arr, arg1); \
mmio_write_32((uintptr_t)&payld_arr[1], arg2); \
} while (0)
#define SCMI_PAYLOAD_ARG3(payld_arr, arg1, arg2, arg3) do { \
SCMI_PAYLOAD_ARG2(payld_arr, arg1, arg2); \
mmio_write_32((uintptr_t)&payld_arr[2], arg3); \
} while (0)
/* Helper macros to read return values from the mailbox payload */
#define SCMI_PAYLOAD_RET_VAL1(payld_arr, val1) \
(val1) = mmio_read_32((uintptr_t)&payld_arr[0])
#define SCMI_PAYLOAD_RET_VAL2(payld_arr, val1, val2) do { \
SCMI_PAYLOAD_RET_VAL1(payld_arr, val1); \
(val2) = mmio_read_32((uintptr_t)&payld_arr[1]); \
} while (0)
#define SCMI_PAYLOAD_RET_VAL3(payld_arr, val1, val2, val3) do { \
SCMI_PAYLOAD_RET_VAL2(payld_arr, val1, val2); \
(val3) = mmio_read_32((uintptr_t)&payld_arr[2]); \
} while (0)
/* Helper macro to ring doorbell */
#define SCMI_RING_DOORBELL(addr, modify_mask, preserve_mask) do { \
uint32_t db = mmio_read_32(addr) & (preserve_mask); \
mmio_write_32(addr, db | (modify_mask)); \
} while (0)
/*
* Private data structure for representing the mailbox memory layout. Refer
* the SCMI specification for more details.
*/
typedef
struct
mailbox_mem
{
uint32_t
res_a
;
/* Reserved */
volatile
uint32_t
status
;
uint64_t
res_b
;
/* Reserved */
uint32_t
flags
;
volatile
uint32_t
len
;
uint32_t
msg_header
;
uint32_t
payload
[];
}
mailbox_mem_t
;
/* Private APIs for use within SCMI driver */
void
scmi_get_channel
(
scmi_channel_t
*
ch
);
void
scmi_send_sync_command
(
scmi_channel_t
*
ch
);
void
scmi_put_channel
(
scmi_channel_t
*
ch
);
static
inline
void
validate_scmi_channel
(
scmi_channel_t
*
ch
)
{
assert
(
ch
&&
ch
->
is_initialized
);
assert
(
ch
->
info
&&
ch
->
info
->
scmi_mbx_mem
);
}
#endif
/* __CSS_SCMI_PRIVATE_H__ */
plat/arm/css/drivers/scmi/scmi_pwr_dmn_proto.c
0 → 100644
View file @
b32e6b2b
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <debug.h>
#include "scmi.h"
#include "scmi_private.h"
/*
* API to set the SCMI power domain power state.
*/
int
scmi_pwr_state_set
(
void
*
p
,
uint32_t
domain_id
,
uint32_t
scmi_pwr_state
)
{
mailbox_mem_t
*
mbx_mem
;
int
token
=
0
,
ret
;
/*
* Only asynchronous mode of `set power state` command is allowed on
* application processors.
*/
uint32_t
pwr_state_set_msg_flag
=
SCMI_PWR_STATE_SET_FLAG_ASYNC
;
scmi_channel_t
*
ch
=
(
scmi_channel_t
*
)
p
;
validate_scmi_channel
(
ch
);
scmi_get_channel
(
ch
);
mbx_mem
=
(
mailbox_mem_t
*
)(
ch
->
info
->
scmi_mbx_mem
);
mbx_mem
->
msg_header
=
SCMI_MSG_CREATE
(
SCMI_PWR_DMN_PROTO_ID
,
SCMI_PWR_STATE_SET_MSG
,
token
);
mbx_mem
->
len
=
SCMI_PWR_STATE_SET_MSG_LEN
;
mbx_mem
->
flags
=
SCMI_FLAG_RESP_POLL
;
SCMI_PAYLOAD_ARG3
(
mbx_mem
->
payload
,
pwr_state_set_msg_flag
,
domain_id
,
scmi_pwr_state
);
scmi_send_sync_command
(
ch
);
/* Get the return values */
SCMI_PAYLOAD_RET_VAL1
(
mbx_mem
->
payload
,
ret
);
assert
(
mbx_mem
->
len
==
SCMI_PWR_STATE_SET_RESP_LEN
);
assert
(
token
==
SCMI_MSG_GET_TOKEN
(
mbx_mem
->
msg_header
));
scmi_put_channel
(
ch
);
return
ret
;
}
/*
* API to get the SCMI power domain power state.
*/
int
scmi_pwr_state_get
(
void
*
p
,
uint32_t
domain_id
,
uint32_t
*
scmi_pwr_state
)
{
mailbox_mem_t
*
mbx_mem
;
int
token
=
0
,
ret
;
scmi_channel_t
*
ch
=
(
scmi_channel_t
*
)
p
;
validate_scmi_channel
(
ch
);
scmi_get_channel
(
ch
);
mbx_mem
=
(
mailbox_mem_t
*
)(
ch
->
info
->
scmi_mbx_mem
);
mbx_mem
->
msg_header
=
SCMI_MSG_CREATE
(
SCMI_PWR_DMN_PROTO_ID
,
SCMI_PWR_STATE_GET_MSG
,
token
);
mbx_mem
->
len
=
SCMI_PWR_STATE_GET_MSG_LEN
;
mbx_mem
->
flags
=
SCMI_FLAG_RESP_POLL
;
SCMI_PAYLOAD_ARG1
(
mbx_mem
->
payload
,
domain_id
);
scmi_send_sync_command
(
ch
);
/* Get the return values */
SCMI_PAYLOAD_RET_VAL2
(
mbx_mem
->
payload
,
ret
,
*
scmi_pwr_state
);
assert
(
mbx_mem
->
len
==
SCMI_PWR_STATE_GET_RESP_LEN
);
assert
(
token
==
SCMI_MSG_GET_TOKEN
(
mbx_mem
->
msg_header
));
scmi_put_channel
(
ch
);
return
ret
;
}
plat/arm/css/drivers/scmi/scmi_sys_pwr_proto.c
0 → 100644
View file @
b32e6b2b
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <debug.h>
#include "scmi.h"
#include "scmi_private.h"
/*
* API to set the SCMI system power state
*/
int
scmi_sys_pwr_state_set
(
void
*
p
,
uint32_t
flags
,
uint32_t
system_state
)
{
mailbox_mem_t
*
mbx_mem
;
int
token
=
0
,
ret
;
scmi_channel_t
*
ch
=
(
scmi_channel_t
*
)
p
;
validate_scmi_channel
(
ch
);
scmi_get_channel
(
ch
);
mbx_mem
=
(
mailbox_mem_t
*
)(
ch
->
info
->
scmi_mbx_mem
);
mbx_mem
->
msg_header
=
SCMI_MSG_CREATE
(
SCMI_SYS_PWR_PROTO_ID
,
SCMI_SYS_PWR_STATE_SET_MSG
,
token
);
mbx_mem
->
len
=
SCMI_SYS_PWR_STATE_SET_MSG_LEN
;
mbx_mem
->
flags
=
SCMI_FLAG_RESP_POLL
;
SCMI_PAYLOAD_ARG2
(
mbx_mem
->
payload
,
flags
,
system_state
);
scmi_send_sync_command
(
ch
);
/* Get the return values */
SCMI_PAYLOAD_RET_VAL1
(
mbx_mem
->
payload
,
ret
);
assert
(
mbx_mem
->
len
==
SCMI_SYS_PWR_STATE_SET_RESP_LEN
);
assert
(
token
==
SCMI_MSG_GET_TOKEN
(
mbx_mem
->
msg_header
));
scmi_put_channel
(
ch
);
return
ret
;
}
/*
* API to get the SCMI system power state
*/
int
scmi_sys_pwr_state_get
(
void
*
p
,
uint32_t
*
system_state
)
{
mailbox_mem_t
*
mbx_mem
;
int
token
=
0
,
ret
;
scmi_channel_t
*
ch
=
(
scmi_channel_t
*
)
p
;
validate_scmi_channel
(
ch
);
scmi_get_channel
(
ch
);
mbx_mem
=
(
mailbox_mem_t
*
)(
ch
->
info
->
scmi_mbx_mem
);
mbx_mem
->
msg_header
=
SCMI_MSG_CREATE
(
SCMI_SYS_PWR_PROTO_ID
,
SCMI_SYS_PWR_STATE_GET_MSG
,
token
);
mbx_mem
->
len
=
SCMI_SYS_PWR_STATE_GET_MSG_LEN
;
mbx_mem
->
flags
=
SCMI_FLAG_RESP_POLL
;
scmi_send_sync_command
(
ch
);
/* Get the return values */
SCMI_PAYLOAD_RET_VAL2
(
mbx_mem
->
payload
,
ret
,
*
system_state
);
assert
(
mbx_mem
->
len
==
SCMI_SYS_PWR_STATE_GET_RESP_LEN
);
assert
(
token
==
SCMI_MSG_GET_TOKEN
(
mbx_mem
->
msg_header
));
scmi_put_channel
(
ch
);
return
ret
;
}
plat/arm/css/drivers/scp/css_pm_scmi.c
0 → 100644
View file @
b32e6b2b
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <css_def.h>
#include <css_pm.h>
#include <debug.h>
#include <plat_arm.h>
#include <platform.h>
#include <string.h>
#include "../scmi/scmi.h"
#include "css_scp.h"
/*
* This file implements the SCP helper functions using SCMI protocol.
*/
/*
* SCMI power state parameter bit field encoding for ARM CSS platforms.
*
* 31 20 19 16 15 12 11 8 7 4 3 0
* +-------------------------------------------------------------+
* | SBZ | Max level | Level 3 | Level 2 | Level 1 | Level 0 |
* | | | state | state | state | state |
* +-------------------------------------------------------------+
*
* `Max level` encodes the highest level that has a valid power state
* encoded in the power state.
*/
#define SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT 16
#define SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH 4
#define SCMI_PWR_STATE_MAX_PWR_LVL_MASK \
((1 << SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH) - 1)
#define SCMI_SET_PWR_STATE_MAX_PWR_LVL(pwr_state, max_lvl) \
(pwr_state) |= ((max_lvl) & SCMI_PWR_STATE_MAX_PWR_LVL_MASK) \
<< SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT
#define SCMI_GET_PWR_STATE_MAX_PWR_LVL(pwr_state) \
(((pwr_state) >> SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT) \
& SCMI_PWR_STATE_MAX_PWR_LVL_MASK)
#define SCMI_PWR_STATE_LVL_WIDTH 4
#define SCMI_PWR_STATE_LVL_MASK \
((1 << SCMI_PWR_STATE_LVL_WIDTH) - 1)
#define SCMI_SET_PWR_STATE_LVL(pwr_state, lvl, lvl_state) \
(pwr_state) |= ((lvl_state) & SCMI_PWR_STATE_LVL_MASK) \
<< (SCMI_PWR_STATE_LVL_WIDTH * (lvl))
#define SCMI_GET_PWR_STATE_LVL(pwr_state, lvl) \
(((pwr_state) >> (SCMI_PWR_STATE_LVL_WIDTH * (lvl))) & \
SCMI_PWR_STATE_LVL_MASK)
/*
* The SCMI power state enumeration for a power domain level
*/
typedef
enum
{
scmi_power_state_off
=
0
,
scmi_power_state_on
=
1
,
scmi_power_state_sleep
=
2
,
}
scmi_power_state_t
;
/*
* This mapping array has to be exported by the platform. Each element at
* a given index maps that core to an SCMI power domain.
*/
extern
uint32_t
plat_css_core_pos_to_scmi_dmn_id_map
[];
/*
* The global handle for invoking the SCMI driver APIs after the driver
* has been initialized.
*/
void
*
scmi_handle
;
/* The SCMI channel global object */
static
scmi_channel_t
scmi_channel
;
ARM_INSTANTIATE_LOCK
/*
* Helper function to suspend a CPU power domain and its parent power domains
* if applicable.
*/
void
css_scp_suspend
(
const
psci_power_state_t
*
target_state
)
{
int
lvl
,
ret
;
uint32_t
scmi_pwr_state
=
0
;
/* At least power domain level 0 should be specified to be suspended */
assert
(
target_state
->
pwr_domain_state
[
ARM_PWR_LVL0
]
==
ARM_LOCAL_STATE_OFF
);
/* Check if power down at system power domain level is requested */
if
(
CSS_SYSTEM_PWR_STATE
(
target_state
)
==
ARM_LOCAL_STATE_OFF
)
{
/* Issue SCMI command for SYSTEM_SUSPEND */
ret
=
scmi_sys_pwr_state_set
(
scmi_handle
,
SCMI_SYS_PWR_FORCEFUL_REQ
,
SCMI_SYS_PWR_SUSPEND
);
if
(
ret
!=
SCMI_E_SUCCESS
)
{
ERROR
(
"SCMI system power domain suspend return 0x%x unexpected
\n
"
,
ret
);
panic
();
}
return
;
}
/*
* If we reach here, then assert that power down at system power domain
* level is running.
*/
assert
(
target_state
->
pwr_domain_state
[
CSS_SYSTEM_PWR_DMN_LVL
]
==
ARM_LOCAL_STATE_RUN
);
/* For level 0, specify `scmi_power_state_sleep` as the power state */
SCMI_SET_PWR_STATE_LVL
(
scmi_pwr_state
,
ARM_PWR_LVL0
,
scmi_power_state_sleep
);
for
(
lvl
=
ARM_PWR_LVL1
;
lvl
<=
PLAT_MAX_PWR_LVL
;
lvl
++
)
{
if
(
target_state
->
pwr_domain_state
[
lvl
]
==
ARM_LOCAL_STATE_RUN
)
break
;
assert
(
target_state
->
pwr_domain_state
[
lvl
]
==
ARM_LOCAL_STATE_OFF
);
/*
* Specify `scmi_power_state_off` as power state for higher
* levels.
*/
SCMI_SET_PWR_STATE_LVL
(
scmi_pwr_state
,
lvl
,
scmi_power_state_off
);
}
SCMI_SET_PWR_STATE_MAX_PWR_LVL
(
scmi_pwr_state
,
lvl
-
1
);
ret
=
scmi_pwr_state_set
(
scmi_handle
,
plat_css_core_pos_to_scmi_dmn_id_map
[
plat_my_core_pos
()],
scmi_pwr_state
);
if
(
ret
!=
SCMI_E_SUCCESS
)
{
ERROR
(
"SCMI set power state command return 0x%x unexpected
\n
"
,
ret
);
panic
();
}
}
/*
* Helper function to turn off a CPU power domain and its parent power domains
* if applicable.
*/
void
css_scp_off
(
const
psci_power_state_t
*
target_state
)
{
int
lvl
=
0
,
ret
;
uint32_t
scmi_pwr_state
=
0
;
/* At-least the CPU level should be specified to be OFF */
assert
(
target_state
->
pwr_domain_state
[
ARM_PWR_LVL0
]
==
ARM_LOCAL_STATE_OFF
);
/* PSCI CPU OFF cannot be used to turn OFF system power domain */
assert
(
target_state
->
pwr_domain_state
[
CSS_SYSTEM_PWR_DMN_LVL
]
==
ARM_LOCAL_STATE_RUN
);
for
(;
lvl
<=
PLAT_MAX_PWR_LVL
;
lvl
++
)
{
if
(
target_state
->
pwr_domain_state
[
lvl
]
==
ARM_LOCAL_STATE_RUN
)
break
;
assert
(
target_state
->
pwr_domain_state
[
lvl
]
==
ARM_LOCAL_STATE_OFF
);
SCMI_SET_PWR_STATE_LVL
(
scmi_pwr_state
,
lvl
,
scmi_power_state_off
);
}
SCMI_SET_PWR_STATE_MAX_PWR_LVL
(
scmi_pwr_state
,
lvl
-
1
);
ret
=
scmi_pwr_state_set
(
scmi_handle
,
plat_css_core_pos_to_scmi_dmn_id_map
[
plat_my_core_pos
()],
scmi_pwr_state
);
if
(
ret
!=
SCMI_E_QUEUED
&&
ret
!=
SCMI_E_SUCCESS
)
{
ERROR
(
"SCMI set power state command return 0x%x unexpected
\n
"
,
ret
);
panic
();
}
}
/*
* Helper function to turn ON a CPU power domain and its parent power domains
* if applicable.
*/
void
css_scp_on
(
u_register_t
mpidr
)
{
int
lvl
=
0
,
ret
;
uint32_t
scmi_pwr_state
=
0
;
for
(;
lvl
<=
PLAT_MAX_PWR_LVL
;
lvl
++
)
SCMI_SET_PWR_STATE_LVL
(
scmi_pwr_state
,
lvl
,
scmi_power_state_on
);
SCMI_SET_PWR_STATE_MAX_PWR_LVL
(
scmi_pwr_state
,
lvl
-
1
);
ret
=
scmi_pwr_state_set
(
scmi_handle
,
plat_css_core_pos_to_scmi_dmn_id_map
[
plat_core_pos_by_mpidr
(
mpidr
)],
scmi_pwr_state
);
if
(
ret
!=
SCMI_E_QUEUED
&&
ret
!=
SCMI_E_SUCCESS
)
{
ERROR
(
"SCMI set power state command return 0x%x unexpected
\n
"
,
ret
);
panic
();
}
}
/*
* Helper function to get the power state of a power domain node as reported
* by the SCP.
*/
int
css_scp_get_power_state
(
u_register_t
mpidr
,
unsigned
int
power_level
)
{
int
ret
,
cpu_idx
;
uint32_t
scmi_pwr_state
=
0
,
lvl_state
;
/* We don't support get power state at the system power domain level */
if
((
power_level
>
PLAT_MAX_PWR_LVL
)
||
(
power_level
==
CSS_SYSTEM_PWR_DMN_LVL
))
{
WARN
(
"Invalid power level %u specified for SCMI get power state
\n
"
,
power_level
);
return
PSCI_E_INVALID_PARAMS
;
}
cpu_idx
=
plat_core_pos_by_mpidr
(
mpidr
);
assert
(
cpu_idx
>
-
1
);
ret
=
scmi_pwr_state_get
(
scmi_handle
,
plat_css_core_pos_to_scmi_dmn_id_map
[
cpu_idx
],
&
scmi_pwr_state
);
if
(
ret
!=
SCMI_E_SUCCESS
)
{
WARN
(
"SCMI get power state command return 0x%x unexpected
\n
"
,
ret
);
return
PSCI_E_INVALID_PARAMS
;
}
/*
* Find the maximum power level described in the get power state
* command. If it is less than the requested power level, then assume
* the requested power level is ON.
*/
if
(
SCMI_GET_PWR_STATE_MAX_PWR_LVL
(
scmi_pwr_state
)
<
power_level
)
return
HW_ON
;
lvl_state
=
SCMI_GET_PWR_STATE_LVL
(
scmi_pwr_state
,
power_level
);
if
(
lvl_state
==
scmi_power_state_on
)
return
HW_ON
;
assert
((
lvl_state
==
scmi_power_state_off
)
||
(
lvl_state
==
scmi_power_state_sleep
));
return
HW_OFF
;
}
/*
* Helper function to shutdown the system via SCMI.
*/
void
__dead2
css_scp_sys_shutdown
(
void
)
{
int
ret
;
/*
* Disable GIC CPU interface to prevent pending interrupt from waking
* up the AP from WFI.
*/
plat_arm_gic_cpuif_disable
();
/*
* Issue SCMI command for SYSTEM_SHUTDOWN. First issue a graceful
* request and if that fails force the request.
*/
ret
=
scmi_sys_pwr_state_set
(
scmi_handle
,
SCMI_SYS_PWR_FORCEFUL_REQ
,
SCMI_SYS_PWR_SHUTDOWN
);
if
(
ret
!=
SCMI_E_SUCCESS
)
{
ERROR
(
"SCMI system power domain shutdown return 0x%x unexpected
\n
"
,
ret
);
panic
();
}
wfi
();
ERROR
(
"CSS System Shutdown: operation not handled.
\n
"
);
panic
();
}
/*
* Helper function to reset the system via SCMI.
*/
void
__dead2
css_scp_sys_reboot
(
void
)
{
int
ret
;
/*
* Disable GIC CPU interface to prevent pending interrupt from waking
* up the AP from WFI.
*/
plat_arm_gic_cpuif_disable
();
/*
* Issue SCMI command for SYSTEM_REBOOT. First issue a graceful
* request and if that fails force the request.
*/
ret
=
scmi_sys_pwr_state_set
(
scmi_handle
,
SCMI_SYS_PWR_FORCEFUL_REQ
,
SCMI_SYS_PWR_COLD_RESET
);
if
(
ret
!=
SCMI_E_SUCCESS
)
{
ERROR
(
"SCMI system power domain reset return 0x%x unexpected
\n
"
,
ret
);
panic
();
}
wfi
();
ERROR
(
"CSS System Reset: operation not handled.
\n
"
);
panic
();
}
scmi_channel_plat_info_t
plat_css_scmi_plat_info
=
{
.
scmi_mbx_mem
=
CSS_SCMI_PAYLOAD_BASE
,
.
db_reg_addr
=
PLAT_CSS_MHU_BASE
+
CSS_SCMI_MHU_DB_REG_OFF
,
.
db_preserve_mask
=
0xfffffffd
,
.
db_modify_mask
=
0x2
,
};
void
plat_arm_pwrc_setup
(
void
)
{
scmi_channel
.
info
=
&
plat_css_scmi_plat_info
;
scmi_channel
.
lock
=
ARM_LOCK_GET_INSTANCE
;
scmi_handle
=
scmi_init
(
&
scmi_channel
);
if
(
scmi_handle
==
NULL
)
{
ERROR
(
"SCMI Initialization failed
\n
"
);
panic
();
}
}
/******************************************************************************
* This function overrides the default definition for ARM platforms. Initialize
* the SCMI driver, query capability via SCMI and modify the PSCI capability
* based on that.
*****************************************************************************/
const
plat_psci_ops_t
*
plat_arm_psci_override_pm_ops
(
plat_psci_ops_t
*
ops
)
{
uint32_t
msg_attr
;
int
ret
;
assert
(
scmi_handle
);
/* Check that power domain POWER_STATE_SET message is supported */
ret
=
scmi_proto_msg_attr
(
scmi_handle
,
SCMI_PWR_DMN_PROTO_ID
,
SCMI_PWR_STATE_SET_MSG
,
&
msg_attr
);
if
(
ret
!=
SCMI_E_SUCCESS
)
{
ERROR
(
"Set power state command is not supported by SCMI
\n
"
);
panic
();
}
/*
* Don't support PSCI NODE_HW_STATE call if SCMI doesn't support
* POWER_STATE_GET message.
*/
ret
=
scmi_proto_msg_attr
(
scmi_handle
,
SCMI_PWR_DMN_PROTO_ID
,
SCMI_PWR_STATE_GET_MSG
,
&
msg_attr
);
if
(
ret
!=
SCMI_E_SUCCESS
)
ops
->
get_node_hw_state
=
NULL
;
/* Check if the SCMI SYSTEM_POWER_STATE_SET message is supported */
ret
=
scmi_proto_msg_attr
(
scmi_handle
,
SCMI_SYS_PWR_PROTO_ID
,
SCMI_SYS_PWR_STATE_SET_MSG
,
&
msg_attr
);
if
(
ret
!=
SCMI_E_SUCCESS
)
{
/* System power management operations are not supported */
ops
->
system_off
=
NULL
;
ops
->
system_reset
=
NULL
;
ops
->
get_sys_suspend_power_state
=
NULL
;
}
else
if
(
!
(
msg_attr
&
SCMI_SYS_PWR_SUSPEND_SUPPORTED
))
{
/*
* System power management protocol is available, but it does
* not support SYSTEM SUSPEND.
*/
ops
->
get_sys_suspend_power_state
=
NULL
;
}
return
ops
;
}
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