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 ********************************************************/
ia_css_queue_map_init(void)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
ia_css_queue_map(unsigned int thread_id,enum ia_css_buffer_type buf_type,bool map)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 */
ia_css_query_internal_queue_id(enum ia_css_buffer_type buf_type,unsigned int thread_id,enum sh_css_queue_id * val)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 ********************************************************/
map_buffer_type_to_queue_id(unsigned int thread_id,enum ia_css_buffer_type buf_type)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
unmap_buffer_type_to_queue_id(unsigned int thread_id,enum ia_css_buffer_type buf_type)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
bufq_get_qhandle(enum sh_css_queue_type type,enum sh_css_queue_id id,int thread)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
init_bufq(unsigned int desc_offset,unsigned int elems_offset,ia_css_queue_t * handle)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
ia_css_bufq_init(void)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
ia_css_bufq_enqueue_buffer(int thread_index,int queue_id,uint32_t item)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
ia_css_bufq_dequeue_buffer(int queue_id,uint32_t * item)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
ia_css_bufq_enqueue_psys_event(u8 evt_id,u8 evt_payload_0,u8 evt_payload_1,uint8_t evt_payload_2)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
ia_css_bufq_dequeue_psys_event(u8 item[BUFQ_EVENT_SIZE])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
ia_css_bufq_dequeue_isys_event(u8 item[BUFQ_EVENT_SIZE])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
ia_css_bufq_enqueue_isys_event(uint8_t evt_id)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
ia_css_bufq_enqueue_tag_cmd(uint32_t item)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
ia_css_bufq_deinit(void)484 int ia_css_bufq_deinit(void)
485 {
486 return 0;
487 }
488
bufq_dump_queue_info(const char * prefix,ia_css_queue_t * qhandle)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
ia_css_bufq_dump_queue_info(void)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