550 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			550 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | |
| /*
 | |
|  * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
 | |
|  *
 | |
|  * Helper functions for handling messages that are send via mailbox to the
 | |
|  * Allegro VCU firmware.
 | |
|  */
 | |
| 
 | |
| #include <linux/bitfield.h>
 | |
| #include <linux/export.h>
 | |
| #include <linux/errno.h>
 | |
| #include <linux/string.h>
 | |
| #include <linux/videodev2.h>
 | |
| 
 | |
| #include "allegro-mail.h"
 | |
| 
 | |
| const char *msg_type_name(enum mcu_msg_type type)
 | |
| {
 | |
| 	static char buf[9];
 | |
| 
 | |
| 	switch (type) {
 | |
| 	case MCU_MSG_TYPE_INIT:
 | |
| 		return "INIT";
 | |
| 	case MCU_MSG_TYPE_CREATE_CHANNEL:
 | |
| 		return "CREATE_CHANNEL";
 | |
| 	case MCU_MSG_TYPE_DESTROY_CHANNEL:
 | |
| 		return "DESTROY_CHANNEL";
 | |
| 	case MCU_MSG_TYPE_ENCODE_FRAME:
 | |
| 		return "ENCODE_FRAME";
 | |
| 	case MCU_MSG_TYPE_PUT_STREAM_BUFFER:
 | |
| 		return "PUT_STREAM_BUFFER";
 | |
| 	case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:
 | |
| 		return "PUSH_BUFFER_INTERMEDIATE";
 | |
| 	case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:
 | |
| 		return "PUSH_BUFFER_REFERENCE";
 | |
| 	default:
 | |
| 		snprintf(buf, sizeof(buf), "(0x%04x)", type);
 | |
| 		return buf;
 | |
| 	}
 | |
| }
 | |
| EXPORT_SYMBOL(msg_type_name);
 | |
| 
 | |
| static ssize_t
 | |
| allegro_enc_init(u32 *dst, struct mcu_msg_init_request *msg)
 | |
| {
 | |
| 	unsigned int i = 0;
 | |
| 	enum mcu_msg_version version = msg->header.version;
 | |
| 
 | |
| 	dst[i++] = msg->reserved0;
 | |
| 	dst[i++] = msg->suballoc_dma;
 | |
| 	dst[i++] = msg->suballoc_size;
 | |
| 	dst[i++] = msg->encoder_buffer_size;
 | |
| 	dst[i++] = msg->encoder_buffer_color_depth;
 | |
| 	dst[i++] = msg->num_cores;
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2) {
 | |
| 		dst[i++] = msg->clk_rate;
 | |
| 		dst[i++] = 0;
 | |
| 	}
 | |
| 
 | |
| 	return i * sizeof(*dst);
 | |
| }
 | |
| 
 | |
| static inline u32 settings_get_mcu_codec(struct create_channel_param *param)
 | |
| {
 | |
| 	enum mcu_msg_version version = param->version;
 | |
| 	u32 pixelformat = param->codec;
 | |
| 
 | |
| 	if (version < MCU_MSG_VERSION_2019_2) {
 | |
| 		switch (pixelformat) {
 | |
| 		case V4L2_PIX_FMT_HEVC:
 | |
| 			return 2;
 | |
| 		case V4L2_PIX_FMT_H264:
 | |
| 		default:
 | |
| 			return 1;
 | |
| 		}
 | |
| 	} else {
 | |
| 		switch (pixelformat) {
 | |
| 		case V4L2_PIX_FMT_HEVC:
 | |
| 			return 1;
 | |
| 		case V4L2_PIX_FMT_H264:
 | |
| 		default:
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| ssize_t
 | |
| allegro_encode_config_blob(u32 *dst, struct create_channel_param *param)
 | |
| {
 | |
| 	enum mcu_msg_version version = param->version;
 | |
| 	unsigned int i = 0;
 | |
| 	unsigned int j = 0;
 | |
| 	u32 val;
 | |
| 	unsigned int codec = settings_get_mcu_codec(param);
 | |
| 
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2)
 | |
| 		dst[i++] = param->layer_id;
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(31, 16), param->height) |
 | |
| 		   FIELD_PREP(GENMASK(15, 0), param->width);
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2)
 | |
| 		dst[i++] = param->videomode;
 | |
| 	dst[i++] = param->format;
 | |
| 	if (version < MCU_MSG_VERSION_2019_2)
 | |
| 		dst[i++] = param->colorspace;
 | |
| 	dst[i++] = param->src_mode;
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2)
 | |
| 		dst[i++] = param->src_bit_depth;
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(31, 24), codec) |
 | |
| 		   FIELD_PREP(GENMASK(23, 8), param->constraint_set_flags) |
 | |
| 		   FIELD_PREP(GENMASK(7, 0), param->profile);
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(31, 16), param->tier) |
 | |
| 		   FIELD_PREP(GENMASK(15, 0), param->level);
 | |
| 
 | |
| 	val = 0;
 | |
| 	val |= param->temporal_mvp_enable ? BIT(20) : 0;
 | |
| 	val |= FIELD_PREP(GENMASK(7, 4), param->log2_max_frame_num);
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2)
 | |
| 		val |= FIELD_PREP(GENMASK(3, 0), param->log2_max_poc - 1);
 | |
| 	else
 | |
| 		val |= FIELD_PREP(GENMASK(3, 0), param->log2_max_poc);
 | |
| 	dst[i++] = val;
 | |
| 
 | |
| 	val = 0;
 | |
| 	val |= param->enable_reordering ? BIT(0) : 0;
 | |
| 	val |= param->dbf_ovr_en ? BIT(2) : 0;
 | |
| 	val |= param->override_lf ? BIT(12) : 0;
 | |
| 	dst[i++] = val;
 | |
| 
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2) {
 | |
| 		val = 0;
 | |
| 		val |= param->custom_lda ? BIT(2) : 0;
 | |
| 		val |= param->rdo_cost_mode ? BIT(20) : 0;
 | |
| 		dst[i++] = val;
 | |
| 
 | |
| 		val = 0;
 | |
| 		val |= param->lf ? BIT(2) : 0;
 | |
| 		val |= param->lf_x_tile ? BIT(3) : 0;
 | |
| 		val |= param->lf_x_slice ? BIT(4) : 0;
 | |
| 		dst[i++] = val;
 | |
| 	} else {
 | |
| 		val = 0;
 | |
| 		dst[i++] = val;
 | |
| 	}
 | |
| 
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(15, 8), param->beta_offset) |
 | |
| 		   FIELD_PREP(GENMASK(7, 0), param->tc_offset);
 | |
| 	dst[i++] = param->unknown11;
 | |
| 	dst[i++] = param->unknown12;
 | |
| 	dst[i++] = param->num_slices;
 | |
| 	dst[i++] = param->encoder_buffer_offset;
 | |
| 	dst[i++] = param->encoder_buffer_enabled;
 | |
| 
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(31, 16), param->clip_vrt_range) |
 | |
| 		   FIELD_PREP(GENMASK(15, 0), param->clip_hrz_range);
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(31, 16), param->me_range[1]) |
 | |
| 		   FIELD_PREP(GENMASK(15, 0), param->me_range[0]);
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(31, 16), param->me_range[3]) |
 | |
| 		   FIELD_PREP(GENMASK(15, 0), param->me_range[2]);
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(31, 24), param->min_tu_size) |
 | |
| 		   FIELD_PREP(GENMASK(23, 16), param->max_tu_size) |
 | |
| 		   FIELD_PREP(GENMASK(15, 8), param->min_cu_size) |
 | |
| 		   FIELD_PREP(GENMASK(8, 0), param->max_cu_size);
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(15, 8), param->max_transfo_depth_intra) |
 | |
| 		   FIELD_PREP(GENMASK(7, 0), param->max_transfo_depth_inter);
 | |
| 	dst[i++] = param->entropy_mode;
 | |
| 	dst[i++] = param->wp_mode;
 | |
| 
 | |
| 	dst[i++] = param->rate_control_mode;
 | |
| 	dst[i++] = param->initial_rem_delay;
 | |
| 	dst[i++] = param->cpb_size;
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(31, 16), param->clk_ratio) |
 | |
| 		   FIELD_PREP(GENMASK(15, 0), param->framerate);
 | |
| 	dst[i++] = param->target_bitrate;
 | |
| 	dst[i++] = param->max_bitrate;
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(31, 16), param->min_qp) |
 | |
| 		   FIELD_PREP(GENMASK(15, 0), param->initial_qp);
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(31, 16), param->ip_delta) |
 | |
| 		   FIELD_PREP(GENMASK(15, 0), param->max_qp);
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(31, 16), param->golden_ref) |
 | |
| 		   FIELD_PREP(GENMASK(15, 0), param->pb_delta);
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(31, 16), param->golden_ref_frequency) |
 | |
| 		   FIELD_PREP(GENMASK(15, 0), param->golden_delta);
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2)
 | |
| 		dst[i++] = param->rate_control_option;
 | |
| 	else
 | |
| 		dst[i++] = 0;
 | |
| 
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2) {
 | |
| 		dst[i++] = param->num_pixel;
 | |
| 		dst[i++] = FIELD_PREP(GENMASK(31, 16), param->max_pixel_value) |
 | |
| 			FIELD_PREP(GENMASK(15, 0), param->max_psnr);
 | |
| 		for (j = 0; j < 3; j++)
 | |
| 			dst[i++] = param->maxpicturesize[j];
 | |
| 	}
 | |
| 
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2)
 | |
| 		dst[i++] = param->gop_ctrl_mode;
 | |
| 	else
 | |
| 		dst[i++] = 0;
 | |
| 
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2)
 | |
| 		dst[i++] = FIELD_PREP(GENMASK(31, 24), param->freq_golden_ref) |
 | |
| 			   FIELD_PREP(GENMASK(23, 16), param->num_b) |
 | |
| 			   FIELD_PREP(GENMASK(15, 0), param->gop_length);
 | |
| 	dst[i++] = param->freq_idr;
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2)
 | |
| 		dst[i++] = param->enable_lt;
 | |
| 	dst[i++] = param->freq_lt;
 | |
| 	dst[i++] = param->gdr_mode;
 | |
| 	if (version < MCU_MSG_VERSION_2019_2)
 | |
| 		dst[i++] = FIELD_PREP(GENMASK(31, 24), param->freq_golden_ref) |
 | |
| 			   FIELD_PREP(GENMASK(23, 16), param->num_b) |
 | |
| 			   FIELD_PREP(GENMASK(15, 0), param->gop_length);
 | |
| 
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2)
 | |
| 		dst[i++] = param->tmpdqp;
 | |
| 
 | |
| 	dst[i++] = param->subframe_latency;
 | |
| 	dst[i++] = param->lda_control_mode;
 | |
| 	if (version < MCU_MSG_VERSION_2019_2)
 | |
| 		dst[i++] = param->unknown41;
 | |
| 
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2) {
 | |
| 		for (j = 0; j < 6; j++)
 | |
| 			dst[i++] = param->lda_factors[j];
 | |
| 		dst[i++] = param->max_num_merge_cand;
 | |
| 	}
 | |
| 
 | |
| 	return i * sizeof(*dst);
 | |
| }
 | |
| 
 | |
| static ssize_t
 | |
| allegro_enc_create_channel(u32 *dst, struct mcu_msg_create_channel *msg)
 | |
| {
 | |
| 	enum mcu_msg_version version = msg->header.version;
 | |
| 	unsigned int i = 0;
 | |
| 
 | |
| 	dst[i++] = msg->user_id;
 | |
| 
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2) {
 | |
| 		dst[i++] = msg->blob_mcu_addr;
 | |
| 	} else {
 | |
| 		memcpy(&dst[i], msg->blob, msg->blob_size);
 | |
| 		i += msg->blob_size / sizeof(*dst);
 | |
| 	}
 | |
| 
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2)
 | |
| 		dst[i++] = msg->ep1_addr;
 | |
| 
 | |
| 	return i * sizeof(*dst);
 | |
| }
 | |
| 
 | |
| ssize_t allegro_decode_config_blob(struct create_channel_param *param,
 | |
| 				   struct mcu_msg_create_channel_response *msg,
 | |
| 				   u32 *src)
 | |
| {
 | |
| 	enum mcu_msg_version version = msg->header.version;
 | |
| 
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2) {
 | |
| 		param->num_ref_idx_l0 = FIELD_GET(GENMASK(7, 4), src[9]);
 | |
| 		param->num_ref_idx_l1 = FIELD_GET(GENMASK(11, 8), src[9]);
 | |
| 	} else {
 | |
| 		param->num_ref_idx_l0 = msg->num_ref_idx_l0;
 | |
| 		param->num_ref_idx_l1 = msg->num_ref_idx_l1;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static ssize_t
 | |
| allegro_enc_destroy_channel(u32 *dst, struct mcu_msg_destroy_channel *msg)
 | |
| {
 | |
| 	unsigned int i = 0;
 | |
| 
 | |
| 	dst[i++] = msg->channel_id;
 | |
| 
 | |
| 	return i * sizeof(*dst);
 | |
| }
 | |
| 
 | |
| static ssize_t
 | |
| allegro_enc_push_buffers(u32 *dst, struct mcu_msg_push_buffers_internal *msg)
 | |
| {
 | |
| 	unsigned int i = 0;
 | |
| 	struct mcu_msg_push_buffers_internal_buffer *buffer;
 | |
| 	unsigned int num_buffers = msg->num_buffers;
 | |
| 	unsigned int j;
 | |
| 
 | |
| 	dst[i++] = msg->channel_id;
 | |
| 
 | |
| 	for (j = 0; j < num_buffers; j++) {
 | |
| 		buffer = &msg->buffer[j];
 | |
| 		dst[i++] = buffer->dma_addr;
 | |
| 		dst[i++] = buffer->mcu_addr;
 | |
| 		dst[i++] = buffer->size;
 | |
| 	}
 | |
| 
 | |
| 	return i * sizeof(*dst);
 | |
| }
 | |
| 
 | |
| static ssize_t
 | |
| allegro_enc_put_stream_buffer(u32 *dst,
 | |
| 			      struct mcu_msg_put_stream_buffer *msg)
 | |
| {
 | |
| 	unsigned int i = 0;
 | |
| 
 | |
| 	dst[i++] = msg->channel_id;
 | |
| 	dst[i++] = msg->dma_addr;
 | |
| 	dst[i++] = msg->mcu_addr;
 | |
| 	dst[i++] = msg->size;
 | |
| 	dst[i++] = msg->offset;
 | |
| 	dst[i++] = lower_32_bits(msg->dst_handle);
 | |
| 	dst[i++] = upper_32_bits(msg->dst_handle);
 | |
| 
 | |
| 	return i * sizeof(*dst);
 | |
| }
 | |
| 
 | |
| static ssize_t
 | |
| allegro_enc_encode_frame(u32 *dst, struct mcu_msg_encode_frame *msg)
 | |
| {
 | |
| 	enum mcu_msg_version version = msg->header.version;
 | |
| 	unsigned int i = 0;
 | |
| 
 | |
| 	dst[i++] = msg->channel_id;
 | |
| 
 | |
| 	dst[i++] = msg->reserved;
 | |
| 	dst[i++] = msg->encoding_options;
 | |
| 	dst[i++] = FIELD_PREP(GENMASK(31, 16), msg->padding) |
 | |
| 		   FIELD_PREP(GENMASK(15, 0), msg->pps_qp);
 | |
| 
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2) {
 | |
| 		dst[i++] = 0;
 | |
| 		dst[i++] = 0;
 | |
| 		dst[i++] = 0;
 | |
| 		dst[i++] = 0;
 | |
| 	}
 | |
| 
 | |
| 	dst[i++] = lower_32_bits(msg->user_param);
 | |
| 	dst[i++] = upper_32_bits(msg->user_param);
 | |
| 	dst[i++] = lower_32_bits(msg->src_handle);
 | |
| 	dst[i++] = upper_32_bits(msg->src_handle);
 | |
| 	dst[i++] = msg->request_options;
 | |
| 	dst[i++] = msg->src_y;
 | |
| 	dst[i++] = msg->src_uv;
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2)
 | |
| 		dst[i++] = msg->is_10_bit;
 | |
| 	dst[i++] = msg->stride;
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2)
 | |
| 		dst[i++] = msg->format;
 | |
| 	dst[i++] = msg->ep2;
 | |
| 	dst[i++] = lower_32_bits(msg->ep2_v);
 | |
| 	dst[i++] = upper_32_bits(msg->ep2_v);
 | |
| 
 | |
| 	return i * sizeof(*dst);
 | |
| }
 | |
| 
 | |
| static ssize_t
 | |
| allegro_dec_init(struct mcu_msg_init_response *msg, u32 *src)
 | |
| {
 | |
| 	unsigned int i = 0;
 | |
| 
 | |
| 	msg->reserved0 = src[i++];
 | |
| 
 | |
| 	return i * sizeof(*src);
 | |
| }
 | |
| 
 | |
| static ssize_t
 | |
| allegro_dec_create_channel(struct mcu_msg_create_channel_response *msg,
 | |
| 			   u32 *src)
 | |
| {
 | |
| 	enum mcu_msg_version version = msg->header.version;
 | |
| 	unsigned int i = 0;
 | |
| 
 | |
| 	msg->channel_id = src[i++];
 | |
| 	msg->user_id = src[i++];
 | |
| 	/*
 | |
| 	 * Version >= MCU_MSG_VERSION_2019_2 is handled in
 | |
| 	 * allegro_decode_config_blob().
 | |
| 	 */
 | |
| 	if (version < MCU_MSG_VERSION_2019_2) {
 | |
| 		msg->options = src[i++];
 | |
| 		msg->num_core = src[i++];
 | |
| 		msg->num_ref_idx_l0 = FIELD_GET(GENMASK(7, 4), src[i]);
 | |
| 		msg->num_ref_idx_l1 = FIELD_GET(GENMASK(11, 8), src[i++]);
 | |
| 	}
 | |
| 	msg->int_buffers_count = src[i++];
 | |
| 	msg->int_buffers_size = src[i++];
 | |
| 	msg->rec_buffers_count = src[i++];
 | |
| 	msg->rec_buffers_size = src[i++];
 | |
| 	msg->reserved = src[i++];
 | |
| 	msg->error_code = src[i++];
 | |
| 
 | |
| 	return i * sizeof(*src);
 | |
| }
 | |
| 
 | |
| static ssize_t
 | |
| allegro_dec_destroy_channel(struct mcu_msg_destroy_channel_response *msg,
 | |
| 			    u32 *src)
 | |
| {
 | |
| 	unsigned int i = 0;
 | |
| 
 | |
| 	msg->channel_id = src[i++];
 | |
| 
 | |
| 	return i * sizeof(*src);
 | |
| }
 | |
| 
 | |
| static ssize_t
 | |
| allegro_dec_encode_frame(struct mcu_msg_encode_frame_response *msg, u32 *src)
 | |
| {
 | |
| 	enum mcu_msg_version version = msg->header.version;
 | |
| 	unsigned int i = 0;
 | |
| 	unsigned int j;
 | |
| 
 | |
| 	msg->channel_id = src[i++];
 | |
| 
 | |
| 	msg->dst_handle = src[i++];
 | |
| 	msg->dst_handle |= (((u64)src[i++]) << 32);
 | |
| 	msg->user_param = src[i++];
 | |
| 	msg->user_param |= (((u64)src[i++]) << 32);
 | |
| 	msg->src_handle = src[i++];
 | |
| 	msg->src_handle |= (((u64)src[i++]) << 32);
 | |
| 	msg->skip = FIELD_GET(GENMASK(31, 16), src[i]);
 | |
| 	msg->is_ref = FIELD_GET(GENMASK(15, 0), src[i++]);
 | |
| 	msg->initial_removal_delay = src[i++];
 | |
| 	msg->dpb_output_delay = src[i++];
 | |
| 	msg->size = src[i++];
 | |
| 	msg->frame_tag_size = src[i++];
 | |
| 	msg->stuffing = src[i++];
 | |
| 	msg->filler = src[i++];
 | |
| 	msg->num_row = FIELD_GET(GENMASK(31, 16), src[i]);
 | |
| 	msg->num_column = FIELD_GET(GENMASK(15, 0), src[i++]);
 | |
| 	msg->num_ref_idx_l1 = FIELD_GET(GENMASK(31, 24), src[i]);
 | |
| 	msg->num_ref_idx_l0 = FIELD_GET(GENMASK(23, 16), src[i]);
 | |
| 	msg->qp = FIELD_GET(GENMASK(15, 0), src[i++]);
 | |
| 	msg->partition_table_offset = src[i++];
 | |
| 	msg->partition_table_size = src[i++];
 | |
| 	msg->sum_complex = src[i++];
 | |
| 	for (j = 0; j < 4; j++)
 | |
| 		msg->tile_width[j] = src[i++];
 | |
| 	for (j = 0; j < 22; j++)
 | |
| 		msg->tile_height[j] = src[i++];
 | |
| 	msg->error_code = src[i++];
 | |
| 	msg->slice_type = src[i++];
 | |
| 	msg->pic_struct = src[i++];
 | |
| 	msg->reserved = FIELD_GET(GENMASK(31, 24), src[i]);
 | |
| 	msg->is_last_slice = FIELD_GET(GENMASK(23, 16), src[i]);
 | |
| 	msg->is_first_slice = FIELD_GET(GENMASK(15, 8), src[i]);
 | |
| 	msg->is_idr = FIELD_GET(GENMASK(7, 0), src[i++]);
 | |
| 
 | |
| 	msg->reserved1 = FIELD_GET(GENMASK(31, 16), src[i]);
 | |
| 	msg->pps_qp = FIELD_GET(GENMASK(15, 0), src[i++]);
 | |
| 
 | |
| 	msg->reserved2 = src[i++];
 | |
| 	if (version >= MCU_MSG_VERSION_2019_2) {
 | |
| 		msg->reserved3 = src[i++];
 | |
| 		msg->reserved4 = src[i++];
 | |
| 		msg->reserved5 = src[i++];
 | |
| 		msg->reserved6 = src[i++];
 | |
| 	}
 | |
| 
 | |
| 	return i * sizeof(*src);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * allegro_encode_mail() - Encode allegro messages to firmware format
 | |
|  * @dst: Pointer to the memory that will be filled with data
 | |
|  * @msg: The allegro message that will be encoded
 | |
|  */
 | |
| ssize_t allegro_encode_mail(u32 *dst, void *msg)
 | |
| {
 | |
| 	const struct mcu_msg_header *header = msg;
 | |
| 	ssize_t size;
 | |
| 
 | |
| 	if (!msg || !dst)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	switch (header->type) {
 | |
| 	case MCU_MSG_TYPE_INIT:
 | |
| 		size = allegro_enc_init(&dst[1], msg);
 | |
| 		break;
 | |
| 	case MCU_MSG_TYPE_CREATE_CHANNEL:
 | |
| 		size = allegro_enc_create_channel(&dst[1], msg);
 | |
| 		break;
 | |
| 	case MCU_MSG_TYPE_DESTROY_CHANNEL:
 | |
| 		size = allegro_enc_destroy_channel(&dst[1], msg);
 | |
| 		break;
 | |
| 	case MCU_MSG_TYPE_ENCODE_FRAME:
 | |
| 		size = allegro_enc_encode_frame(&dst[1], msg);
 | |
| 		break;
 | |
| 	case MCU_MSG_TYPE_PUT_STREAM_BUFFER:
 | |
| 		size = allegro_enc_put_stream_buffer(&dst[1], msg);
 | |
| 		break;
 | |
| 	case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:
 | |
| 	case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:
 | |
| 		size = allegro_enc_push_buffers(&dst[1], msg);
 | |
| 		break;
 | |
| 	default:
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * The encoded messages might have different length depending on
 | |
| 	 * the firmware version or certain fields. Therefore, we have to
 | |
| 	 * set the body length after encoding the message.
 | |
| 	 */
 | |
| 	dst[0] = FIELD_PREP(GENMASK(31, 16), header->type) |
 | |
| 		 FIELD_PREP(GENMASK(15, 0), size);
 | |
| 
 | |
| 	return size + sizeof(*dst);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * allegro_decode_mail() - Parse allegro messages from the firmware.
 | |
|  * @msg: The mcu_msg_response that will be filled with parsed values.
 | |
|  * @src: Pointer to the memory that will be parsed
 | |
|  *
 | |
|  * The message format in the mailbox depends on the firmware. Parse the
 | |
|  * different formats into a uniform message format that can be used without
 | |
|  * taking care of the firmware version.
 | |
|  */
 | |
| int allegro_decode_mail(void *msg, u32 *src)
 | |
| {
 | |
| 	struct mcu_msg_header *header;
 | |
| 
 | |
| 	if (!src || !msg)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	header = msg;
 | |
| 	header->type = FIELD_GET(GENMASK(31, 16), src[0]);
 | |
| 
 | |
| 	src++;
 | |
| 	switch (header->type) {
 | |
| 	case MCU_MSG_TYPE_INIT:
 | |
| 		allegro_dec_init(msg, src);
 | |
| 		break;
 | |
| 	case MCU_MSG_TYPE_CREATE_CHANNEL:
 | |
| 		allegro_dec_create_channel(msg, src);
 | |
| 		break;
 | |
| 	case MCU_MSG_TYPE_DESTROY_CHANNEL:
 | |
| 		allegro_dec_destroy_channel(msg, src);
 | |
| 		break;
 | |
| 	case MCU_MSG_TYPE_ENCODE_FRAME:
 | |
| 		allegro_dec_encode_frame(msg, src);
 | |
| 		break;
 | |
| 	default:
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 |