Browse Source

Merge "fix(plat/marvell/a3k): reset GIC before resetting via CM3 secure coprocessor" into integration

pull/2000/merge
Manish Pandey 5 months ago
committed by TrustedFirmware Code Review
parent
commit
517b7f96c9
  1. 132
      plat/marvell/armada/a3k/common/cm3_system_reset.c
  2. 2
      plat/marvell/armada/a3k/common/include/a3700_pm.h
  3. 2
      plat/marvell/armada/a3k/common/plat_pm.c

132
plat/marvell/armada/a3k/common/cm3_system_reset.c

@ -8,11 +8,22 @@
#include <stdbool.h>
#include <common/debug.h>
#include <drivers/arm/gic_common.h>
#include <drivers/arm/gicv3.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <a3700_pm.h>
#include <platform_def.h>
#include <mvebu_def.h>
/* IO Decoder Error Interrupt Status Registers */
#define MVEBU_DEC_WIN_REGS_BASE(p) (MVEBU_REGS_BASE + 0xC000 + \
(p) * 0x100)
#define MVEBU_DEC_WIN_ERR_INT_STS_REG(p) (MVEBU_DEC_WIN_REGS_BASE(p) + \
0xF8)
/* Cortex-M3 Secure Processor Mailbox Registers */
#define MVEBU_RWTM_PARAM0_REG (MVEBU_RWTM_REG_BASE)
#define MVEBU_RWTM_CMD_REG (MVEBU_RWTM_REG_BASE + 0x40)
@ -23,6 +34,122 @@
#define MVEBU_RWTM_REBOOT_CMD 0x0009
#define MVEBU_RWTM_REBOOT_MAGIC 0xDEADBEEF
static inline uint32_t a3700_gicd_read(uint32_t reg)
{
return mmio_read_32(PLAT_MARVELL_GICD_BASE + reg);
}
static inline void a3700_gicd_write(uint32_t reg, uint32_t value)
{
mmio_write_32(PLAT_MARVELL_GICD_BASE + reg, value);
}
static void a3700_gicd_ctlr_clear_bits(uint32_t bits)
{
uint32_t val;
val = a3700_gicd_read(GICD_CTLR);
if ((val & bits) != 0U) {
a3700_gicd_write(GICD_CTLR, val & ~bits);
mdelay(1);
if ((a3700_gicd_read(GICD_CTLR) & GICD_CTLR_RWP_BIT) != 0U) {
ERROR("could not clear bits 0x%x in GIC distributor control\n",
bits);
}
}
}
static void a3700_gic_dist_disable_irqs(void)
{
int i;
for (i = 32; i < 224; i += 32) {
a3700_gicd_write(GICD_ICENABLER + (i >> 3), GENMASK_32(31, 0));
}
}
static inline uintptr_t a3700_rdist_base(unsigned int proc)
{
return PLAT_MARVELL_GICR_BASE + (proc << GICR_V3_PCPUBASE_SHIFT);
}
static inline uint32_t a3700_gicr_read(unsigned int proc, uint32_t reg)
{
return mmio_read_32(a3700_rdist_base(proc) + reg);
}
static inline void a3700_gicr_write(unsigned int proc, uint32_t reg,
uint32_t value)
{
mmio_write_32(a3700_rdist_base(proc) + reg, value);
}
static void a3700_gic_redist_disable_irqs(unsigned int proc)
{
a3700_gicr_write(proc, GICR_ICENABLER0, GENMASK_32(31, 0));
mdelay(1);
if ((a3700_gicr_read(proc, GICR_CTLR) & GICR_CTLR_RWP_BIT) != 0U) {
ERROR("could not disable core %u PPIs & SGIs\n", proc);
}
}
static void a3700_gic_redist_mark_asleep(unsigned int proc)
{
a3700_gicr_write(proc, GICR_WAKER,
a3700_gicr_read(proc, GICR_WAKER) | WAKER_PS_BIT);
mdelay(1);
if ((a3700_gicr_read(proc, GICR_WAKER) & WAKER_CA_BIT) == 0U) {
ERROR("could not mark core %u redistributor asleep\n", proc);
}
}
static void a3700_io_addr_dec_ack_err_irq(void)
{
unsigned int periph;
for (periph = 0; periph < 16; ++periph) {
/* periph 6 does not exist */
if (periph == 6)
continue;
mmio_write_32(MVEBU_DEC_WIN_ERR_INT_STS_REG(periph),
GENMASK_32(1, 0));
}
}
static void a3700_gic_reset(void)
{
a3700_gic_redist_disable_irqs(0);
a3700_gic_redist_disable_irqs(1);
a3700_gic_redist_mark_asleep(0);
a3700_gic_redist_mark_asleep(1);
a3700_io_addr_dec_ack_err_irq();
a3700_pm_ack_irq();
a3700_gic_dist_disable_irqs();
a3700_gicd_ctlr_clear_bits(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1NS_BIT |
CTLR_ENABLE_G1S_BIT);
/* Clearing ARE_S and ARE_NS bits is undefined in the specification, but
* works if the previous operations are successful. We need to do it in
* order to put GIC into the same state it was in just after reset. If
* this is successful, the rWTM firmware in the secure coprocessor will
* reset all other peripherals one by one, load new firmware and boot
* it, all without triggering the true warm reset via the WARM_RESET
* register (which may hang the board).
*/
a3700_gicd_ctlr_clear_bits(CTLR_ARE_S_BIT);
a3700_gicd_ctlr_clear_bits(CTLR_ARE_NS_BIT);
}
static inline bool rwtm_completed(void)
{
return (mmio_read_32(MVEBU_RWTM_HOST_INT_RESET_REG) &
@ -43,6 +170,11 @@ void cm3_system_reset(void)
{
int tries = 5;
/* Put GIC into the same state it was just after reset. This is needed
* for the reset issue workaround to work.
*/
a3700_gic_reset();
for (; tries > 0; --tries) {
mmio_clrbits_32(MVEBU_RWTM_HOST_INT_RESET_REG,
MVEBU_RWTM_HOST_INT_SP_COMPLETE);

2
plat/marvell/armada/a3k/common/include/a3700_pm.h

@ -48,6 +48,8 @@ struct pm_wake_up_src_config {
struct pm_wake_up_src_config *mv_wake_up_src_config_get(void);
void a3700_pm_ack_irq(void);
void cm3_system_reset(void);
#endif /* A3700_PM_H */

2
plat/marvell/armada/a3k/common/plat_pm.c

@ -197,7 +197,7 @@ void marvell_psci_arch_init(int die_index)
{
}
static void a3700_pm_ack_irq(void)
void a3700_pm_ack_irq(void)
{
uint32_t reg;

Loading…
Cancel
Save