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