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