1 /*
2 * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8
9 #include <arch_helpers.h>
10 #include <common/debug.h>
11 #include <drivers/delay_timer.h>
12 #include <lib/bakery_lock.h>
13 #include <lib/mmio.h>
14
15 #include "corstone700_mhu.h"
16 #include <plat_arm.h>
17 #include <platform_def.h>
18
19 ARM_INSTANTIATE_LOCK;
20
21 #pragma weak plat_arm_pwrc_setup
22
23 /*
24 * Slot 31 is reserved because the MHU hardware uses this register bit to
25 * indicate a non-secure access attempt. The total number of available slots is
26 * therefore 31 [30:0].
27 */
28 #define MHU_MAX_SLOT_ID 30
29
mhu_secure_message_start(uintptr_t address,unsigned int slot_id)30 void mhu_secure_message_start(uintptr_t address, unsigned int slot_id)
31 {
32 unsigned int intr_stat_check;
33 uint64_t timeout_cnt;
34 volatile uint8_t expiration;
35
36 assert(slot_id <= MHU_MAX_SLOT_ID);
37 arm_lock_get();
38
39 /*
40 * Make sure any previous command has finished
41 * and polling timeout not expired
42 */
43
44 timeout_cnt = timeout_init_us(MHU_POLL_INTR_STAT_TIMEOUT);
45
46 do {
47 intr_stat_check = (mmio_read_32(address + CPU_INTR_S_STAT) &
48 (1 << slot_id));
49
50 expiration = timeout_elapsed(timeout_cnt);
51
52 } while ((intr_stat_check != 0U) && (expiration == 0U));
53
54 /*
55 * Note: No risk of timer overflows while waiting
56 * for the timeout expiration.
57 * According to Armv8 TRM: System counter roll-over
58 * time of not less than 40 years
59 */
60 }
61
mhu_secure_message_send(uintptr_t address,unsigned int slot_id,unsigned int message)62 void mhu_secure_message_send(uintptr_t address,
63 unsigned int slot_id,
64 unsigned int message)
65 {
66 unsigned char access_ready;
67 uint64_t timeout_cnt;
68 volatile uint8_t expiration;
69
70 assert(slot_id <= MHU_MAX_SLOT_ID);
71 assert((mmio_read_32(address + CPU_INTR_S_STAT) &
72 (1 << slot_id)) == 0U);
73
74 MHU_V2_ACCESS_REQUEST(address);
75
76 timeout_cnt = timeout_init_us(MHU_POLL_INTR_STAT_TIMEOUT);
77
78 do {
79 access_ready = MHU_V2_IS_ACCESS_READY(address);
80 expiration = timeout_elapsed(timeout_cnt);
81
82 } while ((access_ready == 0U) && (expiration == 0U));
83
84 /*
85 * Note: No risk of timer overflows while waiting
86 * for the timeout expiration.
87 * According to Armv8 TRM: System counter roll-over
88 * time of not less than 40 years
89 */
90
91 mmio_write_32(address + CPU_INTR_S_SET, message);
92 }
93
mhu_secure_message_end(uintptr_t address,unsigned int slot_id)94 void mhu_secure_message_end(uintptr_t address, unsigned int slot_id)
95 {
96 assert(slot_id <= MHU_MAX_SLOT_ID);
97 /*
98 * Clear any response we got by writing one in the relevant slot bit to
99 * the CLEAR register
100 */
101 MHU_V2_CLEAR_REQUEST(address);
102
103 arm_lock_release();
104 }
105
mhu_secure_init(void)106 void __init mhu_secure_init(void)
107 {
108 arm_lock_init();
109
110 /*
111 * The STAT register resets to zero. Ensure it is in the expected state,
112 * as a stale or garbage value would make us think it's a message we've
113 * already sent.
114 */
115
116 assert(mmio_read_32(PLAT_SDK700_MHU0_SEND + CPU_INTR_S_STAT) == 0);
117 }
118