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