1/*
2 * Copyright © 2018 NVIDIA Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23#include <errno.h>
24#include <string.h>
25
26#include "private.h"
27#include "tegra.h"
28#include "vic.h"
29#include "vic41.h"
30
31struct vic41 {
32    struct vic base;
33
34    struct {
35        struct drm_tegra_mapping *map;
36        struct drm_tegra_bo *bo;
37    } config;
38
39    struct {
40        struct drm_tegra_mapping *map;
41        struct drm_tegra_bo *bo;
42    } filter;
43};
44
45static int vic41_fill(struct vic *v, struct vic_image *output,
46                      unsigned int left, unsigned int top,
47                      unsigned int right, unsigned int bottom,
48                      unsigned int alpha, unsigned int red,
49                      unsigned int green, unsigned int blue)
50{
51    struct vic41 *vic = container_of(v, struct vic41, base);
52    ConfigStruct *c;
53    int err;
54
55    err = drm_tegra_bo_map(vic->config.bo, (void **)&c);
56    if (err < 0) {
57        fprintf(stderr, "failed to map configuration structure: %s\n",
58                strerror(-err));
59        return err;
60    }
61
62    memset(c, 0, sizeof(*c));
63
64    c->outputConfig.TargetRectTop = top;
65    c->outputConfig.TargetRectLeft = left;
66    c->outputConfig.TargetRectRight = right;
67    c->outputConfig.TargetRectBottom = bottom;
68    c->outputConfig.BackgroundAlpha = alpha;
69    c->outputConfig.BackgroundR = red;
70    c->outputConfig.BackgroundG = green;
71    c->outputConfig.BackgroundB = blue;
72
73    c->outputSurfaceConfig.OutPixelFormat = output->format;
74    c->outputSurfaceConfig.OutBlkKind = output->kind;
75    c->outputSurfaceConfig.OutBlkHeight = 0;
76    c->outputSurfaceConfig.OutSurfaceWidth = output->width - 1;
77    c->outputSurfaceConfig.OutSurfaceHeight = output->height - 1;
78    c->outputSurfaceConfig.OutLumaWidth = output->stride - 1;
79    c->outputSurfaceConfig.OutLumaHeight = output->height - 1;
80    c->outputSurfaceConfig.OutChromaWidth = 16383;
81    c->outputSurfaceConfig.OutChromaHeight = 16383;
82
83    drm_tegra_bo_unmap(vic->config.bo);
84
85    return 0;
86}
87
88static int vic41_blit(struct vic *v, struct vic_image *output,
89                      struct vic_image *input)
90{
91    struct vic41 *vic = container_of(v, struct vic41, base);
92    SlotSurfaceConfig *surface;
93    SlotConfig *slot;
94    ConfigStruct *c;
95    int err;
96
97    err = drm_tegra_bo_map(vic->config.bo, (void **)&c);
98    if (err < 0) {
99        fprintf(stderr, "failed to map configuration structure: %s\n",
100                strerror(-err));
101        return err;
102    }
103
104    memset(c, 0, sizeof(*c));
105
106    c->outputConfig.TargetRectTop = 0;
107    c->outputConfig.TargetRectLeft = 0;
108    c->outputConfig.TargetRectRight = output->width - 1;
109    c->outputConfig.TargetRectBottom = output->height - 1;
110    c->outputConfig.BackgroundAlpha = 255;
111    c->outputConfig.BackgroundR = 1023;
112    c->outputConfig.BackgroundG = 1023;
113    c->outputConfig.BackgroundB = 1023;
114
115    c->outputSurfaceConfig.OutPixelFormat = output->format;
116    c->outputSurfaceConfig.OutBlkKind = output->kind;
117    c->outputSurfaceConfig.OutBlkHeight = 0;
118    c->outputSurfaceConfig.OutSurfaceWidth = output->width - 1;
119    c->outputSurfaceConfig.OutSurfaceHeight = output->height - 1;
120    c->outputSurfaceConfig.OutLumaWidth = output->stride - 1;
121    c->outputSurfaceConfig.OutLumaHeight = output->height - 1;
122    c->outputSurfaceConfig.OutChromaWidth = 16383;
123    c->outputSurfaceConfig.OutChromaHeight = 16383;
124
125    slot = &c->slotStruct[0].slotConfig;
126    slot->SlotEnable = 1;
127    slot->CurrentFieldEnable = 1;
128    slot->PlanarAlpha = 255;
129    slot->ConstantAlpha = 1;
130    slot->SourceRectLeft = 0 << 16;
131    slot->SourceRectRight = (input->width - 1) << 16;
132    slot->SourceRectTop = 0 << 16;
133    slot->SourceRectBottom = (input->height - 1) << 16;
134    slot->DestRectLeft = 0;
135    slot->DestRectRight = output->width - 1;
136    slot->DestRectTop = 0;
137    slot->DestRectBottom = output->height - 1;
138    slot->SoftClampHigh = 1023;
139
140    surface = &c->slotStruct[0].slotSurfaceConfig;
141    surface->SlotPixelFormat = input->format;
142    surface->SlotBlkKind = input->kind;
143    surface->SlotBlkHeight = 0; /* XXX */
144    surface->SlotCacheWidth = VIC_CACHE_WIDTH_64Bx4; /* XXX */
145    surface->SlotSurfaceWidth = input->width - 1;
146    surface->SlotSurfaceHeight = input->height - 1;
147    surface->SlotLumaWidth = input->stride - 1;
148    surface->SlotLumaHeight = input->height - 1;
149    surface->SlotChromaWidth = 16383;
150    surface->SlotChromaHeight = 16383;
151
152    drm_tegra_bo_unmap(vic->config.bo);
153
154    return 0;
155}
156
157static int vic41_flip(struct vic *v, struct vic_image *output,
158                      struct vic_image *input)
159{
160    struct vic41 *vic = container_of(v, struct vic41, base);
161    SlotSurfaceConfig *surface;
162    SlotConfig *slot;
163    ConfigStruct *c;
164    int err;
165
166    err = drm_tegra_bo_map(vic->config.bo, (void **)&c);
167    if (err < 0) {
168        fprintf(stderr, "failed to map configuration structure: %s\n",
169                strerror(-err));
170        return err;
171    }
172
173    memset(c, 0, sizeof(*c));
174
175    c->outputConfig.TargetRectTop = 0;
176    c->outputConfig.TargetRectLeft = 0;
177    c->outputConfig.TargetRectRight = output->width - 1;
178    c->outputConfig.TargetRectBottom = output->height - 1;
179    c->outputConfig.BackgroundAlpha = 255;
180    c->outputConfig.BackgroundR = 1023;
181    c->outputConfig.BackgroundG = 1023;
182    c->outputConfig.BackgroundB = 1023;
183    c->outputConfig.OutputFlipY = 1;
184
185    c->outputSurfaceConfig.OutPixelFormat = output->format;
186    c->outputSurfaceConfig.OutBlkKind = output->kind;
187    c->outputSurfaceConfig.OutBlkHeight = 0;
188    c->outputSurfaceConfig.OutSurfaceWidth = output->width - 1;
189    c->outputSurfaceConfig.OutSurfaceHeight = output->height - 1;
190    c->outputSurfaceConfig.OutLumaWidth = output->stride - 1;
191    c->outputSurfaceConfig.OutLumaHeight = output->height - 1;
192    c->outputSurfaceConfig.OutChromaWidth = 16383;
193    c->outputSurfaceConfig.OutChromaHeight = 16383;
194
195    slot = &c->slotStruct[0].slotConfig;
196    slot->SlotEnable = 1;
197    slot->CurrentFieldEnable = 1;
198    slot->PlanarAlpha = 255;
199    slot->ConstantAlpha = 1;
200    slot->SourceRectLeft = 0 << 16;
201    slot->SourceRectRight = (input->width - 1) << 16;
202    slot->SourceRectTop = 0 << 16;
203    slot->SourceRectBottom = (input->height - 1) << 16;
204    slot->DestRectLeft = 0;
205    slot->DestRectRight = output->width - 1;
206    slot->DestRectTop = 0;
207    slot->DestRectBottom = output->height - 1;
208    slot->SoftClampHigh = 1023;
209
210    surface = &c->slotStruct[0].slotSurfaceConfig;
211    surface->SlotPixelFormat = input->format;
212    surface->SlotBlkKind = input->kind;
213    surface->SlotBlkHeight = 0; /* XXX */
214    surface->SlotCacheWidth = VIC_CACHE_WIDTH_64Bx4; /* XXX */
215    surface->SlotSurfaceWidth = input->width - 1;
216    surface->SlotSurfaceHeight = input->height - 1;
217    surface->SlotLumaWidth = input->stride - 1;
218    surface->SlotLumaHeight = input->height - 1;
219    surface->SlotChromaWidth = 16383;
220    surface->SlotChromaHeight = 16383;
221
222    drm_tegra_bo_unmap(vic->config.bo);
223
224    return 0;
225}
226
227static int vic41_execute(struct vic *v, struct drm_tegra_pushbuf *pushbuf,
228                         uint32_t **ptrp, struct vic_image *output,
229                         struct vic_image **inputs, unsigned int num_inputs)
230{
231    struct vic41 *vic = container_of(v, struct vic41, base);
232    unsigned int i;
233
234    if (num_inputs > 1)
235        return -EINVAL;
236
237    VIC_PUSH_METHOD(pushbuf, ptrp, NVB1B6_VIDEO_COMPOSITOR_SET_APPLICATION_ID, 1);
238    VIC_PUSH_METHOD(pushbuf, ptrp, NVB1B6_VIDEO_COMPOSITOR_SET_CONTROL_PARAMS, (sizeof(ConfigStruct) / 16) << 16);
239    VIC_PUSH_BUFFER(pushbuf, ptrp, NVB1B6_VIDEO_COMPOSITOR_SET_CONFIG_STRUCT_OFFSET, vic->config.map, 0, 0);
240    VIC_PUSH_BUFFER(pushbuf, ptrp, NVB1B6_VIDEO_COMPOSITOR_SET_FILTER_STRUCT_OFFSET, vic->filter.map, 0, 0);
241    VIC_PUSH_BUFFER(pushbuf, ptrp, NVB1B6_VIDEO_COMPOSITOR_SET_OUTPUT_SURFACE_LUMA_OFFSET, output->map, 0, 0);
242
243    for (i = 0; i < num_inputs; i++) {
244        uint32_t method = NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE0_LUMA_OFFSET(0) + (i * 3) * 4;
245
246        VIC_PUSH_BUFFER(pushbuf, ptrp, method, inputs[i]->map, 0, 0);
247    }
248
249    VIC_PUSH_METHOD(pushbuf, ptrp, NVB1B6_VIDEO_COMPOSITOR_EXECUTE, 1 << 8);
250
251    return 0;
252}
253
254static void vic41_free(struct vic *v)
255{
256    struct vic41 *vic = container_of(v, struct vic41, base);
257
258    drm_tegra_channel_unmap(vic->filter.map);
259    drm_tegra_bo_unref(vic->filter.bo);
260
261    drm_tegra_channel_unmap(vic->config.map);
262    drm_tegra_bo_unref(vic->config.bo);
263
264    drm_tegra_syncpoint_free(v->syncpt);
265
266    free(vic);
267}
268
269static const struct vic_ops vic41_ops = {
270    .fill = vic41_fill,
271    .blit = vic41_blit,
272    .flip = vic41_flip,
273    .execute = vic41_execute,
274    .free = vic41_free,
275};
276
277int vic41_new(struct drm_tegra *drm, struct drm_tegra_channel *channel,
278              struct vic **vicp)
279{
280    struct vic41 *vic;
281    void *ptr;
282    int err;
283
284    vic = calloc(1, sizeof(*vic));
285    if (!vic)
286        return -ENOMEM;
287
288    vic->base.drm = drm;
289    vic->base.channel = channel;
290    vic->base.ops = &vic41_ops;
291    vic->base.version = 0x18;
292
293    err = drm_tegra_syncpoint_new(drm, &vic->base.syncpt);
294    if (err < 0) {
295        fprintf(stderr, "failed to allocate syncpoint: %s\n", strerror(-err));
296        return err;
297    }
298
299    err = drm_tegra_bo_new(drm, 0, 16384, &vic->config.bo);
300    if (err < 0) {
301        fprintf(stderr, "failed to allocate configuration structurer: %s\n",
302                strerror(-err));
303        return err;
304    }
305
306    err = drm_tegra_channel_map(channel, vic->config.bo, DRM_TEGRA_CHANNEL_MAP_READ,
307                                &vic->config.map);
308    if (err < 0) {
309        fprintf(stderr, "failed to map configuration structure: %s\n",
310                strerror(-err));
311        return err;
312    }
313
314    err = drm_tegra_bo_new(drm, 0, 16384, &vic->filter.bo);
315    if (err < 0) {
316        fprintf(stderr, "failed to allocate filter buffer: %s\n",
317                strerror(-err));
318        return err;
319    }
320
321    err = drm_tegra_bo_map(vic->filter.bo, &ptr);
322    if (err < 0) {
323        fprintf(stderr, "failed to map filter buffer: %s\n", strerror(-err));
324        return err;
325    }
326
327    memset(ptr, 0, 16384);
328    drm_tegra_bo_unmap(vic->filter.bo);
329
330    err = drm_tegra_channel_map(channel, vic->filter.bo, DRM_TEGRA_CHANNEL_MAP_READ,
331                                &vic->filter.map);
332    if (err < 0) {
333        fprintf(stderr, "failed to map filter buffer: %s\n",
334                strerror(-err));
335        return err;
336    }
337
338    if (vicp)
339        *vicp = &vic->base;
340
341    return 0;
342}
343