blob: 1867511cb51251ac6602bef2089d6970aaf76a6a [file] [log] [blame]
Varun Wadekara6a357f2017-05-05 09:20:59 -07001/*
2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch_helpers.h>
8#include <assert.h>
9#include <bpmp.h>
10#include <common/debug.h>
11#include <delay_timer.h>
12#include <errno.h>
13#include <mmio.h>
14#include <platform.h>
15#include <stdbool.h>
16#include <string.h>
17#include <tegra_def.h>
18
Peter De Schrijver50168612017-06-15 05:21:50 +030019#define BPMP_TIMEOUT 2
Varun Wadekara6a357f2017-05-05 09:20:59 -070020
21static uint32_t channel_base[NR_CHANNELS];
22static uint32_t bpmp_init_state = BPMP_INIT_PENDING;
23
24static uint32_t channel_field(unsigned int ch)
25{
26 return mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET) & CH_MASK(ch);
27}
28
29static bool master_free(unsigned int ch)
30{
31 return channel_field(ch) == MA_FREE(ch);
32}
33
34static bool master_acked(unsigned int ch)
35{
36 return channel_field(ch) == MA_ACKD(ch);
37}
38
39static void signal_slave(unsigned int ch)
40{
41 mmio_write_32(TEGRA_RES_SEMA_BASE + CLR_OFFSET, CH_MASK(ch));
42}
43
44static void free_master(unsigned int ch)
45{
46 mmio_write_32(TEGRA_RES_SEMA_BASE + CLR_OFFSET,
47 MA_ACKD(ch) ^ MA_FREE(ch));
48}
49
50/* should be called with local irqs disabled */
51int32_t tegra_bpmp_send_receive_atomic(int mrq, const void *ob_data, int ob_sz,
52 void *ib_data, int ib_sz)
53{
54 unsigned int ch = (unsigned int)plat_my_core_pos();
55 mb_data_t *p = (mb_data_t *)(uintptr_t)channel_base[ch];
56 int32_t ret = -ETIMEDOUT, timeout = 0;
57
58 if (bpmp_init_state == BPMP_INIT_COMPLETE) {
59
60 /* loop until BPMP is free */
Peter De Schrijver50168612017-06-15 05:21:50 +030061 for (timeout = 0; timeout < BPMP_TIMEOUT; timeout++) {
Varun Wadekara6a357f2017-05-05 09:20:59 -070062 if (master_free(ch) == true) {
63 break;
64 }
65
Peter De Schrijver50168612017-06-15 05:21:50 +030066 mdelay(1);
Varun Wadekara6a357f2017-05-05 09:20:59 -070067 }
68
Peter De Schrijver50168612017-06-15 05:21:50 +030069 if (timeout != BPMP_TIMEOUT) {
Varun Wadekara6a357f2017-05-05 09:20:59 -070070
71 /* generate the command struct */
72 p->code = mrq;
73 p->flags = DO_ACK;
74 (void)memcpy((void *)p->data, ob_data, (size_t)ob_sz);
75
76 /* signal command ready to the BPMP */
77 signal_slave(ch);
78 mmio_write_32(TEGRA_PRI_ICTLR_BASE + CPU_IEP_FIR_SET,
Anthony Zhou0e07e452017-07-26 17:16:54 +080079 (1U << INT_SHR_SEM_OUTBOX_FULL));
Varun Wadekara6a357f2017-05-05 09:20:59 -070080
81 /* loop until the command is executed */
Peter De Schrijver50168612017-06-15 05:21:50 +030082 for (timeout = 0; timeout < BPMP_TIMEOUT; timeout++) {
Varun Wadekara6a357f2017-05-05 09:20:59 -070083 if (master_acked(ch) == true) {
84 break;
85 }
86
Peter De Schrijver50168612017-06-15 05:21:50 +030087 mdelay(1);
Varun Wadekara6a357f2017-05-05 09:20:59 -070088 }
89
Peter De Schrijver50168612017-06-15 05:21:50 +030090 if (timeout != BPMP_TIMEOUT) {
Varun Wadekara6a357f2017-05-05 09:20:59 -070091
92 /* get the command response */
93 (void)memcpy(ib_data, (const void *)p->data,
94 (size_t)ib_sz);
95
96 /* return error code */
97 ret = p->code;
98
99 /* free this channel */
100 free_master(ch);
101 }
102 }
103
104 } else {
105 /* return error code */
106 ret = -EINVAL;
107 }
108
Peter De Schrijver50168612017-06-15 05:21:50 +0300109 if (timeout == BPMP_TIMEOUT) {
110 ERROR("Timed out waiting for bpmp's response\n");
Varun Wadekara6a357f2017-05-05 09:20:59 -0700111 }
112
113 return ret;
114}
115
116int tegra_bpmp_init(void)
117{
118 uint32_t val, base;
119 unsigned int ch;
120 int ret = 0;
121
122 if (bpmp_init_state != BPMP_INIT_COMPLETE) {
123
124 /* check if the bpmp processor is alive. */
125 val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET);
126 if (val != SIGN_OF_LIFE) {
127 ERROR("BPMP precessor not available\n");
128 ret = -ENOTSUP;
129 }
130
131 /* check if clock for the atomics block is enabled */
132 val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_ENB_V);
133 if ((val & CAR_ENABLE_ATOMICS) == 0) {
134 ERROR("Clock to the atomics block is disabled\n");
135 }
136
137 /* check if the atomics block is out of reset */
138 val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_CLR_V);
Varun Wadekarb37f4ea2017-06-12 16:45:23 -0700139 if ((val & CAR_ENABLE_ATOMICS) == CAR_ENABLE_ATOMICS) {
Varun Wadekara6a357f2017-05-05 09:20:59 -0700140 ERROR("Reset to the atomics block is asserted\n");
141 }
142
143 /* base address to get the result from Atomics */
144 base = TEGRA_ATOMICS_BASE + RESULT0_REG_OFFSET;
145
146 /* channel area is setup by BPMP before signaling handshake */
147 for (ch = 0; ch < NR_CHANNELS; ch++) {
148
149 /* issue command to get the channel base address */
150 mmio_write_32(base, (ch << TRIGGER_ID_SHIFT) |
151 ATOMIC_CMD_GET);
152
153 /* get the base address for the channel */
154 channel_base[ch] = mmio_read_32(base);
155
156 /* increment result register offset */
Anthony Zhou0e07e452017-07-26 17:16:54 +0800157 base += 4U;
Varun Wadekara6a357f2017-05-05 09:20:59 -0700158 }
159
160 /* mark state as "initialized" */
161 if (ret == 0)
162 bpmp_init_state = BPMP_INIT_COMPLETE;
163
164 /* the channel values have to be visible across all cpus */
165 flush_dcache_range((uint64_t)channel_base, sizeof(channel_base));
166 flush_dcache_range((uint64_t)&bpmp_init_state,
167 sizeof(bpmp_init_state));
168
169 INFO("%s: done\n", __func__);
170 }
171
172 return ret;
173}