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