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
1f4d62df
Unverified
Commit
1f4d62df
authored
May 17, 2018
by
danh-arm
Committed by
GitHub
May 17, 2018
Browse files
Merge pull request #1369 from sivadur/xilinxdiff
Xilinx platform mangement related changes
parents
eda9eade
29657d0d
Changes
17
Hide whitespace changes
Inline
Side-by-side
plat/xilinx/zynqmp/aarch64/zynqmp_common.c
View file @
1f4d62df
...
...
@@ -8,8 +8,11 @@
#include <generic_delay_timer.h>
#include <mmio.h>
#include <platform.h>
#include <stdbool.h>
#include <string.h>
#include <xlat_tables.h>
#include "../zynqmp_private.h"
#include "pm_api_sys.h"
/*
* Table of regions to map using the MMU.
...
...
@@ -59,40 +62,103 @@ unsigned int zynqmp_get_uart_clk(void)
#if LOG_LEVEL >= LOG_LEVEL_NOTICE
static
const
struct
{
unsigned
int
id
;
unsigned
int
ver
;
char
*
name
;
bool
evexists
;
}
zynqmp_devices
[]
=
{
{
.
id
=
0x10
,
.
name
=
"3EG"
,
},
{
.
id
=
0x10
,
.
ver
=
0x2c
,
.
name
=
"3CG"
,
},
{
.
id
=
0x11
,
.
name
=
"2EG"
,
},
{
.
id
=
0x11
,
.
ver
=
0x2c
,
.
name
=
"2CG"
,
},
{
.
id
=
0x20
,
.
name
=
"5EV"
,
.
evexists
=
true
,
},
{
.
id
=
0x20
,
.
ver
=
0x100
,
.
name
=
"5EG"
,
.
evexists
=
true
,
},
{
.
id
=
0x20
,
.
ver
=
0x12c
,
.
name
=
"5CG"
,
},
{
.
id
=
0x21
,
.
name
=
"4EV"
,
.
evexists
=
true
,
},
{
.
id
=
0x21
,
.
ver
=
0x100
,
.
name
=
"4EG"
,
.
evexists
=
true
,
},
{
.
id
=
0x21
,
.
ver
=
0x12c
,
.
name
=
"4CG"
,
},
{
.
id
=
0x30
,
.
name
=
"7EV"
,
.
evexists
=
true
,
},
{
.
id
=
0x30
,
.
ver
=
0x100
,
.
name
=
"7EG"
,
.
evexists
=
true
,
},
{
.
id
=
0x30
,
.
ver
=
0x12c
,
.
name
=
"7CG"
,
},
{
.
id
=
0x38
,
.
name
=
"9EG"
,
},
{
.
id
=
0x38
,
.
ver
=
0x2c
,
.
name
=
"9CG"
,
},
{
.
id
=
0x39
,
.
name
=
"6EG"
,
},
{
.
id
=
0x39
,
.
ver
=
0x2c
,
.
name
=
"6CG"
,
},
{
.
id
=
0x40
,
.
name
=
"11EG"
,
},
{
/* For testing purpose only */
.
id
=
0x50
,
.
ver
=
0x2c
,
.
name
=
"15CG"
,
},
{
.
id
=
0x50
,
.
name
=
"15EG"
,
...
...
@@ -105,30 +171,75 @@ static const struct {
.
id
=
0x59
,
.
name
=
"17EG"
,
},
{
.
id
=
0x60
,
.
name
=
"28DR"
,
},
{
.
id
=
0x61
,
.
name
=
"21DR"
,
},
{
.
id
=
0x62
,
.
name
=
"29DR"
,
},
{
.
id
=
0x63
,
.
name
=
"23DR"
,
},
{
.
id
=
0x64
,
.
name
=
"27DR"
,
},
{
.
id
=
0x65
,
.
name
=
"25DR"
,
},
};
static
unsigned
int
zynqmp_get_silicon_id
(
void
)
#define ZYNQMP_PL_STATUS_BIT 9
#define ZYNQMP_PL_STATUS_MASK BIT(ZYNQMP_PL_STATUS_BIT)
#define ZYNQMP_CSU_VERSION_MASK ~(ZYNQMP_PL_STATUS_MASK)
static
char
*
zynqmp_get_silicon_idcode_name
(
void
)
{
uint32_t
id
;
uint32_t
id
,
ver
,
chipid
[
2
];
size_t
i
,
j
,
len
;
enum
pm_ret_status
ret
;
const
char
*
name
=
"EG/EV"
;
id
=
mmio_read_32
(
ZYNQMP_CSU_BASEADDR
+
ZYNQMP_CSU_IDCODE_OFFSET
);
ret
=
pm_get_chipid
(
chipid
);
if
(
ret
)
return
"UNKN"
;
id
&=
ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK
|
ZYNQMP_CSU_IDCODE_SVD_MASK
;
id
=
chipid
[
0
]
&
(
ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK
|
ZYNQMP_CSU_IDCODE_SVD_MASK
);
id
>>=
ZYNQMP_CSU_IDCODE_SVD_SHIFT
;
ver
=
chipid
[
1
]
>>
ZYNQMP_EFUSE_IPDISABLE_SHIFT
;
return
id
;
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
zynqmp_devices
);
i
++
)
{
if
(
zynqmp_devices
[
i
].
id
==
id
&&
zynqmp_devices
[
i
].
ver
==
(
ver
&
ZYNQMP_CSU_VERSION_MASK
))
break
;
}
static
char
*
zynqmp_get_silicon_idcode_name
(
void
)
{
unsigned
int
id
;
if
(
i
>=
ARRAY_SIZE
(
zynqmp_devices
))
return
"UNKN"
;
if
(
!
zynqmp_devices
[
i
].
evexists
)
return
zynqmp_devices
[
i
].
name
;
id
=
zynqmp_get_silicon_id
();
for
(
size_t
i
=
0
;
i
<
ARRAY_SIZE
(
zynqmp_devices
);
i
++
)
{
if
(
zynqmp_devices
[
i
].
id
==
id
)
return
zynqmp_devices
[
i
].
name
;
if
(
ver
&
ZYNQMP_PL_STATUS_MASK
)
return
zynqmp_devices
[
i
].
name
;
len
=
strlen
(
zynqmp_devices
[
i
].
name
)
-
2
;
for
(
j
=
0
;
j
<
strlen
(
name
);
j
++
)
{
zynqmp_devices
[
i
].
name
[
len
]
=
name
[
j
];
len
++
;
}
return
"UNKN"
;
zynqmp_devices
[
i
].
name
[
len
]
=
'\0'
;
return
zynqmp_devices
[
i
].
name
;
}
static
unsigned
int
zynqmp_get_rtl_ver
(
void
)
...
...
@@ -195,60 +306,29 @@ static void zynqmp_print_platform_name(void)
break
;
}
NOTICE
(
"ATF running on XCZU%s/%s v%d/RTL%d.%d at 0x%x
%s
\n
"
,
NOTICE
(
"ATF running on XCZU%s/%s v%d/RTL%d.%d at 0x%x
\n
"
,
zynqmp_print_silicon_idcode
(),
label
,
zynqmp_get_ps_ver
(),
(
rtl
&
0xf0
)
>>
4
,
rtl
&
0xf
,
BL31_BASE
,
zynqmp_is_pmu_up
()
?
", with PMU firmware"
:
""
);
(
rtl
&
0xf0
)
>>
4
,
rtl
&
0xf
,
BL31_BASE
);
}
#else
static
inline
void
zynqmp_print_platform_name
(
void
)
{
}
#endif
/*
* Indicator for PMUFW discovery:
* 0 = No FW found
* non-zero = FW is present
*/
static
int
zynqmp_pmufw_present
;
/*
* zynqmp_discover_pmufw - Discover presence of PMUFW
*
* Discover the presence of PMUFW and store it for later run-time queries
* through zynqmp_is_pmu_up.
* NOTE: This discovery method is fragile and will break if:
* - setting FW_PRESENT is done by PMUFW itself and could be left out in PMUFW
* (be it by error or intentionally)
* - XPPU/XMPU may restrict ATF's access to the PMU address space
*/
static
int
zynqmp_discover_pmufw
(
void
)
unsigned
int
zynqmp_get_bootmode
(
void
)
{
zynqmp_pmufw_present
=
mmio_read_32
(
PMU_GLOBAL_CNTRL
)
;
zynqmp_pmufw_present
&=
PMU_GLOBAL_CNTRL_FW_IS_PRESENT
;
uint32_t
r
;
unsigned
int
ret
;
return
!!
zynqmp_pmufw_present
;
}
ret
=
pm_mmio_read
(
CRL_APB_BOOT_MODE_USER
,
&
r
);
/*
* zynqmp_is_pmu_up - Find if PMU firmware is up and running
*
* Return 0 if firmware is not available, non 0 otherwise
*/
int
zynqmp_is_pmu_up
(
void
)
{
return
zynqmp_pmufw_present
;
}
unsigned
int
zynqmp_get_bootmode
(
void
)
{
uint32_t
r
=
mmio_read_32
(
CRL_APB_BOOT_MODE_USER
);
if
(
ret
!=
PM_RET_SUCCESS
)
r
=
mmio_read_32
(
CRL_APB_BOOT_MODE_USER
);
return
r
&
CRL_APB_BOOT_MODE_MASK
;
}
void
zynqmp_config_setup
(
void
)
{
zynqmp_discover_pmufw
();
zynqmp_print_platform_name
();
generic_delay_timer_init
();
}
...
...
plat/xilinx/zynqmp/bl31_zynqmp_setup.c
View file @
1f4d62df
...
...
@@ -35,6 +35,19 @@ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
return
&
bl32_image_ep_info
;
}
/*
* Set the build time defaults. We want to do this when doing a JTAG boot
* or if we can't find any other config data.
*/
static
inline
void
bl31_set_default_config
(
void
)
{
bl32_image_ep_info
.
pc
=
BL32_BASE
;
bl32_image_ep_info
.
spsr
=
arm_get_spsr_for_bl32_entry
();
bl33_image_ep_info
.
pc
=
plat_get_ns_image_entrypoint
();
bl33_image_ep_info
.
spsr
=
SPSR_64
(
MODE_EL2
,
MODE_SP_ELX
,
DISABLE_ALL_EXCEPTIONS
);
}
/*
* Perform any BL31 specific platform actions. Here is an opportunity to copy
* parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they
...
...
@@ -69,15 +82,15 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2,
SET_SECURITY_STATE
(
bl33_image_ep_info
.
h
.
attr
,
NON_SECURE
);
if
(
zynqmp_get_bootmode
()
==
ZYNQMP_BOOTMODE_JTAG
)
{
/* use build time defaults in JTAG boot mode */
bl32_image_ep_info
.
pc
=
BL32_BASE
;
bl32_image_ep_info
.
spsr
=
arm_get_spsr_for_bl32_entry
();
bl33_image_ep_info
.
pc
=
plat_get_ns_image_entrypoint
();
bl33_image_ep_info
.
spsr
=
SPSR_64
(
MODE_EL2
,
MODE_SP_ELX
,
DISABLE_ALL_EXCEPTIONS
);
bl31_set_default_config
();
}
else
{
/* use parameters from FSBL */
fsbl_atf_handover
(
&
bl32_image_ep_info
,
&
bl33_image_ep_info
);
enum
fsbl_handoff
ret
=
fsbl_atf_handover
(
&
bl32_image_ep_info
,
&
bl33_image_ep_info
);
if
(
ret
==
FSBL_HANDOFF_NO_STRUCT
)
bl31_set_default_config
();
else
if
(
ret
!=
FSBL_HANDOFF_SUCCESS
)
panic
();
}
NOTICE
(
"BL31: Secure code at 0x%lx
\n
"
,
bl32_image_ep_info
.
pc
);
...
...
@@ -103,6 +116,39 @@ static void zynqmp_testing_setup(void)
}
#endif
#if ZYNQMP_WDT_RESTART
static
interrupt_type_handler_t
type_el3_interrupt_table
[
MAX_INTR_EL3
];
int
request_intr_type_el3
(
uint32_t
id
,
interrupt_type_handler_t
handler
)
{
/* Validate 'handler' and 'id' parameters */
if
(
!
handler
||
id
>=
MAX_INTR_EL3
)
return
-
EINVAL
;
/* Check if a handler has already been registered */
if
(
type_el3_interrupt_table
[
id
])
return
-
EALREADY
;
type_el3_interrupt_table
[
id
]
=
handler
;
return
0
;
}
static
uint64_t
rdo_el3_interrupt_handler
(
uint32_t
id
,
uint32_t
flags
,
void
*
handle
,
void
*
cookie
)
{
uint32_t
intr_id
;
interrupt_type_handler_t
handler
;
intr_id
=
plat_ic_get_pending_interrupt_id
();
handler
=
type_el3_interrupt_table
[
intr_id
];
if
(
handler
!=
NULL
)
handler
(
intr_id
,
flags
,
handle
,
cookie
);
return
0
;
}
#endif
void
bl31_platform_setup
(
void
)
{
/* Initialize the gic cpu and distributor interfaces */
...
...
@@ -113,6 +159,16 @@ void bl31_platform_setup(void)
void
bl31_plat_runtime_setup
(
void
)
{
#if ZYNQMP_WDT_RESTART
uint64_t
flags
=
0
;
uint64_t
rc
;
set_interrupt_rm_flag
(
flags
,
NON_SECURE
);
rc
=
register_interrupt_type_handler
(
INTR_TYPE_EL3
,
rdo_el3_interrupt_handler
,
flags
);
if
(
rc
)
panic
();
#endif
}
/*
...
...
plat/xilinx/zynqmp/include/platform_def.h
View file @
1f4d62df
...
...
@@ -96,6 +96,7 @@
* terminology. On a GICv2 system or mode, the lists will be merged and treated
* as Group 0 interrupts.
*/
#if !ZYNQMP_WDT_RESTART
#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
...
...
@@ -115,6 +116,29 @@
GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_EDGE)
#else
#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(IRQ_TTC3_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_EDGE)
#endif
#define PLAT_ARM_G0_IRQ_PROPS(grp)
...
...
plat/xilinx/zynqmp/plat_psci.c
View file @
1f4d62df
...
...
@@ -27,46 +27,6 @@ void zynqmp_cpu_standby(plat_local_state_t cpu_state)
wfi
();
}
static
int
zynqmp_nopmu_pwr_domain_on
(
u_register_t
mpidr
)
{
uint32_t
r
;
unsigned
int
cpu_id
=
plat_core_pos_by_mpidr
(
mpidr
);
VERBOSE
(
"%s: mpidr: 0x%lx
\n
"
,
__func__
,
mpidr
);
if
(
cpu_id
==
-
1
)
return
PSCI_E_INTERN_FAIL
;
/* program RVBAR */
mmio_write_32
(
APU_RVBAR_L_0
+
(
cpu_id
<<
3
),
zynqmp_sec_entry
);
mmio_write_32
(
APU_RVBAR_H_0
+
(
cpu_id
<<
3
),
zynqmp_sec_entry
>>
32
);
/* clear VINITHI */
r
=
mmio_read_32
(
APU_CONFIG_0
);
r
&=
~
(
1
<<
APU_CONFIG_0_VINITHI_SHIFT
<<
cpu_id
);
mmio_write_32
(
APU_CONFIG_0
,
r
);
/* clear power down request */
r
=
mmio_read_32
(
APU_PWRCTL
);
r
&=
~
(
1
<<
cpu_id
);
mmio_write_32
(
APU_PWRCTL
,
r
);
/* power up island */
mmio_write_32
(
PMU_GLOBAL_REQ_PWRUP_EN
,
1
<<
cpu_id
);
mmio_write_32
(
PMU_GLOBAL_REQ_PWRUP_TRIG
,
1
<<
cpu_id
);
/* FIXME: we should have a way to break out */
while
(
mmio_read_32
(
PMU_GLOBAL_REQ_PWRUP_STATUS
)
&
(
1
<<
cpu_id
))
;
/* release core reset */
r
=
mmio_read_32
(
CRF_APB_RST_FPD_APU
);
r
&=
~
((
CRF_APB_RST_FPD_APU_ACPU_PWRON_RESET
|
CRF_APB_RST_FPD_APU_ACPU_RESET
)
<<
cpu_id
);
mmio_write_32
(
CRF_APB_RST_FPD_APU
,
r
);
return
PSCI_E_SUCCESS
;
}
static
int
zynqmp_pwr_domain_on
(
u_register_t
mpidr
)
{
unsigned
int
cpu_id
=
plat_core_pos_by_mpidr
(
mpidr
);
...
...
@@ -78,6 +38,8 @@ static int zynqmp_pwr_domain_on(u_register_t mpidr)
return
PSCI_E_INTERN_FAIL
;
proc
=
pm_get_proc
(
cpu_id
);
/* Clear power down request */
pm_client_wakeup
(
proc
);
/* Send request to PMU to wake up selected APU CPU core */
pm_req_wakeup
(
proc
->
node_id
,
1
,
zynqmp_sec_entry
,
REQ_ACK_BLOCKING
);
...
...
@@ -85,24 +47,6 @@ static int zynqmp_pwr_domain_on(u_register_t mpidr)
return
PSCI_E_SUCCESS
;
}
static
void
zynqmp_nopmu_pwr_domain_off
(
const
psci_power_state_t
*
target_state
)
{
uint32_t
r
;
unsigned
int
cpu_id
=
plat_my_core_pos
();
for
(
size_t
i
=
0
;
i
<=
PLAT_MAX_PWR_LVL
;
i
++
)
VERBOSE
(
"%s: target_state->pwr_domain_state[%lu]=%x
\n
"
,
__func__
,
i
,
target_state
->
pwr_domain_state
[
i
]);
/* Prevent interrupts from spuriously waking up this cpu */
gicv2_cpuif_disable
();
/* set power down request */
r
=
mmio_read_32
(
APU_PWRCTL
);
r
|=
(
1
<<
cpu_id
);
mmio_write_32
(
APU_PWRCTL
,
r
);
}
static
void
zynqmp_pwr_domain_off
(
const
psci_power_state_t
*
target_state
)
{
unsigned
int
cpu_id
=
plat_my_core_pos
();
...
...
@@ -126,33 +70,6 @@ static void zynqmp_pwr_domain_off(const psci_power_state_t *target_state)
pm_self_suspend
(
proc
->
node_id
,
MAX_LATENCY
,
PM_STATE_CPU_IDLE
,
0
);
}
static
void
zynqmp_nopmu_pwr_domain_suspend
(
const
psci_power_state_t
*
target_state
)
{
uint32_t
r
;
unsigned
int
cpu_id
=
plat_my_core_pos
();
for
(
size_t
i
=
0
;
i
<=
PLAT_MAX_PWR_LVL
;
i
++
)
VERBOSE
(
"%s: target_state->pwr_domain_state[%lu]=%x
\n
"
,
__func__
,
i
,
target_state
->
pwr_domain_state
[
i
]);
/* set power down request */
r
=
mmio_read_32
(
APU_PWRCTL
);
r
|=
(
1
<<
cpu_id
);
mmio_write_32
(
APU_PWRCTL
,
r
);
/* program RVBAR */
mmio_write_32
(
APU_RVBAR_L_0
+
(
cpu_id
<<
3
),
zynqmp_sec_entry
);
mmio_write_32
(
APU_RVBAR_H_0
+
(
cpu_id
<<
3
),
zynqmp_sec_entry
>>
32
);
/* clear VINITHI */
r
=
mmio_read_32
(
APU_CONFIG_0
);
r
&=
~
(
1
<<
APU_CONFIG_0_VINITHI_SHIFT
<<
cpu_id
);
mmio_write_32
(
APU_CONFIG_0
,
r
);
/* enable power up on IRQ */
mmio_write_32
(
PMU_GLOBAL_REQ_PWRUP_EN
,
1
<<
cpu_id
);
}
static
void
zynqmp_pwr_domain_suspend
(
const
psci_power_state_t
*
target_state
)
{
unsigned
int
state
;
...
...
@@ -186,24 +103,6 @@ static void zynqmp_pwr_domain_on_finish(const psci_power_state_t *target_state)
gicv2_pcpu_distif_init
();
}
static
void
zynqmp_nopmu_pwr_domain_suspend_finish
(
const
psci_power_state_t
*
target_state
)
{
uint32_t
r
;
unsigned
int
cpu_id
=
plat_my_core_pos
();
for
(
size_t
i
=
0
;
i
<=
PLAT_MAX_PWR_LVL
;
i
++
)
VERBOSE
(
"%s: target_state->pwr_domain_state[%lu]=%x
\n
"
,
__func__
,
i
,
target_state
->
pwr_domain_state
[
i
]);
/* disable power up on IRQ */
mmio_write_32
(
PMU_GLOBAL_REQ_PWRUP_DIS
,
1
<<
cpu_id
);
/* clear powerdown bit */
r
=
mmio_read_32
(
APU_PWRCTL
);
r
&=
~
(
1
<<
cpu_id
);
mmio_write_32
(
APU_PWRCTL
,
r
);
}
static
void
zynqmp_pwr_domain_suspend_finish
(
const
psci_power_state_t
*
target_state
)
{
unsigned
int
cpu_id
=
plat_my_core_pos
();
...
...
@@ -230,15 +129,6 @@ static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_st
/*******************************************************************************
* ZynqMP handlers to shutdown/reboot the system
******************************************************************************/
static
void
__dead2
zynqmp_nopmu_system_off
(
void
)
{
ERROR
(
"ZynqMP System Off: operation not handled.
\n
"
);
/* disable coherency */
plat_arm_interconnect_exit_coherency
();
panic
();
}
static
void
__dead2
zynqmp_system_off
(
void
)
{
...
...
@@ -247,29 +137,7 @@ static void __dead2 zynqmp_system_off(void)
/* Send the power down request to the PMU */
pm_system_shutdown
(
PMF_SHUTDOWN_TYPE_SHUTDOWN
,
PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM
);
while
(
1
)
wfi
();
}
static
void
__dead2
zynqmp_nopmu_system_reset
(
void
)
{
/*
* This currently triggers a system reset. I.e. the whole
* system will be reset! Including RPUs, PMU, PL, etc.
*/
/* disable coherency */
plat_arm_interconnect_exit_coherency
();
/* bypass RPLL (needed on 1.0 silicon) */
uint32_t
reg
=
mmio_read_32
(
CRL_APB_RPLL_CTRL
);
reg
|=
CRL_APB_RPLL_CTRL_BYPASS
;
mmio_write_32
(
CRL_APB_RPLL_CTRL
,
reg
);
/* trigger system reset */
mmio_write_32
(
CRL_APB_RESET_CTRL
,
CRL_APB_RESET_CTRL_SOFT_RESET
);
pm_get_shutdown_scope
());
while
(
1
)
wfi
();
...
...
@@ -282,7 +150,7 @@ static void __dead2 zynqmp_system_reset(void)
/* Send the system reset request to the PMU */
pm_system_shutdown
(
PMF_SHUTDOWN_TYPE_RESET
,
PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM
);
pm_get_shutdown_scope
()
);
while
(
1
)
wfi
();
...
...
@@ -341,20 +209,6 @@ static const struct plat_psci_ops zynqmp_psci_ops = {
.
get_sys_suspend_power_state
=
zynqmp_get_sys_suspend_power_state
,
};
static
const
struct
plat_psci_ops
zynqmp_nopmu_psci_ops
=
{
.
cpu_standby
=
zynqmp_cpu_standby
,
.
pwr_domain_on
=
zynqmp_nopmu_pwr_domain_on
,
.
pwr_domain_off
=
zynqmp_nopmu_pwr_domain_off
,
.
pwr_domain_suspend
=
zynqmp_nopmu_pwr_domain_suspend
,
.
pwr_domain_on_finish
=
zynqmp_pwr_domain_on_finish
,
.
pwr_domain_suspend_finish
=
zynqmp_nopmu_pwr_domain_suspend_finish
,
.
system_off
=
zynqmp_nopmu_system_off
,
.
system_reset
=
zynqmp_nopmu_system_reset
,
.
validate_power_state
=
zynqmp_validate_power_state
,
.
validate_ns_entrypoint
=
zynqmp_validate_ns_entrypoint
,
.
get_sys_suspend_power_state
=
zynqmp_get_sys_suspend_power_state
,
};
/*******************************************************************************
* Export the platform specific power ops.
******************************************************************************/
...
...
@@ -363,10 +217,7 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint,
{
zynqmp_sec_entry
=
sec_entrypoint
;
if
(
zynqmp_is_pmu_up
())
*
psci_ops
=
&
zynqmp_psci_ops
;
else
*
psci_ops
=
&
zynqmp_nopmu_psci_ops
;
*
psci_ops
=
&
zynqmp_psci_ops
;
return
0
;
}
plat/xilinx/zynqmp/plat_startup.c
View file @
1f4d62df
...
...
@@ -9,6 +9,7 @@
#include <debug.h>
#include <mmio.h>
#include "zynqmp_def.h"
#include "zynqmp_private.h"
/*
* ATFHandoffParams
...
...
@@ -147,8 +148,11 @@ static int get_fsbl_estate(const struct xfsbl_partition *partition)
*
* Process the handoff paramters from the FSBL and populate the BL32 and BL33
* image info structures accordingly.
*
* Return: Return the status of the handoff. The value will be from the
* fsbl_handoff enum.
*/
void
fsbl_atf_handover
(
entry_point_info_t
*
bl32
,
entry_point_info_t
*
bl33
)
enum
fsbl_handoff
fsbl_atf_handover
(
entry_point_info_t
*
bl32
,
entry_point_info_t
*
bl33
)
{
uint64_t
atf_handoff_addr
;
const
struct
xfsbl_atf_handoff_params
*
ATFHandoffParams
;
...
...
@@ -157,8 +161,8 @@ void fsbl_atf_handover(entry_point_info_t *bl32, entry_point_info_t *bl33)
assert
((
atf_handoff_addr
<
BL31_BASE
)
||
(
atf_handoff_addr
>
(
uint64_t
)
&
__BL31_END__
));
if
(
!
atf_handoff_addr
)
{
ERROR
(
"BL31: No ATF handoff structure passed
\n
"
);
panic
()
;
WARN
(
"BL31: No ATF handoff structure passed
\n
"
);
return
FSBL_HANDOFF_NO_STRUCT
;
}
ATFHandoffParams
=
(
struct
xfsbl_atf_handoff_params
*
)
atf_handoff_addr
;
...
...
@@ -168,7 +172,7 @@ void fsbl_atf_handover(entry_point_info_t *bl32, entry_point_info_t *bl33)
(
ATFHandoffParams
->
magic
[
3
]
!=
'X'
))
{
ERROR
(
"BL31: invalid ATF handoff structure at %llx
\n
"
,
atf_handoff_addr
);
panic
()
;
return
FSBL_HANDOFF_INVAL_STRUCT
;
}
VERBOSE
(
"BL31: ATF handoff params at:0x%llx, entries:%u
\n
"
,
...
...
@@ -176,7 +180,7 @@ void fsbl_atf_handover(entry_point_info_t *bl32, entry_point_info_t *bl33)
if
(
ATFHandoffParams
->
num_entries
>
FSBL_MAX_PARTITIONS
)
{
ERROR
(
"BL31: ATF handoff params: too many partitions (%u/%u)
\n
"
,
ATFHandoffParams
->
num_entries
,
FSBL_MAX_PARTITIONS
);
panic
()
;
return
FSBL_HANDOFF_TOO_MANY_PARTS
;
}
/*
...
...
@@ -261,4 +265,6 @@ void fsbl_atf_handover(entry_point_info_t *bl32, entry_point_info_t *bl33)
else
EP_SET_EE
(
image
->
h
.
attr
,
EP_EE_LITTLE
);
}
return
FSBL_HANDOFF_SUCCESS
;
}
plat/xilinx/zynqmp/platform.mk
View file @
1f4d62df
...
...
@@ -9,6 +9,7 @@ override PROGRAMMABLE_RESET_ADDRESS := 1
PSCI_EXTENDED_STATE_ID
:=
1
A53_DISABLE_NON_TEMPORAL_HINT
:=
0
SEPARATE_CODE_AND_RODATA
:=
1
ZYNQMP_WDT_RESTART
:=
0
override RESET_TO_BL31
:
= 1
# Do not enable SVE
...
...
@@ -41,6 +42,10 @@ endif
ZYNQMP_CONSOLE
?=
cadence
$(eval
$(call
add_define_val,ZYNQMP_CONSOLE,ZYNQMP_CONSOLE_ID_${ZYNQMP_CONSOLE}))
ifdef
ZYNQMP_WDT_RESTART
$(eval
$(call
add_define,ZYNQMP_WDT_RESTART))
endif
PLAT_INCLUDES
:=
-Iinclude
/plat/arm/common/
\
-Iinclude
/plat/arm/common/aarch64/
\
-Iplat
/xilinx/zynqmp/include/
\
...
...
plat/xilinx/zynqmp/pm_service/pm_api_sys.c
View file @
1f4d62df
...
...
@@ -19,6 +19,19 @@
#include "pm_common.h"
#include "pm_ipi.h"
/* default shutdown/reboot scope is system(2) */
static
unsigned
int
pm_shutdown_scope
=
PMF_SHUTDOWN_SUBTYPE_SYSTEM
;
/**
* pm_get_shutdown_scope() - Get the currently set shutdown scope
*
* @return Shutdown scope value
*/
unsigned
int
pm_get_shutdown_scope
(
void
)
{
return
pm_shutdown_scope
;
}
/**
* Assigning of argument values into array elements.
*/
...
...
@@ -130,10 +143,7 @@ enum pm_ret_status pm_req_wakeup(enum pm_node_id target,
{
uint32_t
payload
[
PAYLOAD_ARG_CNT
];
uint64_t
encoded_address
;
const
struct
pm_proc
*
proc
=
pm_get_proc_by_node
(
target
);
/* invoke APU-specific code for waking up another APU core */
pm_client_wakeup
(
proc
);
/* encode set Address into 1st bit of address */
encoded_address
=
address
;
...
...
@@ -218,7 +228,8 @@ enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target,
/**
* pm_system_shutdown() - PM call to request a system shutdown or restart
* @restart Shutdown or restart? 0 for shutdown, 1 for restart
* @type Shutdown or restart? 0=shutdown, 1=restart, 2=setscope
* @subtype Scope: 0=APU-subsystem, 1=PS, 2=system
*
* @return Returns status, either success or error+reason
*/
...
...
@@ -226,8 +237,14 @@ enum pm_ret_status pm_system_shutdown(unsigned int type, unsigned int subtype)
{
uint32_t
payload
[
PAYLOAD_ARG_CNT
];
if
(
type
==
PMF_SHUTDOWN_TYPE_SETSCOPE_ONLY
)
{
/* Setting scope for subsequent PSCI reboot or shutdown */
pm_shutdown_scope
=
subtype
;
return
PM_RET_SUCCESS
;
}
PM_PACK_PAYLOAD3
(
payload
,
PM_SYSTEM_SHUTDOWN
,
type
,
subtype
);
return
pm_ipi_send
(
primary_proc
,
payload
);
return
pm_ipi_send
_non_blocking
(
primary_proc
,
payload
);
}
/* APIs for managing PM slaves: */
...
...
@@ -342,18 +359,38 @@ enum pm_ret_status pm_set_configuration(unsigned int phys_addr)
}
/**
* pm_get_node_status() - PM call to request a node's current power state
* @nid Node id of the slave
* pm_init_finalize() - Call to notify PMU firmware that master has power
* management enabled and that it has finished its
* initialization
*
* @return Status returned by the PMU firmware
*/
enum
pm_ret_status
pm_init_finalize
(
void
)
{
uint32_t
payload
[
PAYLOAD_ARG_CNT
];
/* Send request to the PMU */
PM_PACK_PAYLOAD1
(
payload
,
PM_INIT_FINALIZE
);
return
pm_ipi_send_sync
(
primary_proc
,
payload
,
NULL
,
0
);
}
/**
* pm_get_node_status() - PM call to request a node's current status
* @nid Node id
* @ret_buff Buffer for the return values:
* [0] - Current power state of the node
* [1] - Current requirements for the node (slave nodes only)
* [2] - Current usage status for the node (slave nodes only)
*
* @return Returns status, either success or error+reason
*/
enum
pm_ret_status
pm_get_node_status
(
enum
pm_node_id
nid
)
enum
pm_ret_status
pm_get_node_status
(
enum
pm_node_id
nid
,
uint32_t
*
ret_buff
)
{
/* TODO: Add power state argument!! */
uint32_t
payload
[
PAYLOAD_ARG_CNT
];
PM_PACK_PAYLOAD2
(
payload
,
PM_GET_NODE_STATUS
,
nid
);
return
pm_ipi_send
(
primary_proc
,
payload
);
return
pm_ipi_send
_sync
(
primary_proc
,
payload
,
ret_buff
,
3
);
}
/**
...
...
@@ -501,7 +538,7 @@ enum pm_ret_status pm_fpga_load(uint32_t address_low,
/* Send request to the PMU */
PM_PACK_PAYLOAD5
(
payload
,
PM_FPGA_LOAD
,
address_high
,
address_low
,
size
,
flags
);
return
pm_ipi_send
(
primary_proc
,
payload
);
return
pm_ipi_send
_sync
(
primary_proc
,
payload
,
NULL
,
0
);
}
/**
...
...
@@ -538,15 +575,30 @@ enum pm_ret_status pm_get_chipid(uint32_t *value)
}
/**
* pm_get_callbackdata() - Read from IPI response buffer
* @data - array of PAYLOAD_ARG_CNT elements
* pm_secure_rsaaes() - Load the secure images.
*
* This function provides access to the xilsecure library to load
* the authenticated, encrypted, and authenicated/encrypted images.
*
* address_low: lower 32-bit Linear memory space address
*
* address_high: higher 32-bit Linear memory space address
*
* size: Number of 32bit words
*
*
Read value from ipi buffer response buffer.
*
@return Returns status, either success or error+reason
*/
void
pm_get_callbackdata
(
uint32_t
*
data
,
size_t
count
)
enum
pm_ret_status
pm_secure_rsaaes
(
uint32_t
address_low
,
uint32_t
address_high
,
uint32_t
size
,
uint32_t
flags
)
{
pm_ipi_buff_read_callb
(
data
,
count
);
pm_ipi_irq_clear
(
primary_proc
);
uint32_t
payload
[
PAYLOAD_ARG_CNT
];
/* Send request to the PMU */
PM_PACK_PAYLOAD5
(
payload
,
PM_SECURE_RSA_AES
,
address_high
,
address_low
,
size
,
flags
);
return
pm_ipi_send_sync
(
primary_proc
,
payload
,
NULL
,
0
);
}
/**
...
...
@@ -1074,3 +1126,43 @@ enum pm_ret_status pm_query_data(enum pm_query_id qid,
return
ret
;
}
enum
pm_ret_status
pm_sha_hash
(
uint32_t
address_high
,
uint32_t
address_low
,
uint32_t
size
,
uint32_t
flags
)
{
uint32_t
payload
[
PAYLOAD_ARG_CNT
];
/* Send request to the PMU */
PM_PACK_PAYLOAD5
(
payload
,
PM_SECURE_SHA
,
address_high
,
address_low
,
size
,
flags
);
return
pm_ipi_send_sync
(
primary_proc
,
payload
,
NULL
,
0
);
}
enum
pm_ret_status
pm_rsa_core
(
uint32_t
address_high
,
uint32_t
address_low
,
uint32_t
size
,
uint32_t
flags
)
{
uint32_t
payload
[
PAYLOAD_ARG_CNT
];
/* Send request to the PMU */
PM_PACK_PAYLOAD5
(
payload
,
PM_SECURE_RSA
,
address_high
,
address_low
,
size
,
flags
);
return
pm_ipi_send_sync
(
primary_proc
,
payload
,
NULL
,
0
);
}
enum
pm_ret_status
pm_secure_image
(
uint32_t
address_low
,
uint32_t
address_high
,
uint32_t
key_lo
,
uint32_t
key_hi
,
uint32_t
*
value
)
{
uint32_t
payload
[
PAYLOAD_ARG_CNT
];
/* Send request to the PMU */
PM_PACK_PAYLOAD5
(
payload
,
PM_SECURE_IMAGE
,
address_high
,
address_low
,
key_hi
,
key_lo
);
return
pm_ipi_send_sync
(
primary_proc
,
payload
,
value
,
2
);
}
plat/xilinx/zynqmp/pm_service/pm_api_sys.h
View file @
1f4d62df
...
...
@@ -76,7 +76,9 @@ enum pm_ret_status pm_set_max_latency(enum pm_node_id nid,
/* Miscellaneous API functions */
enum
pm_ret_status
pm_get_api_version
(
unsigned
int
*
version
);
enum
pm_ret_status
pm_set_configuration
(
unsigned
int
phys_addr
);
enum
pm_ret_status
pm_get_node_status
(
enum
pm_node_id
node
);
enum
pm_ret_status
pm_init_finalize
(
void
);
enum
pm_ret_status
pm_get_node_status
(
enum
pm_node_id
node
,
uint32_t
*
ret_buff
);
enum
pm_ret_status
pm_register_notifier
(
enum
pm_node_id
nid
,
unsigned
int
event
,
unsigned
int
wake
,
...
...
@@ -107,7 +109,11 @@ enum pm_ret_status pm_fpga_load(uint32_t address_low,
enum
pm_ret_status
pm_fpga_get_status
(
unsigned
int
*
value
);
enum
pm_ret_status
pm_get_chipid
(
uint32_t
*
value
);
void
pm_get_callbackdata
(
uint32_t
*
data
,
size_t
count
);
enum
pm_ret_status
pm_secure_rsaaes
(
uint32_t
address_high
,
uint32_t
address_low
,
uint32_t
size
,
uint32_t
flags
);
unsigned
int
pm_get_shutdown_scope
(
void
);
enum
pm_ret_status
pm_pinctrl_request
(
unsigned
int
pin
);
enum
pm_ret_status
pm_pinctrl_release
(
unsigned
int
pin
);
enum
pm_ret_status
pm_pinctrl_get_function
(
unsigned
int
pin
,
...
...
@@ -146,4 +152,17 @@ enum pm_ret_status pm_query_data(enum pm_query_id qid,
unsigned
int
arg2
,
unsigned
int
arg3
,
unsigned
int
*
data
);
enum
pm_ret_status
pm_sha_hash
(
uint32_t
address_high
,
uint32_t
address_low
,
uint32_t
size
,
uint32_t
flags
);
enum
pm_ret_status
pm_rsa_core
(
uint32_t
address_high
,
uint32_t
address_low
,
uint32_t
size
,
uint32_t
flags
);
enum
pm_ret_status
pm_secure_image
(
uint32_t
address_low
,
uint32_t
address_high
,
uint32_t
key_lo
,
uint32_t
key_hi
,
uint32_t
*
value
);
#endif
/* _PM_API_SYS_H_ */
plat/xilinx/zynqmp/pm_service/pm_client.c
View file @
1f4d62df
...
...
@@ -26,10 +26,15 @@
#define NUM_GICD_ISENABLER ((IRQ_MAX >> 5) + 1)
#define UNDEFINED_CPUID (~0)
#define PM_SUSPEND_MODE_STD 0
#define PM_SUSPEND_MODE_POWER_OFF 1
DEFINE_BAKERY_LOCK
(
pm_client_secure_lock
);
extern
const
struct
pm_ipi
apu_ipi
;
static
uint32_t
suspend_mode
=
PM_SUSPEND_MODE_STD
;
/* Order in pm_procs_all array must match cpu ids */
static
const
struct
pm_proc
pm_procs_all
[]
=
{
{
...
...
@@ -165,6 +170,19 @@ static void pm_client_set_wakeup_sources(void)
uint8_t
pm_wakeup_nodes_set
[
NODE_MAX
];
uintptr_t
isenabler1
=
BASE_GICD_BASE
+
GICD_ISENABLER
+
4
;
/* In case of power-off suspend, only NODE_EXTERN must be set */
if
(
suspend_mode
==
PM_SUSPEND_MODE_POWER_OFF
)
{
enum
pm_ret_status
ret
;
ret
=
pm_set_wakeup_source
(
NODE_APU
,
NODE_EXTERN
,
1
);
/**
* If NODE_EXTERN could not be set as wake source, proceed with
* standard suspend (no one will wake the system otherwise)
*/
if
(
ret
==
PM_RET_SUCCESS
)
return
;
}
zeromem
(
&
pm_wakeup_nodes_set
,
sizeof
(
pm_wakeup_nodes_set
));
for
(
reg_num
=
0
;
reg_num
<
NUM_GICD_ISENABLER
;
reg_num
++
)
{
...
...
@@ -305,3 +323,13 @@ void pm_client_wakeup(const struct pm_proc *proc)
bakery_lock_release
(
&
pm_client_secure_lock
);
}
enum
pm_ret_status
pm_set_suspend_mode
(
uint32_t
mode
)
{
if
((
mode
!=
PM_SUSPEND_MODE_STD
)
&&
(
mode
!=
PM_SUSPEND_MODE_POWER_OFF
))
return
PM_RET_ERROR_ARGS
;
suspend_mode
=
mode
;
return
PM_RET_SUCCESS
;
}
plat/xilinx/zynqmp/pm_service/pm_client.h
View file @
1f4d62df
...
...
@@ -20,6 +20,7 @@ void pm_client_suspend(const struct pm_proc *proc, unsigned int state);
void
pm_client_abort_suspend
(
void
);
void
pm_client_wakeup
(
const
struct
pm_proc
*
proc
);
enum
pm_ret_status
set_ocm_retention
(
void
);
enum
pm_ret_status
pm_set_suspend_mode
(
uint32_t
mode
);
/* Global variables to be set in pm_client.c */
extern
const
struct
pm_proc
*
primary_proc
;
...
...
plat/xilinx/zynqmp/pm_service/pm_defs.h
View file @
1f4d62df
...
...
@@ -62,7 +62,7 @@ enum pm_api_id {
PM_RESET_GET_STATUS
,
PM_MMIO_WRITE
,
PM_MMIO_READ
,
PM_INIT
,
PM_INIT
_FINALIZE
,
PM_FPGA_LOAD
,
PM_FPGA_GET_STATUS
,
PM_GET_CHIPID
,
...
...
@@ -88,6 +88,7 @@ enum pm_api_id {
PM_CLOCK_GETRATE
,
PM_CLOCK_SETPARENT
,
PM_CLOCK_GETPARENT
,
PM_SECURE_IMAGE
,
PM_API_MAX
};
...
...
@@ -141,7 +142,7 @@ enum pm_node_id {
NODE_GPIO
,
NODE_CAN_0
,
NODE_CAN_1
,
NODE_
AFI
,
NODE_
EXTERN
,
NODE_APLL
,
NODE_VPLL
,
NODE_DPLL
,
...
...
@@ -239,11 +240,22 @@ enum pm_boot_status {
PM_BOOT_ERROR
,
};
/**
* @PMF_SHUTDOWN_TYPE_SHUTDOWN: shutdown
* @PMF_SHUTDOWN_TYPE_RESET: reset/reboot
* @PMF_SHUTDOWN_TYPE_SETSCOPE_ONLY: set the shutdown/reboot scope
*/
enum
pm_shutdown_type
{
PMF_SHUTDOWN_TYPE_SHUTDOWN
,
PMF_SHUTDOWN_TYPE_RESET
,
PMF_SHUTDOWN_TYPE_SETSCOPE_ONLY
,
};
/**
* @PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM: shutdown/reboot APU subsystem only
* @PMF_SHUTDOWN_SUBTYPE_PS_ONLY: shutdown/reboot entire PS (but not PL)
* @PMF_SHUTDOWN_SUBTYPE_SYSTEM: shutdown/reboot entire system
*/
enum
pm_shutdown_subtype
{
PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM
,
PMF_SHUTDOWN_SUBTYPE_PS_ONLY
,
...
...
plat/xilinx/zynqmp/pm_service/pm_ipi.c
View file @
1f4d62df
...
...
@@ -26,6 +26,9 @@
#define IPI_BUFFER_REQ_OFFSET 0x0U
#define IPI_BUFFER_RESP_OFFSET 0x20U
#define IPI_BLOCKING 1
#define IPI_NON_BLOCKING 0
DEFINE_BAKERY_LOCK
(
pm_secure_lock
);
const
struct
pm_ipi
apu_ipi
=
{
...
...
@@ -63,7 +66,8 @@ int pm_ipi_init(const struct pm_proc *proc)
* @return Returns status, either success or error+reason
*/
static
enum
pm_ret_status
pm_ipi_send_common
(
const
struct
pm_proc
*
proc
,
uint32_t
payload
[
PAYLOAD_ARG_CNT
])
uint32_t
payload
[
PAYLOAD_ARG_CNT
],
uint32_t
is_blocking
)
{
unsigned
int
offset
=
0
;
uintptr_t
buffer_base
=
proc
->
ipi
->
buffer_base
+
...
...
@@ -75,12 +79,38 @@ static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc,
mmio_write_32
(
buffer_base
+
offset
,
payload
[
i
]);
offset
+=
PAYLOAD_ARG_SIZE
;
}
/* Generate IPI to PMU */
ipi_mb_notify
(
proc
->
ipi
->
apu_ipi_id
,
proc
->
ipi
->
pmu_ipi_id
,
1
);
ipi_mb_notify
(
proc
->
ipi
->
apu_ipi_id
,
proc
->
ipi
->
pmu_ipi_id
,
is_blocking
);
return
PM_RET_SUCCESS
;
}
/**
* pm_ipi_send_non_blocking() - Sends IPI request to the PMU without blocking
* notification
* @proc Pointer to the processor who is initiating request
* @payload API id and call arguments to be written in IPI buffer
*
* Send an IPI request to the power controller.
*
* @return Returns status, either success or error+reason
*/
enum
pm_ret_status
pm_ipi_send_non_blocking
(
const
struct
pm_proc
*
proc
,
uint32_t
payload
[
PAYLOAD_ARG_CNT
])
{
enum
pm_ret_status
ret
;
bakery_lock_get
(
&
pm_secure_lock
);
ret
=
pm_ipi_send_common
(
proc
,
payload
,
IPI_NON_BLOCKING
);
bakery_lock_release
(
&
pm_secure_lock
);
return
ret
;
}
/**
* pm_ipi_send() - Sends IPI request to the PMU
* @proc Pointer to the processor who is initiating request
...
...
@@ -97,7 +127,7 @@ enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
bakery_lock_get
(
&
pm_secure_lock
);
ret
=
pm_ipi_send_common
(
proc
,
payload
);
ret
=
pm_ipi_send_common
(
proc
,
payload
,
IPI_BLOCKING
);
bakery_lock_release
(
&
pm_secure_lock
);
...
...
@@ -179,7 +209,7 @@ enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
bakery_lock_get
(
&
pm_secure_lock
);
ret
=
pm_ipi_send_common
(
proc
,
payload
);
ret
=
pm_ipi_send_common
(
proc
,
payload
,
IPI_BLOCKING
);
if
(
ret
!=
PM_RET_SUCCESS
)
goto
unlock
;
...
...
plat/xilinx/zynqmp/pm_service/pm_ipi.h
View file @
1f4d62df
...
...
@@ -13,6 +13,8 @@ int pm_ipi_init(const struct pm_proc *proc);
enum
pm_ret_status
pm_ipi_send
(
const
struct
pm_proc
*
proc
,
uint32_t
payload
[
PAYLOAD_ARG_CNT
]);
enum
pm_ret_status
pm_ipi_send_non_blocking
(
const
struct
pm_proc
*
proc
,
uint32_t
payload
[
PAYLOAD_ARG_CNT
]);
enum
pm_ret_status
pm_ipi_send_sync
(
const
struct
pm_proc
*
proc
,
uint32_t
payload
[
PAYLOAD_ARG_CNT
],
unsigned
int
*
value
,
size_t
count
);
...
...
plat/xilinx/zynqmp/pm_service/pm_svc_main.c
View file @
1f4d62df
...
...
@@ -10,19 +10,30 @@
*/
#include <errno.h>
#include <gic_common.h>
#include <runtime_svc.h>
#include <string.h>
#include "../zynqmp_private.h"
#include "pm_api_sys.h"
#include "pm_client.h"
#include "pm_ipi.h"
#define PM_GET_CALLBACK_DATA 0xa01
#if ZYNQMP_WDT_RESTART
#include <arch_helpers.h>
#include <gicv2.h>
#include <mmio.h>
#include <platform.h>
#include <spinlock.h>
#endif
#define PM_SET_SUSPEND_MODE 0xa02
#define PM_GET_TRUSTZONE_VERSION 0xa03
/* 0 - UP, !0 - DOWN */
static
int32_t
pm_down
=
!
0
;
/* !0 - UP, 0 - DOWN */
static
int32_t
pm_up
=
0
;
#if ZYNQMP_WDT_RESTART
static
spinlock_t
inc_lock
;
static
int
active_cores
=
0
;
#endif
/**
* pm_context - Structure which contains data for power management
...
...
@@ -35,6 +46,142 @@ static struct {
uint32_t
payload
[
PAYLOAD_ARG_CNT
];
}
pm_ctx
;
#if ZYNQMP_WDT_RESTART
/**
* trigger_wdt_restart() - Trigger warm restart event to APU cores
*
* This function triggers SGI for all active APU CPUs. SGI handler then
* power down CPU and call system reset.
*/
static
void
trigger_wdt_restart
(
void
)
{
uint32_t
core_count
=
0
;
uint32_t
core_status
[
3
];
uint32_t
target_cpu_list
=
0
;
int
i
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
pm_get_node_status
(
NODE_APU_0
+
i
,
core_status
);
if
(
core_status
[
0
]
==
1
)
{
core_count
++
;
target_cpu_list
|=
(
1
<<
i
);
}
}
spin_lock
(
&
inc_lock
);
active_cores
=
core_count
;
spin_unlock
(
&
inc_lock
);
INFO
(
"Active Cores: %d
\n
"
,
active_cores
);
/* trigger SGI to active cores */
gicv2_raise_sgi
(
ARM_IRQ_SEC_SGI_7
,
target_cpu_list
);
}
/**
* ttc_fiq_handler() - TTC Handler for timer event
* @id number of the highest priority pending interrupt of the type
* that this handler was registered for
* @flags security state, bit[0]
* @handler pointer to 'cpu_context' structure of the current CPU for the
* security state specified in the 'flags' parameter
* @cookie unused
*
* Function registered as INTR_TYPE_EL3 interrupt handler
*
* When WDT event is received in PMU, PMU needs to notify master to do cleanup
* if required. PMU sets up timer and starts timer to overflow in zero time upon
* WDT event. ATF handles this timer event and takes necessary action required
* for warm restart.
*
* In presence of non-secure software layers (EL1/2) sets the interrupt
* at registered entrance in GIC and informs that PMU responsed or demands
* action.
*/
static
uint64_t
ttc_fiq_handler
(
uint32_t
id
,
uint32_t
flags
,
void
*
handle
,
void
*
cookie
)
{
INFO
(
"BL31: Got TTC FIQ
\n
"
);
/* Clear TTC interrupt by reading interrupt register */
mmio_read_32
(
TTC3_INTR_REGISTER_1
);
/* Disable the timer interrupts */
mmio_write_32
(
TTC3_INTR_ENABLE_1
,
0
);
trigger_wdt_restart
();
return
0
;
}
/**
* zynqmp_sgi7_irq() - Handler for SGI7 IRQ
* @id number of the highest priority pending interrupt of the type
* that this handler was registered for
* @flags security state, bit[0]
* @handler pointer to 'cpu_context' structure of the current CPU for the
* security state specified in the 'flags' parameter
* @cookie unused
*
* Function registered as INTR_TYPE_EL3 interrupt handler
*
* On receiving WDT event from PMU, ATF generates SGI7 to all running CPUs.
* In response to SGI7 interrupt, each CPUs do clean up if required and last
* running CPU calls system restart.
*/
static
uint64_t
__unused
__dead2
zynqmp_sgi7_irq
(
uint32_t
id
,
uint32_t
flags
,
void
*
handle
,
void
*
cookie
)
{
int
i
;
/* enter wfi and stay there */
INFO
(
"Entering wfi
\n
"
);
spin_lock
(
&
inc_lock
);
active_cores
--
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
mmio_write_32
(
BASE_GICD_BASE
+
GICD_CPENDSGIR
+
4
*
i
,
0xffffffff
);
}
spin_unlock
(
&
inc_lock
);
if
(
active_cores
==
0
)
{
pm_system_shutdown
(
PMF_SHUTDOWN_TYPE_RESET
,
PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM
);
}
/* enter wfi and stay there */
while
(
1
)
wfi
();
}
/**
* pm_wdt_restart_setup() - Setup warm restart interrupts
*
* This function sets up handler for SGI7 and TTC interrupts
* used for warm restart.
*/
static
int
pm_wdt_restart_setup
(
void
)
{
int
ret
;
/* register IRQ handler for SGI7 */
ret
=
request_intr_type_el3
(
ARM_IRQ_SEC_SGI_7
,
zynqmp_sgi7_irq
);
if
(
ret
)
{
WARN
(
"BL31: registering SGI7 interrupt failed
\n
"
);
goto
err
;
}
ret
=
request_intr_type_el3
(
IRQ_TTC3_1
,
ttc_fiq_handler
);
if
(
ret
)
WARN
(
"BL31: registering TTC3 interrupt failed
\n
"
);
err:
return
ret
;
}
#endif
/**
* pm_setup() - PM service setup
*
...
...
@@ -52,11 +199,14 @@ int pm_setup(void)
{
int
status
,
ret
;
if
(
!
zynqmp_is_pmu_up
())
return
-
ENODEV
;
status
=
pm_ipi_init
(
primary_proc
);
#if ZYNQMP_WDT_RESTART
status
=
pm_wdt_restart_setup
();
if
(
status
)
WARN
(
"BL31: warm-restart setup failed
\n
"
);
#endif
if
(
status
>=
0
)
{
INFO
(
"BL31: PM Service Init Complete: API v%d.%d
\n
"
,
PM_VERSION_MAJOR
,
PM_VERSION_MINOR
);
...
...
@@ -66,7 +216,7 @@ int pm_setup(void)
ret
=
status
;
}
pm_
down
=
status
;
pm_
up
=
!
status
;
return
ret
;
}
...
...
@@ -95,7 +245,7 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
uint32_t
pm_arg
[
4
];
/* Handle case where PM wasn't initialized properly */
if
(
pm_
down
)
if
(
!
pm_
up
)
SMC_RET1
(
handle
,
SMC_UNK
);
pm_arg
[
0
]
=
(
uint32_t
)
x1
;
...
...
@@ -116,9 +266,16 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
SMC_RET1
(
handle
,
(
uint64_t
)
ret
);
case
PM_REQ_WAKEUP
:
ret
=
pm_req_wakeup
(
pm_arg
[
0
],
pm_arg
[
1
],
pm_arg
[
2
],
{
/* Use address flag is encoded in the 1st bit of the low-word */
unsigned
int
set_addr
=
pm_arg
[
1
]
&
0x1
;
uint64_t
address
=
(
uint64_t
)
pm_arg
[
2
]
<<
32
;
address
|=
pm_arg
[
1
]
&
(
~
0x1
);
ret
=
pm_req_wakeup
(
pm_arg
[
0
],
set_addr
,
address
,
pm_arg
[
3
]);
SMC_RET1
(
handle
,
(
uint64_t
)
ret
);
}
case
PM_FORCE_POWERDOWN
:
ret
=
pm_force_powerdown
(
pm_arg
[
0
],
pm_arg
[
1
]);
...
...
@@ -175,10 +332,19 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
ret
=
pm_set_configuration
(
pm_arg
[
0
]);
SMC_RET1
(
handle
,
(
uint64_t
)
ret
);
case
PM_
GET_NODE_STATUS
:
ret
=
pm_
get_node_status
(
pm_arg
[
0
]
);
case
PM_
INIT_FINALIZE
:
ret
=
pm_
init_finalize
(
);
SMC_RET1
(
handle
,
(
uint64_t
)
ret
);
case
PM_GET_NODE_STATUS
:
{
uint32_t
buff
[
3
];
ret
=
pm_get_node_status
(
pm_arg
[
0
],
buff
);
SMC_RET2
(
handle
,
(
uint64_t
)
ret
|
((
uint64_t
)
buff
[
0
]
<<
32
),
(
uint64_t
)
buff
[
1
]
|
((
uint64_t
)
buff
[
2
]
<<
32
));
}
case
PM_GET_OP_CHARACTERISTIC
:
{
uint32_t
result
;
...
...
@@ -239,15 +405,10 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
result
[
1
]);
}
case
PM_GET_CALLBACK_DATA
:
{
uint32_t
result
[
4
];
pm_get_callbackdata
(
result
,
sizeof
(
result
));
SMC_RET2
(
handle
,
(
uint64_t
)
result
[
0
]
|
((
uint64_t
)
result
[
1
]
<<
32
),
(
uint64_t
)
result
[
2
]
|
((
uint64_t
)
result
[
3
]
<<
32
));
}
case
PM_SECURE_RSA_AES
:
ret
=
pm_secure_rsaaes
(
pm_arg
[
0
],
pm_arg
[
1
],
pm_arg
[
2
],
pm_arg
[
3
]);
SMC_RET1
(
handle
,
(
uint64_t
)
ret
);
case
PM_PINCTRL_REQUEST
:
ret
=
pm_pinctrl_request
(
pm_arg
[
0
]);
...
...
@@ -361,6 +522,30 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
SMC_RET1
(
handle
,
(
uint64_t
)
PM_RET_SUCCESS
|
((
uint64_t
)
ZYNQMP_TZ_VERSION
<<
32
));
case
PM_SET_SUSPEND_MODE
:
ret
=
pm_set_suspend_mode
(
pm_arg
[
0
]);
SMC_RET1
(
handle
,
(
uint64_t
)
ret
);
case
PM_SECURE_SHA
:
ret
=
pm_sha_hash
(
pm_arg
[
0
],
pm_arg
[
1
],
pm_arg
[
2
],
pm_arg
[
3
]);
SMC_RET1
(
handle
,
(
uint64_t
)
ret
);
case
PM_SECURE_RSA
:
ret
=
pm_rsa_core
(
pm_arg
[
0
],
pm_arg
[
1
],
pm_arg
[
2
],
pm_arg
[
3
]);
SMC_RET1
(
handle
,
(
uint64_t
)
ret
);
case
PM_SECURE_IMAGE
:
{
uint32_t
result
[
2
];
ret
=
pm_secure_image
(
pm_arg
[
0
],
pm_arg
[
1
],
pm_arg
[
2
],
pm_arg
[
3
],
&
result
[
0
]);
SMC_RET2
(
handle
,
(
uint64_t
)
ret
|
((
uint64_t
)
result
[
0
]
<<
32
),
result
[
1
]);
}
default:
WARN
(
"Unimplemented PM Service Call: 0x%x
\n
"
,
smc_fid
);
SMC_RET1
(
handle
,
SMC_UNK
);
...
...
plat/xilinx/zynqmp/zynqmp_def.h
View file @
1f4d62df
...
...
@@ -101,6 +101,14 @@
#define BASE_GICH_BASE 0xF9040000
#define BASE_GICV_BASE 0xF9060000
#if ZYNQMP_WDT_RESTART
#define IRQ_SEC_IPI_APU 67
#define IRQ_TTC3_1 77
#define TTC3_BASE_ADDR 0xFF140000
#define TTC3_INTR_REGISTER_1 (TTC3_BASE_ADDR + 0x54)
#define TTC3_INTR_ENABLE_1 (TTC3_BASE_ADDR + 0x60)
#endif
#define ARM_IRQ_SEC_PHY_TIMER 29
#define ARM_IRQ_SEC_SGI_0 8
...
...
@@ -158,7 +166,8 @@
#define ZYNQMP_CSU_IDCODE_XILINX_ID 0x093
#define ZYNQMP_CSU_IDCODE_SVD_SHIFT 12
#define ZYNQMP_CSU_IDCODE_SVD_MASK (0xE << ZYNQMP_CSU_IDCODE_SVD_SHIFT)
#define ZYNQMP_CSU_IDCODE_SVD_MASK (0x7 << \
ZYNQMP_CSU_IDCODE_SVD_SHIFT)
#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT 15
#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK (0xF << ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT)
#define ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT 19
...
...
@@ -173,6 +182,12 @@
#define ZYNQMP_CSU_VERSION_OFFSET 0x44
/* Efuse */
#define EFUSE_BASEADDR 0xFFCC0000
#define EFUSE_IPDISABLE_OFFSET 0x1018
#define EFUSE_IPDISABLE_VERSION 0x1FFU
#define ZYNQMP_EFUSE_IPDISABLE_SHIFT 20
/* Access control register defines */
#define ACTLR_EL3_L2ACTLR_BIT (1 << 6)
#define ACTLR_EL3_CPUACTLR_BIT (1 << 0)
...
...
plat/xilinx/zynqmp/zynqmp_ipi.c
View file @
1f4d62df
...
...
@@ -84,7 +84,7 @@ const static struct zynqmp_ipi_config zynqmp_ipi_table[] = {
{
.
ipi_bit_mask
=
0x20000
,
.
ipi_reg_base
=
0xFF331000
,
.
secure_only
=
IPI_SECURE_MASK
,
.
secure_only
=
0
,
},
/* PMU2 IPI */
{
...
...
plat/xilinx/zynqmp/zynqmp_private.h
View file @
1f4d62df
...
...
@@ -7,17 +7,32 @@
#ifndef __ZYNQMP_PRIVATE_H__
#define __ZYNQMP_PRIVATE_H__
#include <bl_common.h>
#include <interrupt_mgmt.h>
void
zynqmp_config_setup
(
void
);
/* ZynqMP specific functions */
unsigned
int
zynqmp_get_uart_clk
(
void
);
int
zynqmp_is_pmu_up
(
void
);
unsigned
int
zynqmp_get_bootmode
(
void
);
/* For FSBL handover */
void
fsbl_atf_handover
(
entry_point_info_t
*
bl32_image_ep_info
,
enum
fsbl_handoff
{
FSBL_HANDOFF_SUCCESS
=
0
,
FSBL_HANDOFF_NO_STRUCT
,
FSBL_HANDOFF_INVAL_STRUCT
,
FSBL_HANDOFF_TOO_MANY_PARTS
,
};
#if ZYNQMP_WDT_RESTART
/*
* Register handler to specific GIC entrance
* for INTR_TYPE_EL3 type of interrupt
*/
int
request_intr_type_el3
(
uint32_t
,
interrupt_type_handler_t
);
#endif
enum
fsbl_handoff
fsbl_atf_handover
(
entry_point_info_t
*
bl32_image_ep_info
,
entry_point_info_t
*
bl33_image_ep_info
);
#endif
/* __ZYNQMP_PRIVATE_H__ */
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