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