1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Support for Intel Camera Imaging ISP subsystem.
4  * Copyright (c) 2015, Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  */
15 
16 #include "assert_support.h"		/* assert */
17 #include "ia_css_buffer.h"
18 #include "sp.h"
19 #include "ia_css_bufq.h"		/* Bufq API's */
20 #include "ia_css_queue.h"		/* ia_css_queue_t */
21 #include "sw_event_global.h"		/* Event IDs.*/
22 #include "ia_css_eventq.h"		/* ia_css_eventq_recv()*/
23 #include "ia_css_debug.h"		/* ia_css_debug_dtrace*/
24 #include "sh_css_internal.h"		/* sh_css_queue_type */
25 #include "sp_local.h"			/* sp_address_of */
26 #include "sh_css_firmware.h"		/* sh_css_sp_fw*/
27 
28 #define BUFQ_DUMP_FILE_NAME_PREFIX_SIZE 256
29 
30 static char prefix[BUFQ_DUMP_FILE_NAME_PREFIX_SIZE] = {0};
31 
32 /*********************************************************/
33 /* Global Queue objects used by CSS                      */
34 /*********************************************************/
35 
36 struct sh_css_queues {
37 	/* Host2SP buffer queue */
38 	ia_css_queue_t host2sp_buffer_queue_handles
39 	[SH_CSS_MAX_SP_THREADS][SH_CSS_MAX_NUM_QUEUES];
40 	/* SP2Host buffer queue */
41 	ia_css_queue_t sp2host_buffer_queue_handles
42 	[SH_CSS_MAX_NUM_QUEUES];
43 
44 	/* Host2SP event queue */
45 	ia_css_queue_t host2sp_psys_event_queue_handle;
46 
47 	/* SP2Host event queue */
48 	ia_css_queue_t sp2host_psys_event_queue_handle;
49 
50 	/* Host2SP ISYS event queue */
51 	ia_css_queue_t host2sp_isys_event_queue_handle;
52 
53 	/* SP2Host ISYS event queue */
54 	ia_css_queue_t sp2host_isys_event_queue_handle;
55 	/* Tagger command queue */
56 	ia_css_queue_t host2sp_tag_cmd_queue_handle;
57 };
58 
59 /*******************************************************
60 *** Static variables
61 ********************************************************/
62 static struct sh_css_queues css_queues;
63 
64 static int
65 buffer_type_to_queue_id_map[SH_CSS_MAX_SP_THREADS][IA_CSS_NUM_DYNAMIC_BUFFER_TYPE];
66 static bool queue_availability[SH_CSS_MAX_SP_THREADS][SH_CSS_MAX_NUM_QUEUES];
67 
68 /*******************************************************
69 *** Static functions
70 ********************************************************/
71 static void map_buffer_type_to_queue_id(
72     unsigned int thread_id,
73     enum ia_css_buffer_type buf_type
74 );
75 static void unmap_buffer_type_to_queue_id(
76     unsigned int thread_id,
77     enum ia_css_buffer_type buf_type
78 );
79 
80 static ia_css_queue_t *bufq_get_qhandle(
81     enum sh_css_queue_type type,
82     enum sh_css_queue_id id,
83     int thread
84 );
85 
86 /*******************************************************
87 *** Public functions
88 ********************************************************/
89 void ia_css_queue_map_init(void)
90 {
91 	unsigned int i, j;
92 
93 	for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) {
94 		for (j = 0; j < SH_CSS_MAX_NUM_QUEUES; j++)
95 			queue_availability[i][j] = true;
96 	}
97 
98 	for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) {
99 		for (j = 0; j < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE; j++)
100 			buffer_type_to_queue_id_map[i][j] = SH_CSS_INVALID_QUEUE_ID;
101 	}
102 }
103 
104 void ia_css_queue_map(
105     unsigned int thread_id,
106     enum ia_css_buffer_type buf_type,
107     bool map)
108 {
109 	assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
110 	assert(thread_id < SH_CSS_MAX_SP_THREADS);
111 
112 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
113 			    "ia_css_queue_map() enter: buf_type=%d, thread_id=%d\n", buf_type, thread_id);
114 
115 	if (map)
116 		map_buffer_type_to_queue_id(thread_id, buf_type);
117 	else
118 		unmap_buffer_type_to_queue_id(thread_id, buf_type);
119 }
120 
121 /*
122  * @brief Query the internal queue ID.
123  */
124 bool ia_css_query_internal_queue_id(
125     enum ia_css_buffer_type buf_type,
126     unsigned int thread_id,
127     enum sh_css_queue_id *val)
128 {
129 	IA_CSS_ENTER("buf_type=%d, thread_id=%d, val = %p", buf_type, thread_id, val);
130 
131 	if ((!val) || (thread_id >= SH_CSS_MAX_SP_THREADS) ||
132 	    (buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE)) {
133 		IA_CSS_LEAVE("return_val = false");
134 		return false;
135 	}
136 
137 	*val = buffer_type_to_queue_id_map[thread_id][buf_type];
138 	if ((*val == SH_CSS_INVALID_QUEUE_ID) || (*val >= SH_CSS_MAX_NUM_QUEUES)) {
139 		IA_CSS_LOG("INVALID queue ID MAP = %d\n", *val);
140 		IA_CSS_LEAVE("return_val = false");
141 		return false;
142 	}
143 	IA_CSS_LEAVE("return_val = true");
144 	return true;
145 }
146 
147 /*******************************************************
148 *** Static functions
149 ********************************************************/
150 static void map_buffer_type_to_queue_id(
151     unsigned int thread_id,
152     enum ia_css_buffer_type buf_type)
153 {
154 	unsigned int i;
155 
156 	assert(thread_id < SH_CSS_MAX_SP_THREADS);
157 	assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
158 	assert(buffer_type_to_queue_id_map[thread_id][buf_type] ==
159 	       SH_CSS_INVALID_QUEUE_ID);
160 
161 	/* queue 0 is reserved for parameters because it doesn't depend on events */
162 	if (buf_type == IA_CSS_BUFFER_TYPE_PARAMETER_SET) {
163 		assert(queue_availability[thread_id][IA_CSS_PARAMETER_SET_QUEUE_ID]);
164 		queue_availability[thread_id][IA_CSS_PARAMETER_SET_QUEUE_ID] = false;
165 		buffer_type_to_queue_id_map[thread_id][buf_type] =
166 		    IA_CSS_PARAMETER_SET_QUEUE_ID;
167 		return;
168 	}
169 
170 	/* queue 1 is reserved for per frame parameters because it doesn't depend on events */
171 	if (buf_type == IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET) {
172 		assert(queue_availability[thread_id][IA_CSS_PER_FRAME_PARAMETER_SET_QUEUE_ID]);
173 		queue_availability[thread_id][IA_CSS_PER_FRAME_PARAMETER_SET_QUEUE_ID] = false;
174 		buffer_type_to_queue_id_map[thread_id][buf_type] =
175 		    IA_CSS_PER_FRAME_PARAMETER_SET_QUEUE_ID;
176 		return;
177 	}
178 
179 	for (i = SH_CSS_QUEUE_C_ID; i < SH_CSS_MAX_NUM_QUEUES; i++) {
180 		if (queue_availability[thread_id][i]) {
181 			queue_availability[thread_id][i] = false;
182 			buffer_type_to_queue_id_map[thread_id][buf_type] = i;
183 			break;
184 		}
185 	}
186 
187 	assert(i != SH_CSS_MAX_NUM_QUEUES);
188 	return;
189 }
190 
191 static void unmap_buffer_type_to_queue_id(
192     unsigned int thread_id,
193     enum ia_css_buffer_type buf_type)
194 {
195 	int queue_id;
196 
197 	assert(thread_id < SH_CSS_MAX_SP_THREADS);
198 	assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
199 	assert(buffer_type_to_queue_id_map[thread_id][buf_type] !=
200 	       SH_CSS_INVALID_QUEUE_ID);
201 
202 	queue_id = buffer_type_to_queue_id_map[thread_id][buf_type];
203 	buffer_type_to_queue_id_map[thread_id][buf_type] = SH_CSS_INVALID_QUEUE_ID;
204 	queue_availability[thread_id][queue_id] = true;
205 }
206 
207 static ia_css_queue_t *bufq_get_qhandle(
208     enum sh_css_queue_type type,
209     enum sh_css_queue_id id,
210     int thread)
211 {
212 	ia_css_queue_t *q = NULL;
213 
214 	switch (type) {
215 	case sh_css_host2sp_buffer_queue:
216 		if ((thread >= SH_CSS_MAX_SP_THREADS) || (thread < 0) ||
217 		    (id == SH_CSS_INVALID_QUEUE_ID))
218 			break;
219 		q = &css_queues.host2sp_buffer_queue_handles[thread][id];
220 		break;
221 	case sh_css_sp2host_buffer_queue:
222 		if (id == SH_CSS_INVALID_QUEUE_ID)
223 			break;
224 		q = &css_queues.sp2host_buffer_queue_handles[id];
225 		break;
226 	case sh_css_host2sp_psys_event_queue:
227 		q = &css_queues.host2sp_psys_event_queue_handle;
228 		break;
229 	case sh_css_sp2host_psys_event_queue:
230 		q = &css_queues.sp2host_psys_event_queue_handle;
231 		break;
232 	case sh_css_host2sp_isys_event_queue:
233 		q = &css_queues.host2sp_isys_event_queue_handle;
234 		break;
235 	case sh_css_sp2host_isys_event_queue:
236 		q = &css_queues.sp2host_isys_event_queue_handle;
237 		break;
238 	case sh_css_host2sp_tag_cmd_queue:
239 		q = &css_queues.host2sp_tag_cmd_queue_handle;
240 		break;
241 	default:
242 		break;
243 	}
244 
245 	return q;
246 }
247 
248 /* Local function to initialize a buffer queue. This reduces
249  * the chances of copy-paste errors or typos.
250  */
251 static inline void
252 init_bufq(unsigned int desc_offset,
253 	  unsigned int elems_offset,
254 	  ia_css_queue_t *handle)
255 {
256 	const struct ia_css_fw_info *fw;
257 	unsigned int q_base_addr;
258 	ia_css_queue_remote_t remoteq;
259 
260 	fw = &sh_css_sp_fw;
261 	q_base_addr = fw->info.sp.host_sp_queue;
262 
263 	/* Setup queue location as SP and proc id as SP0_ID */
264 	remoteq.location = IA_CSS_QUEUE_LOC_SP;
265 	remoteq.proc_id = SP0_ID;
266 	remoteq.cb_desc_addr = q_base_addr + desc_offset;
267 	remoteq.cb_elems_addr = q_base_addr + elems_offset;
268 	/* Initialize the queue instance and obtain handle */
269 	ia_css_queue_remote_init(handle, &remoteq);
270 }
271 
272 void ia_css_bufq_init(void)
273 {
274 	int i, j;
275 
276 	IA_CSS_ENTER_PRIVATE("");
277 
278 	/* Setup all the local queue descriptors for Host2SP Buffer Queues */
279 	for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++)
280 		for (j = 0; j < SH_CSS_MAX_NUM_QUEUES; j++) {
281 			init_bufq((uint32_t)offsetof(struct host_sp_queues,
282 						     host2sp_buffer_queues_desc[i][j]),
283 				  (uint32_t)offsetof(struct host_sp_queues, host2sp_buffer_queues_elems[i][j]),
284 				  &css_queues.host2sp_buffer_queue_handles[i][j]);
285 		}
286 
287 	/* Setup all the local queue descriptors for SP2Host Buffer Queues */
288 	for (i = 0; i < SH_CSS_MAX_NUM_QUEUES; i++) {
289 		init_bufq(offsetof(struct host_sp_queues, sp2host_buffer_queues_desc[i]),
290 			  offsetof(struct host_sp_queues, sp2host_buffer_queues_elems[i]),
291 			  &css_queues.sp2host_buffer_queue_handles[i]);
292 	}
293 
294 	/* Host2SP event queue*/
295 	init_bufq((uint32_t)offsetof(struct host_sp_queues,
296 				     host2sp_psys_event_queue_desc),
297 		  (uint32_t)offsetof(struct host_sp_queues, host2sp_psys_event_queue_elems),
298 		  &css_queues.host2sp_psys_event_queue_handle);
299 
300 	/* SP2Host event queue */
301 	init_bufq((uint32_t)offsetof(struct host_sp_queues,
302 				     sp2host_psys_event_queue_desc),
303 		  (uint32_t)offsetof(struct host_sp_queues, sp2host_psys_event_queue_elems),
304 		  &css_queues.sp2host_psys_event_queue_handle);
305 
306 	/* Host2SP ISYS event queue */
307 	init_bufq((uint32_t)offsetof(struct host_sp_queues,
308 				     host2sp_isys_event_queue_desc),
309 		  (uint32_t)offsetof(struct host_sp_queues, host2sp_isys_event_queue_elems),
310 		  &css_queues.host2sp_isys_event_queue_handle);
311 
312 	/* SP2Host ISYS event queue*/
313 	init_bufq((uint32_t)offsetof(struct host_sp_queues,
314 				     sp2host_isys_event_queue_desc),
315 		  (uint32_t)offsetof(struct host_sp_queues, sp2host_isys_event_queue_elems),
316 		  &css_queues.sp2host_isys_event_queue_handle);
317 
318 	/* Host2SP tagger command queue */
319 	init_bufq((uint32_t)offsetof(struct host_sp_queues, host2sp_tag_cmd_queue_desc),
320 		  (uint32_t)offsetof(struct host_sp_queues, host2sp_tag_cmd_queue_elems),
321 		  &css_queues.host2sp_tag_cmd_queue_handle);
322 
323 	IA_CSS_LEAVE_PRIVATE("");
324 }
325 
326 int ia_css_bufq_enqueue_buffer(
327     int thread_index,
328     int queue_id,
329     uint32_t item)
330 {
331 	ia_css_queue_t *q;
332 	int error;
333 
334 	IA_CSS_ENTER_PRIVATE("queue_id=%d", queue_id);
335 	if ((thread_index >= SH_CSS_MAX_SP_THREADS) || (thread_index < 0) ||
336 	    (queue_id == SH_CSS_INVALID_QUEUE_ID))
337 		return -EINVAL;
338 
339 	/* Get the queue for communication */
340 	q = bufq_get_qhandle(sh_css_host2sp_buffer_queue,
341 			     queue_id,
342 			     thread_index);
343 	if (q) {
344 		error = ia_css_queue_enqueue(q, item);
345 	} else {
346 		IA_CSS_ERROR("queue is not initialized");
347 		error = -EBUSY;
348 	}
349 
350 	IA_CSS_LEAVE_ERR_PRIVATE(error);
351 	return error;
352 }
353 
354 int ia_css_bufq_dequeue_buffer(
355     int queue_id,
356     uint32_t *item)
357 {
358 	int error;
359 	ia_css_queue_t *q;
360 
361 	IA_CSS_ENTER_PRIVATE("queue_id=%d", queue_id);
362 	if ((!item) ||
363 	    (queue_id <= SH_CSS_INVALID_QUEUE_ID) ||
364 	    (queue_id >= SH_CSS_MAX_NUM_QUEUES)
365 	   )
366 		return -EINVAL;
367 
368 	q = bufq_get_qhandle(sh_css_sp2host_buffer_queue,
369 			     queue_id,
370 			     -1);
371 	if (q) {
372 		error = ia_css_queue_dequeue(q, item);
373 	} else {
374 		IA_CSS_ERROR("queue is not initialized");
375 		error = -EBUSY;
376 	}
377 
378 	IA_CSS_LEAVE_ERR_PRIVATE(error);
379 	return error;
380 }
381 
382 int ia_css_bufq_enqueue_psys_event(
383     u8 evt_id,
384     u8 evt_payload_0,
385     u8 evt_payload_1,
386     uint8_t evt_payload_2)
387 {
388 	int error = 0;
389 	ia_css_queue_t *q;
390 
391 	IA_CSS_ENTER_PRIVATE("evt_id=%d", evt_id);
392 	q = bufq_get_qhandle(sh_css_host2sp_psys_event_queue, -1, -1);
393 	if (!q) {
394 		IA_CSS_ERROR("queue is not initialized");
395 		return -EBUSY;
396 	}
397 
398 	error = ia_css_eventq_send(q,
399 				   evt_id, evt_payload_0, evt_payload_1, evt_payload_2);
400 
401 	IA_CSS_LEAVE_ERR_PRIVATE(error);
402 	return error;
403 }
404 
405 int ia_css_bufq_dequeue_psys_event(
406     u8 item[BUFQ_EVENT_SIZE])
407 {
408 	int error = 0;
409 	ia_css_queue_t *q;
410 
411 	/* No ENTER/LEAVE in this function since this is polled
412 	 * by some test apps. Enablign logging here floods the log
413 	 * files which may cause timeouts. */
414 	if (!item)
415 		return -EINVAL;
416 
417 	q = bufq_get_qhandle(sh_css_sp2host_psys_event_queue, -1, -1);
418 	if (!q) {
419 		IA_CSS_ERROR("queue is not initialized");
420 		return -EBUSY;
421 	}
422 	error = ia_css_eventq_recv(q, item);
423 
424 	return error;
425 }
426 
427 int ia_css_bufq_dequeue_isys_event(
428     u8 item[BUFQ_EVENT_SIZE])
429 {
430 	int error = 0;
431 	ia_css_queue_t *q;
432 
433 	/* No ENTER/LEAVE in this function since this is polled
434 	 * by some test apps. Enablign logging here floods the log
435 	 * files which may cause timeouts. */
436 	if (!item)
437 		return -EINVAL;
438 
439 	q = bufq_get_qhandle(sh_css_sp2host_isys_event_queue, -1, -1);
440 	if (!q) {
441 		IA_CSS_ERROR("queue is not initialized");
442 		return -EBUSY;
443 	}
444 	error = ia_css_eventq_recv(q, item);
445 	return error;
446 }
447 
448 int ia_css_bufq_enqueue_isys_event(uint8_t evt_id)
449 {
450 	int error = 0;
451 	ia_css_queue_t *q;
452 
453 	IA_CSS_ENTER_PRIVATE("event_id=%d", evt_id);
454 	q = bufq_get_qhandle(sh_css_host2sp_isys_event_queue, -1, -1);
455 	if (!q) {
456 		IA_CSS_ERROR("queue is not initialized");
457 		return -EBUSY;
458 	}
459 
460 	error = ia_css_eventq_send(q, evt_id, 0, 0, 0);
461 
462 	IA_CSS_LEAVE_ERR_PRIVATE(error);
463 	return error;
464 }
465 
466 int ia_css_bufq_enqueue_tag_cmd(
467     uint32_t item)
468 {
469 	int error;
470 	ia_css_queue_t *q;
471 
472 	IA_CSS_ENTER_PRIVATE("item=%d", item);
473 	q = bufq_get_qhandle(sh_css_host2sp_tag_cmd_queue, -1, -1);
474 	if (!q) {
475 		IA_CSS_ERROR("queue is not initialized");
476 		return -EBUSY;
477 	}
478 	error = ia_css_queue_enqueue(q, item);
479 
480 	IA_CSS_LEAVE_ERR_PRIVATE(error);
481 	return error;
482 }
483 
484 int ia_css_bufq_deinit(void)
485 {
486 	return 0;
487 }
488 
489 static void bufq_dump_queue_info(const char *prefix, ia_css_queue_t *qhandle)
490 {
491 	u32 free = 0, used = 0;
492 
493 	assert(prefix && qhandle);
494 	ia_css_queue_get_used_space(qhandle, &used);
495 	ia_css_queue_get_free_space(qhandle, &free);
496 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s: used=%u free=%u\n",
497 			    prefix, used, free);
498 }
499 
500 void ia_css_bufq_dump_queue_info(void)
501 {
502 	int i, j;
503 
504 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "Queue Information:\n");
505 
506 	for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) {
507 		for (j = 0; j < SH_CSS_MAX_NUM_QUEUES; j++) {
508 			snprintf(prefix, BUFQ_DUMP_FILE_NAME_PREFIX_SIZE,
509 				 "host2sp_buffer_queue[%u][%u]", i, j);
510 			bufq_dump_queue_info(prefix,
511 					     &css_queues.host2sp_buffer_queue_handles[i][j]);
512 		}
513 	}
514 
515 	for (i = 0; i < SH_CSS_MAX_NUM_QUEUES; i++) {
516 		snprintf(prefix, BUFQ_DUMP_FILE_NAME_PREFIX_SIZE,
517 			 "sp2host_buffer_queue[%u]", i);
518 		bufq_dump_queue_info(prefix,
519 				     &css_queues.sp2host_buffer_queue_handles[i]);
520 	}
521 	bufq_dump_queue_info("host2sp_psys_event",
522 			     &css_queues.host2sp_psys_event_queue_handle);
523 	bufq_dump_queue_info("sp2host_psys_event",
524 			     &css_queues.sp2host_psys_event_queue_handle);
525 
526 	bufq_dump_queue_info("host2sp_isys_event",
527 			     &css_queues.host2sp_isys_event_queue_handle);
528 	bufq_dump_queue_info("sp2host_isys_event",
529 			     &css_queues.sp2host_isys_event_queue_handle);
530 	bufq_dump_queue_info("host2sp_tag_cmd",
531 			     &css_queues.host2sp_tag_cmd_queue_handle);
532 }
533