1 /*
2 * Copyright (c) 2019-2020, ARM Limited and Contributors. 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 <drivers/delay_timer.h>
11 #include <lib/bakery_lock.h>
12
13 #include <brcm_mhu.h>
14 #include <platform_def.h>
15
16 #include "m0_ipc.h"
17
18 #define PLAT_MHU_INTR_REG AP_TO_SCP_MAILBOX1
19
20 /* SCP MHU secure channel registers */
21 #define SCP_INTR_S_STAT CRMU_IHOST_SW_PERSISTENT_REG11
22 #define SCP_INTR_S_SET CRMU_IHOST_SW_PERSISTENT_REG11
23 #define SCP_INTR_S_CLEAR CRMU_IHOST_SW_PERSISTENT_REG11
24
25 /* CPU MHU secure channel registers */
26 #define CPU_INTR_S_STAT CRMU_IHOST_SW_PERSISTENT_REG10
27 #define CPU_INTR_S_SET CRMU_IHOST_SW_PERSISTENT_REG10
28 #define CPU_INTR_S_CLEAR CRMU_IHOST_SW_PERSISTENT_REG10
29
30 static DEFINE_BAKERY_LOCK(bcm_lock);
31
32 /*
33 * Slot 31 is reserved because the MHU hardware uses this register bit to
34 * indicate a non-secure access attempt. The total number of available slots is
35 * therefore 31 [30:0].
36 */
37 #define MHU_MAX_SLOT_ID 30
38
mhu_secure_message_start(unsigned int slot_id)39 void mhu_secure_message_start(unsigned int slot_id)
40 {
41 int iter = 1000000;
42
43 assert(slot_id <= MHU_MAX_SLOT_ID);
44
45 bakery_lock_get(&bcm_lock);
46 /* Make sure any previous command has finished */
47 do {
48 if (!(mmio_read_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_STAT) &
49 (1 << slot_id)))
50 break;
51
52 udelay(1);
53
54 } while (--iter);
55
56 assert(iter != 0);
57 }
58
mhu_secure_message_send(unsigned int slot_id)59 void mhu_secure_message_send(unsigned int slot_id)
60 {
61 uint32_t response, iter = 1000000;
62
63 assert(slot_id <= MHU_MAX_SLOT_ID);
64 assert(!(mmio_read_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_STAT) &
65 (1 << slot_id)));
66
67 /* Send command to SCP */
68 mmio_setbits_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_SET, 1 << slot_id);
69 mmio_write_32(CRMU_MAIL_BOX0, MCU_IPC_MCU_CMD_SCPI);
70 mmio_write_32(PLAT_BRCM_MHU_BASE + PLAT_MHU_INTR_REG, 0x1);
71
72 /* Wait until IPC transport acknowledges reception of SCP command */
73 do {
74 response = mmio_read_32(CRMU_MAIL_BOX0);
75 if ((response & ~MCU_IPC_CMD_REPLY_MASK) ==
76 (MCU_IPC_CMD_DONE_MASK | MCU_IPC_MCU_CMD_SCPI))
77 break;
78
79 udelay(1);
80
81 } while (--iter);
82
83 assert(iter != 0);
84 }
85
mhu_secure_message_wait(void)86 uint32_t mhu_secure_message_wait(void)
87 {
88 /* Wait for response from SCP */
89 uint32_t response, iter = 1000000;
90
91 do {
92 response = mmio_read_32(PLAT_BRCM_MHU_BASE + SCP_INTR_S_STAT);
93 if (!response)
94 break;
95
96 udelay(1);
97 } while (--iter);
98 assert(iter != 0);
99
100 return response;
101 }
102
mhu_secure_message_end(unsigned int slot_id)103 void mhu_secure_message_end(unsigned int slot_id)
104 {
105 assert(slot_id <= MHU_MAX_SLOT_ID);
106
107 /*
108 * Clear any response we got by writing one in the relevant slot bit to
109 * the CLEAR register
110 */
111 mmio_clrbits_32(PLAT_BRCM_MHU_BASE + SCP_INTR_S_CLEAR, 1 << slot_id);
112 bakery_lock_release(&bcm_lock);
113 }
114
mhu_secure_init(void)115 void mhu_secure_init(void)
116 {
117 bakery_lock_init(&bcm_lock);
118
119 /*
120 * The STAT register resets to zero. Ensure it is in the expected state,
121 * as a stale or garbage value would make us think it's a message we've
122 * already sent.
123 */
124 mmio_write_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_STAT, 0);
125 mmio_write_32(PLAT_BRCM_MHU_BASE + SCP_INTR_S_STAT, 0);
126 }
127
plat_brcm_pwrc_setup(void)128 void plat_brcm_pwrc_setup(void)
129 {
130 mhu_secure_init();
131 }
132