1 /*
2  * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <bpmp_ipc.h>
9 #include <common/debug.h>
10 #include <drivers/delay_timer.h>
11 #include <errno.h>
12 #include <lib/mmio.h>
13 #include <lib/utils_def.h>
14 #include <stdbool.h>
15 #include <string.h>
16 #include <tegra_def.h>
17 
18 #include "intf.h"
19 #include "ivc.h"
20 
21 /**
22  * Holds IVC channel data
23  */
24 struct ccplex_bpmp_channel_data {
25 	/* Buffer for incoming data */
26 	struct frame_data *ib;
27 
28 	/* Buffer for outgoing data */
29 	struct frame_data *ob;
30 };
31 
32 static struct ccplex_bpmp_channel_data s_channel;
33 static struct ivc ivc_ccplex_bpmp_channel;
34 
35 /*
36  * Helper functions to access the HSP doorbell registers
37  */
hsp_db_read(uint32_t reg)38 static inline uint32_t hsp_db_read(uint32_t reg)
39 {
40 	return mmio_read_32((uint32_t)(TEGRA_HSP_DBELL_BASE + reg));
41 }
42 
hsp_db_write(uint32_t reg,uint32_t val)43 static inline void hsp_db_write(uint32_t reg, uint32_t val)
44 {
45 	mmio_write_32((uint32_t)(TEGRA_HSP_DBELL_BASE + reg), val);
46 }
47 
48 /*******************************************************************************
49  *      IVC wrappers for CCPLEX <-> BPMP communication.
50  ******************************************************************************/
51 
52 static void tegra_bpmp_ring_bpmp_doorbell(void);
53 
54 /*
55  * Get the next frame where data can be written.
56  */
tegra_bpmp_get_next_out_frame(void)57 static struct frame_data *tegra_bpmp_get_next_out_frame(void)
58 {
59 	struct frame_data *frame;
60 	const struct ivc *ch = &ivc_ccplex_bpmp_channel;
61 
62 	frame = (struct frame_data *)tegra_ivc_write_get_next_frame(ch);
63 	if (frame == NULL) {
64 		ERROR("%s: Error in getting next frame, exiting\n", __func__);
65 	} else {
66 		s_channel.ob = frame;
67 	}
68 
69 	return frame;
70 }
71 
tegra_bpmp_signal_slave(void)72 static void tegra_bpmp_signal_slave(void)
73 {
74 	(void)tegra_ivc_write_advance(&ivc_ccplex_bpmp_channel);
75 	tegra_bpmp_ring_bpmp_doorbell();
76 }
77 
tegra_bpmp_free_master(void)78 static int32_t tegra_bpmp_free_master(void)
79 {
80 	return tegra_ivc_read_advance(&ivc_ccplex_bpmp_channel);
81 }
82 
tegra_bpmp_slave_acked(void)83 static bool tegra_bpmp_slave_acked(void)
84 {
85 	struct frame_data *frame;
86 	bool ret = true;
87 
88 	frame = (struct frame_data *)tegra_ivc_read_get_next_frame(&ivc_ccplex_bpmp_channel);
89 	if (frame == NULL) {
90 		ret = false;
91 	} else {
92 		s_channel.ib = frame;
93 	}
94 
95 	return ret;
96 }
97 
tegra_bpmp_get_cur_in_frame(void)98 static struct frame_data *tegra_bpmp_get_cur_in_frame(void)
99 {
100 	return s_channel.ib;
101 }
102 
103 /*
104  * Enables BPMP to ring CCPlex doorbell
105  */
tegra_bpmp_enable_ccplex_doorbell(void)106 static void tegra_bpmp_enable_ccplex_doorbell(void)
107 {
108 	uint32_t reg;
109 
110 	reg = hsp_db_read(HSP_DBELL_1_ENABLE);
111 	reg |= HSP_MASTER_BPMP_BIT;
112 	hsp_db_write(HSP_DBELL_1_ENABLE, reg);
113 }
114 
115 /*
116  * CCPlex rings the BPMP doorbell
117  */
tegra_bpmp_ring_bpmp_doorbell(void)118 static void tegra_bpmp_ring_bpmp_doorbell(void)
119 {
120 	/*
121 	 * Any writes to this register has the same effect,
122 	 * uses master ID of the write transaction and set
123 	 * corresponding flag.
124 	 */
125 	hsp_db_write(HSP_DBELL_3_TRIGGER, HSP_MASTER_CCPLEX_BIT);
126 }
127 
128 /*
129  * Returns true if CCPLex can ring BPMP doorbell, otherwise false.
130  * This also signals that BPMP is up and ready.
131  */
tegra_bpmp_can_ccplex_ring_doorbell(void)132 static bool tegra_bpmp_can_ccplex_ring_doorbell(void)
133 {
134 	uint32_t reg;
135 
136 	/* check if ccplex can communicate with bpmp */
137 	reg = hsp_db_read(HSP_DBELL_3_ENABLE);
138 
139 	return ((reg & HSP_MASTER_CCPLEX_BIT) != 0U);
140 }
141 
tegra_bpmp_wait_for_slave_ack(void)142 static int32_t tegra_bpmp_wait_for_slave_ack(void)
143 {
144 	uint32_t timeout = TIMEOUT_RESPONSE_FROM_BPMP_US;
145 
146 	while (!tegra_bpmp_slave_acked() && (timeout != 0U)) {
147 		udelay(1);
148 		timeout--;
149 	};
150 
151 	return ((timeout == 0U) ? -ETIMEDOUT : 0);
152 }
153 
154 /*
155  * Notification from the ivc layer
156  */
tegra_bpmp_ivc_notify(const struct ivc * ivc)157 static void tegra_bpmp_ivc_notify(const struct ivc *ivc)
158 {
159 	(void)(ivc);
160 
161 	tegra_bpmp_ring_bpmp_doorbell();
162 }
163 
164 /*
165  * Atomic send/receive API, which means it waits until slave acks
166  */
tegra_bpmp_ipc_send_req_atomic(uint32_t mrq,void * p_out,uint32_t size_out,void * p_in,uint32_t size_in)167 static int32_t tegra_bpmp_ipc_send_req_atomic(uint32_t mrq, void *p_out,
168 			uint32_t size_out, void *p_in, uint32_t size_in)
169 {
170 	struct frame_data *frame = tegra_bpmp_get_next_out_frame();
171 	const struct frame_data *f_in = NULL;
172 	int32_t ret = 0;
173 	void *p_fdata;
174 
175 	if ((p_out == NULL) || (size_out > IVC_DATA_SZ_BYTES) ||
176 	    (frame == NULL)) {
177 		ERROR("%s: invalid parameters, exiting\n", __func__);
178 		return -EINVAL;
179 	}
180 
181 	/* prepare the command frame */
182 	frame->mrq = mrq;
183 	frame->flags = FLAG_DO_ACK;
184 	p_fdata = frame->data;
185 	(void)memcpy(p_fdata, p_out, (size_t)size_out);
186 
187 	/* signal the slave */
188 	tegra_bpmp_signal_slave();
189 
190 	/* wait for slave to ack */
191 	ret = tegra_bpmp_wait_for_slave_ack();
192 	if (ret < 0) {
193 		ERROR("%s: wait for slave failed (%d)\n", __func__, ret);
194 		return ret;
195 	}
196 
197 	/* retrieve the response frame */
198 	if ((size_in <= IVC_DATA_SZ_BYTES) && (p_in != NULL)) {
199 
200 		f_in = tegra_bpmp_get_cur_in_frame();
201 		if (f_in != NULL) {
202 			ERROR("Failed to get next input frame!\n");
203 		} else {
204 			(void)memcpy(p_in, p_fdata, (size_t)size_in);
205 		}
206 	}
207 
208 	ret = tegra_bpmp_free_master();
209 	if (ret < 0) {
210 		ERROR("%s: free master failed (%d)\n", __func__, ret);
211 	}
212 
213 	return ret;
214 }
215 
216 /*
217  * Initializes the BPMP<--->CCPlex communication path.
218  */
tegra_bpmp_ipc_init(void)219 int32_t tegra_bpmp_ipc_init(void)
220 {
221 	size_t msg_size;
222 	uint32_t frame_size, timeout;
223 	int32_t error = 0;
224 
225 	/* allow bpmp to ring CCPLEX's doorbell */
226 	tegra_bpmp_enable_ccplex_doorbell();
227 
228 	/* wait for BPMP to actually ring the doorbell */
229 	timeout = TIMEOUT_RESPONSE_FROM_BPMP_US;
230 	while ((timeout != 0U) && !tegra_bpmp_can_ccplex_ring_doorbell()) {
231 		udelay(1); /* bpmp turn-around time */
232 		timeout--;
233 	}
234 
235 	if (timeout == 0U) {
236 		ERROR("%s: BPMP firmware is not ready\n", __func__);
237 		return -ENOTSUP;
238 	}
239 
240 	INFO("%s: BPMP handshake completed\n", __func__);
241 
242 	msg_size = tegra_ivc_align(IVC_CMD_SZ_BYTES);
243 	frame_size = (uint32_t)tegra_ivc_total_queue_size(msg_size);
244 	if (frame_size > TEGRA_BPMP_IPC_CH_MAP_SIZE) {
245 		ERROR("%s: carveout size is not sufficient\n", __func__);
246 		return -EINVAL;
247 	}
248 
249 	error = tegra_ivc_init(&ivc_ccplex_bpmp_channel,
250 				(uint32_t)TEGRA_BPMP_IPC_RX_PHYS_BASE,
251 				(uint32_t)TEGRA_BPMP_IPC_TX_PHYS_BASE,
252 				1U, frame_size, tegra_bpmp_ivc_notify);
253 	if (error != 0) {
254 
255 		ERROR("%s: IVC init failed (%d)\n", __func__, error);
256 
257 	} else {
258 
259 		/* reset channel */
260 		tegra_ivc_channel_reset(&ivc_ccplex_bpmp_channel);
261 
262 		/* wait for notification from BPMP */
263 		while (tegra_ivc_channel_notified(&ivc_ccplex_bpmp_channel) != 0) {
264 			/*
265 			 * Interrupt BPMP with doorbell each time after
266 			 * tegra_ivc_channel_notified() returns non zero
267 			 * value.
268 			 */
269 			tegra_bpmp_ring_bpmp_doorbell();
270 		}
271 
272 		INFO("%s: All communication channels initialized\n", __func__);
273 	}
274 
275 	return error;
276 }
277 
278 /* Handler to reset a hardware module */
tegra_bpmp_ipc_reset_module(uint32_t rst_id)279 int32_t tegra_bpmp_ipc_reset_module(uint32_t rst_id)
280 {
281 	int32_t ret;
282 	struct mrq_reset_request req = {
283 		.cmd = (uint32_t)CMD_RESET_MODULE,
284 		.reset_id = rst_id
285 	};
286 
287 	/* only GPCDMA/XUSB_PADCTL resets are supported */
288 	assert((rst_id == TEGRA_RESET_ID_XUSB_PADCTL) ||
289 	       (rst_id == TEGRA_RESET_ID_GPCDMA));
290 
291 	ret = tegra_bpmp_ipc_send_req_atomic(MRQ_RESET, &req,
292 			(uint32_t)sizeof(req), NULL, 0);
293 	if (ret != 0) {
294 		ERROR("%s: failed for module %d with error %d\n", __func__,
295 		      rst_id, ret);
296 	}
297 
298 	return ret;
299 }
300 
tegra_bpmp_ipc_enable_clock(uint32_t clk_id)301 int tegra_bpmp_ipc_enable_clock(uint32_t clk_id)
302 {
303 	int ret;
304 	struct mrq_clk_request req;
305 
306 	/* only SE clocks are supported */
307 	if (clk_id != TEGRA_CLK_SE) {
308 		return -ENOTSUP;
309 	}
310 
311 	/* prepare the MRQ_CLK command */
312 	req.cmd_and_id = make_mrq_clk_cmd(CMD_CLK_ENABLE, clk_id);
313 
314 	ret = tegra_bpmp_ipc_send_req_atomic(MRQ_CLK, &req, (uint32_t)sizeof(req),
315 			NULL, 0);
316 	if (ret != 0) {
317 		ERROR("%s: failed for module %d with error %d\n", __func__,
318 		      clk_id, ret);
319 	}
320 
321 	return ret;
322 }
323 
tegra_bpmp_ipc_disable_clock(uint32_t clk_id)324 int tegra_bpmp_ipc_disable_clock(uint32_t clk_id)
325 {
326 	int ret;
327 	struct mrq_clk_request req;
328 
329 	/* only SE clocks are supported */
330 	if (clk_id != TEGRA_CLK_SE) {
331 		return -ENOTSUP;
332 	}
333 
334 	/* prepare the MRQ_CLK command */
335 	req.cmd_and_id = make_mrq_clk_cmd(CMD_CLK_DISABLE, clk_id);
336 
337 	ret = tegra_bpmp_ipc_send_req_atomic(MRQ_CLK, &req, (uint32_t)sizeof(req),
338 			NULL, 0);
339 	if (ret != 0) {
340 		ERROR("%s: failed for module %d with error %d\n", __func__,
341 		      clk_id, ret);
342 	}
343 
344 	return ret;
345 }
346