// SPDX-License-Identifier: GPL-2.0
|
/*
|
* Support for Intel Camera Imaging ISP subsystem.
|
* Copyright (c) 2015, Intel Corporation.
|
*
|
* This program is free software; you can redistribute it and/or modify it
|
* under the terms and conditions of the GNU General Public License,
|
* version 2, as published by the Free Software Foundation.
|
*
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
* more details.
|
*/
|
|
#include "assert_support.h" /* assert */
|
#include "ia_css_buffer.h"
|
#include "sp.h"
|
#include "ia_css_bufq.h" /* Bufq API's */
|
#include "ia_css_queue.h" /* ia_css_queue_t */
|
#include "sw_event_global.h" /* Event IDs.*/
|
#include "ia_css_eventq.h" /* ia_css_eventq_recv()*/
|
#include "ia_css_debug.h" /* ia_css_debug_dtrace*/
|
#include "sh_css_internal.h" /* sh_css_queue_type */
|
#include "sp_local.h" /* sp_address_of */
|
#include "sh_css_firmware.h" /* sh_css_sp_fw*/
|
|
#define BUFQ_DUMP_FILE_NAME_PREFIX_SIZE 256
|
|
static char prefix[BUFQ_DUMP_FILE_NAME_PREFIX_SIZE] = {0};
|
|
/*********************************************************/
|
/* Global Queue objects used by CSS */
|
/*********************************************************/
|
|
struct sh_css_queues {
|
/* Host2SP buffer queue */
|
ia_css_queue_t host2sp_buffer_queue_handles
|
[SH_CSS_MAX_SP_THREADS][SH_CSS_MAX_NUM_QUEUES];
|
/* SP2Host buffer queue */
|
ia_css_queue_t sp2host_buffer_queue_handles
|
[SH_CSS_MAX_NUM_QUEUES];
|
|
/* Host2SP event queue */
|
ia_css_queue_t host2sp_psys_event_queue_handle;
|
|
/* SP2Host event queue */
|
ia_css_queue_t sp2host_psys_event_queue_handle;
|
|
/* Host2SP ISYS event queue */
|
ia_css_queue_t host2sp_isys_event_queue_handle;
|
|
/* SP2Host ISYS event queue */
|
ia_css_queue_t sp2host_isys_event_queue_handle;
|
/* Tagger command queue */
|
ia_css_queue_t host2sp_tag_cmd_queue_handle;
|
};
|
|
/*******************************************************
|
*** Static variables
|
********************************************************/
|
static struct sh_css_queues css_queues;
|
|
static int
|
buffer_type_to_queue_id_map[SH_CSS_MAX_SP_THREADS][IA_CSS_NUM_DYNAMIC_BUFFER_TYPE];
|
static bool queue_availability[SH_CSS_MAX_SP_THREADS][SH_CSS_MAX_NUM_QUEUES];
|
|
/*******************************************************
|
*** Static functions
|
********************************************************/
|
static void map_buffer_type_to_queue_id(
|
unsigned int thread_id,
|
enum ia_css_buffer_type buf_type
|
);
|
static void unmap_buffer_type_to_queue_id(
|
unsigned int thread_id,
|
enum ia_css_buffer_type buf_type
|
);
|
|
static ia_css_queue_t *bufq_get_qhandle(
|
enum sh_css_queue_type type,
|
enum sh_css_queue_id id,
|
int thread
|
);
|
|
/*******************************************************
|
*** Public functions
|
********************************************************/
|
void ia_css_queue_map_init(void)
|
{
|
unsigned int i, j;
|
|
for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) {
|
for (j = 0; j < SH_CSS_MAX_NUM_QUEUES; j++)
|
queue_availability[i][j] = true;
|
}
|
|
for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) {
|
for (j = 0; j < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE; j++)
|
buffer_type_to_queue_id_map[i][j] = SH_CSS_INVALID_QUEUE_ID;
|
}
|
}
|
|
void ia_css_queue_map(
|
unsigned int thread_id,
|
enum ia_css_buffer_type buf_type,
|
bool map)
|
{
|
assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
|
assert(thread_id < SH_CSS_MAX_SP_THREADS);
|
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
|
"ia_css_queue_map() enter: buf_type=%d, thread_id=%d\n", buf_type, thread_id);
|
|
if (map)
|
map_buffer_type_to_queue_id(thread_id, buf_type);
|
else
|
unmap_buffer_type_to_queue_id(thread_id, buf_type);
|
}
|
|
/*
|
* @brief Query the internal queue ID.
|
*/
|
bool ia_css_query_internal_queue_id(
|
enum ia_css_buffer_type buf_type,
|
unsigned int thread_id,
|
enum sh_css_queue_id *val)
|
{
|
IA_CSS_ENTER("buf_type=%d, thread_id=%d, val = %p", buf_type, thread_id, val);
|
|
if ((!val) || (thread_id >= SH_CSS_MAX_SP_THREADS) ||
|
(buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE)) {
|
IA_CSS_LEAVE("return_val = false");
|
return false;
|
}
|
|
*val = buffer_type_to_queue_id_map[thread_id][buf_type];
|
if ((*val == SH_CSS_INVALID_QUEUE_ID) || (*val >= SH_CSS_MAX_NUM_QUEUES)) {
|
IA_CSS_LOG("INVALID queue ID MAP = %d\n", *val);
|
IA_CSS_LEAVE("return_val = false");
|
return false;
|
}
|
IA_CSS_LEAVE("return_val = true");
|
return true;
|
}
|
|
/*******************************************************
|
*** Static functions
|
********************************************************/
|
static void map_buffer_type_to_queue_id(
|
unsigned int thread_id,
|
enum ia_css_buffer_type buf_type)
|
{
|
unsigned int i;
|
|
assert(thread_id < SH_CSS_MAX_SP_THREADS);
|
assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
|
assert(buffer_type_to_queue_id_map[thread_id][buf_type] ==
|
SH_CSS_INVALID_QUEUE_ID);
|
|
/* queue 0 is reserved for parameters because it doesn't depend on events */
|
if (buf_type == IA_CSS_BUFFER_TYPE_PARAMETER_SET) {
|
assert(queue_availability[thread_id][IA_CSS_PARAMETER_SET_QUEUE_ID]);
|
queue_availability[thread_id][IA_CSS_PARAMETER_SET_QUEUE_ID] = false;
|
buffer_type_to_queue_id_map[thread_id][buf_type] =
|
IA_CSS_PARAMETER_SET_QUEUE_ID;
|
return;
|
}
|
|
/* queue 1 is reserved for per frame parameters because it doesn't depend on events */
|
if (buf_type == IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET) {
|
assert(queue_availability[thread_id][IA_CSS_PER_FRAME_PARAMETER_SET_QUEUE_ID]);
|
queue_availability[thread_id][IA_CSS_PER_FRAME_PARAMETER_SET_QUEUE_ID] = false;
|
buffer_type_to_queue_id_map[thread_id][buf_type] =
|
IA_CSS_PER_FRAME_PARAMETER_SET_QUEUE_ID;
|
return;
|
}
|
|
for (i = SH_CSS_QUEUE_C_ID; i < SH_CSS_MAX_NUM_QUEUES; i++) {
|
if (queue_availability[thread_id][i]) {
|
queue_availability[thread_id][i] = false;
|
buffer_type_to_queue_id_map[thread_id][buf_type] = i;
|
break;
|
}
|
}
|
|
assert(i != SH_CSS_MAX_NUM_QUEUES);
|
return;
|
}
|
|
static void unmap_buffer_type_to_queue_id(
|
unsigned int thread_id,
|
enum ia_css_buffer_type buf_type)
|
{
|
int queue_id;
|
|
assert(thread_id < SH_CSS_MAX_SP_THREADS);
|
assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
|
assert(buffer_type_to_queue_id_map[thread_id][buf_type] !=
|
SH_CSS_INVALID_QUEUE_ID);
|
|
queue_id = buffer_type_to_queue_id_map[thread_id][buf_type];
|
buffer_type_to_queue_id_map[thread_id][buf_type] = SH_CSS_INVALID_QUEUE_ID;
|
queue_availability[thread_id][queue_id] = true;
|
}
|
|
static ia_css_queue_t *bufq_get_qhandle(
|
enum sh_css_queue_type type,
|
enum sh_css_queue_id id,
|
int thread)
|
{
|
ia_css_queue_t *q = NULL;
|
|
switch (type) {
|
case sh_css_host2sp_buffer_queue:
|
if ((thread >= SH_CSS_MAX_SP_THREADS) || (thread < 0) ||
|
(id == SH_CSS_INVALID_QUEUE_ID))
|
break;
|
q = &css_queues.host2sp_buffer_queue_handles[thread][id];
|
break;
|
case sh_css_sp2host_buffer_queue:
|
if (id == SH_CSS_INVALID_QUEUE_ID)
|
break;
|
q = &css_queues.sp2host_buffer_queue_handles[id];
|
break;
|
case sh_css_host2sp_psys_event_queue:
|
q = &css_queues.host2sp_psys_event_queue_handle;
|
break;
|
case sh_css_sp2host_psys_event_queue:
|
q = &css_queues.sp2host_psys_event_queue_handle;
|
break;
|
case sh_css_host2sp_isys_event_queue:
|
q = &css_queues.host2sp_isys_event_queue_handle;
|
break;
|
case sh_css_sp2host_isys_event_queue:
|
q = &css_queues.sp2host_isys_event_queue_handle;
|
break;
|
case sh_css_host2sp_tag_cmd_queue:
|
q = &css_queues.host2sp_tag_cmd_queue_handle;
|
break;
|
default:
|
break;
|
}
|
|
return q;
|
}
|
|
/* Local function to initialize a buffer queue. This reduces
|
* the chances of copy-paste errors or typos.
|
*/
|
static inline void
|
init_bufq(unsigned int desc_offset,
|
unsigned int elems_offset,
|
ia_css_queue_t *handle)
|
{
|
const struct ia_css_fw_info *fw;
|
unsigned int q_base_addr;
|
ia_css_queue_remote_t remoteq;
|
|
fw = &sh_css_sp_fw;
|
q_base_addr = fw->info.sp.host_sp_queue;
|
|
/* Setup queue location as SP and proc id as SP0_ID */
|
remoteq.location = IA_CSS_QUEUE_LOC_SP;
|
remoteq.proc_id = SP0_ID;
|
remoteq.cb_desc_addr = q_base_addr + desc_offset;
|
remoteq.cb_elems_addr = q_base_addr + elems_offset;
|
/* Initialize the queue instance and obtain handle */
|
ia_css_queue_remote_init(handle, &remoteq);
|
}
|
|
void ia_css_bufq_init(void)
|
{
|
int i, j;
|
|
IA_CSS_ENTER_PRIVATE("");
|
|
/* Setup all the local queue descriptors for Host2SP Buffer Queues */
|
for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++)
|
for (j = 0; j < SH_CSS_MAX_NUM_QUEUES; j++) {
|
init_bufq((uint32_t)offsetof(struct host_sp_queues,
|
host2sp_buffer_queues_desc[i][j]),
|
(uint32_t)offsetof(struct host_sp_queues, host2sp_buffer_queues_elems[i][j]),
|
&css_queues.host2sp_buffer_queue_handles[i][j]);
|
}
|
|
/* Setup all the local queue descriptors for SP2Host Buffer Queues */
|
for (i = 0; i < SH_CSS_MAX_NUM_QUEUES; i++) {
|
init_bufq(offsetof(struct host_sp_queues, sp2host_buffer_queues_desc[i]),
|
offsetof(struct host_sp_queues, sp2host_buffer_queues_elems[i]),
|
&css_queues.sp2host_buffer_queue_handles[i]);
|
}
|
|
/* Host2SP event queue*/
|
init_bufq((uint32_t)offsetof(struct host_sp_queues,
|
host2sp_psys_event_queue_desc),
|
(uint32_t)offsetof(struct host_sp_queues, host2sp_psys_event_queue_elems),
|
&css_queues.host2sp_psys_event_queue_handle);
|
|
/* SP2Host event queue */
|
init_bufq((uint32_t)offsetof(struct host_sp_queues,
|
sp2host_psys_event_queue_desc),
|
(uint32_t)offsetof(struct host_sp_queues, sp2host_psys_event_queue_elems),
|
&css_queues.sp2host_psys_event_queue_handle);
|
|
/* Host2SP ISYS event queue */
|
init_bufq((uint32_t)offsetof(struct host_sp_queues,
|
host2sp_isys_event_queue_desc),
|
(uint32_t)offsetof(struct host_sp_queues, host2sp_isys_event_queue_elems),
|
&css_queues.host2sp_isys_event_queue_handle);
|
|
/* SP2Host ISYS event queue*/
|
init_bufq((uint32_t)offsetof(struct host_sp_queues,
|
sp2host_isys_event_queue_desc),
|
(uint32_t)offsetof(struct host_sp_queues, sp2host_isys_event_queue_elems),
|
&css_queues.sp2host_isys_event_queue_handle);
|
|
/* Host2SP tagger command queue */
|
init_bufq((uint32_t)offsetof(struct host_sp_queues, host2sp_tag_cmd_queue_desc),
|
(uint32_t)offsetof(struct host_sp_queues, host2sp_tag_cmd_queue_elems),
|
&css_queues.host2sp_tag_cmd_queue_handle);
|
|
IA_CSS_LEAVE_PRIVATE("");
|
}
|
|
int ia_css_bufq_enqueue_buffer(
|
int thread_index,
|
int queue_id,
|
uint32_t item)
|
{
|
ia_css_queue_t *q;
|
int error;
|
|
IA_CSS_ENTER_PRIVATE("queue_id=%d", queue_id);
|
if ((thread_index >= SH_CSS_MAX_SP_THREADS) || (thread_index < 0) ||
|
(queue_id == SH_CSS_INVALID_QUEUE_ID))
|
return -EINVAL;
|
|
/* Get the queue for communication */
|
q = bufq_get_qhandle(sh_css_host2sp_buffer_queue,
|
queue_id,
|
thread_index);
|
if (q) {
|
error = ia_css_queue_enqueue(q, item);
|
} else {
|
IA_CSS_ERROR("queue is not initialized");
|
error = -EBUSY;
|
}
|
|
IA_CSS_LEAVE_ERR_PRIVATE(error);
|
return error;
|
}
|
|
int ia_css_bufq_dequeue_buffer(
|
int queue_id,
|
uint32_t *item)
|
{
|
int error;
|
ia_css_queue_t *q;
|
|
IA_CSS_ENTER_PRIVATE("queue_id=%d", queue_id);
|
if ((!item) ||
|
(queue_id <= SH_CSS_INVALID_QUEUE_ID) ||
|
(queue_id >= SH_CSS_MAX_NUM_QUEUES)
|
)
|
return -EINVAL;
|
|
q = bufq_get_qhandle(sh_css_sp2host_buffer_queue,
|
queue_id,
|
-1);
|
if (q) {
|
error = ia_css_queue_dequeue(q, item);
|
} else {
|
IA_CSS_ERROR("queue is not initialized");
|
error = -EBUSY;
|
}
|
|
IA_CSS_LEAVE_ERR_PRIVATE(error);
|
return error;
|
}
|
|
int ia_css_bufq_enqueue_psys_event(
|
u8 evt_id,
|
u8 evt_payload_0,
|
u8 evt_payload_1,
|
uint8_t evt_payload_2)
|
{
|
int error = 0;
|
ia_css_queue_t *q;
|
|
IA_CSS_ENTER_PRIVATE("evt_id=%d", evt_id);
|
q = bufq_get_qhandle(sh_css_host2sp_psys_event_queue, -1, -1);
|
if (!q) {
|
IA_CSS_ERROR("queue is not initialized");
|
return -EBUSY;
|
}
|
|
error = ia_css_eventq_send(q,
|
evt_id, evt_payload_0, evt_payload_1, evt_payload_2);
|
|
IA_CSS_LEAVE_ERR_PRIVATE(error);
|
return error;
|
}
|
|
int ia_css_bufq_dequeue_psys_event(
|
u8 item[BUFQ_EVENT_SIZE])
|
{
|
int error = 0;
|
ia_css_queue_t *q;
|
|
/* No ENTER/LEAVE in this function since this is polled
|
* by some test apps. Enablign logging here floods the log
|
* files which may cause timeouts. */
|
if (!item)
|
return -EINVAL;
|
|
q = bufq_get_qhandle(sh_css_sp2host_psys_event_queue, -1, -1);
|
if (!q) {
|
IA_CSS_ERROR("queue is not initialized");
|
return -EBUSY;
|
}
|
error = ia_css_eventq_recv(q, item);
|
|
return error;
|
}
|
|
int ia_css_bufq_dequeue_isys_event(
|
u8 item[BUFQ_EVENT_SIZE])
|
{
|
int error = 0;
|
ia_css_queue_t *q;
|
|
/* No ENTER/LEAVE in this function since this is polled
|
* by some test apps. Enablign logging here floods the log
|
* files which may cause timeouts. */
|
if (!item)
|
return -EINVAL;
|
|
q = bufq_get_qhandle(sh_css_sp2host_isys_event_queue, -1, -1);
|
if (!q) {
|
IA_CSS_ERROR("queue is not initialized");
|
return -EBUSY;
|
}
|
error = ia_css_eventq_recv(q, item);
|
return error;
|
}
|
|
int ia_css_bufq_enqueue_isys_event(uint8_t evt_id)
|
{
|
int error = 0;
|
ia_css_queue_t *q;
|
|
IA_CSS_ENTER_PRIVATE("event_id=%d", evt_id);
|
q = bufq_get_qhandle(sh_css_host2sp_isys_event_queue, -1, -1);
|
if (!q) {
|
IA_CSS_ERROR("queue is not initialized");
|
return -EBUSY;
|
}
|
|
error = ia_css_eventq_send(q, evt_id, 0, 0, 0);
|
|
IA_CSS_LEAVE_ERR_PRIVATE(error);
|
return error;
|
}
|
|
int ia_css_bufq_enqueue_tag_cmd(
|
uint32_t item)
|
{
|
int error;
|
ia_css_queue_t *q;
|
|
IA_CSS_ENTER_PRIVATE("item=%d", item);
|
q = bufq_get_qhandle(sh_css_host2sp_tag_cmd_queue, -1, -1);
|
if (!q) {
|
IA_CSS_ERROR("queue is not initialized");
|
return -EBUSY;
|
}
|
error = ia_css_queue_enqueue(q, item);
|
|
IA_CSS_LEAVE_ERR_PRIVATE(error);
|
return error;
|
}
|
|
int ia_css_bufq_deinit(void)
|
{
|
return 0;
|
}
|
|
static void bufq_dump_queue_info(const char *prefix, ia_css_queue_t *qhandle)
|
{
|
u32 free = 0, used = 0;
|
|
assert(prefix && qhandle);
|
ia_css_queue_get_used_space(qhandle, &used);
|
ia_css_queue_get_free_space(qhandle, &free);
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s: used=%u free=%u\n",
|
prefix, used, free);
|
}
|
|
void ia_css_bufq_dump_queue_info(void)
|
{
|
int i, j;
|
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "Queue Information:\n");
|
|
for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) {
|
for (j = 0; j < SH_CSS_MAX_NUM_QUEUES; j++) {
|
snprintf(prefix, BUFQ_DUMP_FILE_NAME_PREFIX_SIZE,
|
"host2sp_buffer_queue[%u][%u]", i, j);
|
bufq_dump_queue_info(prefix,
|
&css_queues.host2sp_buffer_queue_handles[i][j]);
|
}
|
}
|
|
for (i = 0; i < SH_CSS_MAX_NUM_QUEUES; i++) {
|
snprintf(prefix, BUFQ_DUMP_FILE_NAME_PREFIX_SIZE,
|
"sp2host_buffer_queue[%u]", i);
|
bufq_dump_queue_info(prefix,
|
&css_queues.sp2host_buffer_queue_handles[i]);
|
}
|
bufq_dump_queue_info("host2sp_psys_event",
|
&css_queues.host2sp_psys_event_queue_handle);
|
bufq_dump_queue_info("sp2host_psys_event",
|
&css_queues.sp2host_psys_event_queue_handle);
|
|
bufq_dump_queue_info("host2sp_isys_event",
|
&css_queues.host2sp_isys_event_queue_handle);
|
bufq_dump_queue_info("sp2host_isys_event",
|
&css_queues.sp2host_isys_event_queue_handle);
|
bufq_dump_queue_info("host2sp_tag_cmd",
|
&css_queues.host2sp_tag_cmd_queue_handle);
|
}
|