aboutsummaryrefslogtreecommitdiff
path: root/drivers/video/arm/v5xx/base/mve_com_host_interface_v1.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/arm/v5xx/base/mve_com_host_interface_v1.c')
-rw-r--r--drivers/video/arm/v5xx/base/mve_com_host_interface_v1.c821
1 files changed, 821 insertions, 0 deletions
diff --git a/drivers/video/arm/v5xx/base/mve_com_host_interface_v1.c b/drivers/video/arm/v5xx/base/mve_com_host_interface_v1.c
new file mode 100644
index 000000000000..19e6d47efa91
--- /dev/null
+++ b/drivers/video/arm/v5xx/base/mve_com_host_interface_v1.c
@@ -0,0 +1,821 @@
+/*
+ * (C) COPYRIGHT ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation, and any use by you of this program is subject to the terms
+ * of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained
+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef EMULATOR
+#include "emulator_userspace.h"
+#else
+#include <linux/types.h>
+#include <linux/delay.h>
+#endif
+
+#include "mve_session.h"
+#include "mve_com.h"
+#include "mve_rsrc_log.h"
+#include "mve_rsrc_log_ram.h"
+
+#include <host_interface_v1/mve_protocol_kernel.h>
+
+/**
+ * Write data at offset in the buffer pointed out by ptr.
+ * The type of the data is specified by the argument type.
+ */
+#define WRITE_QUEUE(ptr, type, offset, data) \
+ *((type *)&((ptr)[(offset) % MVE_COMM_QUEUE_SIZE_IN_WORDS])) = data
+
+/**
+ * Read data at offset in the buffer pointed out by src.
+ * The type of data is specified by the type argument.
+ */
+#define READ_QUEUE(src, type, offset, dst) \
+ dst = *((type *)&((src)[(offset) % MVE_COMM_QUEUE_SIZE_IN_WORDS]))
+
+/**
+ * Round up value. Rounding must be power of 2.
+ */
+#define ROUNDUP(v, r) (((v) + (r) - 1) & ~(r - 1))
+
+/**
+ * Convert from driver buffer structure to FW buffer structure.
+ */
+static void convert_to_mve_buffer(struct mve_session *session,
+ mve_com_buffer *src,
+ union MVE_BUFFER *dst,
+ enum mve_com_buffer_type type)
+{
+ int i;
+
+ memset(dst, 0, sizeof(union MVE_BUFFER));
+
+ switch (type)
+ {
+ case MVE_COM_BUFFER_TYPE_FRAME:
+ dst->frame.nHandle = src->frame.nHandle;
+ dst->frame.nFlags = src->frame.nFlags;
+ dst->frame.nUserDataTag = src->frame.timestamp;
+ dst->frame.nMVEFlags = src->frame.nMVEFlags;
+ dst->frame.pic_index = src->frame.pic_index;
+ dst->frame.decoded_height = src->frame.decoded_height;
+ dst->frame.decoded_width = src->frame.decoded_width;
+ memcpy(&dst->frame.data, &src->frame.data, sizeof(dst->frame.data));
+ dst->frame.crc_top = src->frame.crc_top;
+ dst->frame.crc_bot = src->frame.crc_bot;
+
+ if ((dst->frame.nMVEFlags & (MVE_FLAGS_TOP_PRESENT | MVE_FLAGS_BOT_PRESENT)) == 0)
+ {
+ dst->frame.decoded_height = 0;
+ dst->frame.decoded_width = 0;
+ }
+ break;
+ case MVE_COM_BUFFER_TYPE_BITSTREAM:
+ dst->bitstream.nHandle = src->bitstream.nHandle;
+ dst->bitstream.nFlags = src->bitstream.nFlags;
+ dst->bitstream.nUserDataTag = src->bitstream.timestamp;
+ dst->bitstream.nAllocLen = src->bitstream.nAllocLen;
+ dst->bitstream.nOffset = src->bitstream.nOffset;
+ dst->bitstream.nFilledLen = src->bitstream.nFilledLen;
+ dst->bitstream.pBufferData = src->bitstream.pBufferData;
+ break;
+ case MVE_COM_BUFFER_TYPE_ROI:
+ dst->region.nRegions = src->roi.nRegions;
+ for (i = 0; i < src->roi.nRegions; ++i)
+ {
+ dst->region.region[i].mbx_left = src->roi.regions[i].mbx_left;
+ dst->region.region[i].mbx_right = src->roi.regions[i].mbx_right;
+ dst->region.region[i].mby_bottom = src->roi.regions[i].mby_bottom;
+ dst->region.region[i].mby_top = src->roi.regions[i].mby_top;
+ dst->region.region[i].qp_delta = (int8_t)src->roi.regions[i].qp_delta;
+ }
+ break;
+ }
+}
+
+/**
+ * Convert from FW buffer structure to driver buffer structure.
+ */
+static void convert_from_mve_buffer(struct mve_session *session,
+ union MVE_BUFFER *src,
+ mve_com_buffer *dst,
+ enum mve_com_buffer_type type)
+{
+ switch (type)
+ {
+ case MVE_COM_BUFFER_TYPE_FRAME:
+ dst->frame.nHandle = src->frame.nHandle;
+ dst->frame.nFlags = src->frame.nFlags;
+ dst->frame.timestamp = src->frame.nUserDataTag;
+ dst->frame.nMVEFlags = src->frame.nMVEFlags;
+ dst->frame.pic_index = src->frame.pic_index;
+ dst->frame.decoded_height = src->frame.decoded_height;
+ dst->frame.decoded_width = src->frame.decoded_width;
+ memcpy(&dst->frame.data, &src->frame.data, sizeof(src->frame.data));
+ dst->frame.crc_top = src->frame.crc_top;
+ dst->frame.crc_bot = src->frame.crc_bot;
+ break;
+ case MVE_COM_BUFFER_TYPE_BITSTREAM:
+ dst->bitstream.nHandle = src->bitstream.nHandle;
+ dst->bitstream.nFlags = src->bitstream.nFlags;
+ dst->bitstream.timestamp = src->bitstream.nUserDataTag;
+ dst->bitstream.nAllocLen = src->bitstream.nAllocLen;
+ dst->bitstream.nOffset = src->bitstream.nOffset;
+ dst->bitstream.nFilledLen = src->bitstream.nFilledLen;
+ dst->bitstream.pBufferData = src->bitstream.pBufferData;
+ break;
+ default:
+ WARN_ON(true); /* Should never end up here */
+ break;
+ }
+}
+
+/**
+ * Waits until there is enough space available in the message in-queue to
+ * add a message of a given size. If a static timeout expires, this function
+ * returns false.
+ * @param rpos Pointer to read position in the queue.
+ * @param wpos Pointer to write position in the queue.
+ * @param words Number of data slot required in the message queue.
+ * @param queue_size Size of the queue
+ * @return MVE_BASE_ERROR_NONE if there is enough space available in the queue to add
+ * a message of the given size. MVE_BASE_ERROR_TIMEOUT if the timeout triggered.
+ */
+static mve_base_error wait_until_space_available(volatile uint16_t *rpos,
+ volatile uint16_t *wpos,
+ uint32_t words,
+ uint32_t queue_size)
+{
+#define ITERATION_TIMEOUT 100
+ int i = 0;
+ mve_base_error ret = MVE_BASE_ERROR_NONE;
+ uint32_t free_words;
+
+ if (words > queue_size)
+ {
+ return MVE_BASE_ERROR_TIMEOUT;
+ }
+
+ do
+ {
+ if (*rpos <= *wpos)
+ {
+ free_words = queue_size - *wpos + *rpos;
+ }
+ else
+ {
+ free_words = *rpos - *wpos;
+ }
+ i++;
+ mb();
+ }
+ while (free_words < (words + 1) && i < ITERATION_TIMEOUT);
+
+ /* Did we timeout? */
+ if (i >= ITERATION_TIMEOUT)
+ {
+ ret = MVE_BASE_ERROR_TIMEOUT;
+ }
+
+ return ret;
+#undef ITERATION_TIMEOUT
+}
+
+/**
+ * Write data the input queue represented by host_area.
+ * @param host_area The host area of the queue.
+ * @param mve_area The MVE area of the queue.
+ * @param header Header of the message to add.
+ * @param data Data section of the message to add.
+ * @param num_words Size of the data section in 32-bit words.
+ * @return MVE_BASE_ERROR_NONE if the message was added to the queue. Error code otherwise.
+ */
+static mve_base_error write_to_queue(struct mve_comm_area_host *host_area,
+ struct mve_comm_area_mve *mve_area,
+ struct mve_msg_header *header,
+ uint32_t *data,
+ uint32_t num_words)
+{
+ mve_base_error ret;
+ uint32_t i;
+ uint16_t wpos;
+
+ ret = wait_until_space_available(&mve_area->in_rpos,
+ &host_area->in_wpos,
+ 1 + num_words,
+ MVE_COMM_QUEUE_SIZE_IN_WORDS);
+ if (MVE_BASE_ERROR_NONE == ret)
+ {
+ wpos = host_area->in_wpos;
+ WRITE_QUEUE(host_area->in_data, struct mve_msg_header, wpos, *header);
+ wpos = (wpos + 1) % MVE_COMM_QUEUE_SIZE_IN_WORDS;
+ for (i = 0; i < num_words; ++i)
+ {
+ WRITE_QUEUE(host_area->in_data, uint32_t, wpos, data[i]);
+ wpos = (wpos + 1) % MVE_COMM_QUEUE_SIZE_IN_WORDS;
+ }
+
+ mve_rsrc_mem_flush_write_buffer();
+ host_area->in_wpos = wpos;
+ mve_rsrc_mem_flush_write_buffer();
+ }
+
+ return ret;
+}
+
+static void read_from_queue(struct mve_comm_area_host *host_area,
+ struct mve_comm_area_mve *mve_area,
+ struct mve_msg_header *header,
+ uint32_t *dst)
+{
+ uint16_t rpos;
+ uint32_t i, words;
+
+ WARN_ON((unsigned short)0 >= (unsigned short)(mve_area->out_wpos - host_area->out_rpos));
+ rpos = host_area->out_rpos;
+ READ_QUEUE(mve_area->out_data, struct mve_msg_header, rpos, *header);
+ rpos = (rpos + 1) % MVE_COMM_QUEUE_SIZE_IN_WORDS;
+ words = (header->size + sizeof(uint32_t) - 1) / sizeof(uint32_t);
+
+ for (i = 0; i < words; ++i)
+ {
+ READ_QUEUE(mve_area->out_data, uint32_t, rpos, dst[i]);
+ rpos = (rpos + 1) % MVE_COMM_QUEUE_SIZE_IN_WORDS;
+ }
+
+ mve_rsrc_mem_flush_write_buffer();
+ host_area->out_rpos = rpos;
+ mve_rsrc_mem_flush_write_buffer();
+}
+
+static void log_header(struct iovec *vec,
+ unsigned count,
+ struct mve_session *session,
+ enum mve_log_fwif_channel channel,
+ enum mve_log_fwif_direction direction)
+{
+ struct mve_log_header header;
+ struct mve_log_fwif fwif;
+ struct timespec timespec;
+ unsigned i;
+
+ getnstimeofday(&timespec);
+
+ header.magic = MVE_LOG_MAGIC;
+ header.length = 0;
+ header.type = MVE_LOG_TYPE_FWIF;
+ header.severity = MVE_LOG_INFO;
+ header.timestamp.sec = timespec.tv_sec;
+ header.timestamp.nsec = timespec.tv_nsec;
+
+ fwif.version_minor = 0;
+ fwif.version_major = 1;
+ fwif.channel = channel;
+ fwif.direction = direction;
+ fwif.session = (uintptr_t)session;
+
+ vec[0].iov_base = &header;
+ vec[0].iov_len = sizeof(header);
+
+ vec[1].iov_base = &fwif;
+ vec[1].iov_len = sizeof(fwif);
+
+ for (i = 1; i < count; ++i)
+ {
+ header.length += vec[i].iov_len;
+ }
+
+ MVE_LOG_DATA(&mve_rsrc_log_fwif, MVE_LOG_INFO, vec, count);
+}
+
+static void log_buffer(struct mve_session *session,
+ enum mve_log_fwif_channel channel,
+ enum mve_log_fwif_direction direction,
+ struct mve_msg_header *msg_header,
+ void *data,
+ unsigned queued)
+{
+ struct
+ {
+ struct mve_msg_header msg_header;
+ struct mve_log_fwif_stat stat;
+ }
+ stat;
+ struct iovec vec[5];
+
+ stat.msg_header.code = MVE_LOG_FWIF_CODE_STAT;
+ stat.msg_header.size = sizeof(stat.stat);
+ stat.stat.handle = 0;
+ stat.stat.queued = queued;
+
+ vec[2].iov_base = msg_header;
+ vec[2].iov_len = sizeof(*msg_header);
+
+ vec[3].iov_base = data;
+ vec[3].iov_len = ROUNDUP(msg_header->size, 4);
+
+ vec[4].iov_base = &stat;
+ vec[4].iov_len = ROUNDUP(sizeof(stat), 4);
+
+ log_header(vec, 5, session, channel, direction);
+}
+
+static void log_message(struct mve_session *session,
+ enum mve_log_fwif_direction direction,
+ struct mve_msg_header *msg_header,
+ void *data)
+{
+ struct iovec vec[4];
+
+ vec[2].iov_base = msg_header;
+ vec[2].iov_len = sizeof(*msg_header);
+
+ vec[3].iov_base = data;
+ vec[3].iov_len = msg_header->size;
+
+ log_header(vec, 4, session, MVE_LOG_FWIF_CHANNEL_MESSAGE, direction);
+}
+
+static mve_base_error add_message(struct mve_session *session,
+ uint16_t code,
+ uint16_t size,
+ uint32_t *data)
+{
+ mve_base_error ret = MVE_BASE_ERROR_NONE;
+
+ struct mve_comm_area_host *host_area;
+ struct mve_comm_area_mve *mve_area;
+
+ if (0 < size && NULL == data)
+ {
+ return MVE_BASE_ERROR_BAD_PARAMETER;
+ }
+
+ host_area = mve_rsrc_dma_mem_map(session->msg_in_queue);
+ mve_area = mve_rsrc_dma_mem_map(session->msg_out_queue);
+
+ if (NULL == host_area || NULL == mve_area)
+ {
+ ret = MVE_BASE_ERROR_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ uint32_t words;
+ struct mve_msg_header header;
+
+ header.code = code;
+ header.size = size;
+
+ words = (size + sizeof(uint32_t) - 1) / sizeof(uint32_t);
+ ret = write_to_queue(host_area, mve_area, &header, data, words);
+
+ MVE_LOG_EXECUTE(&mve_rsrc_log_fwif, MVE_LOG_INFO,
+ log_message(session, MVE_LOG_FWIF_DIRECTION_HOST_TO_FIRMWARE, &header, data));
+ }
+
+ switch (code)
+ {
+ case MVE_MESSAGE_CODE_GO:
+ case MVE_MESSAGE_CODE_STOP:
+ case MVE_MESSAGE_CODE_SET_PARAMETER:
+ case MVE_MESSAGE_CODE_GET_PARAMETER:
+ case MVE_MESSAGE_CODE_SET_CONFIG:
+ case MVE_MESSAGE_CODE_GET_CONFIG:
+ case MVE_MESSAGE_CODE_INPUT_FLUSH:
+ case MVE_MESSAGE_CODE_OUTPUT_FLUSH:
+ session->pending_response_count++;
+ break;
+ default:
+ break;
+ }
+
+ mve_rsrc_dma_mem_unmap(session->msg_out_queue);
+ mve_rsrc_dma_mem_unmap(session->msg_in_queue);
+
+ return ret;
+}
+
+static uint32_t *get_message(struct mve_session *session,
+ struct mve_msg_header *header)
+{
+ uint32_t *ret = NULL;
+ uint32_t available_words;
+
+ struct mve_comm_area_host *host_area;
+ struct mve_comm_area_mve *mve_area;
+
+ if (NULL == header)
+ {
+ return NULL;
+ }
+
+ host_area = mve_rsrc_dma_mem_map(session->msg_in_queue);
+ mve_area = mve_rsrc_dma_mem_map(session->msg_out_queue);
+
+ mve_rsrc_dma_mem_invalidate_cache(session->msg_out_queue);
+
+ if (host_area->out_rpos <= mve_area->out_wpos)
+ {
+ available_words = mve_area->out_wpos - host_area->out_rpos;
+ }
+ else
+ {
+ available_words = MVE_COMM_QUEUE_SIZE_IN_WORDS + mve_area->out_wpos - host_area->out_rpos;
+ }
+
+ if (available_words > 0)
+ {
+ /* There is a message in the queue */
+ uint16_t rpos;
+ uint32_t words;
+
+ rpos = host_area->out_rpos;
+
+ *header = *((struct mve_msg_header *)&mve_area->out_data[rpos]);
+ rpos = (rpos + 1) % MVE_COMM_QUEUE_SIZE_IN_WORDS;
+
+ words = (header->size + sizeof(uint32_t) - 1) / sizeof(uint32_t);
+
+ ret = MVE_RSRC_MEM_CACHE_ALLOC(words * sizeof(uint32_t), GFP_KERNEL);
+ if (NULL == ret)
+ {
+ /* Failed to allocate temporary memory needed to process this
+ * message. This message will be dropped! */
+ MVE_LOG_PRINT_SESSION(&mve_rsrc_log_session, MVE_LOG_WARNING, session, "Message from MVE dropped due to out of memory conditions.");
+ /* Update rpos to skip this message */
+ rpos += words;
+ }
+ else
+ {
+ int i;
+
+ /* Read the data associated with the message */
+ for (i = 0; i < words; ++i)
+ {
+ ret[i] = mve_area->out_data[rpos];
+ rpos = (rpos + 1) % MVE_COMM_QUEUE_SIZE_IN_WORDS;
+ }
+
+ mb();
+
+ MVE_LOG_EXECUTE(&mve_rsrc_log_fwif, MVE_LOG_INFO,
+ log_message(session, MVE_LOG_FWIF_DIRECTION_FIRMWARE_TO_HOST, header, ret));
+ }
+
+ host_area->out_rpos = rpos;
+ mb();
+
+ switch (header->code)
+ {
+ case MVE_RESPONSE_CODE_STATE_CHANGE:
+ case MVE_RESPONSE_CODE_GET_PARAMETER_REPLY:
+ case MVE_RESPONSE_CODE_SET_PARAMETER_REPLY:
+ case MVE_RESPONSE_CODE_GET_CONFIG_REPLY:
+ case MVE_RESPONSE_CODE_SET_CONFIG_REPLY:
+ case MVE_RESPONSE_CODE_INPUT_FLUSHED:
+ case MVE_RESPONSE_CODE_OUTPUT_FLUSHED:
+ session->pending_response_count--;
+ break;
+ default:
+ break;
+ }
+
+ mve_rsrc_dma_mem_clean_cache(session->msg_in_queue);
+ mve_rsrc_dma_mem_invalidate_cache(session->msg_out_queue);
+ }
+
+ mve_rsrc_dma_mem_unmap(session->msg_out_queue);
+ mve_rsrc_dma_mem_unmap(session->msg_in_queue);
+
+ return ret;
+}
+
+/**
+ * Send a buffer message to the FW.
+ */
+static mve_base_error send_buffer_msg(struct mve_session *session,
+ mve_com_buffer *buffer,
+ enum mve_com_buffer_type type,
+ struct mve_comm_area_host *host_area,
+ struct mve_comm_area_mve *mve_area,
+ union MVE_BUFFER *mve_buffer,
+ struct mve_msg_header *header)
+{
+ mve_base_error ret = MVE_BASE_ERROR_NONE;
+
+ switch (type)
+ {
+ case MVE_COM_BUFFER_TYPE_BITSTREAM:
+ header->code = MVE_MSG_HEADER_CODE_BUFFER_BITSTREAM;
+ header->size = sizeof(struct MVE_BUFFER_BITSTREAM);
+ break;
+
+ case MVE_COM_BUFFER_TYPE_FRAME:
+ header->code = MVE_MSG_HEADER_CODE_BUFFER_FRAME;
+ header->size = sizeof(struct MVE_BUFFER_FRAME);
+ break;
+
+ case MVE_COM_BUFFER_TYPE_ROI:
+ header->code = MVE_MSG_HEADER_CODE_BUFFER_REGION;
+ header->size = sizeof(struct MVE_BUFFER_REGION);
+ break;
+
+ default:
+ MVE_LOG_PRINT(&mve_rsrc_log, MVE_LOG_ERROR, "Unknown type (%d).", type);
+ ret = MVE_BASE_ERROR_BAD_PARAMETER;
+ }
+
+ if (MVE_BASE_ERROR_NONE == ret)
+ {
+ uint32_t words;
+ uint32_t *data;
+
+ convert_to_mve_buffer(session, buffer, mve_buffer, type);
+
+ words = (header->size + sizeof(uint32_t) - 1) / sizeof(uint32_t);
+ data = (uint32_t *)mve_buffer;
+ ret = write_to_queue(host_area, mve_area, header, data, words);
+ }
+
+ return ret;
+}
+
+static mve_base_error add_input_buffer(struct mve_session *session,
+ mve_com_buffer *buffer,
+ enum mve_com_buffer_type type)
+{
+ mve_base_error ret = MVE_BASE_ERROR_NONE;
+
+ struct mve_comm_area_host *host_area;
+ struct mve_comm_area_mve *mve_area;
+
+ host_area = mve_rsrc_dma_mem_map(session->buf_input_in);
+ mve_area = mve_rsrc_dma_mem_map(session->buf_input_out);
+
+ if (NULL == host_area || NULL == mve_area || NULL == buffer)
+ {
+ ret = MVE_BASE_ERROR_BAD_PARAMETER;
+ }
+ else
+ {
+ union MVE_BUFFER mve_buffer;
+ struct mve_msg_header header;
+
+ ret = send_buffer_msg(session, buffer, type, host_area, mve_area, &mve_buffer, &header);
+
+ if (MVE_BASE_ERROR_NONE == ret)
+ {
+ MVE_LOG_EXECUTE(&mve_rsrc_log_fwif, MVE_LOG_INFO,
+ log_buffer(session,
+ MVE_LOG_FWIF_CHANNEL_INPUT_BUFFER,
+ MVE_LOG_FWIF_DIRECTION_HOST_TO_FIRMWARE,
+ &header,
+ &mve_buffer,
+ session->input_buffer_count + 1));
+ }
+ }
+
+ mve_rsrc_dma_mem_unmap(session->buf_input_in);
+ mve_rsrc_dma_mem_unmap(session->buf_input_out);
+
+ return ret;
+}
+
+static mve_base_error add_output_buffer(struct mve_session *session,
+ mve_com_buffer *buffer,
+ enum mve_com_buffer_type type)
+{
+ mve_base_error ret = MVE_BASE_ERROR_NONE;
+
+ struct mve_comm_area_host *host_area;
+ struct mve_comm_area_mve *mve_area;
+
+ host_area = mve_rsrc_dma_mem_map(session->buf_output_in);
+ mve_area = mve_rsrc_dma_mem_map(session->buf_output_out);
+
+ if (NULL == host_area || NULL == mve_area || NULL == buffer)
+ {
+ ret = MVE_BASE_ERROR_BAD_PARAMETER;
+ }
+ else
+ {
+ union MVE_BUFFER mve_buffer;
+ struct mve_msg_header header;
+
+ ret = send_buffer_msg(session, buffer, type, host_area, mve_area, &mve_buffer, &header);
+
+ if (MVE_BASE_ERROR_NONE == ret)
+ {
+ MVE_LOG_EXECUTE(&mve_rsrc_log_fwif, MVE_LOG_INFO,
+ log_buffer(session,
+ MVE_LOG_FWIF_CHANNEL_OUTPUT_BUFFER,
+ MVE_LOG_FWIF_DIRECTION_HOST_TO_FIRMWARE,
+ &header,
+ &mve_buffer,
+ session->output_buffer_count + 1));
+ }
+ }
+
+ mve_rsrc_dma_mem_unmap(session->buf_output_in);
+ mve_rsrc_dma_mem_unmap(session->buf_output_out);
+
+ return ret;
+}
+
+static mve_base_error get_input_buffer(struct mve_session *session,
+ mve_com_buffer *buffer)
+{
+ mve_base_error ret = MVE_BASE_ERROR_BAD_PARAMETER;
+ struct mve_comm_area_host *host_area;
+ struct mve_comm_area_mve *mve_area;
+
+ host_area = mve_rsrc_dma_mem_map(session->buf_input_in);
+ mve_area = mve_rsrc_dma_mem_map(session->buf_input_out);
+ if (NULL != host_area && NULL != mve_area)
+ {
+ union MVE_BUFFER mve_buffer;
+ struct mve_msg_header header;
+ enum mve_com_buffer_type type;
+
+ mve_rsrc_dma_mem_invalidate_cache(session->buf_input_out);
+ read_from_queue(host_area, mve_area, &header, (uint32_t *)&mve_buffer);
+ mve_rsrc_dma_mem_clean_cache(session->buf_input_in);
+
+ type = (MVE_SESSION_TYPE_DECODER == session->session_type) ?
+ MVE_COM_BUFFER_TYPE_BITSTREAM :
+ MVE_COM_BUFFER_TYPE_FRAME;
+ convert_from_mve_buffer(session, &mve_buffer, buffer, type);
+ ret = MVE_BASE_ERROR_NONE;
+
+ MVE_LOG_EXECUTE(&mve_rsrc_log_fwif, MVE_LOG_INFO,
+ log_buffer(session, MVE_LOG_FWIF_CHANNEL_INPUT_BUFFER, MVE_LOG_FWIF_DIRECTION_FIRMWARE_TO_HOST, &header, &mve_buffer, session->input_buffer_count - 1));
+ }
+
+ mve_rsrc_dma_mem_unmap(session->buf_input_in);
+ mve_rsrc_dma_mem_unmap(session->buf_input_out);
+
+ return ret;
+}
+
+static mve_base_error get_output_buffer(struct mve_session *session,
+ mve_com_buffer *buffer)
+{
+ mve_base_error ret = MVE_BASE_ERROR_BAD_PARAMETER;
+ struct mve_comm_area_host *host_area;
+ struct mve_comm_area_mve *mve_area;
+
+ host_area = mve_rsrc_dma_mem_map(session->buf_output_in);
+ mve_area = mve_rsrc_dma_mem_map(session->buf_output_out);
+ if (NULL != host_area && NULL != mve_area)
+ {
+ union MVE_BUFFER mve_buffer;
+ struct mve_msg_header header;
+ enum mve_com_buffer_type type;
+
+ mve_rsrc_dma_mem_invalidate_cache(session->buf_output_out);
+ read_from_queue(host_area, mve_area, &header, (uint32_t *)&mve_buffer);
+ mve_rsrc_dma_mem_clean_cache(session->buf_output_in);
+
+ type = (MVE_SESSION_TYPE_DECODER == session->session_type) ?
+ MVE_COM_BUFFER_TYPE_FRAME :
+ MVE_COM_BUFFER_TYPE_BITSTREAM;
+ convert_from_mve_buffer(session, &mve_buffer, buffer, type);
+ ret = MVE_BASE_ERROR_NONE;
+
+ MVE_LOG_EXECUTE(&mve_rsrc_log_fwif, MVE_LOG_INFO,
+ log_buffer(session, MVE_LOG_FWIF_CHANNEL_OUTPUT_BUFFER, MVE_LOG_FWIF_DIRECTION_FIRMWARE_TO_HOST, &header, &mve_buffer, session->output_buffer_count - 1));
+ }
+
+ mve_rsrc_dma_mem_unmap(session->buf_output_in);
+ mve_rsrc_dma_mem_unmap(session->buf_output_out);
+
+ return ret;
+}
+
+static mve_base_error get_rpc_message(struct mve_session *session,
+ mve_com_rpc *rpc)
+{
+ struct mve_rpc_comunication_area *rpc_area;
+ mve_base_error err = MVE_BASE_ERROR_NOT_READY;
+
+ rpc_area = mve_rsrc_dma_mem_map(session->rpc_area);
+ if (NULL == rpc_area)
+ {
+ return MVE_BASE_ERROR_INSUFFICIENT_RESOURCES;
+ }
+
+ mve_rsrc_dma_mem_invalidate_cache(session->rpc_area);
+
+ if (MVE_RPC_STATE_PARAM == rpc_area->state)
+ {
+ /* Copy RPC details to the client supplied structure */
+ rpc->state = rpc_area->state;
+ rpc->call_id = rpc_area->call_id;
+ rpc->size = rpc_area->size;
+
+ switch (rpc_area->call_id)
+ {
+ case MVE_RPC_FUNCTION_DEBUG_PRINTF:
+ memcpy(rpc->params.debug_print.string,
+ rpc_area->params.debug_print.string,
+ MVE_RPC_DATA_SIZE_IN_WORDS * 4);
+ break;
+ case MVE_RPC_FUNCTION_MEM_ALLOC:
+ rpc->params.mem_alloc.size = rpc_area->params.mem_alloc.size;
+ rpc->params.mem_alloc.max_size = rpc_area->params.mem_alloc.max_size;
+ rpc->params.mem_alloc.region = rpc_area->params.mem_alloc.region;
+ rpc->params.mem_alloc.log2_alignment = MVE_MMU_PAGE_SHIFT;
+ break;
+ case MVE_RPC_FUNCTION_MEM_RESIZE:
+ rpc->params.mem_resize.ve_pointer = rpc_area->params.mem_resize.ve_pointer;
+ rpc->params.mem_resize.new_size = rpc_area->params.mem_resize.new_size;
+ break;
+ case MVE_RPC_FUNCTION_MEM_FREE:
+ rpc->params.mem_free.ve_pointer = rpc_area->params.mem_free.ve_pointer;
+ break;
+ }
+
+ err = MVE_BASE_ERROR_NONE;
+ }
+
+ mve_rsrc_dma_mem_unmap(session->rpc_area);
+
+ return err;
+}
+
+static mve_base_error put_rpc_message(struct mve_session *session,
+ mve_com_rpc *rpc)
+{
+ struct mve_rpc_comunication_area *rpc_area;
+
+ rpc_area = mve_rsrc_dma_mem_map(session->rpc_area);
+ if (NULL == rpc_area)
+ {
+ return MVE_BASE_ERROR_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Copy RPC details to the client supplied structure */
+ switch (rpc->call_id)
+ {
+ case MVE_RPC_FUNCTION_DEBUG_PRINTF:
+ break;
+ case MVE_RPC_FUNCTION_MEM_ALLOC:
+ rpc_area->params.data[0] = rpc->params.data[0];
+ break;
+ case MVE_RPC_FUNCTION_MEM_RESIZE:
+ rpc_area->params.data[0] = rpc->params.data[0];
+ break;
+ case MVE_RPC_FUNCTION_MEM_FREE:
+ break;
+ }
+
+ rpc_area->call_id = rpc->call_id;
+ rpc_area->size = rpc->size;
+ wmb();
+ rpc_area->state = rpc->state;
+
+ wmb();
+ mve_rsrc_dma_mem_clean_cache(session->rpc_area);
+ mve_rsrc_dma_mem_unmap(session->rpc_area);
+
+ return MVE_BASE_ERROR_NONE;
+}
+
+static void mve_com_host_interface_v1_construct(struct mve_com *com)
+{
+ memset(com, 0, sizeof(*com));
+
+ com->host_interface.add_message = add_message;
+ com->host_interface.get_message = get_message;
+ com->host_interface.add_input_buffer = add_input_buffer;
+ com->host_interface.add_output_buffer = add_output_buffer;
+ com->host_interface.get_input_buffer = get_input_buffer;
+ com->host_interface.get_output_buffer = get_output_buffer;
+ com->host_interface.get_rpc_message = get_rpc_message;
+ com->host_interface.put_rpc_message = put_rpc_message;
+}
+
+struct mve_com *mve_com_host_interface_v1_new(void)
+{
+ struct mve_com *com;
+
+ /* Allocate com object. */
+ com = MVE_RSRC_MEM_ZALLOC(sizeof(*com), GFP_KERNEL);
+ if (com == NULL)
+ {
+ MVE_LOG_PRINT(&mve_rsrc_log, MVE_LOG_WARNING, "Failed to allocate com object.");
+ return NULL;
+ }
+
+ /* Run constructor. */
+ mve_com_host_interface_v1_construct(com);
+
+ return com;
+}