xref: /linux/drivers/media/platform/allegro-dvt/allegro-mail.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
4  *
5  * Helper functions for handling messages that are send via mailbox to the
6  * 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 
msg_type_name(enum mcu_msg_type type)17 const 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 }
41 EXPORT_SYMBOL(msg_type_name);
42 
43 static ssize_t
allegro_enc_init(u32 * dst,struct mcu_msg_init_request * msg)44 allegro_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 
settings_get_mcu_codec(struct create_channel_param * param)63 static 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 
87 ssize_t
allegro_encode_config_blob(u32 * dst,struct create_channel_param * param)88 allegro_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 	else
120 		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 	else
186 		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 	else
199 		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 
232 static ssize_t
allegro_enc_create_channel(u32 * dst,struct mcu_msg_create_channel * msg)233 allegro_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 
allegro_decode_config_blob(struct create_channel_param * param,struct mcu_msg_create_channel_response * msg,u32 * src)253 ssize_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 
270 static ssize_t
allegro_enc_destroy_channel(u32 * dst,struct mcu_msg_destroy_channel * msg)271 allegro_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 
280 static ssize_t
allegro_enc_push_buffers(u32 * dst,struct mcu_msg_push_buffers_internal * msg)281 allegro_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 
300 static ssize_t
allegro_enc_put_stream_buffer(u32 * dst,struct mcu_msg_put_stream_buffer * msg)301 allegro_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 
317 static ssize_t
allegro_enc_encode_frame(u32 * dst,struct mcu_msg_encode_frame * msg)318 allegro_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 
356 static ssize_t
allegro_dec_init(struct mcu_msg_init_response * msg,u32 * src)357 allegro_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 
366 static ssize_t
allegro_dec_create_channel(struct mcu_msg_create_channel_response * msg,u32 * src)367 allegro_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 in
377 	 * 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 
395 static ssize_t
allegro_dec_destroy_channel(struct mcu_msg_destroy_channel_response * msg,u32 * src)396 allegro_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 
406 static ssize_t
allegro_dec_encode_frame(struct mcu_msg_encode_frame_response * msg,u32 * src)407 allegro_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 format
465  * @dst: Pointer to the memory that will be filled with data
466  * @msg: The allegro message that will be encoded
467  */
allegro_encode_mail(u32 * dst,void * msg)468 ssize_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 on
502 	 * the firmware version or certain fields. Therefore, we have to
503 	 * 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 parsed
515  *
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.
519  */
allegro_decode_mail(void * msg,u32 * src)520 int 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