diff --git a/plat/socionext/synquacer/drivers/mhu/sq_mhu.c b/plat/socionext/synquacer/drivers/mhu/sq_mhu.c new file mode 100644 index 0000000..5c2a635 --- /dev/null +++ b/plat/socionext/synquacer/drivers/mhu/sq_mhu.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include "sq_mhu.h" + +/* SCP MHU secure channel registers */ +#define SCP_INTR_S_STAT 0x200 +#define SCP_INTR_S_SET 0x208 +#define SCP_INTR_S_CLEAR 0x210 + +/* CPU MHU secure channel registers */ +#define CPU_INTR_S_STAT 0x300 +#define CPU_INTR_S_SET 0x308 +#define CPU_INTR_S_CLEAR 0x310 + +DEFINE_BAKERY_LOCK(sq_lock); + +/* + * Slot 31 is reserved because the MHU hardware uses this register bit to + * indicate a non-secure access attempt. The total number of available slots is + * therefore 31 [30:0]. + */ +#define MHU_MAX_SLOT_ID 30 + +void mhu_secure_message_start(unsigned int slot_id) +{ + assert(slot_id <= MHU_MAX_SLOT_ID); + + bakery_lock_get(&sq_lock); + + /* Make sure any previous command has finished */ + while (mmio_read_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_STAT) & + (1 << slot_id)) + ; +} + +void mhu_secure_message_send(unsigned int slot_id) +{ + assert(slot_id <= MHU_MAX_SLOT_ID); + assert(!(mmio_read_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_STAT) & + (1 << slot_id))); + + /* Send command to SCP */ + mmio_write_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_SET, 1 << slot_id); +} + +uint32_t mhu_secure_message_wait(void) +{ + uint32_t response; + + /* Wait for response from SCP */ + while (!(response = mmio_read_32(PLAT_SQ_MHU_BASE + SCP_INTR_S_STAT))) + ; + + return response; +} + +void mhu_secure_message_end(unsigned int slot_id) +{ + assert(slot_id <= MHU_MAX_SLOT_ID); + + /* + * Clear any response we got by writing one in the relevant slot bit to + * the CLEAR register + */ + mmio_write_32(PLAT_SQ_MHU_BASE + SCP_INTR_S_CLEAR, 1 << slot_id); + + bakery_lock_release(&sq_lock); +} + +void mhu_secure_init(void) +{ + bakery_lock_init(&sq_lock); + + /* + * The STAT register resets to zero. Ensure it is in the expected state, + * as a stale or garbage value would make us think it's a message we've + * already sent. + */ + assert(mmio_read_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_STAT) == 0); +} + +void plat_sq_pwrc_setup(void) +{ + mhu_secure_init(); +} diff --git a/plat/socionext/synquacer/drivers/mhu/sq_mhu.h b/plat/socionext/synquacer/drivers/mhu/sq_mhu.h new file mode 100644 index 0000000..bef117d --- /dev/null +++ b/plat/socionext/synquacer/drivers/mhu/sq_mhu.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __SQ_MHU_H__ +#define __SQ_MHU_H__ + +#include + +void mhu_secure_message_start(unsigned int slot_id); +void mhu_secure_message_send(unsigned int slot_id); +uint32_t mhu_secure_message_wait(void); +void mhu_secure_message_end(unsigned int slot_id); + +void mhu_secure_init(void); + +#endif /* __SQ_MHU_H__ */ diff --git a/plat/socionext/synquacer/include/platform_def.h b/plat/socionext/synquacer/include/platform_def.h index aa15234..07db2b6 100644 --- a/plat/socionext/synquacer/include/platform_def.h +++ b/plat/socionext/synquacer/include/platform_def.h @@ -54,6 +54,8 @@ #define SQ_SYS_TIMCTL_BASE 0x2a810000 #define PLAT_SQ_NSTIMER_FRAME_ID 0 +#define PLAT_SQ_MHU_BASE 0x45000000 + #define SQ_BOOT_CFG_ADDR 0x45410000 #define PLAT_SQ_PRIMARY_CPU_SHIFT 8 #define PLAT_SQ_PRIMARY_CPU_BIT_WIDTH 6 diff --git a/plat/socionext/synquacer/include/sq_common.h b/plat/socionext/synquacer/include/sq_common.h index b9600f0..8839a05 100644 --- a/plat/socionext/synquacer/include/sq_common.h +++ b/plat/socionext/synquacer/include/sq_common.h @@ -10,6 +10,8 @@ #include #include +void plat_sq_pwrc_setup(void); + void plat_sq_interconnect_init(void); void plat_sq_interconnect_enter_coherency(void); void plat_sq_interconnect_exit_coherency(void); diff --git a/plat/socionext/synquacer/sq_bl31_setup.c b/plat/socionext/synquacer/sq_bl31_setup.c index 1d3d3b6..4d7c851 100644 --- a/plat/socionext/synquacer/sq_bl31_setup.c +++ b/plat/socionext/synquacer/sq_bl31_setup.c @@ -125,6 +125,9 @@ /* Allow access to the System counter timer module */ sq_configure_sys_timer(); + + /* Initialize power controller before setting up topology */ + plat_sq_pwrc_setup(); } void bl31_plat_runtime_setup(void)