blob: 6a75cba4886f325cd360ae47e871685d7ea45486 [file] [log] [blame]
// 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);
}