blob: 56f44e0f2afc2ae563100460cecf90a24f781010 [file] [log] [blame]
Sheetal Tigadoli2a96dc22019-12-18 12:01:01 +05301/*
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
30static 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
39void 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
59void 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
86uint32_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
103void 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
115void 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
128void plat_brcm_pwrc_setup(void)
129{
130 mhu_secure_init();
131}