1 | /* |
2 | * Copyright 2018 Red Hat Inc. |
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 | #include "wndw.h" |
23 | #include "atom.h" |
24 | |
25 | #include <drm/drm_atomic_helper.h> |
26 | #include <nouveau_bo.h> |
27 | |
28 | #include <nvif/if0014.h> |
29 | #include <nvif/pushc37b.h> |
30 | |
31 | #include <nvhw/class/clc37e.h> |
32 | |
33 | static int |
34 | wndwc37e_csc_clr(struct nv50_wndw *wndw) |
35 | { |
36 | return 0; |
37 | } |
38 | |
39 | static int |
40 | wndwc37e_csc_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) |
41 | { |
42 | struct nvif_push *push = wndw->wndw.push; |
43 | int ret; |
44 | |
45 | if ((ret = PUSH_WAIT(push, 13))) |
46 | return ret; |
47 | |
48 | PUSH_MTHD(push, NVC37E, SET_CSC_RED2RED, asyw->csc.matrix, 12); |
49 | return 0; |
50 | } |
51 | |
52 | static int |
53 | wndwc37e_ilut_clr(struct nv50_wndw *wndw) |
54 | { |
55 | struct nvif_push *push = wndw->wndw.push; |
56 | int ret; |
57 | |
58 | if ((ret = PUSH_WAIT(push, 2))) |
59 | return ret; |
60 | |
61 | PUSH_MTHD(push, NVC37E, SET_CONTEXT_DMA_INPUT_LUT, 0x00000000); |
62 | return 0; |
63 | } |
64 | |
65 | static int |
66 | wndwc37e_ilut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) |
67 | { |
68 | struct nvif_push *push = wndw->wndw.push; |
69 | int ret; |
70 | |
71 | if ((ret = PUSH_WAIT(push, 4))) |
72 | return ret; |
73 | |
74 | PUSH_MTHD(push, NVC37E, SET_CONTROL_INPUT_LUT, |
75 | NVVAL(NVC37E, SET_CONTROL_INPUT_LUT, OUTPUT_MODE, asyw->xlut.i.output_mode) | |
76 | NVVAL(NVC37E, SET_CONTROL_INPUT_LUT, RANGE, asyw->xlut.i.range) | |
77 | NVVAL(NVC37E, SET_CONTROL_INPUT_LUT, SIZE, asyw->xlut.i.size), |
78 | |
79 | SET_OFFSET_INPUT_LUT, asyw->xlut.i.offset >> 8, |
80 | SET_CONTEXT_DMA_INPUT_LUT, asyw->xlut.handle); |
81 | return 0; |
82 | } |
83 | |
84 | static void |
85 | wndwc37e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size) |
86 | { |
87 | asyw->xlut.i.size = size == 1024 ? NVC37E_SET_CONTROL_INPUT_LUT_SIZE_SIZE_1025 : |
88 | NVC37E_SET_CONTROL_INPUT_LUT_SIZE_SIZE_257; |
89 | asyw->xlut.i.range = NVC37E_SET_CONTROL_INPUT_LUT_RANGE_UNITY; |
90 | asyw->xlut.i.output_mode = NVC37E_SET_CONTROL_INPUT_LUT_OUTPUT_MODE_INTERPOLATE; |
91 | asyw->xlut.i.load = head907d_olut_load; |
92 | } |
93 | |
94 | int |
95 | wndwc37e_blend_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) |
96 | { |
97 | struct nvif_push *push = wndw->wndw.push; |
98 | int ret; |
99 | |
100 | if ((ret = PUSH_WAIT(push, 8))) |
101 | return ret; |
102 | |
103 | PUSH_MTHD(push, NVC37E, SET_COMPOSITION_CONTROL, |
104 | NVDEF(NVC37E, SET_COMPOSITION_CONTROL, COLOR_KEY_SELECT, DISABLE) | |
105 | NVVAL(NVC37E, SET_COMPOSITION_CONTROL, DEPTH, asyw->blend.depth), |
106 | |
107 | SET_COMPOSITION_CONSTANT_ALPHA, |
108 | NVVAL(NVC37E, SET_COMPOSITION_CONSTANT_ALPHA, K1, asyw->blend.k1) | |
109 | NVVAL(NVC37E, SET_COMPOSITION_CONSTANT_ALPHA, K2, 0), |
110 | |
111 | SET_COMPOSITION_FACTOR_SELECT, |
112 | NVVAL(NVC37E, SET_COMPOSITION_FACTOR_SELECT, SRC_COLOR_FACTOR_MATCH_SELECT, |
113 | asyw->blend.src_color) | |
114 | NVVAL(NVC37E, SET_COMPOSITION_FACTOR_SELECT, SRC_COLOR_FACTOR_NO_MATCH_SELECT, |
115 | asyw->blend.src_color) | |
116 | NVVAL(NVC37E, SET_COMPOSITION_FACTOR_SELECT, DST_COLOR_FACTOR_MATCH_SELECT, |
117 | asyw->blend.dst_color) | |
118 | NVVAL(NVC37E, SET_COMPOSITION_FACTOR_SELECT, DST_COLOR_FACTOR_NO_MATCH_SELECT, |
119 | asyw->blend.dst_color), |
120 | |
121 | SET_KEY_ALPHA, |
122 | NVVAL(NVC37E, SET_KEY_ALPHA, MIN, 0x0000) | |
123 | NVVAL(NVC37E, SET_KEY_ALPHA, MAX, 0xffff), |
124 | |
125 | SET_KEY_RED_CR, |
126 | NVVAL(NVC37E, SET_KEY_RED_CR, MIN, 0x0000) | |
127 | NVVAL(NVC37E, SET_KEY_RED_CR, MAX, 0xffff), |
128 | |
129 | SET_KEY_GREEN_Y, |
130 | NVVAL(NVC37E, SET_KEY_GREEN_Y, MIN, 0x0000) | |
131 | NVVAL(NVC37E, SET_KEY_GREEN_Y, MAX, 0xffff), |
132 | |
133 | SET_KEY_BLUE_CB, |
134 | NVVAL(NVC37E, SET_KEY_BLUE_CB, MIN, 0x0000) | |
135 | NVVAL(NVC37E, SET_KEY_BLUE_CB, MAX, 0xffff)); |
136 | return 0; |
137 | } |
138 | |
139 | int |
140 | wndwc37e_image_clr(struct nv50_wndw *wndw) |
141 | { |
142 | struct nvif_push *push = wndw->wndw.push; |
143 | int ret; |
144 | |
145 | if ((ret = PUSH_WAIT(push, 4))) |
146 | return ret; |
147 | |
148 | PUSH_MTHD(push, NVC37E, SET_PRESENT_CONTROL, |
149 | NVVAL(NVC37E, SET_PRESENT_CONTROL, MIN_PRESENT_INTERVAL, 0) | |
150 | NVDEF(NVC37E, SET_PRESENT_CONTROL, BEGIN_MODE, NON_TEARING)); |
151 | |
152 | PUSH_MTHD(push, NVC37E, SET_CONTEXT_DMA_ISO(0), 0x00000000); |
153 | return 0; |
154 | } |
155 | |
156 | static int |
157 | wndwc37e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) |
158 | { |
159 | struct nvif_push *push = wndw->wndw.push; |
160 | int ret; |
161 | |
162 | if ((ret = PUSH_WAIT(push, 17))) |
163 | return ret; |
164 | |
165 | PUSH_MTHD(push, NVC37E, SET_PRESENT_CONTROL, |
166 | NVVAL(NVC37E, SET_PRESENT_CONTROL, MIN_PRESENT_INTERVAL, asyw->image.interval) | |
167 | NVVAL(NVC37E, SET_PRESENT_CONTROL, BEGIN_MODE, asyw->image.mode) | |
168 | NVDEF(NVC37E, SET_PRESENT_CONTROL, TIMESTAMP_MODE, DISABLE)); |
169 | |
170 | PUSH_MTHD(push, NVC37E, SET_SIZE, |
171 | NVVAL(NVC37E, SET_SIZE, WIDTH, asyw->image.w) | |
172 | NVVAL(NVC37E, SET_SIZE, HEIGHT, asyw->image.h), |
173 | |
174 | SET_STORAGE, |
175 | NVVAL(NVC37E, SET_STORAGE, BLOCK_HEIGHT, asyw->image.blockh) | |
176 | NVVAL(NVC37E, SET_STORAGE, MEMORY_LAYOUT, asyw->image.layout), |
177 | |
178 | SET_PARAMS, |
179 | NVVAL(NVC37E, SET_PARAMS, FORMAT, asyw->image.format) | |
180 | NVVAL(NVC37E, SET_PARAMS, COLOR_SPACE, asyw->image.colorspace) | |
181 | NVDEF(NVC37E, SET_PARAMS, INPUT_RANGE, BYPASS) | |
182 | NVDEF(NVC37E, SET_PARAMS, UNDERREPLICATE, DISABLE) | |
183 | NVDEF(NVC37E, SET_PARAMS, DE_GAMMA, NONE) | |
184 | NVVAL(NVC37E, SET_PARAMS, CSC, asyw->csc.valid) | |
185 | NVDEF(NVC37E, SET_PARAMS, CLAMP_BEFORE_BLEND, DISABLE) | |
186 | NVDEF(NVC37E, SET_PARAMS, SWAP_UV, DISABLE), |
187 | |
188 | SET_PLANAR_STORAGE(0), |
189 | NVVAL(NVC37E, SET_PLANAR_STORAGE, PITCH, asyw->image.blocks[0]) | |
190 | NVVAL(NVC37E, SET_PLANAR_STORAGE, PITCH, asyw->image.pitch[0] >> 6)); |
191 | |
192 | PUSH_MTHD(push, NVC37E, SET_CONTEXT_DMA_ISO(0), asyw->image.handle, 1); |
193 | PUSH_MTHD(push, NVC37E, SET_OFFSET(0), asyw->image.offset[0] >> 8); |
194 | |
195 | PUSH_MTHD(push, NVC37E, SET_POINT_IN(0), |
196 | NVVAL(NVC37E, SET_POINT_IN, X, asyw->state.src_x >> 16) | |
197 | NVVAL(NVC37E, SET_POINT_IN, Y, asyw->state.src_y >> 16)); |
198 | |
199 | PUSH_MTHD(push, NVC37E, SET_SIZE_IN, |
200 | NVVAL(NVC37E, SET_SIZE_IN, WIDTH, asyw->state.src_w >> 16) | |
201 | NVVAL(NVC37E, SET_SIZE_IN, HEIGHT, asyw->state.src_h >> 16)); |
202 | |
203 | PUSH_MTHD(push, NVC37E, SET_SIZE_OUT, |
204 | NVVAL(NVC37E, SET_SIZE_OUT, WIDTH, asyw->state.crtc_w) | |
205 | NVVAL(NVC37E, SET_SIZE_OUT, HEIGHT, asyw->state.crtc_h)); |
206 | return 0; |
207 | } |
208 | |
209 | int |
210 | wndwc37e_ntfy_clr(struct nv50_wndw *wndw) |
211 | { |
212 | struct nvif_push *push = wndw->wndw.push; |
213 | int ret; |
214 | |
215 | if ((ret = PUSH_WAIT(push, 2))) |
216 | return ret; |
217 | |
218 | PUSH_MTHD(push, NVC37E, SET_CONTEXT_DMA_NOTIFIER, 0x00000000); |
219 | return 0; |
220 | } |
221 | |
222 | int |
223 | wndwc37e_ntfy_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) |
224 | { |
225 | struct nvif_push *push = wndw->wndw.push; |
226 | int ret; |
227 | |
228 | if ((ret = PUSH_WAIT(push, 3))) |
229 | return ret; |
230 | |
231 | PUSH_MTHD(push, NVC37E, SET_CONTEXT_DMA_NOTIFIER, asyw->ntfy.handle, |
232 | |
233 | SET_NOTIFIER_CONTROL, |
234 | NVVAL(NVC37E, SET_NOTIFIER_CONTROL, MODE, asyw->ntfy.awaken) | |
235 | NVVAL(NVC37E, SET_NOTIFIER_CONTROL, OFFSET, asyw->ntfy.offset >> 4)); |
236 | return 0; |
237 | } |
238 | |
239 | int |
240 | wndwc37e_sema_clr(struct nv50_wndw *wndw) |
241 | { |
242 | struct nvif_push *push = wndw->wndw.push; |
243 | int ret; |
244 | |
245 | if ((ret = PUSH_WAIT(push, 2))) |
246 | return ret; |
247 | |
248 | PUSH_MTHD(push, NVC37E, SET_CONTEXT_DMA_SEMAPHORE, 0x00000000); |
249 | return 0; |
250 | } |
251 | |
252 | int |
253 | wndwc37e_sema_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) |
254 | { |
255 | struct nvif_push *push = wndw->wndw.push; |
256 | int ret; |
257 | |
258 | if ((ret = PUSH_WAIT(push, 5))) |
259 | return ret; |
260 | |
261 | PUSH_MTHD(push, NVC37E, SET_SEMAPHORE_CONTROL, asyw->sema.offset, |
262 | SET_SEMAPHORE_ACQUIRE, asyw->sema.acquire, |
263 | SET_SEMAPHORE_RELEASE, asyw->sema.release, |
264 | SET_CONTEXT_DMA_SEMAPHORE, asyw->sema.handle); |
265 | return 0; |
266 | } |
267 | |
268 | int |
269 | wndwc37e_update(struct nv50_wndw *wndw, u32 *interlock) |
270 | { |
271 | struct nvif_push *push = wndw->wndw.push; |
272 | int ret; |
273 | |
274 | if ((ret = PUSH_WAIT(push, 5))) |
275 | return ret; |
276 | |
277 | PUSH_MTHD(push, NVC37E, SET_INTERLOCK_FLAGS, interlock[NV50_DISP_INTERLOCK_CURS] << 1 | |
278 | interlock[NV50_DISP_INTERLOCK_CORE], |
279 | SET_WINDOW_INTERLOCK_FLAGS, interlock[NV50_DISP_INTERLOCK_WNDW]); |
280 | |
281 | PUSH_MTHD(push, NVC37E, UPDATE, 0x00000001 | |
282 | NVVAL(NVC37E, UPDATE, INTERLOCK_WITH_WIN_IMM, |
283 | !!(interlock[NV50_DISP_INTERLOCK_WIMM] & wndw->interlock.data))); |
284 | |
285 | return PUSH_KICK(push); |
286 | } |
287 | |
288 | void |
289 | wndwc37e_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, |
290 | struct nv50_head_atom *asyh) |
291 | { |
292 | } |
293 | |
294 | int |
295 | wndwc37e_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, |
296 | struct nv50_head_atom *asyh) |
297 | { |
298 | return drm_atomic_helper_check_plane_state(plane_state: &asyw->state, crtc_state: &asyh->state, |
299 | DRM_PLANE_NO_SCALING, |
300 | DRM_PLANE_NO_SCALING, |
301 | can_position: true, can_update_disabled: true); |
302 | } |
303 | |
304 | static const u32 |
305 | wndwc37e_format[] = { |
306 | DRM_FORMAT_C8, |
307 | DRM_FORMAT_YUYV, |
308 | DRM_FORMAT_UYVY, |
309 | DRM_FORMAT_XRGB8888, |
310 | DRM_FORMAT_ARGB8888, |
311 | DRM_FORMAT_RGB565, |
312 | DRM_FORMAT_XRGB1555, |
313 | DRM_FORMAT_ARGB1555, |
314 | DRM_FORMAT_XBGR2101010, |
315 | DRM_FORMAT_ABGR2101010, |
316 | DRM_FORMAT_XBGR8888, |
317 | DRM_FORMAT_ABGR8888, |
318 | DRM_FORMAT_XRGB2101010, |
319 | DRM_FORMAT_ARGB2101010, |
320 | DRM_FORMAT_XBGR16161616F, |
321 | DRM_FORMAT_ABGR16161616F, |
322 | 0 |
323 | }; |
324 | |
325 | static const struct nv50_wndw_func |
326 | wndwc37e = { |
327 | .acquire = wndwc37e_acquire, |
328 | .release = wndwc37e_release, |
329 | .sema_set = wndwc37e_sema_set, |
330 | .sema_clr = wndwc37e_sema_clr, |
331 | .ntfy_set = wndwc37e_ntfy_set, |
332 | .ntfy_clr = wndwc37e_ntfy_clr, |
333 | .ntfy_reset = corec37d_ntfy_init, |
334 | .ntfy_wait_begun = base507c_ntfy_wait_begun, |
335 | .ilut = wndwc37e_ilut, |
336 | .ilut_size = 1024, |
337 | .xlut_set = wndwc37e_ilut_set, |
338 | .xlut_clr = wndwc37e_ilut_clr, |
339 | .csc = base907c_csc, |
340 | .csc_set = wndwc37e_csc_set, |
341 | .csc_clr = wndwc37e_csc_clr, |
342 | .image_set = wndwc37e_image_set, |
343 | .image_clr = wndwc37e_image_clr, |
344 | .blend_set = wndwc37e_blend_set, |
345 | .update = wndwc37e_update, |
346 | }; |
347 | |
348 | int |
349 | wndwc37e_new_(const struct nv50_wndw_func *func, struct nouveau_drm *drm, |
350 | enum drm_plane_type type, int index, s32 oclass, u32 heads, |
351 | struct nv50_wndw **pwndw) |
352 | { |
353 | struct nvif_disp_chan_v0 args = { |
354 | .id = index, |
355 | }; |
356 | struct nv50_disp *disp = nv50_disp(dev: drm->dev); |
357 | struct nv50_wndw *wndw; |
358 | int ret; |
359 | |
360 | ret = nv50_wndw_new_(func, drm->dev, type, name: "wndw" , index, |
361 | format: wndwc37e_format, heads, NV50_DISP_INTERLOCK_WNDW, |
362 | BIT(index), &wndw); |
363 | if (*pwndw = wndw, ret) |
364 | return ret; |
365 | |
366 | ret = nv50_dmac_create(device: &drm->client.device, disp: &disp->disp->object, |
367 | oclass: &oclass, head: 0, data: &args, size: sizeof(args), |
368 | syncbuf: disp->sync->offset, dmac: &wndw->wndw); |
369 | if (ret) { |
370 | NV_ERROR(drm, "qndw%04x allocation failed: %d\n" , oclass, ret); |
371 | return ret; |
372 | } |
373 | |
374 | wndw->ntfy = NV50_DISP_WNDW_NTFY(wndw->id); |
375 | wndw->sema = NV50_DISP_WNDW_SEM0(wndw->id); |
376 | wndw->data = 0x00000000; |
377 | return 0; |
378 | } |
379 | |
380 | int |
381 | wndwc37e_new(struct nouveau_drm *drm, enum drm_plane_type type, int index, |
382 | s32 oclass, struct nv50_wndw **pwndw) |
383 | { |
384 | return wndwc37e_new_(&wndwc37e, drm, type, index, oclass, |
385 | BIT(index >> 1), pwndw); |
386 | } |
387 | |