550 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>4 *5 * Helper functions for handling messages that are send via mailbox to the6 * Allegro VCU firmware.7 */8 9#include <linux/bitfield.h>10#include <linux/export.h>11#include <linux/errno.h>12#include <linux/string.h>13#include <linux/videodev2.h>14 15#include "allegro-mail.h"16 17const char *msg_type_name(enum mcu_msg_type type)18{19 static char buf[13];20 21 switch (type) {22 case MCU_MSG_TYPE_INIT:23 return "INIT";24 case MCU_MSG_TYPE_CREATE_CHANNEL:25 return "CREATE_CHANNEL";26 case MCU_MSG_TYPE_DESTROY_CHANNEL:27 return "DESTROY_CHANNEL";28 case MCU_MSG_TYPE_ENCODE_FRAME:29 return "ENCODE_FRAME";30 case MCU_MSG_TYPE_PUT_STREAM_BUFFER:31 return "PUT_STREAM_BUFFER";32 case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:33 return "PUSH_BUFFER_INTERMEDIATE";34 case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:35 return "PUSH_BUFFER_REFERENCE";36 default:37 snprintf(buf, sizeof(buf), "(0x%04x)", type);38 return buf;39 }40}41EXPORT_SYMBOL(msg_type_name);42 43static ssize_t44allegro_enc_init(u32 *dst, struct mcu_msg_init_request *msg)45{46 unsigned int i = 0;47 enum mcu_msg_version version = msg->header.version;48 49 dst[i++] = msg->reserved0;50 dst[i++] = msg->suballoc_dma;51 dst[i++] = msg->suballoc_size;52 dst[i++] = msg->encoder_buffer_size;53 dst[i++] = msg->encoder_buffer_color_depth;54 dst[i++] = msg->num_cores;55 if (version >= MCU_MSG_VERSION_2019_2) {56 dst[i++] = msg->clk_rate;57 dst[i++] = 0;58 }59 60 return i * sizeof(*dst);61}62 63static inline u32 settings_get_mcu_codec(struct create_channel_param *param)64{65 enum mcu_msg_version version = param->version;66 u32 pixelformat = param->codec;67 68 if (version < MCU_MSG_VERSION_2019_2) {69 switch (pixelformat) {70 case V4L2_PIX_FMT_HEVC:71 return 2;72 case V4L2_PIX_FMT_H264:73 default:74 return 1;75 }76 } else {77 switch (pixelformat) {78 case V4L2_PIX_FMT_HEVC:79 return 1;80 case V4L2_PIX_FMT_H264:81 default:82 return 0;83 }84 }85}86 87ssize_t88allegro_encode_config_blob(u32 *dst, struct create_channel_param *param)89{90 enum mcu_msg_version version = param->version;91 unsigned int i = 0;92 unsigned int j = 0;93 u32 val;94 unsigned int codec = settings_get_mcu_codec(param);95 96 if (version >= MCU_MSG_VERSION_2019_2)97 dst[i++] = param->layer_id;98 dst[i++] = FIELD_PREP(GENMASK(31, 16), param->height) |99 FIELD_PREP(GENMASK(15, 0), param->width);100 if (version >= MCU_MSG_VERSION_2019_2)101 dst[i++] = param->videomode;102 dst[i++] = param->format;103 if (version < MCU_MSG_VERSION_2019_2)104 dst[i++] = param->colorspace;105 dst[i++] = param->src_mode;106 if (version >= MCU_MSG_VERSION_2019_2)107 dst[i++] = param->src_bit_depth;108 dst[i++] = FIELD_PREP(GENMASK(31, 24), codec) |109 FIELD_PREP(GENMASK(23, 8), param->constraint_set_flags) |110 FIELD_PREP(GENMASK(7, 0), param->profile);111 dst[i++] = FIELD_PREP(GENMASK(31, 16), param->tier) |112 FIELD_PREP(GENMASK(15, 0), param->level);113 114 val = 0;115 val |= param->temporal_mvp_enable ? BIT(20) : 0;116 val |= FIELD_PREP(GENMASK(7, 4), param->log2_max_frame_num);117 if (version >= MCU_MSG_VERSION_2019_2)118 val |= FIELD_PREP(GENMASK(3, 0), param->log2_max_poc - 1);119 else120 val |= FIELD_PREP(GENMASK(3, 0), param->log2_max_poc);121 dst[i++] = val;122 123 val = 0;124 val |= param->enable_reordering ? BIT(0) : 0;125 val |= param->dbf_ovr_en ? BIT(2) : 0;126 val |= param->override_lf ? BIT(12) : 0;127 dst[i++] = val;128 129 if (version >= MCU_MSG_VERSION_2019_2) {130 val = 0;131 val |= param->custom_lda ? BIT(2) : 0;132 val |= param->rdo_cost_mode ? BIT(20) : 0;133 dst[i++] = val;134 135 val = 0;136 val |= param->lf ? BIT(2) : 0;137 val |= param->lf_x_tile ? BIT(3) : 0;138 val |= param->lf_x_slice ? BIT(4) : 0;139 dst[i++] = val;140 } else {141 val = 0;142 dst[i++] = val;143 }144 145 dst[i++] = FIELD_PREP(GENMASK(15, 8), param->beta_offset) |146 FIELD_PREP(GENMASK(7, 0), param->tc_offset);147 dst[i++] = param->unknown11;148 dst[i++] = param->unknown12;149 dst[i++] = param->num_slices;150 dst[i++] = param->encoder_buffer_offset;151 dst[i++] = param->encoder_buffer_enabled;152 153 dst[i++] = FIELD_PREP(GENMASK(31, 16), param->clip_vrt_range) |154 FIELD_PREP(GENMASK(15, 0), param->clip_hrz_range);155 dst[i++] = FIELD_PREP(GENMASK(31, 16), param->me_range[1]) |156 FIELD_PREP(GENMASK(15, 0), param->me_range[0]);157 dst[i++] = FIELD_PREP(GENMASK(31, 16), param->me_range[3]) |158 FIELD_PREP(GENMASK(15, 0), param->me_range[2]);159 dst[i++] = FIELD_PREP(GENMASK(31, 24), param->min_tu_size) |160 FIELD_PREP(GENMASK(23, 16), param->max_tu_size) |161 FIELD_PREP(GENMASK(15, 8), param->min_cu_size) |162 FIELD_PREP(GENMASK(8, 0), param->max_cu_size);163 dst[i++] = FIELD_PREP(GENMASK(15, 8), param->max_transfo_depth_intra) |164 FIELD_PREP(GENMASK(7, 0), param->max_transfo_depth_inter);165 dst[i++] = param->entropy_mode;166 dst[i++] = param->wp_mode;167 168 dst[i++] = param->rate_control_mode;169 dst[i++] = param->initial_rem_delay;170 dst[i++] = param->cpb_size;171 dst[i++] = FIELD_PREP(GENMASK(31, 16), param->clk_ratio) |172 FIELD_PREP(GENMASK(15, 0), param->framerate);173 dst[i++] = param->target_bitrate;174 dst[i++] = param->max_bitrate;175 dst[i++] = FIELD_PREP(GENMASK(31, 16), param->min_qp) |176 FIELD_PREP(GENMASK(15, 0), param->initial_qp);177 dst[i++] = FIELD_PREP(GENMASK(31, 16), param->ip_delta) |178 FIELD_PREP(GENMASK(15, 0), param->max_qp);179 dst[i++] = FIELD_PREP(GENMASK(31, 16), param->golden_ref) |180 FIELD_PREP(GENMASK(15, 0), param->pb_delta);181 dst[i++] = FIELD_PREP(GENMASK(31, 16), param->golden_ref_frequency) |182 FIELD_PREP(GENMASK(15, 0), param->golden_delta);183 if (version >= MCU_MSG_VERSION_2019_2)184 dst[i++] = param->rate_control_option;185 else186 dst[i++] = 0;187 188 if (version >= MCU_MSG_VERSION_2019_2) {189 dst[i++] = param->num_pixel;190 dst[i++] = FIELD_PREP(GENMASK(31, 16), param->max_pixel_value) |191 FIELD_PREP(GENMASK(15, 0), param->max_psnr);192 for (j = 0; j < 3; j++)193 dst[i++] = param->maxpicturesize[j];194 }195 196 if (version >= MCU_MSG_VERSION_2019_2)197 dst[i++] = param->gop_ctrl_mode;198 else199 dst[i++] = 0;200 201 if (version >= MCU_MSG_VERSION_2019_2)202 dst[i++] = FIELD_PREP(GENMASK(31, 24), param->freq_golden_ref) |203 FIELD_PREP(GENMASK(23, 16), param->num_b) |204 FIELD_PREP(GENMASK(15, 0), param->gop_length);205 dst[i++] = param->freq_idr;206 if (version >= MCU_MSG_VERSION_2019_2)207 dst[i++] = param->enable_lt;208 dst[i++] = param->freq_lt;209 dst[i++] = param->gdr_mode;210 if (version < MCU_MSG_VERSION_2019_2)211 dst[i++] = FIELD_PREP(GENMASK(31, 24), param->freq_golden_ref) |212 FIELD_PREP(GENMASK(23, 16), param->num_b) |213 FIELD_PREP(GENMASK(15, 0), param->gop_length);214 215 if (version >= MCU_MSG_VERSION_2019_2)216 dst[i++] = param->tmpdqp;217 218 dst[i++] = param->subframe_latency;219 dst[i++] = param->lda_control_mode;220 if (version < MCU_MSG_VERSION_2019_2)221 dst[i++] = param->unknown41;222 223 if (version >= MCU_MSG_VERSION_2019_2) {224 for (j = 0; j < 6; j++)225 dst[i++] = param->lda_factors[j];226 dst[i++] = param->max_num_merge_cand;227 }228 229 return i * sizeof(*dst);230}231 232static ssize_t233allegro_enc_create_channel(u32 *dst, struct mcu_msg_create_channel *msg)234{235 enum mcu_msg_version version = msg->header.version;236 unsigned int i = 0;237 238 dst[i++] = msg->user_id;239 240 if (version >= MCU_MSG_VERSION_2019_2) {241 dst[i++] = msg->blob_mcu_addr;242 } else {243 memcpy(&dst[i], msg->blob, msg->blob_size);244 i += msg->blob_size / sizeof(*dst);245 }246 247 if (version >= MCU_MSG_VERSION_2019_2)248 dst[i++] = msg->ep1_addr;249 250 return i * sizeof(*dst);251}252 253ssize_t allegro_decode_config_blob(struct create_channel_param *param,254 struct mcu_msg_create_channel_response *msg,255 u32 *src)256{257 enum mcu_msg_version version = msg->header.version;258 259 if (version >= MCU_MSG_VERSION_2019_2) {260 param->num_ref_idx_l0 = FIELD_GET(GENMASK(7, 4), src[9]);261 param->num_ref_idx_l1 = FIELD_GET(GENMASK(11, 8), src[9]);262 } else {263 param->num_ref_idx_l0 = msg->num_ref_idx_l0;264 param->num_ref_idx_l1 = msg->num_ref_idx_l1;265 }266 267 return 0;268}269 270static ssize_t271allegro_enc_destroy_channel(u32 *dst, struct mcu_msg_destroy_channel *msg)272{273 unsigned int i = 0;274 275 dst[i++] = msg->channel_id;276 277 return i * sizeof(*dst);278}279 280static ssize_t281allegro_enc_push_buffers(u32 *dst, struct mcu_msg_push_buffers_internal *msg)282{283 unsigned int i = 0;284 struct mcu_msg_push_buffers_internal_buffer *buffer;285 unsigned int num_buffers = msg->num_buffers;286 unsigned int j;287 288 dst[i++] = msg->channel_id;289 290 for (j = 0; j < num_buffers; j++) {291 buffer = &msg->buffer[j];292 dst[i++] = buffer->dma_addr;293 dst[i++] = buffer->mcu_addr;294 dst[i++] = buffer->size;295 }296 297 return i * sizeof(*dst);298}299 300static ssize_t301allegro_enc_put_stream_buffer(u32 *dst,302 struct mcu_msg_put_stream_buffer *msg)303{304 unsigned int i = 0;305 306 dst[i++] = msg->channel_id;307 dst[i++] = msg->dma_addr;308 dst[i++] = msg->mcu_addr;309 dst[i++] = msg->size;310 dst[i++] = msg->offset;311 dst[i++] = lower_32_bits(msg->dst_handle);312 dst[i++] = upper_32_bits(msg->dst_handle);313 314 return i * sizeof(*dst);315}316 317static ssize_t318allegro_enc_encode_frame(u32 *dst, struct mcu_msg_encode_frame *msg)319{320 enum mcu_msg_version version = msg->header.version;321 unsigned int i = 0;322 323 dst[i++] = msg->channel_id;324 325 dst[i++] = msg->reserved;326 dst[i++] = msg->encoding_options;327 dst[i++] = FIELD_PREP(GENMASK(31, 16), msg->padding) |328 FIELD_PREP(GENMASK(15, 0), msg->pps_qp);329 330 if (version >= MCU_MSG_VERSION_2019_2) {331 dst[i++] = 0;332 dst[i++] = 0;333 dst[i++] = 0;334 dst[i++] = 0;335 }336 337 dst[i++] = lower_32_bits(msg->user_param);338 dst[i++] = upper_32_bits(msg->user_param);339 dst[i++] = lower_32_bits(msg->src_handle);340 dst[i++] = upper_32_bits(msg->src_handle);341 dst[i++] = msg->request_options;342 dst[i++] = msg->src_y;343 dst[i++] = msg->src_uv;344 if (version >= MCU_MSG_VERSION_2019_2)345 dst[i++] = msg->is_10_bit;346 dst[i++] = msg->stride;347 if (version >= MCU_MSG_VERSION_2019_2)348 dst[i++] = msg->format;349 dst[i++] = msg->ep2;350 dst[i++] = lower_32_bits(msg->ep2_v);351 dst[i++] = upper_32_bits(msg->ep2_v);352 353 return i * sizeof(*dst);354}355 356static ssize_t357allegro_dec_init(struct mcu_msg_init_response *msg, u32 *src)358{359 unsigned int i = 0;360 361 msg->reserved0 = src[i++];362 363 return i * sizeof(*src);364}365 366static ssize_t367allegro_dec_create_channel(struct mcu_msg_create_channel_response *msg,368 u32 *src)369{370 enum mcu_msg_version version = msg->header.version;371 unsigned int i = 0;372 373 msg->channel_id = src[i++];374 msg->user_id = src[i++];375 /*376 * Version >= MCU_MSG_VERSION_2019_2 is handled in377 * allegro_decode_config_blob().378 */379 if (version < MCU_MSG_VERSION_2019_2) {380 msg->options = src[i++];381 msg->num_core = src[i++];382 msg->num_ref_idx_l0 = FIELD_GET(GENMASK(7, 4), src[i]);383 msg->num_ref_idx_l1 = FIELD_GET(GENMASK(11, 8), src[i++]);384 }385 msg->int_buffers_count = src[i++];386 msg->int_buffers_size = src[i++];387 msg->rec_buffers_count = src[i++];388 msg->rec_buffers_size = src[i++];389 msg->reserved = src[i++];390 msg->error_code = src[i++];391 392 return i * sizeof(*src);393}394 395static ssize_t396allegro_dec_destroy_channel(struct mcu_msg_destroy_channel_response *msg,397 u32 *src)398{399 unsigned int i = 0;400 401 msg->channel_id = src[i++];402 403 return i * sizeof(*src);404}405 406static ssize_t407allegro_dec_encode_frame(struct mcu_msg_encode_frame_response *msg, u32 *src)408{409 enum mcu_msg_version version = msg->header.version;410 unsigned int i = 0;411 unsigned int j;412 413 msg->channel_id = src[i++];414 415 msg->dst_handle = src[i++];416 msg->dst_handle |= (((u64)src[i++]) << 32);417 msg->user_param = src[i++];418 msg->user_param |= (((u64)src[i++]) << 32);419 msg->src_handle = src[i++];420 msg->src_handle |= (((u64)src[i++]) << 32);421 msg->skip = FIELD_GET(GENMASK(31, 16), src[i]);422 msg->is_ref = FIELD_GET(GENMASK(15, 0), src[i++]);423 msg->initial_removal_delay = src[i++];424 msg->dpb_output_delay = src[i++];425 msg->size = src[i++];426 msg->frame_tag_size = src[i++];427 msg->stuffing = src[i++];428 msg->filler = src[i++];429 msg->num_row = FIELD_GET(GENMASK(31, 16), src[i]);430 msg->num_column = FIELD_GET(GENMASK(15, 0), src[i++]);431 msg->num_ref_idx_l1 = FIELD_GET(GENMASK(31, 24), src[i]);432 msg->num_ref_idx_l0 = FIELD_GET(GENMASK(23, 16), src[i]);433 msg->qp = FIELD_GET(GENMASK(15, 0), src[i++]);434 msg->partition_table_offset = src[i++];435 msg->partition_table_size = src[i++];436 msg->sum_complex = src[i++];437 for (j = 0; j < 4; j++)438 msg->tile_width[j] = src[i++];439 for (j = 0; j < 22; j++)440 msg->tile_height[j] = src[i++];441 msg->error_code = src[i++];442 msg->slice_type = src[i++];443 msg->pic_struct = src[i++];444 msg->reserved = FIELD_GET(GENMASK(31, 24), src[i]);445 msg->is_last_slice = FIELD_GET(GENMASK(23, 16), src[i]);446 msg->is_first_slice = FIELD_GET(GENMASK(15, 8), src[i]);447 msg->is_idr = FIELD_GET(GENMASK(7, 0), src[i++]);448 449 msg->reserved1 = FIELD_GET(GENMASK(31, 16), src[i]);450 msg->pps_qp = FIELD_GET(GENMASK(15, 0), src[i++]);451 452 msg->reserved2 = src[i++];453 if (version >= MCU_MSG_VERSION_2019_2) {454 msg->reserved3 = src[i++];455 msg->reserved4 = src[i++];456 msg->reserved5 = src[i++];457 msg->reserved6 = src[i++];458 }459 460 return i * sizeof(*src);461}462 463/**464 * allegro_encode_mail() - Encode allegro messages to firmware format465 * @dst: Pointer to the memory that will be filled with data466 * @msg: The allegro message that will be encoded467 */468ssize_t allegro_encode_mail(u32 *dst, void *msg)469{470 const struct mcu_msg_header *header = msg;471 ssize_t size;472 473 if (!msg || !dst)474 return -EINVAL;475 476 switch (header->type) {477 case MCU_MSG_TYPE_INIT:478 size = allegro_enc_init(&dst[1], msg);479 break;480 case MCU_MSG_TYPE_CREATE_CHANNEL:481 size = allegro_enc_create_channel(&dst[1], msg);482 break;483 case MCU_MSG_TYPE_DESTROY_CHANNEL:484 size = allegro_enc_destroy_channel(&dst[1], msg);485 break;486 case MCU_MSG_TYPE_ENCODE_FRAME:487 size = allegro_enc_encode_frame(&dst[1], msg);488 break;489 case MCU_MSG_TYPE_PUT_STREAM_BUFFER:490 size = allegro_enc_put_stream_buffer(&dst[1], msg);491 break;492 case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:493 case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:494 size = allegro_enc_push_buffers(&dst[1], msg);495 break;496 default:497 return -EINVAL;498 }499 500 /*501 * The encoded messages might have different length depending on502 * the firmware version or certain fields. Therefore, we have to503 * set the body length after encoding the message.504 */505 dst[0] = FIELD_PREP(GENMASK(31, 16), header->type) |506 FIELD_PREP(GENMASK(15, 0), size);507 508 return size + sizeof(*dst);509}510 511/**512 * allegro_decode_mail() - Parse allegro messages from the firmware.513 * @msg: The mcu_msg_response that will be filled with parsed values.514 * @src: Pointer to the memory that will be parsed515 *516 * The message format in the mailbox depends on the firmware. Parse the517 * different formats into a uniform message format that can be used without518 * taking care of the firmware version.519 */520int allegro_decode_mail(void *msg, u32 *src)521{522 struct mcu_msg_header *header;523 524 if (!src || !msg)525 return -EINVAL;526 527 header = msg;528 header->type = FIELD_GET(GENMASK(31, 16), src[0]);529 530 src++;531 switch (header->type) {532 case MCU_MSG_TYPE_INIT:533 allegro_dec_init(msg, src);534 break;535 case MCU_MSG_TYPE_CREATE_CHANNEL:536 allegro_dec_create_channel(msg, src);537 break;538 case MCU_MSG_TYPE_DESTROY_CHANNEL:539 allegro_dec_destroy_channel(msg, src);540 break;541 case MCU_MSG_TYPE_ENCODE_FRAME:542 allegro_dec_encode_frame(msg, src);543 break;544 default:545 return -EINVAL;546 }547 548 return 0;549}550