1 // SPDX-License-Identifier: GPL-2.0
5 * Helper functions for handling messages that are send via mailbox to the
6 * Allegro VCU firmware.
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>
15 #include "allegro-mail.h"
17 const char *msg_type_name(enum mcu_msg_type type)
22 case MCU_MSG_TYPE_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";
37 snprintf(buf, sizeof(buf), "(0x%04x)", type);
41 EXPORT_SYMBOL(msg_type_name);
44 allegro_enc_init(u32 *dst, struct mcu_msg_init_request *msg)
47 enum mcu_msg_version version = msg->header.version;
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;
60 return i * sizeof(*dst);
63 static inline u32 settings_get_mcu_codec(struct create_channel_param *param)
65 enum mcu_msg_version version = param->version;
66 u32 pixelformat = param->codec;
68 if (version < MCU_MSG_VERSION_2019_2) {
69 switch (pixelformat) {
70 case V4L2_PIX_FMT_HEVC:
72 case V4L2_PIX_FMT_H264:
77 switch (pixelformat) {
78 case V4L2_PIX_FMT_HEVC:
80 case V4L2_PIX_FMT_H264:
88 allegro_encode_config_blob(u32 *dst, struct create_channel_param *param)
90 enum mcu_msg_version version = param->version;
94 unsigned int codec = settings_get_mcu_codec(param);
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);
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);
120 val |= FIELD_PREP(GENMASK(3, 0), param->log2_max_poc);
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;
129 if (version >= MCU_MSG_VERSION_2019_2) {
131 val |= param->custom_lda ? BIT(2) : 0;
132 val |= param->rdo_cost_mode ? BIT(20) : 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;
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;
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;
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;
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];
196 if (version >= MCU_MSG_VERSION_2019_2)
197 dst[i++] = param->gop_ctrl_mode;
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);
215 if (version >= MCU_MSG_VERSION_2019_2)
216 dst[i++] = param->tmpdqp;
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;
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;
229 return i * sizeof(*dst);
233 allegro_enc_create_channel(u32 *dst, struct mcu_msg_create_channel *msg)
235 enum mcu_msg_version version = msg->header.version;
238 dst[i++] = msg->user_id;
240 if (version >= MCU_MSG_VERSION_2019_2) {
241 dst[i++] = msg->blob_mcu_addr;
243 memcpy(&dst[i], msg->blob, msg->blob_size);
244 i += msg->blob_size / sizeof(*dst);
247 if (version >= MCU_MSG_VERSION_2019_2)
248 dst[i++] = msg->ep1_addr;
250 return i * sizeof(*dst);
253 ssize_t allegro_decode_config_blob(struct create_channel_param *param,
254 struct mcu_msg_create_channel_response *msg,
257 enum mcu_msg_version version = msg->header.version;
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]);
263 param->num_ref_idx_l0 = msg->num_ref_idx_l0;
264 param->num_ref_idx_l1 = msg->num_ref_idx_l1;
271 allegro_enc_destroy_channel(u32 *dst, struct mcu_msg_destroy_channel *msg)
275 dst[i++] = msg->channel_id;
277 return i * sizeof(*dst);
281 allegro_enc_push_buffers(u32 *dst, struct mcu_msg_push_buffers_internal *msg)
284 struct mcu_msg_push_buffers_internal_buffer *buffer;
285 unsigned int num_buffers = msg->num_buffers;
288 dst[i++] = msg->channel_id;
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;
297 return i * sizeof(*dst);
301 allegro_enc_put_stream_buffer(u32 *dst,
302 struct mcu_msg_put_stream_buffer *msg)
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);
314 return i * sizeof(*dst);
318 allegro_enc_encode_frame(u32 *dst, struct mcu_msg_encode_frame *msg)
320 enum mcu_msg_version version = msg->header.version;
323 dst[i++] = msg->channel_id;
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);
330 if (version >= MCU_MSG_VERSION_2019_2) {
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;
350 dst[i++] = lower_32_bits(msg->ep2_v);
351 dst[i++] = upper_32_bits(msg->ep2_v);
353 return i * sizeof(*dst);
357 allegro_dec_init(struct mcu_msg_init_response *msg, u32 *src)
361 msg->reserved0 = src[i++];
363 return i * sizeof(*src);
367 allegro_dec_create_channel(struct mcu_msg_create_channel_response *msg,
370 enum mcu_msg_version version = msg->header.version;
373 msg->channel_id = src[i++];
374 msg->user_id = src[i++];
376 * Version >= MCU_MSG_VERSION_2019_2 is handled in
377 * allegro_decode_config_blob().
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++]);
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++];
392 return i * sizeof(*src);
396 allegro_dec_destroy_channel(struct mcu_msg_destroy_channel_response *msg,
401 msg->channel_id = src[i++];
403 return i * sizeof(*src);
407 allegro_dec_encode_frame(struct mcu_msg_encode_frame_response *msg, u32 *src)
409 enum mcu_msg_version version = msg->header.version;
413 msg->channel_id = src[i++];
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++]);
449 msg->reserved1 = FIELD_GET(GENMASK(31, 16), src[i]);
450 msg->pps_qp = FIELD_GET(GENMASK(15, 0), src[i++]);
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++];
460 return i * sizeof(*src);
464 * allegro_encode_mail() - Encode allegro messages to firmware format
465 * @dst: Pointer to the memory that will be filled with data
466 * @msg: The allegro message that will be encoded
468 ssize_t allegro_encode_mail(u32 *dst, void *msg)
470 const struct mcu_msg_header *header = msg;
476 switch (header->type) {
477 case MCU_MSG_TYPE_INIT:
478 size = allegro_enc_init(&dst[1], msg);
480 case MCU_MSG_TYPE_CREATE_CHANNEL:
481 size = allegro_enc_create_channel(&dst[1], msg);
483 case MCU_MSG_TYPE_DESTROY_CHANNEL:
484 size = allegro_enc_destroy_channel(&dst[1], msg);
486 case MCU_MSG_TYPE_ENCODE_FRAME:
487 size = allegro_enc_encode_frame(&dst[1], msg);
489 case MCU_MSG_TYPE_PUT_STREAM_BUFFER:
490 size = allegro_enc_put_stream_buffer(&dst[1], msg);
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);
501 * The encoded messages might have different length depending on
502 * the firmware version or certain fields. Therefore, we have to
503 * set the body length after encoding the message.
505 dst[0] = FIELD_PREP(GENMASK(31, 16), header->type) |
506 FIELD_PREP(GENMASK(15, 0), size);
508 return size + sizeof(*dst);
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 parsed
516 * The message format in the mailbox depends on the firmware. Parse the
517 * different formats into a uniform message format that can be used without
518 * taking care of the firmware version.
520 int allegro_decode_mail(void *msg, u32 *src)
522 struct mcu_msg_header *header;
528 header->type = FIELD_GET(GENMASK(31, 16), src[0]);
531 switch (header->type) {
532 case MCU_MSG_TYPE_INIT:
533 allegro_dec_init(msg, src);
535 case MCU_MSG_TYPE_CREATE_CHANNEL:
536 allegro_dec_create_channel(msg, src);
538 case MCU_MSG_TYPE_DESTROY_CHANNEL:
539 allegro_dec_destroy_channel(msg, src);
541 case MCU_MSG_TYPE_ENCODE_FRAME:
542 allegro_dec_encode_frame(msg, src);