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 "base.h" |
23 | |
24 | #include <nvif/if0014.h> |
25 | #include <nvif/push507c.h> |
26 | #include <nvif/timer.h> |
27 | |
28 | #include <nvhw/class/cl507c.h> |
29 | |
30 | #include <drm/drm_atomic_helper.h> |
31 | #include <drm/drm_fourcc.h> |
32 | |
33 | #include "nouveau_bo.h" |
34 | |
35 | int |
36 | base507c_update(struct nv50_wndw *wndw, u32 *interlock) |
37 | { |
38 | struct nvif_push *push = wndw->wndw.push; |
39 | int ret; |
40 | |
41 | if ((ret = PUSH_WAIT(push, 2))) |
42 | return ret; |
43 | |
44 | PUSH_MTHD(push, NV507C, UPDATE, interlock[NV50_DISP_INTERLOCK_CORE]); |
45 | return PUSH_KICK(push); |
46 | } |
47 | |
48 | int |
49 | base507c_image_clr(struct nv50_wndw *wndw) |
50 | { |
51 | struct nvif_push *push = wndw->wndw.push; |
52 | int ret; |
53 | |
54 | if ((ret = PUSH_WAIT(push, 4))) |
55 | return ret; |
56 | |
57 | PUSH_MTHD(push, NV507C, SET_PRESENT_CONTROL, |
58 | NVDEF(NV507C, SET_PRESENT_CONTROL, BEGIN_MODE, NON_TEARING) | |
59 | NVVAL(NV507C, SET_PRESENT_CONTROL, MIN_PRESENT_INTERVAL, 0)); |
60 | |
61 | PUSH_MTHD(push, NV507C, SET_CONTEXT_DMA_ISO, 0x00000000); |
62 | return 0; |
63 | } |
64 | |
65 | static int |
66 | base507c_image_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, 13))) |
72 | return ret; |
73 | |
74 | PUSH_MTHD(push, NV507C, SET_PRESENT_CONTROL, |
75 | NVVAL(NV507C, SET_PRESENT_CONTROL, BEGIN_MODE, asyw->image.mode) | |
76 | NVVAL(NV507C, SET_PRESENT_CONTROL, MIN_PRESENT_INTERVAL, asyw->image.interval)); |
77 | |
78 | PUSH_MTHD(push, NV507C, SET_CONTEXT_DMA_ISO, asyw->image.handle[0]); |
79 | |
80 | if (asyw->image.format == NV507C_SURFACE_SET_PARAMS_FORMAT_RF16_GF16_BF16_AF16) { |
81 | PUSH_MTHD(push, NV507C, SET_PROCESSING, |
82 | NVDEF(NV507C, SET_PROCESSING, USE_GAIN_OFS, ENABLE), |
83 | |
84 | SET_CONVERSION, |
85 | NVVAL(NV507C, SET_CONVERSION, GAIN, 0) | |
86 | NVVAL(NV507C, SET_CONVERSION, OFS, 0x64)); |
87 | } else { |
88 | PUSH_MTHD(push, NV507C, SET_PROCESSING, |
89 | NVDEF(NV507C, SET_PROCESSING, USE_GAIN_OFS, DISABLE), |
90 | |
91 | SET_CONVERSION, |
92 | NVVAL(NV507C, SET_CONVERSION, GAIN, 0) | |
93 | NVVAL(NV507C, SET_CONVERSION, OFS, 0)); |
94 | } |
95 | |
96 | PUSH_MTHD(push, NV507C, SURFACE_SET_OFFSET(0, 0), asyw->image.offset[0] >> 8); |
97 | |
98 | PUSH_MTHD(push, NV507C, SURFACE_SET_SIZE(0), |
99 | NVVAL(NV507C, SURFACE_SET_SIZE, WIDTH, asyw->image.w) | |
100 | NVVAL(NV507C, SURFACE_SET_SIZE, HEIGHT, asyw->image.h), |
101 | |
102 | SURFACE_SET_STORAGE(0), |
103 | NVVAL(NV507C, SURFACE_SET_STORAGE, MEMORY_LAYOUT, asyw->image.layout) | |
104 | NVVAL(NV507C, SURFACE_SET_STORAGE, PITCH, asyw->image.pitch[0] >> 8) | |
105 | NVVAL(NV507C, SURFACE_SET_STORAGE, PITCH, asyw->image.blocks[0]) | |
106 | NVVAL(NV507C, SURFACE_SET_STORAGE, BLOCK_HEIGHT, asyw->image.blockh), |
107 | |
108 | SURFACE_SET_PARAMS(0), |
109 | NVVAL(NV507C, SURFACE_SET_PARAMS, FORMAT, asyw->image.format) | |
110 | NVDEF(NV507C, SURFACE_SET_PARAMS, SUPER_SAMPLE, X1_AA) | |
111 | NVDEF(NV507C, SURFACE_SET_PARAMS, GAMMA, LINEAR) | |
112 | NVDEF(NV507C, SURFACE_SET_PARAMS, LAYOUT, FRM) | |
113 | NVVAL(NV507C, SURFACE_SET_PARAMS, KIND, asyw->image.kind) | |
114 | NVDEF(NV507C, SURFACE_SET_PARAMS, PART_STRIDE, PARTSTRIDE_256)); |
115 | return 0; |
116 | } |
117 | |
118 | int |
119 | base507c_xlut_clr(struct nv50_wndw *wndw) |
120 | { |
121 | struct nvif_push *push = wndw->wndw.push; |
122 | int ret; |
123 | |
124 | if ((ret = PUSH_WAIT(push, 2))) |
125 | return ret; |
126 | |
127 | PUSH_MTHD(push, NV507C, SET_BASE_LUT_LO, |
128 | NVDEF(NV507C, SET_BASE_LUT_LO, ENABLE, DISABLE)); |
129 | return 0; |
130 | } |
131 | |
132 | int |
133 | base507c_xlut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) |
134 | { |
135 | struct nvif_push *push = wndw->wndw.push; |
136 | int ret; |
137 | |
138 | if ((ret = PUSH_WAIT(push, 2))) |
139 | return ret; |
140 | |
141 | PUSH_MTHD(push, NV507C, SET_BASE_LUT_LO, |
142 | NVDEF(NV507C, SET_BASE_LUT_LO, ENABLE, USE_CORE_LUT)); |
143 | return 0; |
144 | } |
145 | |
146 | int |
147 | base507c_ntfy_wait_begun(struct nouveau_bo *bo, u32 offset, |
148 | struct nvif_device *device) |
149 | { |
150 | s64 time = nvif_msec(device, 2000ULL, |
151 | if (NVBO_TD32(bo, offset, NV_DISP_BASE_NOTIFIER_1, _0, STATUS, ==, BEGUN)) |
152 | break; |
153 | usleep_range(1, 2); |
154 | ); |
155 | return time < 0 ? time : 0; |
156 | } |
157 | |
158 | int |
159 | base507c_ntfy_clr(struct nv50_wndw *wndw) |
160 | { |
161 | struct nvif_push *push = wndw->wndw.push; |
162 | int ret; |
163 | |
164 | if ((ret = PUSH_WAIT(push, 2))) |
165 | return ret; |
166 | |
167 | PUSH_MTHD(push, NV507C, SET_CONTEXT_DMA_NOTIFIER, 0x00000000); |
168 | return 0; |
169 | } |
170 | |
171 | int |
172 | base507c_ntfy_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) |
173 | { |
174 | struct nvif_push *push = wndw->wndw.push; |
175 | int ret; |
176 | |
177 | if ((ret = PUSH_WAIT(push, 3))) |
178 | return ret; |
179 | |
180 | PUSH_MTHD(push, NV507C, SET_NOTIFIER_CONTROL, |
181 | NVVAL(NV507C, SET_NOTIFIER_CONTROL, MODE, asyw->ntfy.awaken) | |
182 | NVVAL(NV507C, SET_NOTIFIER_CONTROL, OFFSET, asyw->ntfy.offset >> 2), |
183 | |
184 | SET_CONTEXT_DMA_NOTIFIER, asyw->ntfy.handle); |
185 | return 0; |
186 | } |
187 | |
188 | void |
189 | base507c_ntfy_reset(struct nouveau_bo *bo, u32 offset) |
190 | { |
191 | NVBO_WR32(bo, offset, NV_DISP_BASE_NOTIFIER_1, _0, |
192 | NVDEF(NV_DISP_BASE_NOTIFIER_1, _0, STATUS, NOT_BEGUN)); |
193 | } |
194 | |
195 | int |
196 | base507c_sema_clr(struct nv50_wndw *wndw) |
197 | { |
198 | struct nvif_push *push = wndw->wndw.push; |
199 | int ret; |
200 | |
201 | if ((ret = PUSH_WAIT(push, 2))) |
202 | return ret; |
203 | |
204 | PUSH_MTHD(push, NV507C, SET_CONTEXT_DMA_SEMAPHORE, 0x00000000); |
205 | return 0; |
206 | } |
207 | |
208 | int |
209 | base507c_sema_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) |
210 | { |
211 | struct nvif_push *push = wndw->wndw.push; |
212 | int ret; |
213 | |
214 | if ((ret = PUSH_WAIT(push, 5))) |
215 | return ret; |
216 | |
217 | PUSH_MTHD(push, NV507C, SET_SEMAPHORE_CONTROL, asyw->sema.offset, |
218 | SET_SEMAPHORE_ACQUIRE, asyw->sema.acquire, |
219 | SET_SEMAPHORE_RELEASE, asyw->sema.release, |
220 | SET_CONTEXT_DMA_SEMAPHORE, asyw->sema.handle); |
221 | return 0; |
222 | } |
223 | |
224 | void |
225 | base507c_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, |
226 | struct nv50_head_atom *asyh) |
227 | { |
228 | asyh->base.cpp = 0; |
229 | } |
230 | |
231 | int |
232 | base507c_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, |
233 | struct nv50_head_atom *asyh) |
234 | { |
235 | const struct drm_framebuffer *fb = asyw->state.fb; |
236 | int ret; |
237 | |
238 | ret = drm_atomic_helper_check_plane_state(plane_state: &asyw->state, crtc_state: &asyh->state, |
239 | DRM_PLANE_NO_SCALING, |
240 | DRM_PLANE_NO_SCALING, |
241 | can_position: false, can_update_disabled: true); |
242 | if (ret) |
243 | return ret; |
244 | |
245 | if (!wndw->func->ilut) { |
246 | if ((asyh->base.cpp != 1) ^ (fb->format->cpp[0] != 1)) |
247 | asyh->state.color_mgmt_changed = true; |
248 | } |
249 | |
250 | asyh->base.depth = fb->format->depth; |
251 | asyh->base.cpp = fb->format->cpp[0]; |
252 | asyh->base.x = asyw->state.src.x1 >> 16; |
253 | asyh->base.y = asyw->state.src.y1 >> 16; |
254 | asyh->base.w = asyw->state.fb->width; |
255 | asyh->base.h = asyw->state.fb->height; |
256 | |
257 | /* Some newer formats, esp FP16 ones, don't have a |
258 | * "depth". There's nothing that really makes sense there |
259 | * either, so just set it to the implicit bit count. |
260 | */ |
261 | if (!asyh->base.depth) |
262 | asyh->base.depth = asyh->base.cpp * 8; |
263 | |
264 | return 0; |
265 | } |
266 | |
267 | const u32 |
268 | base507c_format[] = { |
269 | DRM_FORMAT_C8, |
270 | DRM_FORMAT_RGB565, |
271 | DRM_FORMAT_XRGB1555, |
272 | DRM_FORMAT_ARGB1555, |
273 | DRM_FORMAT_XRGB8888, |
274 | DRM_FORMAT_ARGB8888, |
275 | DRM_FORMAT_XBGR2101010, |
276 | DRM_FORMAT_ABGR2101010, |
277 | DRM_FORMAT_XBGR8888, |
278 | DRM_FORMAT_ABGR8888, |
279 | DRM_FORMAT_XBGR16161616F, |
280 | DRM_FORMAT_ABGR16161616F, |
281 | 0 |
282 | }; |
283 | |
284 | static const struct nv50_wndw_func |
285 | base507c = { |
286 | .acquire = base507c_acquire, |
287 | .release = base507c_release, |
288 | .sema_set = base507c_sema_set, |
289 | .sema_clr = base507c_sema_clr, |
290 | .ntfy_reset = base507c_ntfy_reset, |
291 | .ntfy_set = base507c_ntfy_set, |
292 | .ntfy_clr = base507c_ntfy_clr, |
293 | .ntfy_wait_begun = base507c_ntfy_wait_begun, |
294 | .olut_core = 1, |
295 | .xlut_set = base507c_xlut_set, |
296 | .xlut_clr = base507c_xlut_clr, |
297 | .image_set = base507c_image_set, |
298 | .image_clr = base507c_image_clr, |
299 | .update = base507c_update, |
300 | }; |
301 | |
302 | int |
303 | base507c_new_(const struct nv50_wndw_func *func, const u32 *format, |
304 | struct nouveau_drm *drm, int head, s32 oclass, u32 interlock_data, |
305 | struct nv50_wndw **pwndw) |
306 | { |
307 | struct nvif_disp_chan_v0 args = { |
308 | .id = head, |
309 | }; |
310 | struct nouveau_display *disp = nouveau_display(drm->dev); |
311 | struct nv50_disp *disp50 = nv50_disp(dev: drm->dev); |
312 | struct nv50_wndw *wndw; |
313 | int ret; |
314 | |
315 | ret = nv50_wndw_new_(func, drm->dev, DRM_PLANE_TYPE_PRIMARY, |
316 | name: "base" , index: head, format, BIT(head), |
317 | NV50_DISP_INTERLOCK_BASE, interlock_data, &wndw); |
318 | if (*pwndw = wndw, ret) |
319 | return ret; |
320 | |
321 | ret = nv50_dmac_create(device: &drm->client.device, disp: &disp->disp.object, |
322 | oclass: &oclass, head, data: &args, size: sizeof(args), |
323 | syncbuf: disp50->sync->offset, dmac: &wndw->wndw); |
324 | if (ret) { |
325 | NV_ERROR(drm, "base%04x allocation failed: %d\n" , oclass, ret); |
326 | return ret; |
327 | } |
328 | |
329 | wndw->ntfy = NV50_DISP_BASE_NTFY(wndw->id); |
330 | wndw->sema = NV50_DISP_BASE_SEM0(wndw->id); |
331 | wndw->data = 0x00000000; |
332 | return 0; |
333 | } |
334 | |
335 | int |
336 | base507c_new(struct nouveau_drm *drm, int head, s32 oclass, |
337 | struct nv50_wndw **pwndw) |
338 | { |
339 | return base507c_new_(&base507c, format: base507c_format, drm, head, oclass, |
340 | interlock_data: 0x00000002 << (head * 8), pwndw); |
341 | } |
342 | |