synquacer: Add MHU driver
authorSumit Garg <sumit.garg@linaro.org>
Fri, 15 Jun 2018 09:47:10 +0000 (15:17 +0530)
committerSumit Garg <sumit.garg@linaro.org>
Thu, 21 Jun 2018 05:53:09 +0000 (11:23 +0530)
Add Message Handling Unit (MHU) driver used to communicate among
Application Processors (AP) and System Control Processor (SCP).

Signed-off-by: Sumit Garg <sumit.garg@linaro.org>
plat/socionext/synquacer/drivers/mhu/sq_mhu.c [new file with mode: 0644]
plat/socionext/synquacer/drivers/mhu/sq_mhu.h [new file with mode: 0644]
plat/socionext/synquacer/include/platform_def.h
plat/socionext/synquacer/include/sq_common.h
plat/socionext/synquacer/sq_bl31_setup.c

diff --git a/plat/socionext/synquacer/drivers/mhu/sq_mhu.c b/plat/socionext/synquacer/drivers/mhu/sq_mhu.c
new file mode 100644 (file)
index 0000000..5c2a635
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bakery_lock.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <sq_common.h>
+#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 (file)
index 0000000..bef117d
--- /dev/null
@@ -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 <stdint.h>
+
+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__ */
index aa15234f53792ce200aaa5e00fac1e7a64df1b19..07db2b6de016b07a46d245b11bc319aec9af3cbd 100644 (file)
@@ -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
index b9600f02ca0d8f5e30d5ad2edec6ad1dc41051c3..8839a051d1b5d5a0702781d0ecb4fcf6314604ec 100644 (file)
@@ -10,6 +10,8 @@
 #include <sys/types.h>
 #include <xlat_tables_v2.h>
 
+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);
index 1d3d3b6142d54d42da773835d9fa817d2ebf73bd..4d7c85129e8217957ec7cf2bf0d9d765c59610c9 100644 (file)
@@ -125,6 +125,9 @@ void bl31_platform_setup(void)
 
        /* 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)