1 /* Copyright 2022 Advanced Micro Devices, Inc.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
17 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19 * OTHER DEALINGS IN THE SOFTWARE.
20 *
21 * Authors: AMD
22 *
23 */
24 #include "vpe_assert.h"
25 #include "common.h"
26 #include "vpe_priv.h"
27 #include "vpe_command.h"
28 #include "vpe10_cmd_builder.h"
29 #include "plane_desc_writer.h"
30 #include "reg_helper.h"
31
32 /***** Internal helpers *****/
33 static void get_np(struct vpe_priv *vpe_priv, struct vpe_cmd_info *cmd_info, int32_t *nps0,
34 int32_t *nps1, int32_t *npd0, int32_t *npd1);
35
36 static enum VPE_PLANE_CFG_ELEMENT_SIZE vpe_get_element_size(
37 enum vpe_surface_pixel_format format, int plane_idx);
38
vpe10_construct_cmd_builder(struct vpe_priv * vpe_priv,struct cmd_builder * builder)39 void vpe10_construct_cmd_builder(struct vpe_priv *vpe_priv, struct cmd_builder *builder)
40 {
41 builder->build_noops = vpe10_build_noops;
42 builder->build_vpe_cmd = vpe10_build_vpe_cmd;
43 builder->build_plane_descriptor = vpe10_build_plane_descriptor;
44 }
45
vpe10_build_noops(struct vpe_priv * vpe_priv,uint32_t ** ppbuf,uint32_t num_dwords)46 enum vpe_status vpe10_build_noops(struct vpe_priv *vpe_priv, uint32_t **ppbuf, uint32_t num_dwords)
47 {
48 uint32_t i;
49 uint32_t *buffer = *ppbuf;
50 uint32_t noop = VPE_CMD_HEADER(VPE_CMD_OPCODE_NOP, 0);
51
52 for (i = 0; i < num_dwords; i++)
53 *buffer++ = noop;
54
55 *ppbuf = buffer;
56
57 return VPE_STATUS_OK;
58 }
59
vpe10_build_vpe_cmd(struct vpe_priv * vpe_priv,struct vpe_build_bufs * cur_bufs,uint32_t cmd_idx)60 enum vpe_status vpe10_build_vpe_cmd(
61 struct vpe_priv *vpe_priv, struct vpe_build_bufs *cur_bufs, uint32_t cmd_idx)
62 {
63 struct cmd_builder *builder = &vpe_priv->resource.cmd_builder;
64 struct vpe_buf *emb_buf = &cur_bufs->emb_buf;
65 struct vpe_cmd_info *cmd_info = &vpe_priv->vpe_cmd_info[cmd_idx];
66 struct output_ctx *output_ctx;
67 struct pipe_ctx *pipe_ctx = NULL;
68 uint32_t i, j;
69
70 vpe_desc_writer_init(&vpe_priv->vpe_desc_writer, &cur_bufs->cmd_buf, cmd_info->cd);
71
72 // plane descriptor
73 builder->build_plane_descriptor(vpe_priv, emb_buf, cmd_idx);
74
75 vpe_desc_writer_add_plane_desc(
76 &vpe_priv->vpe_desc_writer, vpe_priv->plane_desc_writer.base_gpu_va, emb_buf->tmz);
77
78 // reclaim any pipe if the owner no longer presents
79 vpe_pipe_reclaim(vpe_priv, cmd_info);
80
81 config_writer_init(&vpe_priv->config_writer, emb_buf);
82
83 // frontend programming
84 for (i = 0; i < cmd_info->num_inputs; i++) {
85 bool reuse;
86 struct stream_ctx *stream_ctx;
87 enum vpe_cmd_type cmd_type = VPE_CMD_TYPE_COUNT;
88
89 // keep using the same pipe whenever possible
90 // this would allow reuse of the previous register configs
91 pipe_ctx = vpe_pipe_find_owner(vpe_priv, cmd_info->inputs[i].stream_idx, &reuse);
92 VPE_ASSERT(pipe_ctx);
93
94 if (!reuse) {
95 vpe_priv->resource.program_frontend(vpe_priv, pipe_ctx->pipe_idx, cmd_idx, i, false);
96 } else {
97 if (vpe_priv->init.debug.disable_reuse_bit)
98 reuse = false;
99
100 stream_ctx = &vpe_priv->stream_ctx[cmd_info->inputs[i].stream_idx];
101
102 // frame specific for same type of command
103 if (cmd_info->ops == VPE_CMD_OPS_BG)
104 cmd_type = VPE_CMD_TYPE_BG;
105 else if (cmd_info->ops == VPE_CMD_OPS_COMPOSITING)
106 cmd_type = VPE_CMD_TYPE_COMPOSITING;
107 else if (cmd_info->ops == VPE_CMD_OPS_BG_VSCF_INPUT)
108 cmd_type = VPE_CMD_TYPE_BG_VSCF_INPUT;
109 else if (cmd_info->ops == VPE_CMD_OPS_BG_VSCF_OUTPUT)
110 cmd_type = VPE_CMD_TYPE_BG_VSCF_OUTPUT;
111 else {
112 VPE_ASSERT(0);
113 return VPE_STATUS_ERROR;
114 }
115
116 // follow the same order of config generation in "non-reuse" case
117 // stream sharing
118 VPE_ASSERT(stream_ctx->num_configs);
119 for (j = 0; j < stream_ctx->num_configs; j++) {
120 vpe_desc_writer_add_config_desc(&vpe_priv->vpe_desc_writer,
121 stream_ctx->configs[j].config_base_addr, reuse, emb_buf->tmz);
122 }
123
124 // stream-op sharing
125 for (j = 0; j < stream_ctx->num_stream_op_configs[cmd_type]; j++) {
126 vpe_desc_writer_add_config_desc(&vpe_priv->vpe_desc_writer,
127 stream_ctx->stream_op_configs[cmd_type][j].config_base_addr, reuse,
128 emb_buf->tmz);
129 }
130
131 // command specific
132 vpe_priv->resource.program_frontend(vpe_priv, pipe_ctx->pipe_idx, cmd_idx, i, true);
133 }
134 }
135
136 VPE_ASSERT(pipe_ctx);
137
138 // If config writer has been crashed due to buffer overflow
139 if (vpe_priv->config_writer.status != VPE_STATUS_OK) {
140 return vpe_priv->config_writer.status;
141 }
142
143 // backend programming
144 output_ctx = &vpe_priv->output_ctx;
145 if (!output_ctx->num_configs) {
146 vpe_priv->resource.program_backend(vpe_priv, pipe_ctx->pipe_idx, cmd_idx, false);
147 } else {
148 bool reuse = !vpe_priv->init.debug.disable_reuse_bit;
149 // re-use output register configs
150 for (j = 0; j < output_ctx->num_configs; j++) {
151 vpe_desc_writer_add_config_desc(&vpe_priv->vpe_desc_writer,
152 output_ctx->configs[j].config_base_addr, reuse, emb_buf->tmz);
153 }
154
155 vpe_priv->resource.program_backend(vpe_priv, pipe_ctx->pipe_idx, cmd_idx, true);
156 }
157
158 /* If writer crashed due to buffer overflow */
159 if (vpe_priv->vpe_desc_writer.status != VPE_STATUS_OK) {
160 return vpe_priv->vpe_desc_writer.status;
161 }
162 vpe_desc_writer_complete(&vpe_priv->vpe_desc_writer);
163
164 return VPE_STATUS_OK;
165 }
166
vpe10_build_plane_descriptor(struct vpe_priv * vpe_priv,struct vpe_buf * buf,uint32_t cmd_idx)167 enum vpe_status vpe10_build_plane_descriptor(
168 struct vpe_priv *vpe_priv, struct vpe_buf *buf, uint32_t cmd_idx)
169 {
170 struct stream_ctx *stream_ctx;
171 struct vpe_surface_info *surface_info;
172 int32_t nps0, nps1, npd0, npd1;
173 int32_t stream_idx;
174 struct vpe_cmd_info *cmd_info;
175 PHYSICAL_ADDRESS_LOC *addrloc;
176 struct plane_desc_src src;
177 struct plane_desc_dst dst;
178
179 cmd_info = &vpe_priv->vpe_cmd_info[cmd_idx];
180
181 VPE_ASSERT(cmd_info->num_inputs == 1);
182
183 // obtains number of planes for each source/destination stream
184 get_np(vpe_priv, cmd_info, &nps0, &nps1, &npd0, &npd1);
185
186 plane_desc_writer_init(
187 &vpe_priv->plane_desc_writer, buf, nps0, npd0, nps1, npd1, VPE_PLANE_CFG_SUBOP_1_TO_1);
188
189 stream_idx = cmd_info->inputs[0].stream_idx;
190 stream_ctx = &vpe_priv->stream_ctx[stream_idx];
191 surface_info = &stream_ctx->stream.surface_info;
192
193 src.tmz = surface_info->address.tmz_surface;
194 src.swizzle = surface_info->swizzle;
195 src.rotation = stream_ctx->stream.rotation;
196
197 if (surface_info->address.type == VPE_PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) {
198 addrloc = &surface_info->address.video_progressive.luma_addr;
199
200 src.base_addr_lo = addrloc->u.low_part;
201 src.base_addr_hi = (uint32_t)addrloc->u.high_part;
202 src.pitch = (uint16_t)surface_info->plane_size.surface_pitch;
203 src.viewport_x = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.x;
204 src.viewport_y = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.y;
205 src.viewport_w = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.width;
206 src.viewport_h = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.height;
207 src.elem_size = (uint8_t)(vpe_get_element_size(surface_info->format, 0));
208
209 plane_desc_writer_add_source(&vpe_priv->plane_desc_writer, &src, true);
210
211 if (vpe_is_dual_plane_format(surface_info->format)) {
212 addrloc = &surface_info->address.video_progressive.chroma_addr;
213
214 src.base_addr_lo = addrloc->u.low_part;
215 src.base_addr_hi = (uint32_t)addrloc->u.high_part;
216 src.pitch = (uint16_t)surface_info->plane_size.chroma_pitch;
217 src.viewport_x = (uint16_t)cmd_info->inputs[0].scaler_data.viewport_c.x;
218 src.viewport_y = (uint16_t)cmd_info->inputs[0].scaler_data.viewport_c.y;
219 src.viewport_w = (uint16_t)cmd_info->inputs[0].scaler_data.viewport_c.width;
220 src.viewport_h = (uint16_t)cmd_info->inputs[0].scaler_data.viewport_c.height;
221 src.elem_size = (uint8_t)(vpe_get_element_size(surface_info->format, 1));
222
223 plane_desc_writer_add_source(&vpe_priv->plane_desc_writer, &src, false);
224 }
225 } else {
226 addrloc = &surface_info->address.grph.addr;
227
228 src.base_addr_lo = addrloc->u.low_part;
229 src.base_addr_hi = (uint32_t)addrloc->u.high_part;
230 src.pitch = (uint16_t)surface_info->plane_size.surface_pitch;
231 src.viewport_x = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.x;
232 src.viewport_y = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.y;
233 src.viewport_w = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.width;
234 src.viewport_h = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.height;
235 src.elem_size = (uint8_t)(vpe_get_element_size(surface_info->format, 0));
236
237 plane_desc_writer_add_source(&vpe_priv->plane_desc_writer, &src, true);
238 }
239
240 surface_info = &vpe_priv->output_ctx.surface;
241
242 VPE_ASSERT(surface_info->address.type == VPE_PLN_ADDR_TYPE_GRAPHICS);
243
244 addrloc = &surface_info->address.grph.addr;
245
246 dst.tmz = surface_info->address.tmz_surface;
247 dst.swizzle = surface_info->swizzle;
248
249 if (stream_ctx->flip_horizonal_output)
250 dst.mirror = VPE_MIRROR_HORIZONTAL;
251 else
252 dst.mirror = VPE_MIRROR_NONE;
253
254 dst.base_addr_lo = addrloc->u.low_part;
255 dst.base_addr_hi = (uint32_t)addrloc->u.high_part;
256 dst.pitch = (uint16_t)surface_info->plane_size.surface_pitch;
257 dst.viewport_x = (uint16_t)cmd_info->dst_viewport.x;
258 dst.viewport_y = (uint16_t)cmd_info->dst_viewport.y;
259 dst.viewport_w = (uint16_t)cmd_info->dst_viewport.width;
260 dst.viewport_h = (uint16_t)cmd_info->dst_viewport.height;
261 dst.elem_size = (uint8_t)(vpe_get_element_size(surface_info->format, 0));
262
263 plane_desc_writer_add_destination(&vpe_priv->plane_desc_writer, &dst, true);
264
265 return vpe_priv->plane_desc_writer.status;
266 }
267
get_np(struct vpe_priv * vpe_priv,struct vpe_cmd_info * cmd_info,int32_t * nps0,int32_t * nps1,int32_t * npd0,int32_t * npd1)268 static void get_np(struct vpe_priv *vpe_priv, struct vpe_cmd_info *cmd_info, int32_t *nps0,
269 int32_t *nps1, int32_t *npd0, int32_t *npd1)
270 {
271 *npd1 = 0;
272
273 if (cmd_info->num_inputs == 1) {
274 *nps1 = 0;
275 if (vpe_is_dual_plane_format(
276 vpe_priv->stream_ctx[cmd_info->inputs[0].stream_idx].stream.surface_info.format))
277 *nps0 = VPE_PLANE_CFG_TWO_PLANES;
278 else
279 *nps0 = VPE_PLANE_CFG_ONE_PLANE;
280 } else if (cmd_info->num_inputs == 2) {
281 if (vpe_is_dual_plane_format(
282 vpe_priv->stream_ctx[cmd_info->inputs[0].stream_idx].stream.surface_info.format))
283 *nps0 = VPE_PLANE_CFG_TWO_PLANES;
284 else
285 *nps0 = VPE_PLANE_CFG_ONE_PLANE;
286
287 if (vpe_is_dual_plane_format(
288 vpe_priv->stream_ctx[cmd_info->inputs[1].stream_idx].stream.surface_info.format))
289 *nps1 = VPE_PLANE_CFG_TWO_PLANES;
290 else
291 *nps1 = VPE_PLANE_CFG_ONE_PLANE;
292 } else {
293 *nps0 = 0;
294 *nps1 = 0;
295 *npd0 = 0;
296 return;
297 }
298
299 if (vpe_is_dual_plane_format(vpe_priv->output_ctx.surface.format))
300 *npd0 = 1;
301 else
302 *npd0 = 0;
303 }
304
vpe_get_element_size(enum vpe_surface_pixel_format format,int plane_idx)305 static enum VPE_PLANE_CFG_ELEMENT_SIZE vpe_get_element_size(
306 enum vpe_surface_pixel_format format, int plane_idx)
307 {
308 switch (format) {
309 // nv12/21
310 case VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
311 case VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
312 if (plane_idx == 0)
313 return VPE_PLANE_CFG_ELEMENT_SIZE_8BPE;
314 else
315 return VPE_PLANE_CFG_ELEMENT_SIZE_16BPE;
316 // P010
317 case VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
318 case VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
319 if (plane_idx == 0)
320 return VPE_PLANE_CFG_ELEMENT_SIZE_16BPE;
321 else
322 return VPE_PLANE_CFG_ELEMENT_SIZE_32BPE;
323 // 64bpp
324 case VPE_SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
325 case VPE_SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
326 case VPE_SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
327 case VPE_SURFACE_PIXEL_FORMAT_GRPH_RGBA16161616F:
328 case VPE_SURFACE_PIXEL_FORMAT_GRPH_BGRA16161616F:
329 return VPE_PLANE_CFG_ELEMENT_SIZE_64BPE;
330 default:
331 break;
332 }
333 return VPE_PLANE_CFG_ELEMENT_SIZE_32BPE;
334 }
335