162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Helper functions for handling messages that are send via mailbox to the 662306a36Sopenharmony_ci * Allegro VCU firmware. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/bitfield.h> 1062306a36Sopenharmony_ci#include <linux/export.h> 1162306a36Sopenharmony_ci#include <linux/errno.h> 1262306a36Sopenharmony_ci#include <linux/string.h> 1362306a36Sopenharmony_ci#include <linux/videodev2.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "allegro-mail.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ciconst char *msg_type_name(enum mcu_msg_type type) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci static char buf[9]; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci switch (type) { 2262306a36Sopenharmony_ci case MCU_MSG_TYPE_INIT: 2362306a36Sopenharmony_ci return "INIT"; 2462306a36Sopenharmony_ci case MCU_MSG_TYPE_CREATE_CHANNEL: 2562306a36Sopenharmony_ci return "CREATE_CHANNEL"; 2662306a36Sopenharmony_ci case MCU_MSG_TYPE_DESTROY_CHANNEL: 2762306a36Sopenharmony_ci return "DESTROY_CHANNEL"; 2862306a36Sopenharmony_ci case MCU_MSG_TYPE_ENCODE_FRAME: 2962306a36Sopenharmony_ci return "ENCODE_FRAME"; 3062306a36Sopenharmony_ci case MCU_MSG_TYPE_PUT_STREAM_BUFFER: 3162306a36Sopenharmony_ci return "PUT_STREAM_BUFFER"; 3262306a36Sopenharmony_ci case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE: 3362306a36Sopenharmony_ci return "PUSH_BUFFER_INTERMEDIATE"; 3462306a36Sopenharmony_ci case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE: 3562306a36Sopenharmony_ci return "PUSH_BUFFER_REFERENCE"; 3662306a36Sopenharmony_ci default: 3762306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "(0x%04x)", type); 3862306a36Sopenharmony_ci return buf; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ciEXPORT_SYMBOL(msg_type_name); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic ssize_t 4462306a36Sopenharmony_ciallegro_enc_init(u32 *dst, struct mcu_msg_init_request *msg) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci unsigned int i = 0; 4762306a36Sopenharmony_ci enum mcu_msg_version version = msg->header.version; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci dst[i++] = msg->reserved0; 5062306a36Sopenharmony_ci dst[i++] = msg->suballoc_dma; 5162306a36Sopenharmony_ci dst[i++] = msg->suballoc_size; 5262306a36Sopenharmony_ci dst[i++] = msg->encoder_buffer_size; 5362306a36Sopenharmony_ci dst[i++] = msg->encoder_buffer_color_depth; 5462306a36Sopenharmony_ci dst[i++] = msg->num_cores; 5562306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) { 5662306a36Sopenharmony_ci dst[i++] = msg->clk_rate; 5762306a36Sopenharmony_ci dst[i++] = 0; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return i * sizeof(*dst); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic inline u32 settings_get_mcu_codec(struct create_channel_param *param) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci enum mcu_msg_version version = param->version; 6662306a36Sopenharmony_ci u32 pixelformat = param->codec; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (version < MCU_MSG_VERSION_2019_2) { 6962306a36Sopenharmony_ci switch (pixelformat) { 7062306a36Sopenharmony_ci case V4L2_PIX_FMT_HEVC: 7162306a36Sopenharmony_ci return 2; 7262306a36Sopenharmony_ci case V4L2_PIX_FMT_H264: 7362306a36Sopenharmony_ci default: 7462306a36Sopenharmony_ci return 1; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci } else { 7762306a36Sopenharmony_ci switch (pixelformat) { 7862306a36Sopenharmony_ci case V4L2_PIX_FMT_HEVC: 7962306a36Sopenharmony_ci return 1; 8062306a36Sopenharmony_ci case V4L2_PIX_FMT_H264: 8162306a36Sopenharmony_ci default: 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cissize_t 8862306a36Sopenharmony_ciallegro_encode_config_blob(u32 *dst, struct create_channel_param *param) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci enum mcu_msg_version version = param->version; 9162306a36Sopenharmony_ci unsigned int i = 0; 9262306a36Sopenharmony_ci unsigned int j = 0; 9362306a36Sopenharmony_ci u32 val; 9462306a36Sopenharmony_ci unsigned int codec = settings_get_mcu_codec(param); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) 9762306a36Sopenharmony_ci dst[i++] = param->layer_id; 9862306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 16), param->height) | 9962306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), param->width); 10062306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) 10162306a36Sopenharmony_ci dst[i++] = param->videomode; 10262306a36Sopenharmony_ci dst[i++] = param->format; 10362306a36Sopenharmony_ci if (version < MCU_MSG_VERSION_2019_2) 10462306a36Sopenharmony_ci dst[i++] = param->colorspace; 10562306a36Sopenharmony_ci dst[i++] = param->src_mode; 10662306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) 10762306a36Sopenharmony_ci dst[i++] = param->src_bit_depth; 10862306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 24), codec) | 10962306a36Sopenharmony_ci FIELD_PREP(GENMASK(23, 8), param->constraint_set_flags) | 11062306a36Sopenharmony_ci FIELD_PREP(GENMASK(7, 0), param->profile); 11162306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 16), param->tier) | 11262306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), param->level); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci val = 0; 11562306a36Sopenharmony_ci val |= param->temporal_mvp_enable ? BIT(20) : 0; 11662306a36Sopenharmony_ci val |= FIELD_PREP(GENMASK(7, 4), param->log2_max_frame_num); 11762306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) 11862306a36Sopenharmony_ci val |= FIELD_PREP(GENMASK(3, 0), param->log2_max_poc - 1); 11962306a36Sopenharmony_ci else 12062306a36Sopenharmony_ci val |= FIELD_PREP(GENMASK(3, 0), param->log2_max_poc); 12162306a36Sopenharmony_ci dst[i++] = val; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci val = 0; 12462306a36Sopenharmony_ci val |= param->enable_reordering ? BIT(0) : 0; 12562306a36Sopenharmony_ci val |= param->dbf_ovr_en ? BIT(2) : 0; 12662306a36Sopenharmony_ci val |= param->override_lf ? BIT(12) : 0; 12762306a36Sopenharmony_ci dst[i++] = val; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) { 13062306a36Sopenharmony_ci val = 0; 13162306a36Sopenharmony_ci val |= param->custom_lda ? BIT(2) : 0; 13262306a36Sopenharmony_ci val |= param->rdo_cost_mode ? BIT(20) : 0; 13362306a36Sopenharmony_ci dst[i++] = val; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci val = 0; 13662306a36Sopenharmony_ci val |= param->lf ? BIT(2) : 0; 13762306a36Sopenharmony_ci val |= param->lf_x_tile ? BIT(3) : 0; 13862306a36Sopenharmony_ci val |= param->lf_x_slice ? BIT(4) : 0; 13962306a36Sopenharmony_ci dst[i++] = val; 14062306a36Sopenharmony_ci } else { 14162306a36Sopenharmony_ci val = 0; 14262306a36Sopenharmony_ci dst[i++] = val; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(15, 8), param->beta_offset) | 14662306a36Sopenharmony_ci FIELD_PREP(GENMASK(7, 0), param->tc_offset); 14762306a36Sopenharmony_ci dst[i++] = param->unknown11; 14862306a36Sopenharmony_ci dst[i++] = param->unknown12; 14962306a36Sopenharmony_ci dst[i++] = param->num_slices; 15062306a36Sopenharmony_ci dst[i++] = param->encoder_buffer_offset; 15162306a36Sopenharmony_ci dst[i++] = param->encoder_buffer_enabled; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 16), param->clip_vrt_range) | 15462306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), param->clip_hrz_range); 15562306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 16), param->me_range[1]) | 15662306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), param->me_range[0]); 15762306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 16), param->me_range[3]) | 15862306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), param->me_range[2]); 15962306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 24), param->min_tu_size) | 16062306a36Sopenharmony_ci FIELD_PREP(GENMASK(23, 16), param->max_tu_size) | 16162306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 8), param->min_cu_size) | 16262306a36Sopenharmony_ci FIELD_PREP(GENMASK(8, 0), param->max_cu_size); 16362306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(15, 8), param->max_transfo_depth_intra) | 16462306a36Sopenharmony_ci FIELD_PREP(GENMASK(7, 0), param->max_transfo_depth_inter); 16562306a36Sopenharmony_ci dst[i++] = param->entropy_mode; 16662306a36Sopenharmony_ci dst[i++] = param->wp_mode; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci dst[i++] = param->rate_control_mode; 16962306a36Sopenharmony_ci dst[i++] = param->initial_rem_delay; 17062306a36Sopenharmony_ci dst[i++] = param->cpb_size; 17162306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 16), param->clk_ratio) | 17262306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), param->framerate); 17362306a36Sopenharmony_ci dst[i++] = param->target_bitrate; 17462306a36Sopenharmony_ci dst[i++] = param->max_bitrate; 17562306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 16), param->min_qp) | 17662306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), param->initial_qp); 17762306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 16), param->ip_delta) | 17862306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), param->max_qp); 17962306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 16), param->golden_ref) | 18062306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), param->pb_delta); 18162306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 16), param->golden_ref_frequency) | 18262306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), param->golden_delta); 18362306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) 18462306a36Sopenharmony_ci dst[i++] = param->rate_control_option; 18562306a36Sopenharmony_ci else 18662306a36Sopenharmony_ci dst[i++] = 0; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) { 18962306a36Sopenharmony_ci dst[i++] = param->num_pixel; 19062306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 16), param->max_pixel_value) | 19162306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), param->max_psnr); 19262306a36Sopenharmony_ci for (j = 0; j < 3; j++) 19362306a36Sopenharmony_ci dst[i++] = param->maxpicturesize[j]; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) 19762306a36Sopenharmony_ci dst[i++] = param->gop_ctrl_mode; 19862306a36Sopenharmony_ci else 19962306a36Sopenharmony_ci dst[i++] = 0; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) 20262306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 24), param->freq_golden_ref) | 20362306a36Sopenharmony_ci FIELD_PREP(GENMASK(23, 16), param->num_b) | 20462306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), param->gop_length); 20562306a36Sopenharmony_ci dst[i++] = param->freq_idr; 20662306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) 20762306a36Sopenharmony_ci dst[i++] = param->enable_lt; 20862306a36Sopenharmony_ci dst[i++] = param->freq_lt; 20962306a36Sopenharmony_ci dst[i++] = param->gdr_mode; 21062306a36Sopenharmony_ci if (version < MCU_MSG_VERSION_2019_2) 21162306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 24), param->freq_golden_ref) | 21262306a36Sopenharmony_ci FIELD_PREP(GENMASK(23, 16), param->num_b) | 21362306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), param->gop_length); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) 21662306a36Sopenharmony_ci dst[i++] = param->tmpdqp; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci dst[i++] = param->subframe_latency; 21962306a36Sopenharmony_ci dst[i++] = param->lda_control_mode; 22062306a36Sopenharmony_ci if (version < MCU_MSG_VERSION_2019_2) 22162306a36Sopenharmony_ci dst[i++] = param->unknown41; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) { 22462306a36Sopenharmony_ci for (j = 0; j < 6; j++) 22562306a36Sopenharmony_ci dst[i++] = param->lda_factors[j]; 22662306a36Sopenharmony_ci dst[i++] = param->max_num_merge_cand; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return i * sizeof(*dst); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic ssize_t 23362306a36Sopenharmony_ciallegro_enc_create_channel(u32 *dst, struct mcu_msg_create_channel *msg) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci enum mcu_msg_version version = msg->header.version; 23662306a36Sopenharmony_ci unsigned int i = 0; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci dst[i++] = msg->user_id; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) { 24162306a36Sopenharmony_ci dst[i++] = msg->blob_mcu_addr; 24262306a36Sopenharmony_ci } else { 24362306a36Sopenharmony_ci memcpy(&dst[i], msg->blob, msg->blob_size); 24462306a36Sopenharmony_ci i += msg->blob_size / sizeof(*dst); 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) 24862306a36Sopenharmony_ci dst[i++] = msg->ep1_addr; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci return i * sizeof(*dst); 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cissize_t allegro_decode_config_blob(struct create_channel_param *param, 25462306a36Sopenharmony_ci struct mcu_msg_create_channel_response *msg, 25562306a36Sopenharmony_ci u32 *src) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci enum mcu_msg_version version = msg->header.version; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) { 26062306a36Sopenharmony_ci param->num_ref_idx_l0 = FIELD_GET(GENMASK(7, 4), src[9]); 26162306a36Sopenharmony_ci param->num_ref_idx_l1 = FIELD_GET(GENMASK(11, 8), src[9]); 26262306a36Sopenharmony_ci } else { 26362306a36Sopenharmony_ci param->num_ref_idx_l0 = msg->num_ref_idx_l0; 26462306a36Sopenharmony_ci param->num_ref_idx_l1 = msg->num_ref_idx_l1; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci return 0; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic ssize_t 27162306a36Sopenharmony_ciallegro_enc_destroy_channel(u32 *dst, struct mcu_msg_destroy_channel *msg) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci unsigned int i = 0; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci dst[i++] = msg->channel_id; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci return i * sizeof(*dst); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic ssize_t 28162306a36Sopenharmony_ciallegro_enc_push_buffers(u32 *dst, struct mcu_msg_push_buffers_internal *msg) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci unsigned int i = 0; 28462306a36Sopenharmony_ci struct mcu_msg_push_buffers_internal_buffer *buffer; 28562306a36Sopenharmony_ci unsigned int num_buffers = msg->num_buffers; 28662306a36Sopenharmony_ci unsigned int j; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci dst[i++] = msg->channel_id; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci for (j = 0; j < num_buffers; j++) { 29162306a36Sopenharmony_ci buffer = &msg->buffer[j]; 29262306a36Sopenharmony_ci dst[i++] = buffer->dma_addr; 29362306a36Sopenharmony_ci dst[i++] = buffer->mcu_addr; 29462306a36Sopenharmony_ci dst[i++] = buffer->size; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return i * sizeof(*dst); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic ssize_t 30162306a36Sopenharmony_ciallegro_enc_put_stream_buffer(u32 *dst, 30262306a36Sopenharmony_ci struct mcu_msg_put_stream_buffer *msg) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci unsigned int i = 0; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci dst[i++] = msg->channel_id; 30762306a36Sopenharmony_ci dst[i++] = msg->dma_addr; 30862306a36Sopenharmony_ci dst[i++] = msg->mcu_addr; 30962306a36Sopenharmony_ci dst[i++] = msg->size; 31062306a36Sopenharmony_ci dst[i++] = msg->offset; 31162306a36Sopenharmony_ci dst[i++] = lower_32_bits(msg->dst_handle); 31262306a36Sopenharmony_ci dst[i++] = upper_32_bits(msg->dst_handle); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return i * sizeof(*dst); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic ssize_t 31862306a36Sopenharmony_ciallegro_enc_encode_frame(u32 *dst, struct mcu_msg_encode_frame *msg) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci enum mcu_msg_version version = msg->header.version; 32162306a36Sopenharmony_ci unsigned int i = 0; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci dst[i++] = msg->channel_id; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci dst[i++] = msg->reserved; 32662306a36Sopenharmony_ci dst[i++] = msg->encoding_options; 32762306a36Sopenharmony_ci dst[i++] = FIELD_PREP(GENMASK(31, 16), msg->padding) | 32862306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), msg->pps_qp); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) { 33162306a36Sopenharmony_ci dst[i++] = 0; 33262306a36Sopenharmony_ci dst[i++] = 0; 33362306a36Sopenharmony_ci dst[i++] = 0; 33462306a36Sopenharmony_ci dst[i++] = 0; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci dst[i++] = lower_32_bits(msg->user_param); 33862306a36Sopenharmony_ci dst[i++] = upper_32_bits(msg->user_param); 33962306a36Sopenharmony_ci dst[i++] = lower_32_bits(msg->src_handle); 34062306a36Sopenharmony_ci dst[i++] = upper_32_bits(msg->src_handle); 34162306a36Sopenharmony_ci dst[i++] = msg->request_options; 34262306a36Sopenharmony_ci dst[i++] = msg->src_y; 34362306a36Sopenharmony_ci dst[i++] = msg->src_uv; 34462306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) 34562306a36Sopenharmony_ci dst[i++] = msg->is_10_bit; 34662306a36Sopenharmony_ci dst[i++] = msg->stride; 34762306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) 34862306a36Sopenharmony_ci dst[i++] = msg->format; 34962306a36Sopenharmony_ci dst[i++] = msg->ep2; 35062306a36Sopenharmony_ci dst[i++] = lower_32_bits(msg->ep2_v); 35162306a36Sopenharmony_ci dst[i++] = upper_32_bits(msg->ep2_v); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci return i * sizeof(*dst); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic ssize_t 35762306a36Sopenharmony_ciallegro_dec_init(struct mcu_msg_init_response *msg, u32 *src) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci unsigned int i = 0; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci msg->reserved0 = src[i++]; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return i * sizeof(*src); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic ssize_t 36762306a36Sopenharmony_ciallegro_dec_create_channel(struct mcu_msg_create_channel_response *msg, 36862306a36Sopenharmony_ci u32 *src) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci enum mcu_msg_version version = msg->header.version; 37162306a36Sopenharmony_ci unsigned int i = 0; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci msg->channel_id = src[i++]; 37462306a36Sopenharmony_ci msg->user_id = src[i++]; 37562306a36Sopenharmony_ci /* 37662306a36Sopenharmony_ci * Version >= MCU_MSG_VERSION_2019_2 is handled in 37762306a36Sopenharmony_ci * allegro_decode_config_blob(). 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_ci if (version < MCU_MSG_VERSION_2019_2) { 38062306a36Sopenharmony_ci msg->options = src[i++]; 38162306a36Sopenharmony_ci msg->num_core = src[i++]; 38262306a36Sopenharmony_ci msg->num_ref_idx_l0 = FIELD_GET(GENMASK(7, 4), src[i]); 38362306a36Sopenharmony_ci msg->num_ref_idx_l1 = FIELD_GET(GENMASK(11, 8), src[i++]); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci msg->int_buffers_count = src[i++]; 38662306a36Sopenharmony_ci msg->int_buffers_size = src[i++]; 38762306a36Sopenharmony_ci msg->rec_buffers_count = src[i++]; 38862306a36Sopenharmony_ci msg->rec_buffers_size = src[i++]; 38962306a36Sopenharmony_ci msg->reserved = src[i++]; 39062306a36Sopenharmony_ci msg->error_code = src[i++]; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci return i * sizeof(*src); 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic ssize_t 39662306a36Sopenharmony_ciallegro_dec_destroy_channel(struct mcu_msg_destroy_channel_response *msg, 39762306a36Sopenharmony_ci u32 *src) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci unsigned int i = 0; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci msg->channel_id = src[i++]; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return i * sizeof(*src); 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic ssize_t 40762306a36Sopenharmony_ciallegro_dec_encode_frame(struct mcu_msg_encode_frame_response *msg, u32 *src) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci enum mcu_msg_version version = msg->header.version; 41062306a36Sopenharmony_ci unsigned int i = 0; 41162306a36Sopenharmony_ci unsigned int j; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci msg->channel_id = src[i++]; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci msg->dst_handle = src[i++]; 41662306a36Sopenharmony_ci msg->dst_handle |= (((u64)src[i++]) << 32); 41762306a36Sopenharmony_ci msg->user_param = src[i++]; 41862306a36Sopenharmony_ci msg->user_param |= (((u64)src[i++]) << 32); 41962306a36Sopenharmony_ci msg->src_handle = src[i++]; 42062306a36Sopenharmony_ci msg->src_handle |= (((u64)src[i++]) << 32); 42162306a36Sopenharmony_ci msg->skip = FIELD_GET(GENMASK(31, 16), src[i]); 42262306a36Sopenharmony_ci msg->is_ref = FIELD_GET(GENMASK(15, 0), src[i++]); 42362306a36Sopenharmony_ci msg->initial_removal_delay = src[i++]; 42462306a36Sopenharmony_ci msg->dpb_output_delay = src[i++]; 42562306a36Sopenharmony_ci msg->size = src[i++]; 42662306a36Sopenharmony_ci msg->frame_tag_size = src[i++]; 42762306a36Sopenharmony_ci msg->stuffing = src[i++]; 42862306a36Sopenharmony_ci msg->filler = src[i++]; 42962306a36Sopenharmony_ci msg->num_row = FIELD_GET(GENMASK(31, 16), src[i]); 43062306a36Sopenharmony_ci msg->num_column = FIELD_GET(GENMASK(15, 0), src[i++]); 43162306a36Sopenharmony_ci msg->num_ref_idx_l1 = FIELD_GET(GENMASK(31, 24), src[i]); 43262306a36Sopenharmony_ci msg->num_ref_idx_l0 = FIELD_GET(GENMASK(23, 16), src[i]); 43362306a36Sopenharmony_ci msg->qp = FIELD_GET(GENMASK(15, 0), src[i++]); 43462306a36Sopenharmony_ci msg->partition_table_offset = src[i++]; 43562306a36Sopenharmony_ci msg->partition_table_size = src[i++]; 43662306a36Sopenharmony_ci msg->sum_complex = src[i++]; 43762306a36Sopenharmony_ci for (j = 0; j < 4; j++) 43862306a36Sopenharmony_ci msg->tile_width[j] = src[i++]; 43962306a36Sopenharmony_ci for (j = 0; j < 22; j++) 44062306a36Sopenharmony_ci msg->tile_height[j] = src[i++]; 44162306a36Sopenharmony_ci msg->error_code = src[i++]; 44262306a36Sopenharmony_ci msg->slice_type = src[i++]; 44362306a36Sopenharmony_ci msg->pic_struct = src[i++]; 44462306a36Sopenharmony_ci msg->reserved = FIELD_GET(GENMASK(31, 24), src[i]); 44562306a36Sopenharmony_ci msg->is_last_slice = FIELD_GET(GENMASK(23, 16), src[i]); 44662306a36Sopenharmony_ci msg->is_first_slice = FIELD_GET(GENMASK(15, 8), src[i]); 44762306a36Sopenharmony_ci msg->is_idr = FIELD_GET(GENMASK(7, 0), src[i++]); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci msg->reserved1 = FIELD_GET(GENMASK(31, 16), src[i]); 45062306a36Sopenharmony_ci msg->pps_qp = FIELD_GET(GENMASK(15, 0), src[i++]); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci msg->reserved2 = src[i++]; 45362306a36Sopenharmony_ci if (version >= MCU_MSG_VERSION_2019_2) { 45462306a36Sopenharmony_ci msg->reserved3 = src[i++]; 45562306a36Sopenharmony_ci msg->reserved4 = src[i++]; 45662306a36Sopenharmony_ci msg->reserved5 = src[i++]; 45762306a36Sopenharmony_ci msg->reserved6 = src[i++]; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci return i * sizeof(*src); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci/** 46462306a36Sopenharmony_ci * allegro_encode_mail() - Encode allegro messages to firmware format 46562306a36Sopenharmony_ci * @dst: Pointer to the memory that will be filled with data 46662306a36Sopenharmony_ci * @msg: The allegro message that will be encoded 46762306a36Sopenharmony_ci */ 46862306a36Sopenharmony_cissize_t allegro_encode_mail(u32 *dst, void *msg) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci const struct mcu_msg_header *header = msg; 47162306a36Sopenharmony_ci ssize_t size; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (!msg || !dst) 47462306a36Sopenharmony_ci return -EINVAL; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci switch (header->type) { 47762306a36Sopenharmony_ci case MCU_MSG_TYPE_INIT: 47862306a36Sopenharmony_ci size = allegro_enc_init(&dst[1], msg); 47962306a36Sopenharmony_ci break; 48062306a36Sopenharmony_ci case MCU_MSG_TYPE_CREATE_CHANNEL: 48162306a36Sopenharmony_ci size = allegro_enc_create_channel(&dst[1], msg); 48262306a36Sopenharmony_ci break; 48362306a36Sopenharmony_ci case MCU_MSG_TYPE_DESTROY_CHANNEL: 48462306a36Sopenharmony_ci size = allegro_enc_destroy_channel(&dst[1], msg); 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci case MCU_MSG_TYPE_ENCODE_FRAME: 48762306a36Sopenharmony_ci size = allegro_enc_encode_frame(&dst[1], msg); 48862306a36Sopenharmony_ci break; 48962306a36Sopenharmony_ci case MCU_MSG_TYPE_PUT_STREAM_BUFFER: 49062306a36Sopenharmony_ci size = allegro_enc_put_stream_buffer(&dst[1], msg); 49162306a36Sopenharmony_ci break; 49262306a36Sopenharmony_ci case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE: 49362306a36Sopenharmony_ci case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE: 49462306a36Sopenharmony_ci size = allegro_enc_push_buffers(&dst[1], msg); 49562306a36Sopenharmony_ci break; 49662306a36Sopenharmony_ci default: 49762306a36Sopenharmony_ci return -EINVAL; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* 50162306a36Sopenharmony_ci * The encoded messages might have different length depending on 50262306a36Sopenharmony_ci * the firmware version or certain fields. Therefore, we have to 50362306a36Sopenharmony_ci * set the body length after encoding the message. 50462306a36Sopenharmony_ci */ 50562306a36Sopenharmony_ci dst[0] = FIELD_PREP(GENMASK(31, 16), header->type) | 50662306a36Sopenharmony_ci FIELD_PREP(GENMASK(15, 0), size); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return size + sizeof(*dst); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci/** 51262306a36Sopenharmony_ci * allegro_decode_mail() - Parse allegro messages from the firmware. 51362306a36Sopenharmony_ci * @msg: The mcu_msg_response that will be filled with parsed values. 51462306a36Sopenharmony_ci * @src: Pointer to the memory that will be parsed 51562306a36Sopenharmony_ci * 51662306a36Sopenharmony_ci * The message format in the mailbox depends on the firmware. Parse the 51762306a36Sopenharmony_ci * different formats into a uniform message format that can be used without 51862306a36Sopenharmony_ci * taking care of the firmware version. 51962306a36Sopenharmony_ci */ 52062306a36Sopenharmony_ciint allegro_decode_mail(void *msg, u32 *src) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci struct mcu_msg_header *header; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (!src || !msg) 52562306a36Sopenharmony_ci return -EINVAL; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci header = msg; 52862306a36Sopenharmony_ci header->type = FIELD_GET(GENMASK(31, 16), src[0]); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci src++; 53162306a36Sopenharmony_ci switch (header->type) { 53262306a36Sopenharmony_ci case MCU_MSG_TYPE_INIT: 53362306a36Sopenharmony_ci allegro_dec_init(msg, src); 53462306a36Sopenharmony_ci break; 53562306a36Sopenharmony_ci case MCU_MSG_TYPE_CREATE_CHANNEL: 53662306a36Sopenharmony_ci allegro_dec_create_channel(msg, src); 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci case MCU_MSG_TYPE_DESTROY_CHANNEL: 53962306a36Sopenharmony_ci allegro_dec_destroy_channel(msg, src); 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci case MCU_MSG_TYPE_ENCODE_FRAME: 54262306a36Sopenharmony_ci allegro_dec_encode_frame(msg, src); 54362306a36Sopenharmony_ci break; 54462306a36Sopenharmony_ci default: 54562306a36Sopenharmony_ci return -EINVAL; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci return 0; 54962306a36Sopenharmony_ci} 550