Commit | Line | Data |
---|---|---|
56d237d2 | 1 | /* |
26f6d88b BS |
2 | * Copyright 2011 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 | * Authors: Ben Skeggs | |
23 | */ | |
1590700d BS |
24 | #include "disp.h" |
25 | #include "atom.h" | |
26 | #include "core.h" | |
27 | #include "head.h" | |
28 | #include "wndw.h" | |
0bc8ffe0 | 29 | #include "handles.h" |
26f6d88b | 30 | |
379ca03b | 31 | #include <linux/backlight.h> |
51beb428 | 32 | #include <linux/dma-mapping.h> |
34fd3e5d | 33 | #include <linux/hdmi.h> |
742db30c | 34 | #include <linux/component.h> |
6eca310e | 35 | #include <linux/iopoll.h> |
83fc083c | 36 | |
da68386d | 37 | #include <drm/display/drm_dp_helper.h> |
644edf52 | 38 | #include <drm/display/drm_scdc_helper.h> |
eca22edb | 39 | #include <drm/drm_atomic.h> |
973f10c2 | 40 | #include <drm/drm_atomic_helper.h> |
690ae20c | 41 | #include <drm/drm_edid.h> |
439590ac | 42 | #include <drm/drm_eld.h> |
b516a9ef | 43 | #include <drm/drm_fb_helper.h> |
191dc439 | 44 | #include <drm/drm_fixed.h> |
fcd70cd3 | 45 | #include <drm/drm_probe_helper.h> |
690ae20c | 46 | #include <drm/drm_vblank.h> |
26f6d88b | 47 | |
0a960996 BS |
48 | #include <nvif/push507c.h> |
49 | ||
1590700d BS |
50 | #include <nvif/class.h> |
51 | #include <nvif/cl0002.h> | |
1590700d | 52 | #include <nvif/event.h> |
f530bc60 | 53 | #include <nvif/if0012.h> |
889fcbe9 | 54 | #include <nvif/if0014.h> |
ed3d1489 | 55 | #include <nvif/timer.h> |
f4778f08 | 56 | |
0a960996 | 57 | #include <nvhw/class/cl507c.h> |
344c2e5a BS |
58 | #include <nvhw/class/cl507d.h> |
59 | #include <nvhw/class/cl837d.h> | |
60 | #include <nvhw/class/cl887d.h> | |
61 | #include <nvhw/class/cl907d.h> | |
62 | #include <nvhw/class/cl917d.h> | |
0a960996 | 63 | |
1590700d BS |
64 | #include "nouveau_drv.h" |
65 | #include "nouveau_dma.h" | |
66 | #include "nouveau_gem.h" | |
67 | #include "nouveau_connector.h" | |
68 | #include "nouveau_encoder.h" | |
69 | #include "nouveau_fence.h" | |
504e72ed | 70 | #include "nv50_display.h" |
f4778f08 | 71 | |
1590700d BS |
72 | /****************************************************************************** |
73 | * EVO channel | |
74 | *****************************************************************************/ | |
3dbd036b BS |
75 | |
76 | static int | |
1590700d BS |
77 | nv50_chan_create(struct nvif_device *device, struct nvif_object *disp, |
78 | const s32 *oclass, u8 head, void *data, u32 size, | |
79 | struct nv50_chan *chan) | |
3dbd036b | 80 | { |
1590700d BS |
81 | struct nvif_sclass *sclass; |
82 | int ret, i, n; | |
839ca903 | 83 | |
1590700d | 84 | chan->device = device; |
ad633619 | 85 | |
1590700d BS |
86 | ret = n = nvif_object_sclass_get(disp, &sclass); |
87 | if (ret < 0) | |
88 | return ret; | |
ea8ee390 | 89 | |
1590700d BS |
90 | while (oclass[0]) { |
91 | for (i = 0; i < n; i++) { | |
92 | if (sclass[i].oclass == oclass[0]) { | |
9ac596a4 BS |
93 | ret = nvif_object_ctor(disp, "kmsChan", 0, |
94 | oclass[0], data, size, | |
95 | &chan->user); | |
8d7b2d3a BS |
96 | if (ret == 0) { |
97 | ret = nvif_object_map(&chan->user, NULL, 0); | |
98 | if (ret) | |
99 | nvif_object_dtor(&chan->user); | |
100 | } | |
1590700d BS |
101 | nvif_object_sclass_put(&sclass); |
102 | return ret; | |
103 | } | |
ea8ee390 | 104 | } |
1590700d | 105 | oclass++; |
3dbd036b BS |
106 | } |
107 | ||
1590700d BS |
108 | nvif_object_sclass_put(&sclass); |
109 | return -ENOSYS; | |
3dbd036b BS |
110 | } |
111 | ||
839ca903 | 112 | static void |
1590700d | 113 | nv50_chan_destroy(struct nv50_chan *chan) |
839ca903 | 114 | { |
9ac596a4 | 115 | nvif_object_dtor(&chan->user); |
839ca903 BS |
116 | } |
117 | ||
1590700d BS |
118 | /****************************************************************************** |
119 | * DMA EVO channel | |
120 | *****************************************************************************/ | |
839ca903 | 121 | |
1590700d BS |
122 | void |
123 | nv50_dmac_destroy(struct nv50_dmac *dmac) | |
839ca903 | 124 | { |
9ac596a4 BS |
125 | nvif_object_dtor(&dmac->vram); |
126 | nvif_object_dtor(&dmac->sync); | |
839ca903 | 127 | |
1590700d | 128 | nv50_chan_destroy(&dmac->base); |
839ca903 | 129 | |
61671d85 | 130 | nvif_mem_dtor(&dmac->push.mem); |
2853ccf0 BS |
131 | } |
132 | ||
133 | static void | |
134 | nv50_dmac_kick(struct nvif_push *push) | |
135 | { | |
61671d85 | 136 | struct nv50_dmac *dmac = container_of(push, typeof(*dmac), push); |
0a960996 | 137 | |
61671d85 | 138 | dmac->cur = push->cur - (u32 __iomem *)dmac->push.mem.object.map.ptr; |
0a960996 BS |
139 | if (dmac->put != dmac->cur) { |
140 | /* Push buffer fetches are not coherent with BAR1, we need to ensure | |
141 | * writes have been flushed right through to VRAM before writing PUT. | |
142 | */ | |
61671d85 | 143 | if (dmac->push.mem.type & NVIF_MEM_VRAM) { |
0a960996 BS |
144 | struct nvif_device *device = dmac->base.device; |
145 | nvif_wr32(&device->object, 0x070000, 0x00000001); | |
146 | nvif_msec(device, 2000, | |
147 | if (!(nvif_rd32(&device->object, 0x070000) & 0x00000002)) | |
148 | break; | |
149 | ); | |
150 | } | |
151 | ||
152 | NVIF_WV32(&dmac->base.user, NV507C, PUT, PTR, dmac->cur); | |
153 | dmac->put = dmac->cur; | |
154 | } | |
155 | ||
156 | push->bgn = push->cur; | |
157 | } | |
158 | ||
159 | static int | |
160 | nv50_dmac_free(struct nv50_dmac *dmac) | |
161 | { | |
162 | u32 get = NVIF_RV32(&dmac->base.user, NV507C, GET, PTR); | |
163 | if (get > dmac->cur) /* NVIDIA stay 5 away from GET, do the same. */ | |
164 | return get - dmac->cur - 5; | |
165 | return dmac->max - dmac->cur; | |
166 | } | |
167 | ||
168 | static int | |
169 | nv50_dmac_wind(struct nv50_dmac *dmac) | |
170 | { | |
171 | /* Wait for GET to depart from the beginning of the push buffer to | |
172 | * prevent writing PUT == GET, which would be ignored by HW. | |
173 | */ | |
174 | u32 get = NVIF_RV32(&dmac->base.user, NV507C, GET, PTR); | |
175 | if (get == 0) { | |
176 | /* Corner-case, HW idle, but non-committed work pending. */ | |
177 | if (dmac->put == 0) | |
61671d85 | 178 | nv50_dmac_kick(&dmac->push); |
0a960996 BS |
179 | |
180 | if (nvif_msec(dmac->base.device, 2000, | |
181 | if (NVIF_TV32(&dmac->base.user, NV507C, GET, PTR, >, 0)) | |
182 | break; | |
183 | ) < 0) | |
184 | return -ETIMEDOUT; | |
185 | } | |
186 | ||
61671d85 | 187 | PUSH_RSVD(&dmac->push, PUSH_JUMP(&dmac->push, 0)); |
0a960996 BS |
188 | dmac->cur = 0; |
189 | return 0; | |
2853ccf0 BS |
190 | } |
191 | ||
192 | static int | |
193 | nv50_dmac_wait(struct nvif_push *push, u32 size) | |
194 | { | |
61671d85 | 195 | struct nv50_dmac *dmac = container_of(push, typeof(*dmac), push); |
0a960996 BS |
196 | int free; |
197 | ||
198 | if (WARN_ON(size > dmac->max)) | |
199 | return -EINVAL; | |
200 | ||
61671d85 | 201 | dmac->cur = push->cur - (u32 __iomem *)dmac->push.mem.object.map.ptr; |
0a960996 BS |
202 | if (dmac->cur + size >= dmac->max) { |
203 | int ret = nv50_dmac_wind(dmac); | |
204 | if (ret) | |
205 | return ret; | |
206 | ||
61671d85 | 207 | push->cur = dmac->push.mem.object.map.ptr; |
0a960996 BS |
208 | push->cur = push->cur + dmac->cur; |
209 | nv50_dmac_kick(push); | |
210 | } | |
211 | ||
212 | if (nvif_msec(dmac->base.device, 2000, | |
213 | if ((free = nv50_dmac_free(dmac)) >= size) | |
214 | break; | |
215 | ) < 0) { | |
216 | WARN_ON(1); | |
2853ccf0 | 217 | return -ETIMEDOUT; |
0a960996 | 218 | } |
2853ccf0 | 219 | |
61671d85 | 220 | push->bgn = dmac->push.mem.object.map.ptr; |
0a960996 BS |
221 | push->bgn = push->bgn + dmac->cur; |
222 | push->cur = push->bgn; | |
223 | push->end = push->cur + free; | |
2853ccf0 | 224 | return 0; |
839ca903 BS |
225 | } |
226 | ||
a708d8a7 BS |
227 | MODULE_PARM_DESC(kms_vram_pushbuf, "Place EVO/NVD push buffers in VRAM (default: auto)"); |
228 | static int nv50_dmac_vram_pushbuf = -1; | |
229 | module_param_named(kms_vram_pushbuf, nv50_dmac_vram_pushbuf, int, 0400); | |
230 | ||
1590700d | 231 | int |
3019023e | 232 | nv50_dmac_create(struct nouveau_drm *drm, |
caeb6ab8 | 233 | const s32 *oclass, u8 head, void *data, u32 size, s64 syncbuf, |
1590700d | 234 | struct nv50_dmac *dmac) |
9bfdee9a | 235 | { |
3019023e BS |
236 | struct nvif_device *device = &drm->device; |
237 | struct nvif_object *disp = &drm->display->disp.object; | |
889fcbe9 | 238 | struct nvif_disp_chan_v0 *args = data; |
d00ddd9d | 239 | u8 type = NVIF_MEM_COHERENT; |
1590700d | 240 | int ret; |
9bfdee9a | 241 | |
d00ddd9d BS |
242 | /* Pascal added support for 47-bit physical addresses, but some |
243 | * parts of EVO still only accept 40-bit PAs. | |
244 | * | |
245 | * To avoid issues on systems with large amounts of RAM, and on | |
246 | * systems where an IOMMU maps pages at a high address, we need | |
247 | * to allocate push buffers in VRAM instead. | |
248 | * | |
249 | * This appears to match NVIDIA's behaviour on Pascal. | |
250 | */ | |
a708d8a7 BS |
251 | if ((nv50_dmac_vram_pushbuf > 0) || |
252 | (nv50_dmac_vram_pushbuf < 0 && device->info.family == NV_DEVICE_INFO_V0_PASCAL)) | |
d00ddd9d BS |
253 | type |= NVIF_MEM_VRAM; |
254 | ||
61671d85 | 255 | ret = nvif_mem_ctor_map(&drm->mmu, "kmsChanPush", type, 0x1000, &dmac->push.mem); |
1590700d BS |
256 | if (ret) |
257 | return ret; | |
438d99e3 | 258 | |
61671d85 BS |
259 | dmac->push.wait = nv50_dmac_wait; |
260 | dmac->push.kick = nv50_dmac_kick; | |
261 | dmac->push.bgn = dmac->push.mem.object.map.ptr; | |
262 | dmac->push.cur = dmac->push.bgn; | |
263 | dmac->push.end = dmac->push.bgn; | |
0a960996 | 264 | dmac->max = 0x1000/4 - 1; |
438d99e3 | 265 | |
ca386aa7 BS |
266 | /* EVO channels are affected by a HW bug where the last 12 DWORDs |
267 | * of the push buffer aren't able to be used safely. | |
268 | */ | |
269 | if (disp->oclass < GV100_DISP) | |
270 | dmac->max -= 12; | |
271 | ||
61671d85 | 272 | args->pushbuf = nvif_handle(&dmac->push.mem.object); |
438d99e3 | 273 | |
1590700d BS |
274 | ret = nv50_chan_create(device, disp, oclass, head, data, size, |
275 | &dmac->base); | |
276 | if (ret) | |
973f10c2 | 277 | return ret; |
973f10c2 | 278 | |
caeb6ab8 | 279 | if (syncbuf < 0) |
facaed62 BS |
280 | return 0; |
281 | ||
9ac596a4 | 282 | ret = nvif_object_ctor(&dmac->base.user, "kmsSyncCtxDma", NV50_DISP_HANDLE_SYNCBUF, |
0bc8ffe0 | 283 | NV_DMA_IN_MEMORY, |
1590700d BS |
284 | &(struct nv_dma_v0) { |
285 | .target = NV_DMA_V0_TARGET_VRAM, | |
286 | .access = NV_DMA_V0_ACCESS_RDWR, | |
287 | .start = syncbuf + 0x0000, | |
288 | .limit = syncbuf + 0x0fff, | |
289 | }, sizeof(struct nv_dma_v0), | |
290 | &dmac->sync); | |
291 | if (ret) | |
292 | return ret; | |
b5a794b0 | 293 | |
9ac596a4 | 294 | ret = nvif_object_ctor(&dmac->base.user, "kmsVramCtxDma", NV50_DISP_HANDLE_VRAM, |
0bc8ffe0 | 295 | NV_DMA_IN_MEMORY, |
1590700d BS |
296 | &(struct nv_dma_v0) { |
297 | .target = NV_DMA_V0_TARGET_VRAM, | |
298 | .access = NV_DMA_V0_ACCESS_RDWR, | |
299 | .start = 0, | |
300 | .limit = device->info.ram_user - 1, | |
301 | }, sizeof(struct nv_dma_v0), | |
302 | &dmac->vram); | |
438d99e3 | 303 | if (ret) |
1590700d BS |
304 | return ret; |
305 | ||
438d99e3 BS |
306 | return ret; |
307 | } | |
308 | ||
a91d3221 | 309 | /****************************************************************************** |
d92c8adf | 310 | * Output path helpers |
a91d3221 | 311 | *****************************************************************************/ |
36dc1777 LP |
312 | static void |
313 | nv50_outp_dump_caps(struct nouveau_drm *drm, | |
314 | struct nouveau_encoder *outp) | |
315 | { | |
316 | NV_DEBUG(drm, "%s caps: dp_interlace=%d\n", | |
317 | outp->base.base.name, outp->caps.dp_interlace); | |
318 | } | |
319 | ||
d92c8adf BS |
320 | static int |
321 | nv50_outp_atomic_check_view(struct drm_encoder *encoder, | |
322 | struct drm_crtc_state *crtc_state, | |
323 | struct drm_connector_state *conn_state, | |
324 | struct drm_display_mode *native_mode) | |
325 | { | |
326 | struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; | |
327 | struct drm_display_mode *mode = &crtc_state->mode; | |
328 | struct drm_connector *connector = conn_state->connector; | |
329 | struct nouveau_conn_atom *asyc = nouveau_conn_atom(conn_state); | |
330 | struct nouveau_drm *drm = nouveau_drm(encoder->dev); | |
331 | ||
332 | NV_ATOMIC(drm, "%s atomic_check\n", encoder->name); | |
333 | asyc->scaler.full = false; | |
334 | if (!native_mode) | |
335 | return 0; | |
336 | ||
337 | if (asyc->scaler.mode == DRM_MODE_SCALE_NONE) { | |
338 | switch (connector->connector_type) { | |
339 | case DRM_MODE_CONNECTOR_LVDS: | |
340 | case DRM_MODE_CONNECTOR_eDP: | |
f8d6211a IM |
341 | /* Don't force scaler for EDID modes with |
342 | * same size as the native one (e.g. different | |
343 | * refresh rate) | |
344 | */ | |
3d1890ef BS |
345 | if (mode->hdisplay == native_mode->hdisplay && |
346 | mode->vdisplay == native_mode->vdisplay && | |
347 | mode->type & DRM_MODE_TYPE_DRIVER) | |
d92c8adf BS |
348 | break; |
349 | mode = native_mode; | |
350 | asyc->scaler.full = true; | |
351 | break; | |
352 | default: | |
353 | break; | |
354 | } | |
355 | } else { | |
356 | mode = native_mode; | |
357 | } | |
358 | ||
359 | if (!drm_mode_equal(adjusted_mode, mode)) { | |
360 | drm_mode_copy(adjusted_mode, mode); | |
361 | crtc_state->mode_changed = true; | |
362 | } | |
363 | ||
364 | return 0; | |
365 | } | |
366 | ||
7f67aa09 KH |
367 | static void |
368 | nv50_outp_atomic_fix_depth(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state) | |
369 | { | |
370 | struct nv50_head_atom *asyh = nv50_head_atom(crtc_state); | |
371 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | |
372 | struct drm_display_mode *mode = &asyh->state.adjusted_mode; | |
373 | unsigned int max_rate, mode_rate; | |
374 | ||
375 | switch (nv_encoder->dcb->type) { | |
376 | case DCB_OUTPUT_DP: | |
377 | max_rate = nv_encoder->dp.link_nr * nv_encoder->dp.link_bw; | |
378 | ||
379 | /* we don't support more than 10 anyway */ | |
380 | asyh->or.bpc = min_t(u8, asyh->or.bpc, 10); | |
381 | ||
382 | /* reduce the bpc until it works out */ | |
383 | while (asyh->or.bpc > 6) { | |
384 | mode_rate = DIV_ROUND_UP(mode->clock * asyh->or.bpc * 3, 8); | |
385 | if (mode_rate <= max_rate) | |
386 | break; | |
387 | ||
388 | asyh->or.bpc -= 2; | |
389 | } | |
390 | break; | |
391 | default: | |
392 | break; | |
393 | } | |
394 | } | |
395 | ||
839ca903 BS |
396 | static int |
397 | nv50_outp_atomic_check(struct drm_encoder *encoder, | |
398 | struct drm_crtc_state *crtc_state, | |
399 | struct drm_connector_state *conn_state) | |
a91d3221 | 400 | { |
ac2d9275 LP |
401 | struct drm_connector *connector = conn_state->connector; |
402 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | |
403 | struct nv50_head_atom *asyh = nv50_head_atom(crtc_state); | |
404 | int ret; | |
405 | ||
406 | ret = nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, | |
407 | nv_connector->native_mode); | |
408 | if (ret) | |
409 | return ret; | |
410 | ||
411 | if (crtc_state->mode_changed || crtc_state->connectors_changed) | |
412 | asyh->or.bpc = connector->display_info.bpc; | |
413 | ||
7f67aa09 KH |
414 | /* We might have to reduce the bpc */ |
415 | nv50_outp_atomic_fix_depth(encoder, crtc_state); | |
416 | ||
ac2d9275 | 417 | return 0; |
a91d3221 BS |
418 | } |
419 | ||
09838c4e | 420 | struct nouveau_connector * |
cd5609f7 | 421 | nv50_outp_get_new_connector(struct drm_atomic_state *state, struct nouveau_encoder *outp) |
09838c4e LP |
422 | { |
423 | struct drm_connector *connector; | |
424 | struct drm_connector_state *connector_state; | |
425 | struct drm_encoder *encoder = to_drm_encoder(outp); | |
426 | int i; | |
427 | ||
428 | for_each_new_connector_in_state(state, connector, connector_state, i) { | |
429 | if (connector_state->best_encoder == encoder) | |
430 | return nouveau_connector(connector); | |
431 | } | |
432 | ||
433 | return NULL; | |
434 | } | |
435 | ||
436 | struct nouveau_connector * | |
cd5609f7 | 437 | nv50_outp_get_old_connector(struct drm_atomic_state *state, struct nouveau_encoder *outp) |
09838c4e LP |
438 | { |
439 | struct drm_connector *connector; | |
440 | struct drm_connector_state *connector_state; | |
441 | struct drm_encoder *encoder = to_drm_encoder(outp); | |
442 | int i; | |
443 | ||
444 | for_each_old_connector_in_state(state, connector, connector_state, i) { | |
445 | if (connector_state->best_encoder == encoder) | |
446 | return nouveau_connector(connector); | |
447 | } | |
448 | ||
449 | return NULL; | |
450 | } | |
451 | ||
1b38cf6b LP |
452 | static struct nouveau_crtc * |
453 | nv50_outp_get_new_crtc(const struct drm_atomic_state *state, const struct nouveau_encoder *outp) | |
454 | { | |
455 | struct drm_crtc *crtc; | |
456 | struct drm_crtc_state *crtc_state; | |
457 | const u32 mask = drm_encoder_mask(&outp->base.base); | |
458 | int i; | |
459 | ||
460 | for_each_new_crtc_in_state(state, crtc, crtc_state, i) { | |
461 | if (crtc_state->encoder_mask & mask) | |
462 | return nouveau_crtc(crtc); | |
463 | } | |
464 | ||
465 | return NULL; | |
466 | } | |
467 | ||
26f6d88b BS |
468 | /****************************************************************************** |
469 | * DAC | |
470 | *****************************************************************************/ | |
0a368771 | 471 | static void |
fa9f9489 | 472 | nv50_dac_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) |
0a368771 BS |
473 | { |
474 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | |
475 | struct nv50_core *core = nv50_disp(encoder->dev)->core; | |
344c2e5a | 476 | const u32 ctrl = NVDEF(NV507D, DAC_SET_CONTROL, OWNER, NONE); |
f575f2bd | 477 | |
ea6143a8 | 478 | core->func->dac->ctrl(core, nv_encoder->outp.or.id, ctrl, NULL); |
f20c665c | 479 | nv_encoder->crtc = NULL; |
8eaa9669 BS |
480 | } |
481 | ||
482 | static void | |
fa9f9489 | 483 | nv50_dac_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) |
8eaa9669 BS |
484 | { |
485 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | |
1b38cf6b LP |
486 | struct nouveau_crtc *nv_crtc = nv50_outp_get_new_crtc(state, nv_encoder); |
487 | struct nv50_head_atom *asyh = | |
488 | nv50_head_atom(drm_atomic_get_new_crtc_state(state, &nv_crtc->base)); | |
0a368771 | 489 | struct nv50_core *core = nv50_disp(encoder->dev)->core; |
344c2e5a BS |
490 | u32 ctrl = 0; |
491 | ||
492 | switch (nv_crtc->index) { | |
493 | case 0: ctrl |= NVDEF(NV507D, DAC_SET_CONTROL, OWNER, HEAD0); break; | |
494 | case 1: ctrl |= NVDEF(NV507D, DAC_SET_CONTROL, OWNER, HEAD1); break; | |
495 | case 2: ctrl |= NVDEF(NV907D, DAC_SET_CONTROL, OWNER_MASK, HEAD2); break; | |
496 | case 3: ctrl |= NVDEF(NV907D, DAC_SET_CONTROL, OWNER_MASK, HEAD3); break; | |
497 | default: | |
498 | WARN_ON(1); | |
499 | break; | |
500 | } | |
501 | ||
502 | ctrl |= NVDEF(NV507D, DAC_SET_CONTROL, PROTOCOL, RGB_CRT); | |
8eaa9669 | 503 | |
724e0f3b BS |
504 | if (!nvif_outp_acquired(&nv_encoder->outp)) |
505 | nvif_outp_acquire_dac(&nv_encoder->outp); | |
6c22ea37 | 506 | |
ea6143a8 | 507 | core->func->dac->ctrl(core, nv_encoder->outp.or.id, ctrl, asyh); |
2ca7fb5c | 508 | asyh->or.depth = 0; |
8eaa9669 | 509 | |
1b38cf6b | 510 | nv_encoder->crtc = &nv_crtc->base; |
8eaa9669 BS |
511 | } |
512 | ||
b6d8e7ec | 513 | static enum drm_connector_status |
e225f446 | 514 | nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) |
b6d8e7ec | 515 | { |
c4abd317 | 516 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
dfc4005f | 517 | u32 loadval; |
c4abd317 BS |
518 | int ret; |
519 | ||
dfc4005f BS |
520 | loadval = nouveau_drm(encoder->dev)->vbios.dactestval; |
521 | if (loadval == 0) | |
522 | loadval = 340; | |
b681993f | 523 | |
dfc4005f BS |
524 | ret = nvif_outp_load_detect(&nv_encoder->outp, loadval); |
525 | if (ret <= 0) | |
35b21d39 | 526 | return connector_status_disconnected; |
b681993f | 527 | |
35b21d39 | 528 | return connector_status_connected; |
b6d8e7ec BS |
529 | } |
530 | ||
f20c665c BS |
531 | static const struct drm_encoder_helper_funcs |
532 | nv50_dac_help = { | |
839ca903 | 533 | .atomic_check = nv50_outp_atomic_check, |
fa9f9489 LP |
534 | .atomic_enable = nv50_dac_atomic_enable, |
535 | .atomic_disable = nv50_dac_atomic_disable, | |
e225f446 | 536 | .detect = nv50_dac_detect |
8eaa9669 BS |
537 | }; |
538 | ||
f20c665c BS |
539 | static void |
540 | nv50_dac_destroy(struct drm_encoder *encoder) | |
541 | { | |
1b255f1c BS |
542 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
543 | ||
544 | nvif_outp_dtor(&nv_encoder->outp); | |
545 | ||
f20c665c BS |
546 | drm_encoder_cleanup(encoder); |
547 | kfree(encoder); | |
548 | } | |
549 | ||
550 | static const struct drm_encoder_funcs | |
551 | nv50_dac_func = { | |
e225f446 | 552 | .destroy = nv50_dac_destroy, |
8eaa9669 BS |
553 | }; |
554 | ||
555 | static int | |
e32de3da | 556 | nv50_dac_create(struct nouveau_encoder *nv_encoder) |
8eaa9669 | 557 | { |
e32de3da | 558 | struct drm_connector *connector = &nv_encoder->conn->base; |
5ed50209 | 559 | struct nouveau_drm *drm = nouveau_drm(connector->dev); |
6901f1d6 | 560 | struct nvkm_i2c *i2c = nvxx_i2c(drm); |
2aa5eac5 | 561 | struct nvkm_i2c_bus *bus; |
8eaa9669 | 562 | struct drm_encoder *encoder; |
e32de3da | 563 | struct dcb_output *dcbe = nv_encoder->dcb; |
5ed50209 | 564 | int type = DRM_MODE_ENCODER_DAC; |
8eaa9669 | 565 | |
2aa5eac5 BS |
566 | bus = nvkm_i2c_bus_find(i2c, dcbe->i2c_index); |
567 | if (bus) | |
568 | nv_encoder->i2c = &bus->i2c; | |
8eaa9669 BS |
569 | |
570 | encoder = to_drm_encoder(nv_encoder); | |
5a223dac BS |
571 | drm_encoder_init(connector->dev, encoder, &nv50_dac_func, type, |
572 | "dac-%04x-%04x", dcbe->hasht, dcbe->hashm); | |
f20c665c | 573 | drm_encoder_helper_add(encoder, &nv50_dac_help); |
8eaa9669 | 574 | |
cde4c44d | 575 | drm_connector_attach_encoder(connector, encoder); |
e32de3da | 576 | return 0; |
8eaa9669 | 577 | } |
26f6d88b | 578 | |
742db30c TI |
579 | /* |
580 | * audio component binding for ELD notification | |
581 | */ | |
582 | static void | |
61a41097 TI |
583 | nv50_audio_component_eld_notify(struct drm_audio_component *acomp, int port, |
584 | int dev_id) | |
742db30c TI |
585 | { |
586 | if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) | |
587 | acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, | |
61a41097 | 588 | port, dev_id); |
742db30c TI |
589 | } |
590 | ||
591 | static int | |
61a41097 | 592 | nv50_audio_component_get_eld(struct device *kdev, int port, int dev_id, |
742db30c TI |
593 | bool *enabled, unsigned char *buf, int max_bytes) |
594 | { | |
448359c1 | 595 | struct nouveau_drm *drm = dev_get_drvdata(kdev); |
742db30c TI |
596 | struct drm_encoder *encoder; |
597 | struct nouveau_encoder *nv_encoder; | |
742db30c TI |
598 | struct nouveau_crtc *nv_crtc; |
599 | int ret = 0; | |
600 | ||
601 | *enabled = false; | |
09838c4e | 602 | |
9125e242 LP |
603 | mutex_lock(&drm->audio.lock); |
604 | ||
742db30c | 605 | drm_for_each_encoder(encoder, drm->dev) { |
09838c4e LP |
606 | struct nouveau_connector *nv_connector = NULL; |
607 | ||
9125e242 LP |
608 | if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) |
609 | continue; /* TODO */ | |
610 | ||
742db30c | 611 | nv_encoder = nouveau_encoder(encoder); |
42db5692 | 612 | nv_connector = nv_encoder->conn; |
9125e242 | 613 | nv_crtc = nouveau_crtc(nv_encoder->crtc); |
09838c4e | 614 | |
ea6143a8 | 615 | if (!nv_crtc || nv_encoder->outp.or.id != port || nv_crtc->index != dev_id) |
09838c4e LP |
616 | continue; |
617 | ||
9125e242 | 618 | *enabled = nv_encoder->audio.enabled; |
742db30c TI |
619 | if (*enabled) { |
620 | ret = drm_eld_size(nv_connector->base.eld); | |
621 | memcpy(buf, nv_connector->base.eld, | |
622 | min(max_bytes, ret)); | |
623 | } | |
624 | break; | |
625 | } | |
09838c4e | 626 | |
9125e242 LP |
627 | mutex_unlock(&drm->audio.lock); |
628 | ||
742db30c TI |
629 | return ret; |
630 | } | |
631 | ||
632 | static const struct drm_audio_component_ops nv50_audio_component_ops = { | |
633 | .get_eld = nv50_audio_component_get_eld, | |
634 | }; | |
635 | ||
636 | static int | |
637 | nv50_audio_component_bind(struct device *kdev, struct device *hda_kdev, | |
638 | void *data) | |
639 | { | |
448359c1 | 640 | struct nouveau_drm *drm = dev_get_drvdata(kdev); |
742db30c TI |
641 | struct drm_audio_component *acomp = data; |
642 | ||
643 | if (WARN_ON(!device_link_add(hda_kdev, kdev, DL_FLAG_STATELESS))) | |
644 | return -ENOMEM; | |
645 | ||
448359c1 | 646 | drm_modeset_lock_all(drm->dev); |
742db30c TI |
647 | acomp->ops = &nv50_audio_component_ops; |
648 | acomp->dev = kdev; | |
649 | drm->audio.component = acomp; | |
448359c1 | 650 | drm_modeset_unlock_all(drm->dev); |
7a154d5b | 651 | return 0; |
742db30c TI |
652 | } |
653 | ||
654 | static void | |
655 | nv50_audio_component_unbind(struct device *kdev, struct device *hda_kdev, | |
656 | void *data) | |
657 | { | |
448359c1 | 658 | struct nouveau_drm *drm = dev_get_drvdata(kdev); |
742db30c TI |
659 | struct drm_audio_component *acomp = data; |
660 | ||
448359c1 | 661 | drm_modeset_lock_all(drm->dev); |
742db30c TI |
662 | drm->audio.component = NULL; |
663 | acomp->ops = NULL; | |
664 | acomp->dev = NULL; | |
448359c1 | 665 | drm_modeset_unlock_all(drm->dev); |
742db30c TI |
666 | } |
667 | ||
668 | static const struct component_ops nv50_audio_component_bind_ops = { | |
669 | .bind = nv50_audio_component_bind, | |
670 | .unbind = nv50_audio_component_unbind, | |
671 | }; | |
672 | ||
673 | static void | |
674 | nv50_audio_component_init(struct nouveau_drm *drm) | |
675 | { | |
9125e242 LP |
676 | if (component_add(drm->dev->dev, &nv50_audio_component_bind_ops)) |
677 | return; | |
678 | ||
679 | drm->audio.component_registered = true; | |
680 | mutex_init(&drm->audio.lock); | |
742db30c TI |
681 | } |
682 | ||
683 | static void | |
684 | nv50_audio_component_fini(struct nouveau_drm *drm) | |
685 | { | |
9125e242 LP |
686 | if (!drm->audio.component_registered) |
687 | return; | |
688 | ||
689 | component_del(drm->dev->dev, &nv50_audio_component_bind_ops); | |
690 | drm->audio.component_registered = false; | |
691 | mutex_destroy(&drm->audio.lock); | |
742db30c TI |
692 | } |
693 | ||
78951d22 BS |
694 | /****************************************************************************** |
695 | * Audio | |
696 | *****************************************************************************/ | |
a9f5d772 BS |
697 | static bool |
698 | nv50_audio_supported(struct drm_encoder *encoder) | |
699 | { | |
700 | struct nv50_disp *disp = nv50_disp(encoder->dev); | |
701 | ||
702 | if (disp->disp->object.oclass <= GT200_DISP || | |
703 | disp->disp->object.oclass == GT206_DISP) | |
704 | return false; | |
705 | ||
c0f7b729 BS |
706 | if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { |
707 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | |
708 | ||
709 | switch (nv_encoder->dcb->type) { | |
710 | case DCB_OUTPUT_TMDS: | |
711 | case DCB_OUTPUT_DP: | |
712 | break; | |
713 | default: | |
714 | return false; | |
715 | } | |
716 | } | |
717 | ||
a9f5d772 BS |
718 | return true; |
719 | } | |
720 | ||
78951d22 | 721 | static void |
f20c665c BS |
722 | nv50_audio_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc) |
723 | { | |
742db30c | 724 | struct nouveau_drm *drm = nouveau_drm(encoder->dev); |
f20c665c | 725 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
ea6143a8 | 726 | struct nvif_outp *outp = &nv_encoder->outp; |
a9f5d772 BS |
727 | |
728 | if (!nv50_audio_supported(encoder)) | |
729 | return; | |
f20c665c | 730 | |
9125e242 LP |
731 | mutex_lock(&drm->audio.lock); |
732 | if (nv_encoder->audio.enabled) { | |
733 | nv_encoder->audio.enabled = false; | |
a9f5d772 | 734 | nvif_outp_hda_eld(&nv_encoder->outp, nv_crtc->index, NULL, 0); |
9125e242 LP |
735 | } |
736 | mutex_unlock(&drm->audio.lock); | |
742db30c | 737 | |
ea6143a8 | 738 | nv50_audio_component_eld_notify(drm->audio.component, outp->or.id, nv_crtc->index); |
f20c665c BS |
739 | } |
740 | ||
741 | static void | |
1b38cf6b LP |
742 | nv50_audio_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, |
743 | struct nouveau_connector *nv_connector, struct drm_atomic_state *state, | |
09838c4e | 744 | struct drm_display_mode *mode) |
78951d22 | 745 | { |
742db30c | 746 | struct nouveau_drm *drm = nouveau_drm(encoder->dev); |
78951d22 | 747 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
ea6143a8 | 748 | struct nvif_outp *outp = &nv_encoder->outp; |
a9f5d772 | 749 | |
444f396c | 750 | if (!nv50_audio_supported(encoder) || !nv_connector->base.display_info.has_audio) |
78951d22 BS |
751 | return; |
752 | ||
9125e242 LP |
753 | mutex_lock(&drm->audio.lock); |
754 | ||
a9f5d772 BS |
755 | nvif_outp_hda_eld(&nv_encoder->outp, nv_crtc->index, nv_connector->base.eld, |
756 | drm_eld_size(nv_connector->base.eld)); | |
9125e242 | 757 | nv_encoder->audio.enabled = true; |
9125e242 LP |
758 | |
759 | mutex_unlock(&drm->audio.lock); | |
742db30c | 760 | |
ea6143a8 | 761 | nv50_audio_component_eld_notify(drm->audio.component, outp->or.id, nv_crtc->index); |
78951d22 BS |
762 | } |
763 | ||
f20c665c BS |
764 | /****************************************************************************** |
765 | * HDMI | |
766 | *****************************************************************************/ | |
78951d22 | 767 | static void |
1b38cf6b LP |
768 | nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, |
769 | struct nouveau_connector *nv_connector, struct drm_atomic_state *state, | |
f530bc60 | 770 | struct drm_display_mode *mode, bool hda) |
78951d22 | 771 | { |
7a406f8a | 772 | struct nouveau_drm *drm = nouveau_drm(encoder->dev); |
64d9cc04 | 773 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
f530bc60 | 774 | struct drm_hdmi_info *hdmi = &nv_connector->base.display_info.hdmi; |
c02f20d3 | 775 | union hdmi_infoframe infoframe = { 0 }; |
f530bc60 | 776 | const u8 rekey = 56; /* binary driver, and tegra, constant */ |
64d9cc04 | 777 | u32 max_ac_packet; |
f530bc60 BS |
778 | struct { |
779 | struct nvif_outp_infoframe_v0 infoframe; | |
780 | u8 data[17]; | |
c02f20d3 | 781 | } args = { 0 }; |
f530bc60 | 782 | int ret, size; |
34fd3e5d | 783 | |
64d9cc04 | 784 | max_ac_packet = mode->htotal - mode->hdisplay; |
f530bc60 | 785 | max_ac_packet -= rekey; |
64d9cc04 | 786 | max_ac_packet -= 18; /* constant from tegra */ |
f530bc60 | 787 | max_ac_packet /= 32; |
091e40cd | 788 | |
6c6abab2 | 789 | if (nv_encoder->i2c && hdmi->scdc.scrambling.supported) { |
f530bc60 | 790 | const bool high_tmds_clock_ratio = mode->clock > 340000; |
6c6abab2 | 791 | u8 scdc; |
7a406f8a | 792 | |
c02f20d3 | 793 | ret = drm_scdc_readb(nv_encoder->i2c, SCDC_TMDS_CONFIG, &scdc); |
f530bc60 BS |
794 | if (ret < 0) { |
795 | NV_ERROR(drm, "Failure to read SCDC_TMDS_CONFIG: %d\n", ret); | |
796 | return; | |
797 | } | |
7a406f8a | 798 | |
c02f20d3 | 799 | scdc &= ~(SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE); |
f530bc60 | 800 | if (high_tmds_clock_ratio || hdmi->scdc.scrambling.low_rates) |
c02f20d3 | 801 | scdc |= SCDC_SCRAMBLING_ENABLE; |
f530bc60 | 802 | if (high_tmds_clock_ratio) |
c02f20d3 | 803 | scdc |= SCDC_TMDS_BIT_CLOCK_RATIO_BY_40; |
7a406f8a | 804 | |
c02f20d3 | 805 | ret = drm_scdc_writeb(nv_encoder->i2c, SCDC_TMDS_CONFIG, scdc); |
f530bc60 BS |
806 | if (ret < 0) |
807 | NV_ERROR(drm, "Failure to write SCDC_TMDS_CONFIG = 0x%02x: %d\n", | |
c02f20d3 | 808 | scdc, ret); |
f530bc60 | 809 | } |
7a406f8a | 810 | |
6c6abab2 BS |
811 | ret = nvif_outp_hdmi(&nv_encoder->outp, nv_crtc->index, true, max_ac_packet, rekey, |
812 | mode->clock, hdmi->scdc.supported, hdmi->scdc.scrambling.supported, | |
813 | hdmi->scdc.scrambling.low_rates); | |
f530bc60 | 814 | if (ret) |
7a406f8a | 815 | return; |
f530bc60 BS |
816 | |
817 | /* AVI InfoFrame. */ | |
818 | args.infoframe.version = 0; | |
819 | args.infoframe.head = nv_crtc->index; | |
820 | ||
821 | if (!drm_hdmi_avi_infoframe_from_display_mode(&infoframe.avi, &nv_connector->base, mode)) { | |
822 | drm_hdmi_avi_infoframe_quant_range(&infoframe.avi, &nv_connector->base, mode, | |
823 | HDMI_QUANTIZATION_RANGE_FULL); | |
824 | ||
c02f20d3 | 825 | size = hdmi_infoframe_pack(&infoframe, args.data, ARRAY_SIZE(args.data)); |
f530bc60 BS |
826 | } else { |
827 | size = 0; | |
7a406f8a | 828 | } |
f530bc60 BS |
829 | |
830 | nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_AVI, &args.infoframe, size); | |
831 | ||
832 | /* Vendor InfoFrame. */ | |
c02f20d3 | 833 | memset(&args.data, 0, sizeof(args.data)); |
f530bc60 BS |
834 | if (!drm_hdmi_vendor_infoframe_from_display_mode(&infoframe.vendor.hdmi, |
835 | &nv_connector->base, mode)) | |
c02f20d3 | 836 | size = hdmi_infoframe_pack(&infoframe, args.data, ARRAY_SIZE(args.data)); |
f530bc60 BS |
837 | else |
838 | size = 0; | |
839 | ||
840 | nvif_outp_infoframe(&nv_encoder->outp, NVIF_OUTP_INFOFRAME_V0_VSI, &args.infoframe, size); | |
8ed09421 BS |
841 | |
842 | nv_encoder->hdmi.enabled = true; | |
78951d22 BS |
843 | } |
844 | ||
52aa30f2 BS |
845 | /****************************************************************************** |
846 | * MST | |
847 | *****************************************************************************/ | |
f479c0ba BS |
848 | #define nv50_mstm(p) container_of((p), struct nv50_mstm, mgr) |
849 | #define nv50_mstc(p) container_of((p), struct nv50_mstc, connector) | |
850 | #define nv50_msto(p) container_of((p), struct nv50_msto, encoder) | |
851 | ||
f479c0ba BS |
852 | struct nv50_mstc { |
853 | struct nv50_mstm *mstm; | |
854 | struct drm_dp_mst_port *port; | |
855 | struct drm_connector connector; | |
856 | ||
857 | struct drm_display_mode *native; | |
858 | struct edid *edid; | |
52aa30f2 BS |
859 | }; |
860 | ||
f479c0ba BS |
861 | struct nv50_msto { |
862 | struct drm_encoder encoder; | |
863 | ||
1b38cf6b | 864 | /* head is statically assigned on msto creation */ |
f479c0ba BS |
865 | struct nv50_head *head; |
866 | struct nv50_mstc *mstc; | |
867 | bool disabled; | |
4d07b0bc | 868 | bool enabled; |
1958d69f BS |
869 | |
870 | u32 display_id; | |
f479c0ba BS |
871 | }; |
872 | ||
12885ecb LP |
873 | struct nouveau_encoder *nv50_real_outp(struct drm_encoder *encoder) |
874 | { | |
875 | struct nv50_msto *msto; | |
876 | ||
877 | if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) | |
878 | return nouveau_encoder(encoder); | |
879 | ||
880 | msto = nv50_msto(encoder); | |
881 | if (!msto->mstc) | |
882 | return NULL; | |
883 | return msto->mstc->mstm->outp; | |
884 | } | |
885 | ||
f479c0ba | 886 | static void |
4d07b0bc | 887 | nv50_msto_cleanup(struct drm_atomic_state *state, |
5aa1dfcd | 888 | struct drm_dp_mst_topology_state *new_mst_state, |
4d07b0bc LP |
889 | struct drm_dp_mst_topology_mgr *mgr, |
890 | struct nv50_msto *msto) | |
f479c0ba BS |
891 | { |
892 | struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev); | |
5aa1dfcd WL |
893 | struct drm_dp_mst_atomic_payload *new_payload = |
894 | drm_atomic_get_mst_payload_state(new_mst_state, msto->mstc->port); | |
895 | struct drm_dp_mst_topology_state *old_mst_state = | |
896 | drm_atomic_get_old_mst_topology_state(state, mgr); | |
897 | const struct drm_dp_mst_atomic_payload *old_payload = | |
898 | drm_atomic_get_mst_payload_state(old_mst_state, msto->mstc->port); | |
1958d69f BS |
899 | struct nv50_mstc *mstc = msto->mstc; |
900 | struct nv50_mstm *mstm = mstc->mstm; | |
5e292e76 | 901 | |
f479c0ba | 902 | NV_ATOMIC(drm, "%s: msto cleanup\n", msto->encoder.name); |
5e292e76 | 903 | |
4d07b0bc | 904 | if (msto->disabled) { |
1958d69f BS |
905 | if (msto->head->func->display_id) { |
906 | nvif_outp_dp_mst_id_put(&mstm->outp->outp, msto->display_id); | |
907 | msto->display_id = 0; | |
908 | } | |
909 | ||
4d07b0bc LP |
910 | msto->mstc = NULL; |
911 | msto->disabled = false; | |
5aa1dfcd | 912 | drm_dp_remove_payload_part2(mgr, new_mst_state, old_payload, new_payload); |
4d07b0bc | 913 | } else if (msto->enabled) { |
8a0a7b98 | 914 | drm_dp_add_payload_part2(mgr, new_payload); |
4d07b0bc LP |
915 | msto->enabled = false; |
916 | } | |
f479c0ba BS |
917 | } |
918 | ||
919 | static void | |
4d07b0bc LP |
920 | nv50_msto_prepare(struct drm_atomic_state *state, |
921 | struct drm_dp_mst_topology_state *mst_state, | |
922 | struct drm_dp_mst_topology_mgr *mgr, | |
923 | struct nv50_msto *msto) | |
f479c0ba BS |
924 | { |
925 | struct nouveau_drm *drm = nouveau_drm(msto->encoder.dev); | |
926 | struct nv50_mstc *mstc = msto->mstc; | |
927 | struct nv50_mstm *mstm = mstc->mstm; | |
5aa1dfcd | 928 | struct drm_dp_mst_atomic_payload *payload; |
16763084 | 929 | int ret = 0; |
f479c0ba BS |
930 | |
931 | NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name); | |
4d07b0bc LP |
932 | |
933 | payload = drm_atomic_get_mst_payload_state(mst_state, mstc->port); | |
934 | ||
4d07b0bc | 935 | if (msto->disabled) { |
5aa1dfcd | 936 | drm_dp_remove_payload_part1(mgr, mst_state, payload); |
8c7d980d | 937 | nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0); |
16763084 | 938 | ret = 1; |
4d07b0bc LP |
939 | } else { |
940 | if (msto->enabled) | |
16763084 BS |
941 | ret = drm_dp_add_payload_part1(mgr, mst_state, payload); |
942 | } | |
4d07b0bc | 943 | |
16763084 | 944 | if (ret == 0) { |
8c7d980d BS |
945 | nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, |
946 | payload->vc_start_slot, payload->time_slots, | |
191dc439 ID |
947 | payload->pbn, |
948 | payload->time_slots * dfixed_trunc(mst_state->pbn_div)); | |
16763084 BS |
949 | } else { |
950 | nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0); | |
f479c0ba | 951 | } |
f479c0ba BS |
952 | } |
953 | ||
954 | static int | |
955 | nv50_msto_atomic_check(struct drm_encoder *encoder, | |
956 | struct drm_crtc_state *crtc_state, | |
957 | struct drm_connector_state *conn_state) | |
958 | { | |
232c9eec LP |
959 | struct drm_atomic_state *state = crtc_state->state; |
960 | struct drm_connector *connector = conn_state->connector; | |
4d07b0bc | 961 | struct drm_dp_mst_topology_state *mst_state; |
232c9eec | 962 | struct nv50_mstc *mstc = nv50_mstc(connector); |
f479c0ba | 963 | struct nv50_mstm *mstm = mstc->mstm; |
88ec89ad | 964 | struct nv50_head_atom *asyh = nv50_head_atom(crtc_state); |
f479c0ba | 965 | int slots; |
310d3577 | 966 | int ret; |
f479c0ba | 967 | |
310d3577 LP |
968 | ret = nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, |
969 | mstc->native); | |
970 | if (ret) | |
971 | return ret; | |
f479c0ba | 972 | |
21167510 | 973 | if (!drm_atomic_crtc_needs_modeset(crtc_state)) |
310d3577 | 974 | return 0; |
88ec89ad | 975 | |
310d3577 LP |
976 | /* |
977 | * When restoring duplicated states, we need to make sure that the bw | |
978 | * remains the same and avoid recalculating it, as the connector's bpc | |
979 | * may have changed after the state was duplicated | |
980 | */ | |
981 | if (!state->duplicated) { | |
310d3577 LP |
982 | const int clock = crtc_state->adjusted_mode.clock; |
983 | ||
bbdf6a58 | 984 | asyh->or.bpc = connector->display_info.bpc; |
7707dd60 | 985 | asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3 << 4); |
232c9eec | 986 | } |
f479c0ba | 987 | |
4d07b0bc LP |
988 | mst_state = drm_atomic_get_mst_topology_state(state, &mstm->mgr); |
989 | if (IS_ERR(mst_state)) | |
990 | return PTR_ERR(mst_state); | |
991 | ||
191dc439 | 992 | if (!mst_state->pbn_div.full) { |
4d07b0bc LP |
993 | struct nouveau_encoder *outp = mstc->mstm->outp; |
994 | ||
995 | mst_state->pbn_div = drm_dp_get_vc_payload_bw(&mstm->mgr, | |
996 | outp->dp.link_bw, outp->dp.link_nr); | |
997 | } | |
998 | ||
999 | slots = drm_dp_atomic_find_time_slots(state, &mstm->mgr, mstc->port, asyh->dp.pbn); | |
310d3577 LP |
1000 | if (slots < 0) |
1001 | return slots; | |
1002 | ||
1003 | asyh->dp.tu = slots; | |
1004 | ||
1005 | return 0; | |
f479c0ba BS |
1006 | } |
1007 | ||
ac2d9275 LP |
1008 | static u8 |
1009 | nv50_dp_bpc_to_depth(unsigned int bpc) | |
1010 | { | |
1011 | switch (bpc) { | |
344c2e5a BS |
1012 | case 6: return NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_BPP_18_444; |
1013 | case 8: return NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_BPP_24_444; | |
f6e7393e | 1014 | case 10: |
344c2e5a | 1015 | default: return NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_BPP_30_444; |
ac2d9275 LP |
1016 | } |
1017 | } | |
1018 | ||
f479c0ba | 1019 | static void |
fa9f9489 | 1020 | nv50_msto_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) |
f479c0ba | 1021 | { |
f479c0ba | 1022 | struct nv50_msto *msto = nv50_msto(encoder); |
1b38cf6b LP |
1023 | struct nv50_head *head = msto->head; |
1024 | struct nv50_head_atom *asyh = | |
1025 | nv50_head_atom(drm_atomic_get_new_crtc_state(state, &head->base.base)); | |
f479c0ba BS |
1026 | struct nv50_mstc *mstc = NULL; |
1027 | struct nv50_mstm *mstm = NULL; | |
1028 | struct drm_connector *connector; | |
875dd626 | 1029 | struct drm_connector_list_iter conn_iter; |
ac2d9275 | 1030 | u8 proto; |
f479c0ba | 1031 | |
875dd626 GP |
1032 | drm_connector_list_iter_begin(encoder->dev, &conn_iter); |
1033 | drm_for_each_connector_iter(connector, &conn_iter) { | |
f479c0ba BS |
1034 | if (connector->state->best_encoder == &msto->encoder) { |
1035 | mstc = nv50_mstc(connector); | |
1036 | mstm = mstc->mstm; | |
1037 | break; | |
1038 | } | |
1039 | } | |
875dd626 | 1040 | drm_connector_list_iter_end(&conn_iter); |
f479c0ba BS |
1041 | |
1042 | if (WARN_ON(!mstc)) | |
1043 | return; | |
1044 | ||
ea6143a8 | 1045 | if (!mstm->links++) { |
cefc3c14 | 1046 | nvif_outp_acquire_sor(&mstm->outp->outp, false /*TODO: MST audio... */); |
63371650 | 1047 | nouveau_dp_train(mstm->outp, true, 0, 0); |
ea6143a8 | 1048 | } |
6c22ea37 | 1049 | |
1958d69f BS |
1050 | if (head->func->display_id) { |
1051 | if (!WARN_ON(nvif_outp_dp_mst_id_get(&mstm->outp->outp, &msto->display_id))) | |
1052 | head->func->display_id(head, msto->display_id); | |
1053 | } | |
1054 | ||
ea6143a8 | 1055 | if (mstm->outp->outp.or.link & 1) |
344c2e5a | 1056 | proto = NV917D_SOR_SET_CONTROL_PROTOCOL_DP_A; |
f479c0ba | 1057 | else |
344c2e5a | 1058 | proto = NV917D_SOR_SET_CONTROL_PROTOCOL_DP_B; |
f479c0ba | 1059 | |
f60f8705 LP |
1060 | mstm->outp->update(mstm->outp, head->base.index, asyh, proto, |
1061 | nv50_dp_bpc_to_depth(asyh->or.bpc)); | |
f479c0ba | 1062 | |
f479c0ba | 1063 | msto->mstc = mstc; |
4d07b0bc | 1064 | msto->enabled = true; |
f479c0ba BS |
1065 | mstm->modified = true; |
1066 | } | |
1067 | ||
1068 | static void | |
fa9f9489 | 1069 | nv50_msto_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) |
f479c0ba BS |
1070 | { |
1071 | struct nv50_msto *msto = nv50_msto(encoder); | |
1072 | struct nv50_mstc *mstc = msto->mstc; | |
1073 | struct nv50_mstm *mstm = mstc->mstm; | |
1074 | ||
1958d69f BS |
1075 | if (msto->head->func->display_id) |
1076 | msto->head->func->display_id(msto->head, 0); | |
1077 | ||
f479c0ba BS |
1078 | mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0); |
1079 | mstm->modified = true; | |
6c22ea37 BS |
1080 | if (!--mstm->links) |
1081 | mstm->disabled = true; | |
f479c0ba BS |
1082 | msto->disabled = true; |
1083 | } | |
1084 | ||
1085 | static const struct drm_encoder_helper_funcs | |
1086 | nv50_msto_help = { | |
fa9f9489 LP |
1087 | .atomic_disable = nv50_msto_atomic_disable, |
1088 | .atomic_enable = nv50_msto_atomic_enable, | |
f479c0ba BS |
1089 | .atomic_check = nv50_msto_atomic_check, |
1090 | }; | |
1091 | ||
1092 | static void | |
1093 | nv50_msto_destroy(struct drm_encoder *encoder) | |
1094 | { | |
1095 | struct nv50_msto *msto = nv50_msto(encoder); | |
1096 | drm_encoder_cleanup(&msto->encoder); | |
1097 | kfree(msto); | |
1098 | } | |
1099 | ||
1100 | static const struct drm_encoder_funcs | |
1101 | nv50_msto = { | |
1102 | .destroy = nv50_msto_destroy, | |
1103 | }; | |
1104 | ||
5ff0cb1c LP |
1105 | static struct nv50_msto * |
1106 | nv50_msto_new(struct drm_device *dev, struct nv50_head *head, int id) | |
f479c0ba BS |
1107 | { |
1108 | struct nv50_msto *msto; | |
1109 | int ret; | |
1110 | ||
5ff0cb1c LP |
1111 | msto = kzalloc(sizeof(*msto), GFP_KERNEL); |
1112 | if (!msto) | |
1113 | return ERR_PTR(-ENOMEM); | |
f479c0ba BS |
1114 | |
1115 | ret = drm_encoder_init(dev, &msto->encoder, &nv50_msto, | |
5ff0cb1c | 1116 | DRM_MODE_ENCODER_DPMST, "mst-%d", id); |
f479c0ba | 1117 | if (ret) { |
5ff0cb1c LP |
1118 | kfree(msto); |
1119 | return ERR_PTR(ret); | |
f479c0ba BS |
1120 | } |
1121 | ||
1122 | drm_encoder_helper_add(&msto->encoder, &nv50_msto_help); | |
5ff0cb1c LP |
1123 | msto->encoder.possible_crtcs = drm_crtc_mask(&head->base.base); |
1124 | msto->head = head; | |
1125 | return msto; | |
f479c0ba BS |
1126 | } |
1127 | ||
1128 | static struct drm_encoder * | |
1129 | nv50_mstc_atomic_best_encoder(struct drm_connector *connector, | |
eca22edb | 1130 | struct drm_atomic_state *state) |
f479c0ba | 1131 | { |
eca22edb MR |
1132 | struct drm_connector_state *connector_state = drm_atomic_get_new_connector_state(state, |
1133 | connector); | |
f479c0ba | 1134 | struct nv50_mstc *mstc = nv50_mstc(connector); |
5ff0cb1c | 1135 | struct drm_crtc *crtc = connector_state->crtc; |
7b0f61e9 | 1136 | |
5ff0cb1c LP |
1137 | if (!(mstc->mstm->outp->dcb->heads & drm_crtc_mask(crtc))) |
1138 | return NULL; | |
1139 | ||
1140 | return &nv50_head(crtc)->msto->encoder; | |
f479c0ba BS |
1141 | } |
1142 | ||
f479c0ba BS |
1143 | static enum drm_mode_status |
1144 | nv50_mstc_mode_valid(struct drm_connector *connector, | |
1145 | struct drm_display_mode *mode) | |
1146 | { | |
d6a9efec LP |
1147 | struct nv50_mstc *mstc = nv50_mstc(connector); |
1148 | struct nouveau_encoder *outp = mstc->mstm->outp; | |
1149 | ||
1150 | /* TODO: calculate the PBN from the dotclock and validate against the | |
1151 | * MSTB's max possible PBN | |
1152 | */ | |
1153 | ||
949ab38a | 1154 | return nv50_dp_mode_valid(outp, mode, NULL); |
f479c0ba BS |
1155 | } |
1156 | ||
1157 | static int | |
1158 | nv50_mstc_get_modes(struct drm_connector *connector) | |
1159 | { | |
1160 | struct nv50_mstc *mstc = nv50_mstc(connector); | |
1161 | int ret = 0; | |
1162 | ||
1163 | mstc->edid = drm_dp_mst_get_edid(&mstc->connector, mstc->port->mgr, mstc->port); | |
c555f023 | 1164 | drm_connector_update_edid_property(&mstc->connector, mstc->edid); |
d471ed04 | 1165 | if (mstc->edid) |
f479c0ba | 1166 | ret = drm_add_edid_modes(&mstc->connector, mstc->edid); |
f479c0ba | 1167 | |
bbdf6a58 LP |
1168 | /* |
1169 | * XXX: Since we don't use HDR in userspace quite yet, limit the bpc | |
1170 | * to 8 to save bandwidth on the topology. In the future, we'll want | |
1171 | * to properly fix this by dynamically selecting the highest possible | |
1172 | * bpc that would fit in the topology | |
1173 | */ | |
1174 | if (connector->display_info.bpc) | |
1175 | connector->display_info.bpc = | |
1176 | clamp(connector->display_info.bpc, 6U, 8U); | |
1177 | else | |
1178 | connector->display_info.bpc = 8; | |
f479c0ba BS |
1179 | |
1180 | if (mstc->native) | |
1181 | drm_mode_destroy(mstc->connector.dev, mstc->native); | |
1182 | mstc->native = nouveau_conn_native_mode(&mstc->connector); | |
1183 | return ret; | |
1184 | } | |
1185 | ||
232c9eec LP |
1186 | static int |
1187 | nv50_mstc_atomic_check(struct drm_connector *connector, | |
6f3b6278 | 1188 | struct drm_atomic_state *state) |
232c9eec | 1189 | { |
232c9eec LP |
1190 | struct nv50_mstc *mstc = nv50_mstc(connector); |
1191 | struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr; | |
232c9eec | 1192 | |
df78f7f6 | 1193 | return drm_dp_atomic_release_time_slots(state, mgr, mstc->port); |
232c9eec LP |
1194 | } |
1195 | ||
3f9b3f02 LP |
1196 | static int |
1197 | nv50_mstc_detect(struct drm_connector *connector, | |
1198 | struct drm_modeset_acquire_ctx *ctx, bool force) | |
f479c0ba BS |
1199 | { |
1200 | struct nv50_mstc *mstc = nv50_mstc(connector); | |
e46368cf LP |
1201 | int ret; |
1202 | ||
d79a3c52 | 1203 | if (drm_connector_is_unregistered(connector)) |
f479c0ba | 1204 | return connector_status_disconnected; |
e46368cf LP |
1205 | |
1206 | ret = pm_runtime_get_sync(connector->dev->dev); | |
dc455f4c DL |
1207 | if (ret < 0 && ret != -EACCES) { |
1208 | pm_runtime_put_autosuspend(connector->dev->dev); | |
e46368cf | 1209 | return connector_status_disconnected; |
dc455f4c | 1210 | } |
e46368cf | 1211 | |
3f9b3f02 LP |
1212 | ret = drm_dp_mst_detect_port(connector, ctx, mstc->port->mgr, |
1213 | mstc->port); | |
409d3813 LP |
1214 | if (ret != connector_status_connected) |
1215 | goto out; | |
e46368cf | 1216 | |
409d3813 | 1217 | out: |
e46368cf LP |
1218 | pm_runtime_mark_last_busy(connector->dev->dev); |
1219 | pm_runtime_put_autosuspend(connector->dev->dev); | |
3f9b3f02 | 1220 | return ret; |
f479c0ba BS |
1221 | } |
1222 | ||
3f9b3f02 LP |
1223 | static const struct drm_connector_helper_funcs |
1224 | nv50_mstc_help = { | |
1225 | .get_modes = nv50_mstc_get_modes, | |
1226 | .mode_valid = nv50_mstc_mode_valid, | |
3f9b3f02 LP |
1227 | .atomic_best_encoder = nv50_mstc_atomic_best_encoder, |
1228 | .atomic_check = nv50_mstc_atomic_check, | |
1229 | .detect_ctx = nv50_mstc_detect, | |
1230 | }; | |
1231 | ||
f479c0ba BS |
1232 | static void |
1233 | nv50_mstc_destroy(struct drm_connector *connector) | |
1234 | { | |
1235 | struct nv50_mstc *mstc = nv50_mstc(connector); | |
81640f01 | 1236 | |
f479c0ba | 1237 | drm_connector_cleanup(&mstc->connector); |
d79a3c52 | 1238 | drm_dp_mst_put_port_malloc(mstc->port); |
81640f01 | 1239 | |
f479c0ba BS |
1240 | kfree(mstc); |
1241 | } | |
1242 | ||
1243 | static const struct drm_connector_funcs | |
1244 | nv50_mstc = { | |
f479c0ba | 1245 | .reset = nouveau_conn_reset, |
f479c0ba | 1246 | .fill_modes = drm_helper_probe_single_connector_modes, |
f479c0ba BS |
1247 | .destroy = nv50_mstc_destroy, |
1248 | .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state, | |
1249 | .atomic_destroy_state = nouveau_conn_atomic_destroy_state, | |
1250 | .atomic_set_property = nouveau_conn_atomic_set_property, | |
1251 | .atomic_get_property = nouveau_conn_atomic_get_property, | |
1252 | }; | |
1253 | ||
1254 | static int | |
1255 | nv50_mstc_new(struct nv50_mstm *mstm, struct drm_dp_mst_port *port, | |
1256 | const char *path, struct nv50_mstc **pmstc) | |
1257 | { | |
1258 | struct drm_device *dev = mstm->outp->base.base.dev; | |
5ff0cb1c | 1259 | struct drm_crtc *crtc; |
f479c0ba | 1260 | struct nv50_mstc *mstc; |
5ff0cb1c | 1261 | int ret; |
f479c0ba BS |
1262 | |
1263 | if (!(mstc = *pmstc = kzalloc(sizeof(*mstc), GFP_KERNEL))) | |
1264 | return -ENOMEM; | |
1265 | mstc->mstm = mstm; | |
1266 | mstc->port = port; | |
1267 | ||
1268 | ret = drm_connector_init(dev, &mstc->connector, &nv50_mstc, | |
1269 | DRM_MODE_CONNECTOR_DisplayPort); | |
1270 | if (ret) { | |
1271 | kfree(*pmstc); | |
1272 | *pmstc = NULL; | |
1273 | return ret; | |
1274 | } | |
1275 | ||
1276 | drm_connector_helper_add(&mstc->connector, &nv50_mstc_help); | |
1277 | ||
1278 | mstc->connector.funcs->reset(&mstc->connector); | |
1279 | nouveau_conn_attach_properties(&mstc->connector); | |
1280 | ||
5ff0cb1c LP |
1281 | drm_for_each_crtc(crtc, dev) { |
1282 | if (!(mstm->outp->dcb->heads & drm_crtc_mask(crtc))) | |
1283 | continue; | |
1284 | ||
1285 | drm_connector_attach_encoder(&mstc->connector, | |
1286 | &nv50_head(crtc)->msto->encoder); | |
1287 | } | |
f479c0ba BS |
1288 | |
1289 | drm_object_attach_property(&mstc->connector.base, dev->mode_config.path_property, 0); | |
1290 | drm_object_attach_property(&mstc->connector.base, dev->mode_config.tile_property, 0); | |
97e14fbe | 1291 | drm_connector_set_path_property(&mstc->connector, path); |
81640f01 | 1292 | drm_dp_mst_get_port_malloc(port); |
f479c0ba BS |
1293 | return 0; |
1294 | } | |
1295 | ||
1296 | static void | |
4d07b0bc LP |
1297 | nv50_mstm_cleanup(struct drm_atomic_state *state, |
1298 | struct drm_dp_mst_topology_state *mst_state, | |
1299 | struct nv50_mstm *mstm) | |
f479c0ba BS |
1300 | { |
1301 | struct nouveau_drm *drm = nouveau_drm(mstm->outp->base.base.dev); | |
1302 | struct drm_encoder *encoder; | |
f479c0ba BS |
1303 | |
1304 | NV_ATOMIC(drm, "%s: mstm cleanup\n", mstm->outp->base.base.name); | |
606be062 | 1305 | drm_dp_check_act_status(&mstm->mgr); |
f479c0ba | 1306 | |
f479c0ba BS |
1307 | drm_for_each_encoder(encoder, mstm->outp->base.base.dev) { |
1308 | if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) { | |
1309 | struct nv50_msto *msto = nv50_msto(encoder); | |
1310 | struct nv50_mstc *mstc = msto->mstc; | |
1311 | if (mstc && mstc->mstm == mstm) | |
4d07b0bc | 1312 | nv50_msto_cleanup(state, mst_state, &mstm->mgr, msto); |
f479c0ba BS |
1313 | } |
1314 | } | |
1315 | ||
b24bf8b8 | 1316 | if (mstm->disabled) { |
75703380 | 1317 | nouveau_dp_power_down(mstm->outp); |
b24bf8b8 BS |
1318 | nvif_outp_release(&mstm->outp->outp); |
1319 | mstm->disabled = false; | |
1320 | } | |
1321 | ||
f479c0ba BS |
1322 | mstm->modified = false; |
1323 | } | |
1324 | ||
1325 | static void | |
4d07b0bc LP |
1326 | nv50_mstm_prepare(struct drm_atomic_state *state, |
1327 | struct drm_dp_mst_topology_state *mst_state, | |
1328 | struct nv50_mstm *mstm) | |
f479c0ba BS |
1329 | { |
1330 | struct nouveau_drm *drm = nouveau_drm(mstm->outp->base.base.dev); | |
1331 | struct drm_encoder *encoder; | |
f479c0ba BS |
1332 | |
1333 | NV_ATOMIC(drm, "%s: mstm prepare\n", mstm->outp->base.base.name); | |
f479c0ba | 1334 | |
4d07b0bc | 1335 | /* Disable payloads first */ |
f479c0ba BS |
1336 | drm_for_each_encoder(encoder, mstm->outp->base.base.dev) { |
1337 | if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) { | |
1338 | struct nv50_msto *msto = nv50_msto(encoder); | |
1339 | struct nv50_mstc *mstc = msto->mstc; | |
4d07b0bc LP |
1340 | if (mstc && mstc->mstm == mstm && msto->disabled) |
1341 | nv50_msto_prepare(state, mst_state, &mstm->mgr, msto); | |
1342 | } | |
1343 | } | |
1344 | ||
1345 | /* Add payloads for new heads, while also updating the start slots of any unmodified (but | |
1346 | * active) heads that may have had their VC slots shifted left after the previous step | |
1347 | */ | |
1348 | drm_for_each_encoder(encoder, mstm->outp->base.base.dev) { | |
1349 | if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) { | |
1350 | struct nv50_msto *msto = nv50_msto(encoder); | |
1351 | struct nv50_mstc *mstc = msto->mstc; | |
1352 | if (mstc && mstc->mstm == mstm && !msto->disabled) | |
1353 | nv50_msto_prepare(state, mst_state, &mstm->mgr, msto); | |
f479c0ba BS |
1354 | } |
1355 | } | |
1356 | } | |
1357 | ||
f479c0ba BS |
1358 | static struct drm_connector * |
1359 | nv50_mstm_add_connector(struct drm_dp_mst_topology_mgr *mgr, | |
1360 | struct drm_dp_mst_port *port, const char *path) | |
1361 | { | |
1362 | struct nv50_mstm *mstm = nv50_mstm(mgr); | |
1363 | struct nv50_mstc *mstc; | |
1364 | int ret; | |
1365 | ||
1366 | ret = nv50_mstc_new(mstm, port, path, &mstc); | |
01324093 | 1367 | if (ret) |
f479c0ba | 1368 | return NULL; |
f479c0ba BS |
1369 | |
1370 | return &mstc->connector; | |
1371 | } | |
1372 | ||
1373 | static const struct drm_dp_mst_topology_cbs | |
1374 | nv50_mstm = { | |
1375 | .add_connector = nv50_mstm_add_connector, | |
f479c0ba BS |
1376 | }; |
1377 | ||
a0922278 LP |
1378 | bool |
1379 | nv50_mstm_service(struct nouveau_drm *drm, | |
1380 | struct nouveau_connector *nv_connector, | |
1381 | struct nv50_mstm *mstm) | |
f479c0ba | 1382 | { |
a0922278 LP |
1383 | struct drm_dp_aux *aux = &nv_connector->aux; |
1384 | bool handled = true, ret = true; | |
1385 | int rc; | |
f479c0ba BS |
1386 | u8 esi[8] = {}; |
1387 | ||
1388 | while (handled) { | |
72f1de49 WL |
1389 | u8 ack[8] = {}; |
1390 | ||
a0922278 LP |
1391 | rc = drm_dp_dpcd_read(aux, DP_SINK_COUNT_ESI, esi, 8); |
1392 | if (rc != 8) { | |
1393 | ret = false; | |
1394 | break; | |
f479c0ba BS |
1395 | } |
1396 | ||
72f1de49 | 1397 | drm_dp_mst_hpd_irq_handle_event(&mstm->mgr, esi, ack, &handled); |
f479c0ba BS |
1398 | if (!handled) |
1399 | break; | |
1400 | ||
72f1de49 WL |
1401 | rc = drm_dp_dpcd_writeb(aux, DP_SINK_COUNT_ESI + 1, ack[1]); |
1402 | ||
1403 | if (rc != 1) { | |
a0922278 LP |
1404 | ret = false; |
1405 | break; | |
1406 | } | |
72f1de49 WL |
1407 | |
1408 | drm_dp_mst_hpd_irq_send_new_request(&mstm->mgr); | |
f479c0ba | 1409 | } |
a0922278 LP |
1410 | |
1411 | if (!ret) | |
1412 | NV_DEBUG(drm, "Failed to handle ESI on %s: %d\n", | |
1413 | nv_connector->base.name, rc); | |
1414 | ||
1415 | return ret; | |
f479c0ba BS |
1416 | } |
1417 | ||
1418 | void | |
1419 | nv50_mstm_remove(struct nv50_mstm *mstm) | |
1420 | { | |
a0922278 LP |
1421 | mstm->is_mst = false; |
1422 | drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, false); | |
f479c0ba BS |
1423 | } |
1424 | ||
52aa30f2 | 1425 | int |
a0922278 | 1426 | nv50_mstm_detect(struct nouveau_encoder *outp) |
52aa30f2 | 1427 | { |
a0922278 | 1428 | struct nv50_mstm *mstm = outp->dp.mstm; |
b26b4590 LP |
1429 | struct drm_dp_aux *aux; |
1430 | int ret; | |
52aa30f2 | 1431 | |
a0922278 | 1432 | if (!mstm || !mstm->can_mst) |
52aa30f2 BS |
1433 | return 0; |
1434 | ||
b26b4590 LP |
1435 | aux = mstm->mgr.aux; |
1436 | ||
a0922278 LP |
1437 | /* Clear any leftover MST state we didn't set ourselves by first |
1438 | * disabling MST if it was already enabled | |
1439 | */ | |
1440 | ret = drm_dp_dpcd_writeb(aux, DP_MSTM_CTRL, 0); | |
1441 | if (ret < 0) | |
1442 | return ret; | |
52aa30f2 | 1443 | |
a0922278 | 1444 | /* And start enabling */ |
a0922278 | 1445 | ret = drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, true); |
81344372 | 1446 | if (ret) |
a0922278 | 1447 | return ret; |
b26b4590 | 1448 | |
a0922278 LP |
1449 | mstm->is_mst = true; |
1450 | return 1; | |
52aa30f2 BS |
1451 | } |
1452 | ||
f479c0ba | 1453 | static void |
a0922278 | 1454 | nv50_mstm_fini(struct nouveau_encoder *outp) |
f479c0ba | 1455 | { |
a0922278 LP |
1456 | struct nv50_mstm *mstm = outp->dp.mstm; |
1457 | ||
1458 | if (!mstm) | |
1459 | return; | |
1460 | ||
1461 | /* Don't change the MST state of this connector until we've finished | |
1462 | * resuming, since we can't safely grab hpd_irq_lock in our resume | |
1463 | * path to protect mstm->is_mst without potentially deadlocking | |
1464 | */ | |
1465 | mutex_lock(&outp->dp.hpd_irq_lock); | |
1466 | mstm->suspended = true; | |
1467 | mutex_unlock(&outp->dp.hpd_irq_lock); | |
1468 | ||
1469 | if (mstm->is_mst) | |
f479c0ba BS |
1470 | drm_dp_mst_topology_mgr_suspend(&mstm->mgr); |
1471 | } | |
1472 | ||
1473 | static void | |
a0922278 | 1474 | nv50_mstm_init(struct nouveau_encoder *outp, bool runtime) |
f479c0ba | 1475 | { |
a0922278 LP |
1476 | struct nv50_mstm *mstm = outp->dp.mstm; |
1477 | int ret = 0; | |
b89fdf7a | 1478 | |
a0922278 | 1479 | if (!mstm) |
b89fdf7a LP |
1480 | return; |
1481 | ||
a0922278 LP |
1482 | if (mstm->is_mst) { |
1483 | ret = drm_dp_mst_topology_mgr_resume(&mstm->mgr, !runtime); | |
1484 | if (ret == -1) | |
1485 | nv50_mstm_remove(mstm); | |
b89fdf7a | 1486 | } |
a0922278 LP |
1487 | |
1488 | mutex_lock(&outp->dp.hpd_irq_lock); | |
1489 | mstm->suspended = false; | |
1490 | mutex_unlock(&outp->dp.hpd_irq_lock); | |
1491 | ||
1492 | if (ret == -1) | |
1493 | drm_kms_helper_hotplug_event(mstm->mgr.dev); | |
f479c0ba BS |
1494 | } |
1495 | ||
52aa30f2 BS |
1496 | static void |
1497 | nv50_mstm_del(struct nv50_mstm **pmstm) | |
1498 | { | |
1499 | struct nv50_mstm *mstm = *pmstm; | |
1500 | if (mstm) { | |
24199c54 | 1501 | drm_dp_mst_topology_mgr_destroy(&mstm->mgr); |
52aa30f2 BS |
1502 | kfree(*pmstm); |
1503 | *pmstm = NULL; | |
1504 | } | |
1505 | } | |
1506 | ||
1507 | static int | |
1508 | nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max, | |
1509 | int conn_base_id, struct nv50_mstm **pmstm) | |
1510 | { | |
1511 | const int max_payloads = hweight8(outp->dcb->heads); | |
1512 | struct drm_device *dev = outp->base.base.dev; | |
1513 | struct nv50_mstm *mstm; | |
5ff0cb1c | 1514 | int ret; |
52aa30f2 BS |
1515 | |
1516 | if (!(mstm = *pmstm = kzalloc(sizeof(*mstm), GFP_KERNEL))) | |
1517 | return -ENOMEM; | |
1518 | mstm->outp = outp; | |
f479c0ba | 1519 | mstm->mgr.cbs = &nv50_mstm; |
52aa30f2 | 1520 | |
7b0a89a6 | 1521 | ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev, aux, aux_max, |
4d07b0bc | 1522 | max_payloads, conn_base_id); |
52aa30f2 BS |
1523 | if (ret) |
1524 | return ret; | |
1525 | ||
1526 | return 0; | |
1527 | } | |
1528 | ||
26f6d88b BS |
1529 | /****************************************************************************** |
1530 | * SOR | |
1531 | *****************************************************************************/ | |
4cbb0f8d | 1532 | static void |
d665c7e9 | 1533 | nv50_sor_update(struct nouveau_encoder *nv_encoder, u8 head, |
2ca7fb5c | 1534 | struct nv50_head_atom *asyh, u8 proto, u8 depth) |
4cbb0f8d | 1535 | { |
9ca6f1eb | 1536 | struct nv50_disp *disp = nv50_disp(nv_encoder->base.base.dev); |
0a368771 | 1537 | struct nv50_core *core = disp->core; |
d665c7e9 | 1538 | |
2ca7fb5c | 1539 | if (!asyh) { |
d665c7e9 | 1540 | nv_encoder->ctrl &= ~BIT(head); |
344c2e5a | 1541 | if (NVDEF_TEST(nv_encoder->ctrl, NV507D, SOR_SET_CONTROL, OWNER, ==, NONE)) |
d665c7e9 BS |
1542 | nv_encoder->ctrl = 0; |
1543 | } else { | |
344c2e5a | 1544 | nv_encoder->ctrl |= NVVAL(NV507D, SOR_SET_CONTROL, PROTOCOL, proto); |
d665c7e9 | 1545 | nv_encoder->ctrl |= BIT(head); |
2ca7fb5c | 1546 | asyh->or.depth = depth; |
d665c7e9 BS |
1547 | } |
1548 | ||
ea6143a8 | 1549 | core->func->sor->ctrl(core, nv_encoder->outp.or.id, nv_encoder->ctrl, asyh); |
e84a35a8 BS |
1550 | } |
1551 | ||
6eca310e LP |
1552 | /* TODO: Should we extend this to PWM-only backlights? |
1553 | * As well, should we add a DRM helper for waiting for the backlight to acknowledge | |
1554 | * the panel backlight has been shut off? Intel doesn't seem to do this, and uses a | |
1555 | * fixed time delay from the vbios… | |
1556 | */ | |
e84a35a8 | 1557 | static void |
fa9f9489 | 1558 | nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) |
e84a35a8 BS |
1559 | { |
1560 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | |
1958d69f | 1561 | struct nv50_head *head = nv50_head(nv_encoder->crtc); |
98c9644f | 1562 | #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT |
a4ead6e3 | 1563 | struct nouveau_connector *nv_connector = nv50_outp_get_old_connector(state, nv_encoder); |
98c9644f | 1564 | struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); |
6eca310e | 1565 | struct nouveau_backlight *backlight = nv_connector->backlight; |
f575f2bd | 1566 | struct drm_dp_aux *aux = &nv_connector->aux; |
6eca310e | 1567 | int ret; |
839ca903 | 1568 | |
6eca310e LP |
1569 | if (backlight && backlight->uses_dpcd) { |
1570 | ret = drm_edp_backlight_disable(aux, &backlight->edp_info); | |
1571 | if (ret < 0) | |
1572 | NV_ERROR(drm, "Failed to disable backlight on [CONNECTOR:%d:%s]: %d\n", | |
1573 | nv_connector->base.base.id, nv_connector->base.name, ret); | |
1574 | } | |
98c9644f | 1575 | #endif |
6eca310e | 1576 | |
8ed09421 | 1577 | if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS && nv_encoder->hdmi.enabled) { |
1958d69f | 1578 | nvif_outp_hdmi(&nv_encoder->outp, head->base.index, |
8ed09421 BS |
1579 | false, 0, 0, 0, false, false, false); |
1580 | nv_encoder->hdmi.enabled = false; | |
1581 | } | |
1582 | ||
75703380 BS |
1583 | if (nv_encoder->dcb->type == DCB_OUTPUT_DP) |
1584 | nouveau_dp_power_down(nv_encoder); | |
f575f2bd | 1585 | |
1958d69f BS |
1586 | if (head->func->display_id) |
1587 | head->func->display_id(head, 0); | |
1588 | ||
1589 | nv_encoder->update(nv_encoder, head->base.index, NULL, 0, 0); | |
1590 | nv50_audio_disable(encoder, &head->base); | |
9125e242 | 1591 | nv_encoder->crtc = NULL; |
4cbb0f8d BS |
1592 | } |
1593 | ||
9e994444 BS |
1594 | // common/inc/displayport/displayport.h |
1595 | #define DP_CONFIG_WATERMARK_ADJUST 2 | |
1596 | #define DP_CONFIG_WATERMARK_LIMIT 20 | |
1597 | #define DP_CONFIG_INCREASED_WATERMARK_ADJUST 8 | |
1598 | #define DP_CONFIG_INCREASED_WATERMARK_LIMIT 22 | |
1599 | ||
1600 | static bool | |
1601 | nv50_sor_dp_watermark_sst(struct nouveau_encoder *outp, | |
1602 | struct nv50_head *head, struct nv50_head_atom *asyh) | |
1603 | { | |
1604 | bool enhancedFraming = outp->dp.dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP; | |
1605 | u64 minRate = outp->dp.link_bw * 1000; | |
1606 | unsigned tuSize = 64; | |
1607 | unsigned waterMark; | |
1608 | unsigned hBlankSym; | |
1609 | unsigned vBlankSym; | |
1610 | unsigned watermarkAdjust = DP_CONFIG_WATERMARK_ADJUST; | |
1611 | unsigned watermarkMinimum = DP_CONFIG_WATERMARK_LIMIT; | |
1612 | // depth is multiplied by 16 in case of DSC enable | |
1613 | s32 hblank_symbols; | |
1614 | // number of link clocks per line. | |
1615 | int vblank_symbols = 0; | |
1616 | bool bEnableDsc = false; | |
1617 | unsigned surfaceWidth = asyh->mode.h.blanks - asyh->mode.h.blanke; | |
1618 | unsigned rasterWidth = asyh->mode.h.active; | |
1619 | unsigned depth = asyh->or.bpc * 3; | |
1620 | unsigned DSC_FACTOR = bEnableDsc ? 16 : 1; | |
1621 | u64 pixelClockHz = asyh->mode.clock * 1000; | |
1622 | u64 PrecisionFactor = 100000, ratioF, watermarkF; | |
1623 | u32 numLanesPerLink = outp->dp.link_nr; | |
1624 | u32 numSymbolsPerLine; | |
1625 | u32 BlankingBits; | |
1626 | u32 surfaceWidthPerLink; | |
1627 | u32 PixelSteeringBits; | |
1628 | u64 NumBlankingLinkClocks; | |
1629 | u32 MinHBlank; | |
1630 | ||
1631 | if (outp->outp.info.dp.increased_wm) { | |
1632 | watermarkAdjust = DP_CONFIG_INCREASED_WATERMARK_ADJUST; | |
1633 | watermarkMinimum = DP_CONFIG_INCREASED_WATERMARK_LIMIT; | |
1634 | } | |
1635 | ||
1636 | if ((pixelClockHz * depth) >= (8 * minRate * outp->dp.link_nr * DSC_FACTOR)) | |
1637 | { | |
1638 | return false; | |
1639 | } | |
1640 | ||
1641 | // | |
1642 | // For DSC, if (pclk * bpp) < (1/64 * orclk * 8 * lanes) then some TU may end up with | |
1643 | // 0 active symbols. This may cause HW hang. Bug 200379426 | |
1644 | // | |
1645 | if ((bEnableDsc) && | |
7e6bd640 | 1646 | ((pixelClockHz * depth) < div_u64(8 * minRate * outp->dp.link_nr * DSC_FACTOR, 64))) |
9e994444 BS |
1647 | { |
1648 | return false; | |
1649 | } | |
1650 | ||
1651 | // | |
1652 | // Perform the SST calculation. | |
1653 | // For auto mode the watermark calculation does not need to track accumulated error the | |
1654 | // formulas for manual mode will not work. So below calculation was extracted from the DTB. | |
1655 | // | |
7e6bd640 | 1656 | ratioF = div_u64((u64)pixelClockHz * depth * PrecisionFactor, DSC_FACTOR); |
9e994444 | 1657 | |
7e6bd640 | 1658 | ratioF = div_u64(ratioF, 8 * (u64) minRate * outp->dp.link_nr); |
9e994444 BS |
1659 | |
1660 | if (PrecisionFactor < ratioF) // Assert if we will end up with a negative number in below | |
1661 | return false; | |
1662 | ||
7e6bd640 DA |
1663 | watermarkF = div_u64(ratioF * tuSize * (PrecisionFactor - ratioF), PrecisionFactor); |
1664 | waterMark = (unsigned)(watermarkAdjust + (div_u64(2 * div_u64(depth * PrecisionFactor, 8 * numLanesPerLink * DSC_FACTOR) + watermarkF, PrecisionFactor))); | |
9e994444 BS |
1665 | |
1666 | // | |
1667 | // Bounds check the watermark | |
1668 | // | |
7e6bd640 | 1669 | numSymbolsPerLine = div_u64(surfaceWidth * depth, 8 * outp->dp.link_nr * DSC_FACTOR); |
9e994444 BS |
1670 | |
1671 | if (WARN_ON(waterMark > 39 || waterMark > numSymbolsPerLine)) | |
1672 | return false; | |
1673 | ||
1674 | // | |
1675 | // Clamp the low side | |
1676 | // | |
1677 | if (waterMark < watermarkMinimum) | |
1678 | waterMark = watermarkMinimum; | |
1679 | ||
1680 | //Bits to send BS/BE/Extra symbols due to pixel padding | |
1681 | //Also accounts for enhanced framing. | |
1682 | BlankingBits = 3*8*numLanesPerLink + (enhancedFraming ? 3*8*numLanesPerLink : 0); | |
1683 | ||
1684 | //VBID/MVID/MAUD sent 4 times all the time | |
1685 | BlankingBits += 3*8*4; | |
1686 | ||
1687 | surfaceWidthPerLink = surfaceWidth; | |
1688 | ||
1689 | //Extra bits sent due to pixel steering | |
7e6bd640 DA |
1690 | u32 remain; |
1691 | div_u64_rem(surfaceWidthPerLink, numLanesPerLink, &remain); | |
1692 | PixelSteeringBits = remain ? div_u64((numLanesPerLink - remain) * depth, DSC_FACTOR) : 0; | |
9e994444 BS |
1693 | |
1694 | BlankingBits += PixelSteeringBits; | |
7e6bd640 DA |
1695 | NumBlankingLinkClocks = div_u64((u64)BlankingBits * PrecisionFactor, (8 * numLanesPerLink)); |
1696 | MinHBlank = (u32)(div_u64(div_u64(NumBlankingLinkClocks * pixelClockHz, minRate), PrecisionFactor)); | |
9e994444 BS |
1697 | MinHBlank += 12; |
1698 | ||
1699 | if (WARN_ON(MinHBlank > rasterWidth - surfaceWidth)) | |
1700 | return false; | |
1701 | ||
1702 | // Bug 702290 - Active Width should be greater than 60 | |
1703 | if (WARN_ON(surfaceWidth <= 60)) | |
1704 | return false; | |
1705 | ||
1706 | ||
7e6bd640 | 1707 | hblank_symbols = (s32)(div_u64((u64)(rasterWidth - surfaceWidth - MinHBlank) * minRate, pixelClockHz)); |
9e994444 BS |
1708 | |
1709 | //reduce HBlank Symbols to account for secondary data packet | |
1710 | hblank_symbols -= 1; //Stuffer latency to send BS | |
1711 | hblank_symbols -= 3; //SPKT latency to send data to stuffer | |
1712 | ||
1713 | hblank_symbols -= numLanesPerLink == 1 ? 9 : numLanesPerLink == 2 ? 6 : 3; | |
1714 | ||
1715 | hBlankSym = (hblank_symbols < 0) ? 0 : hblank_symbols; | |
1716 | ||
1717 | // Refer to dev_disp.ref for more information. | |
1718 | // # symbols/vblank = ((SetRasterBlankEnd.X + SetRasterSize.Width - SetRasterBlankStart.X - 40) * link_clk / pclk) - Y - 1; | |
1719 | // where Y = (# lanes == 4) 12 : (# lanes == 2) ? 21 : 39 | |
1720 | if (surfaceWidth < 40) | |
1721 | { | |
1722 | vblank_symbols = 0; | |
1723 | } | |
1724 | else | |
1725 | { | |
7e6bd640 | 1726 | vblank_symbols = (s32)((div_u64((u64)(surfaceWidth - 40) * minRate, pixelClockHz))) - 1; |
9e994444 BS |
1727 | |
1728 | vblank_symbols -= numLanesPerLink == 1 ? 39 : numLanesPerLink == 2 ? 21 : 12; | |
1729 | } | |
1730 | ||
1731 | vBlankSym = (vblank_symbols < 0) ? 0 : vblank_symbols; | |
1732 | ||
1733 | return nvif_outp_dp_sst(&outp->outp, head->base.index, waterMark, hBlankSym, vBlankSym); | |
1734 | } | |
1735 | ||
83fc083c | 1736 | static void |
fa9f9489 | 1737 | nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) |
83fc083c | 1738 | { |
a3761fa2 | 1739 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
1b38cf6b LP |
1740 | struct nouveau_crtc *nv_crtc = nv50_outp_get_new_crtc(state, nv_encoder); |
1741 | struct nv50_head_atom *asyh = | |
1742 | nv50_head_atom(drm_atomic_get_new_crtc_state(state, &nv_crtc->base)); | |
2ca7fb5c | 1743 | struct drm_display_mode *mode = &asyh->state.adjusted_mode; |
e225f446 | 1744 | struct nv50_disp *disp = nv50_disp(encoder->dev); |
1958d69f | 1745 | struct nv50_head *head = nv50_head(&nv_crtc->base); |
f530bc60 | 1746 | struct nvif_outp *outp = &nv_encoder->outp; |
78951d22 | 1747 | struct drm_device *dev = encoder->dev; |
77145f1c | 1748 | struct nouveau_drm *drm = nouveau_drm(dev); |
3b6d83d1 | 1749 | struct nouveau_connector *nv_connector; |
6eca310e LP |
1750 | #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT |
1751 | struct nouveau_backlight *backlight; | |
1752 | #endif | |
77145f1c | 1753 | struct nvbios *bios = &drm->vbios; |
9793083f | 1754 | bool lvds_dual = false, lvds_8bpc = false, hda = false; |
344c2e5a BS |
1755 | u8 proto = NV507D_SOR_SET_CONTROL_PROTOCOL_CUSTOM; |
1756 | u8 depth = NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_DEFAULT; | |
83fc083c | 1757 | |
cd5609f7 | 1758 | nv_connector = nv50_outp_get_new_connector(state, nv_encoder); |
1b38cf6b | 1759 | nv_encoder->crtc = &nv_crtc->base; |
6f8dbcf1 BS |
1760 | |
1761 | if ((disp->disp->object.oclass == GT214_DISP || | |
1762 | disp->disp->object.oclass >= GF110_DISP) && | |
cefc3c14 | 1763 | nv_encoder->dcb->type != DCB_OUTPUT_LVDS && |
444f396c | 1764 | nv_connector->base.display_info.has_audio) |
6f8dbcf1 | 1765 | hda = true; |
e84a35a8 | 1766 | |
cefc3c14 BS |
1767 | if (!nvif_outp_acquired(outp)) |
1768 | nvif_outp_acquire_sor(outp, hda); | |
1769 | ||
3b6d83d1 | 1770 | switch (nv_encoder->dcb->type) { |
cb75d97e | 1771 | case DCB_OUTPUT_TMDS: |
cefc3c14 | 1772 | if (disp->disp->object.oclass != NV50_DISP && |
444f396c | 1773 | nv_connector->base.display_info.is_hdmi) |
f530bc60 BS |
1774 | nv50_hdmi_enable(encoder, nv_crtc, nv_connector, state, mode, hda); |
1775 | ||
ea6143a8 | 1776 | if (nv_encoder->outp.or.link & 1) { |
344c2e5a | 1777 | proto = NV507D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_A; |
16ef53a9 HM |
1778 | /* Only enable dual-link if: |
1779 | * - Need to (i.e. rate > 165MHz) | |
1780 | * - DCB says we can | |
1781 | * - Not an HDMI monitor, since there's no dual-link | |
1782 | * on HDMI. | |
1783 | */ | |
1784 | if (mode->clock >= 165000 && | |
1785 | nv_encoder->dcb->duallink_possible && | |
444f396c | 1786 | !nv_connector->base.display_info.is_hdmi) |
344c2e5a | 1787 | proto = NV507D_SOR_SET_CONTROL_PROTOCOL_DUAL_TMDS; |
3b6d83d1 | 1788 | } else { |
344c2e5a | 1789 | proto = NV507D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_B; |
3b6d83d1 | 1790 | } |
3b6d83d1 | 1791 | break; |
cb75d97e | 1792 | case DCB_OUTPUT_LVDS: |
344c2e5a | 1793 | proto = NV507D_SOR_SET_CONTROL_PROTOCOL_LVDS_CUSTOM; |
419e8dc0 | 1794 | |
3b6d83d1 | 1795 | if (bios->fp_no_ddc) { |
9793083f BS |
1796 | lvds_dual = bios->fp.dual_link; |
1797 | lvds_8bpc = bios->fp.if_is_24bit; | |
3b6d83d1 | 1798 | } else { |
befb51e9 | 1799 | if (nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) { |
3b6d83d1 | 1800 | if (((u8 *)nv_connector->edid)[121] == 2) |
9793083f | 1801 | lvds_dual = true; |
3b6d83d1 BS |
1802 | } else |
1803 | if (mode->clock >= bios->fp.duallink_transition_clk) { | |
9793083f | 1804 | lvds_dual = true; |
3b6d83d1 | 1805 | } |
83fc083c | 1806 | |
9793083f | 1807 | if (lvds_dual) { |
3b6d83d1 | 1808 | if (bios->fp.strapless_is_24bit & 2) |
9793083f | 1809 | lvds_8bpc = true; |
3b6d83d1 BS |
1810 | } else { |
1811 | if (bios->fp.strapless_is_24bit & 1) | |
9793083f | 1812 | lvds_8bpc = true; |
3b6d83d1 BS |
1813 | } |
1814 | ||
ac2d9275 | 1815 | if (asyh->or.bpc == 8) |
9793083f | 1816 | lvds_8bpc = true; |
3b6d83d1 | 1817 | } |
4a230fa6 | 1818 | |
5b9c0307 | 1819 | nvif_outp_lvds(&nv_encoder->outp, lvds_dual, lvds_8bpc); |
3b6d83d1 | 1820 | break; |
cb75d97e | 1821 | case DCB_OUTPUT_DP: |
63371650 | 1822 | nouveau_dp_train(nv_encoder, false, mode->clock, asyh->or.bpc); |
9e994444 | 1823 | nv50_sor_dp_watermark_sst(nv_encoder, head, asyh); |
ac2d9275 | 1824 | depth = nv50_dp_bpc_to_depth(asyh->or.bpc); |
6e83fda2 | 1825 | |
ea6143a8 | 1826 | if (nv_encoder->outp.or.link & 1) |
344c2e5a | 1827 | proto = NV887D_SOR_SET_CONTROL_PROTOCOL_DP_A; |
6e83fda2 | 1828 | else |
344c2e5a | 1829 | proto = NV887D_SOR_SET_CONTROL_PROTOCOL_DP_B; |
f20c665c | 1830 | |
6eca310e LP |
1831 | #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT |
1832 | backlight = nv_connector->backlight; | |
1833 | if (backlight && backlight->uses_dpcd) | |
1834 | drm_edp_backlight_enable(&nv_connector->aux, &backlight->edp_info, | |
1835 | (u16)backlight->dev->props.brightness); | |
1836 | #endif | |
1837 | ||
6e83fda2 | 1838 | break; |
3b6d83d1 | 1839 | default: |
af7db03e | 1840 | BUG(); |
3b6d83d1 BS |
1841 | break; |
1842 | } | |
ff8ff503 | 1843 | |
1958d69f | 1844 | if (head->func->display_id) |
0a4410a7 | 1845 | head->func->display_id(head, BIT(nv_encoder->outp.id)); |
1958d69f | 1846 | |
2ca7fb5c | 1847 | nv_encoder->update(nv_encoder, nv_crtc->index, asyh, proto, depth); |
83fc083c BS |
1848 | } |
1849 | ||
f20c665c BS |
1850 | static const struct drm_encoder_helper_funcs |
1851 | nv50_sor_help = { | |
839ca903 | 1852 | .atomic_check = nv50_outp_atomic_check, |
fa9f9489 LP |
1853 | .atomic_enable = nv50_sor_atomic_enable, |
1854 | .atomic_disable = nv50_sor_atomic_disable, | |
f20c665c BS |
1855 | }; |
1856 | ||
83fc083c | 1857 | static void |
e225f446 | 1858 | nv50_sor_destroy(struct drm_encoder *encoder) |
83fc083c | 1859 | { |
52aa30f2 | 1860 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
1b255f1c | 1861 | |
52aa30f2 | 1862 | nv50_mstm_del(&nv_encoder->dp.mstm); |
83fc083c | 1863 | drm_encoder_cleanup(encoder); |
a0922278 LP |
1864 | |
1865 | if (nv_encoder->dcb->type == DCB_OUTPUT_DP) | |
1866 | mutex_destroy(&nv_encoder->dp.hpd_irq_lock); | |
1867 | ||
bd7a61bc | 1868 | nvif_outp_dtor(&nv_encoder->outp); |
83fc083c BS |
1869 | kfree(encoder); |
1870 | } | |
1871 | ||
f20c665c BS |
1872 | static const struct drm_encoder_funcs |
1873 | nv50_sor_func = { | |
e225f446 | 1874 | .destroy = nv50_sor_destroy, |
83fc083c BS |
1875 | }; |
1876 | ||
1877 | static int | |
e32de3da | 1878 | nv50_sor_create(struct nouveau_encoder *nv_encoder) |
83fc083c | 1879 | { |
e32de3da | 1880 | struct drm_connector *connector = &nv_encoder->conn->base; |
52aa30f2 | 1881 | struct nouveau_connector *nv_connector = nouveau_connector(connector); |
5ed50209 | 1882 | struct nouveau_drm *drm = nouveau_drm(connector->dev); |
6901f1d6 | 1883 | struct nvkm_i2c *i2c = nvxx_i2c(drm); |
83fc083c | 1884 | struct drm_encoder *encoder; |
e32de3da | 1885 | struct dcb_output *dcbe = nv_encoder->dcb; |
4a2cb418 | 1886 | struct nv50_disp *disp = nv50_disp(connector->dev); |
52aa30f2 | 1887 | int type, ret; |
5ed50209 BS |
1888 | |
1889 | switch (dcbe->type) { | |
1890 | case DCB_OUTPUT_LVDS: type = DRM_MODE_ENCODER_LVDS; break; | |
1891 | case DCB_OUTPUT_TMDS: | |
1892 | case DCB_OUTPUT_DP: | |
1893 | default: | |
1894 | type = DRM_MODE_ENCODER_TMDS; | |
1895 | break; | |
1896 | } | |
83fc083c | 1897 | |
d665c7e9 | 1898 | nv_encoder->update = nv50_sor_update; |
83fc083c | 1899 | |
52aa30f2 | 1900 | encoder = to_drm_encoder(nv_encoder); |
5a223dac BS |
1901 | drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type, |
1902 | "sor-%04x-%04x", dcbe->hasht, dcbe->hashm); | |
f20c665c | 1903 | drm_encoder_helper_add(encoder, &nv50_sor_help); |
52aa30f2 | 1904 | |
cde4c44d | 1905 | drm_connector_attach_encoder(connector, encoder); |
52aa30f2 | 1906 | |
4a2cb418 | 1907 | disp->core->func->sor->get_caps(disp, nv_encoder, ffs(dcbe->or) - 1); |
36dc1777 | 1908 | nv50_outp_dump_caps(drm, nv_encoder); |
4a2cb418 | 1909 | |
2aa5eac5 | 1910 | if (dcbe->type == DCB_OUTPUT_DP) { |
a0922278 LP |
1911 | mutex_init(&nv_encoder->dp.hpd_irq_lock); |
1912 | ||
bd7a61bc BS |
1913 | if (disp->disp->object.oclass < GF110_DISP) { |
1914 | /* HW has no support for address-only | |
1915 | * transactions, so we're required to | |
1916 | * use custom I2C-over-AUX code. | |
1917 | */ | |
1918 | struct nvkm_i2c_aux *aux; | |
1919 | ||
1920 | aux = nvkm_i2c_aux_find(i2c, dcbe->i2c_index); | |
1921 | if (!aux) | |
1922 | return -EINVAL; | |
1923 | ||
1924 | nv_encoder->i2c = &aux->i2c; | |
1925 | } else { | |
1926 | nv_encoder->i2c = &nv_connector->aux.ddc; | |
2aa5eac5 | 1927 | } |
52aa30f2 | 1928 | |
0a4410a7 | 1929 | if (nv_connector->type != DCB_CONNECTOR_eDP && nv_encoder->outp.info.dp.mst) { |
5ff0cb1c LP |
1930 | ret = nv50_mstm_new(nv_encoder, &nv_connector->aux, |
1931 | 16, nv_connector->base.base.id, | |
52aa30f2 BS |
1932 | &nv_encoder->dp.mstm); |
1933 | if (ret) | |
1934 | return ret; | |
1935 | } | |
0a4410a7 BS |
1936 | } else |
1937 | if (nv_encoder->outp.info.ddc != NVIF_OUTP_DDC_INVALID) { | |
2aa5eac5 BS |
1938 | struct nvkm_i2c_bus *bus = |
1939 | nvkm_i2c_bus_find(i2c, dcbe->i2c_index); | |
1940 | if (bus) | |
1941 | nv_encoder->i2c = &bus->i2c; | |
1942 | } | |
1943 | ||
e32de3da | 1944 | return 0; |
83fc083c | 1945 | } |
26f6d88b | 1946 | |
eb6313ad BS |
1947 | /****************************************************************************** |
1948 | * PIOR | |
1949 | *****************************************************************************/ | |
839ca903 BS |
1950 | static int |
1951 | nv50_pior_atomic_check(struct drm_encoder *encoder, | |
1952 | struct drm_crtc_state *crtc_state, | |
1953 | struct drm_connector_state *conn_state) | |
eb6313ad | 1954 | { |
839ca903 BS |
1955 | int ret = nv50_outp_atomic_check(encoder, crtc_state, conn_state); |
1956 | if (ret) | |
1957 | return ret; | |
1958 | crtc_state->adjusted_mode.clock *= 2; | |
1959 | return 0; | |
eb6313ad BS |
1960 | } |
1961 | ||
1962 | static void | |
fa9f9489 | 1963 | nv50_pior_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) |
eb6313ad | 1964 | { |
f20c665c | 1965 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
0a368771 | 1966 | struct nv50_core *core = nv50_disp(encoder->dev)->core; |
344c2e5a | 1967 | const u32 ctrl = NVDEF(NV507D, PIOR_SET_CONTROL, OWNER, NONE); |
f575f2bd | 1968 | |
ea6143a8 | 1969 | core->func->pior->ctrl(core, nv_encoder->outp.or.id, ctrl, NULL); |
f20c665c | 1970 | nv_encoder->crtc = NULL; |
eb6313ad BS |
1971 | } |
1972 | ||
1973 | static void | |
fa9f9489 | 1974 | nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) |
eb6313ad | 1975 | { |
eb6313ad | 1976 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
1b38cf6b LP |
1977 | struct nouveau_crtc *nv_crtc = nv50_outp_get_new_crtc(state, nv_encoder); |
1978 | struct nv50_head_atom *asyh = | |
1979 | nv50_head_atom(drm_atomic_get_new_crtc_state(state, &nv_crtc->base)); | |
0a368771 | 1980 | struct nv50_core *core = nv50_disp(encoder->dev)->core; |
344c2e5a BS |
1981 | u32 ctrl = 0; |
1982 | ||
1983 | switch (nv_crtc->index) { | |
1984 | case 0: ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, OWNER, HEAD0); break; | |
1985 | case 1: ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, OWNER, HEAD1); break; | |
1986 | default: | |
1987 | WARN_ON(1); | |
1988 | break; | |
1989 | } | |
eb6313ad | 1990 | |
ac2d9275 | 1991 | switch (asyh->or.bpc) { |
344c2e5a BS |
1992 | case 10: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_BPP_30_444; break; |
1993 | case 8: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_BPP_24_444; break; | |
1994 | case 6: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_BPP_18_444; break; | |
1995 | default: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_DEFAULT; break; | |
eb6313ad BS |
1996 | } |
1997 | ||
cefc3c14 BS |
1998 | if (!nvif_outp_acquired(&nv_encoder->outp)) |
1999 | nvif_outp_acquire_pior(&nv_encoder->outp); | |
2000 | ||
eb6313ad BS |
2001 | switch (nv_encoder->dcb->type) { |
2002 | case DCB_OUTPUT_TMDS: | |
ea6143a8 | 2003 | ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC); |
ea6143a8 | 2004 | break; |
eb6313ad | 2005 | case DCB_OUTPUT_DP: |
344c2e5a | 2006 | ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC); |
63371650 | 2007 | nouveau_dp_train(nv_encoder, false, asyh->state.adjusted_mode.clock, 6); |
eb6313ad BS |
2008 | break; |
2009 | default: | |
af7db03e | 2010 | BUG(); |
eb6313ad BS |
2011 | break; |
2012 | } | |
2013 | ||
ea6143a8 | 2014 | core->func->pior->ctrl(core, nv_encoder->outp.or.id, ctrl, asyh); |
5c6fb4b2 | 2015 | nv_encoder->crtc = &nv_crtc->base; |
eb6313ad BS |
2016 | } |
2017 | ||
f20c665c BS |
2018 | static const struct drm_encoder_helper_funcs |
2019 | nv50_pior_help = { | |
839ca903 | 2020 | .atomic_check = nv50_pior_atomic_check, |
fa9f9489 LP |
2021 | .atomic_enable = nv50_pior_atomic_enable, |
2022 | .atomic_disable = nv50_pior_atomic_disable, | |
eb6313ad BS |
2023 | }; |
2024 | ||
f20c665c BS |
2025 | static void |
2026 | nv50_pior_destroy(struct drm_encoder *encoder) | |
2027 | { | |
1b255f1c BS |
2028 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
2029 | ||
2030 | nvif_outp_dtor(&nv_encoder->outp); | |
2031 | ||
f20c665c | 2032 | drm_encoder_cleanup(encoder); |
ea293f82 BS |
2033 | |
2034 | mutex_destroy(&nv_encoder->dp.hpd_irq_lock); | |
f20c665c BS |
2035 | kfree(encoder); |
2036 | } | |
2037 | ||
2038 | static const struct drm_encoder_funcs | |
2039 | nv50_pior_func = { | |
eb6313ad BS |
2040 | .destroy = nv50_pior_destroy, |
2041 | }; | |
2042 | ||
2043 | static int | |
e32de3da | 2044 | nv50_pior_create(struct nouveau_encoder *nv_encoder) |
eb6313ad | 2045 | { |
e32de3da | 2046 | struct drm_connector *connector = &nv_encoder->conn->base; |
4a2cb418 LP |
2047 | struct drm_device *dev = connector->dev; |
2048 | struct nouveau_drm *drm = nouveau_drm(dev); | |
2049 | struct nv50_disp *disp = nv50_disp(dev); | |
6901f1d6 | 2050 | struct nvkm_i2c *i2c = nvxx_i2c(drm); |
2aa5eac5 BS |
2051 | struct nvkm_i2c_bus *bus = NULL; |
2052 | struct nvkm_i2c_aux *aux = NULL; | |
2053 | struct i2c_adapter *ddc; | |
eb6313ad | 2054 | struct drm_encoder *encoder; |
e32de3da | 2055 | struct dcb_output *dcbe = nv_encoder->dcb; |
eb6313ad BS |
2056 | int type; |
2057 | ||
2058 | switch (dcbe->type) { | |
2059 | case DCB_OUTPUT_TMDS: | |
0a4410a7 | 2060 | bus = nvkm_i2c_bus_find(i2c, nv_encoder->outp.info.ddc); |
2aa5eac5 | 2061 | ddc = bus ? &bus->i2c : NULL; |
eb6313ad BS |
2062 | type = DRM_MODE_ENCODER_TMDS; |
2063 | break; | |
2064 | case DCB_OUTPUT_DP: | |
0a4410a7 | 2065 | aux = nvkm_i2c_aux_find(i2c, nv_encoder->outp.info.dp.aux); |
62b290fc | 2066 | ddc = aux ? &aux->i2c : NULL; |
eb6313ad BS |
2067 | type = DRM_MODE_ENCODER_TMDS; |
2068 | break; | |
2069 | default: | |
2070 | return -ENODEV; | |
2071 | } | |
2072 | ||
eb6313ad BS |
2073 | nv_encoder->i2c = ddc; |
2074 | ||
ea293f82 BS |
2075 | mutex_init(&nv_encoder->dp.hpd_irq_lock); |
2076 | ||
eb6313ad | 2077 | encoder = to_drm_encoder(nv_encoder); |
5a223dac BS |
2078 | drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type, |
2079 | "pior-%04x-%04x", dcbe->hasht, dcbe->hashm); | |
f20c665c | 2080 | drm_encoder_helper_add(encoder, &nv50_pior_help); |
eb6313ad | 2081 | |
cde4c44d | 2082 | drm_connector_attach_encoder(connector, encoder); |
4a2cb418 LP |
2083 | |
2084 | disp->core->func->pior->get_caps(disp, nv_encoder, ffs(dcbe->or) - 1); | |
36dc1777 | 2085 | nv50_outp_dump_caps(drm, nv_encoder); |
4a2cb418 | 2086 | |
e32de3da | 2087 | return 0; |
eb6313ad BS |
2088 | } |
2089 | ||
839ca903 BS |
2090 | /****************************************************************************** |
2091 | * Atomic | |
2092 | *****************************************************************************/ | |
2093 | ||
2094 | static void | |
df0c97e2 | 2095 | nv50_disp_atomic_commit_core(struct drm_atomic_state *state, u32 *interlock) |
839ca903 | 2096 | { |
4d07b0bc LP |
2097 | struct drm_dp_mst_topology_mgr *mgr; |
2098 | struct drm_dp_mst_topology_state *mst_state; | |
df0c97e2 | 2099 | struct nouveau_drm *drm = nouveau_drm(state->dev); |
839ca903 | 2100 | struct nv50_disp *disp = nv50_disp(drm->dev); |
c0f7b729 | 2101 | struct nv50_atom *atom = nv50_atom(state); |
09e1b78a | 2102 | struct nv50_core *core = disp->core; |
c0f7b729 | 2103 | struct nv50_outp_atom *outp; |
f479c0ba | 2104 | struct nv50_mstm *mstm; |
4d07b0bc | 2105 | int i; |
839ca903 | 2106 | |
53e0a3e7 | 2107 | NV_ATOMIC(drm, "commit core %08x\n", interlock[NV50_DISP_INTERLOCK_BASE]); |
839ca903 | 2108 | |
4d07b0bc LP |
2109 | for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { |
2110 | mstm = nv50_mstm(mgr); | |
2111 | if (mstm->modified) | |
2112 | nv50_mstm_prepare(state, mst_state, mstm); | |
f479c0ba BS |
2113 | } |
2114 | ||
09e1b78a BS |
2115 | core->func->ntfy_init(disp->sync, NV50_DISP_CORE_NTFY); |
2116 | core->func->update(core, interlock, true); | |
2117 | if (core->func->ntfy_wait_done(disp->sync, NV50_DISP_CORE_NTFY, | |
2118 | disp->core->chan.base.device)) | |
2119 | NV_ERROR(drm, "core notifier timeout\n"); | |
f479c0ba | 2120 | |
4d07b0bc LP |
2121 | for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { |
2122 | mstm = nv50_mstm(mgr); | |
2123 | if (mstm->modified) | |
2124 | nv50_mstm_cleanup(state, mst_state, mstm); | |
f479c0ba | 2125 | } |
c0f7b729 BS |
2126 | |
2127 | list_for_each_entry(outp, &atom->outp, head) { | |
2128 | if (outp->encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { | |
2129 | struct nouveau_encoder *nv_encoder = nouveau_encoder(outp->encoder); | |
2130 | ||
2131 | if (outp->enabled) { | |
2132 | nv50_audio_enable(outp->encoder, nouveau_crtc(nv_encoder->crtc), | |
2133 | nv_encoder->conn, NULL, NULL); | |
2134 | outp->enabled = outp->disabled = false; | |
2135 | } else { | |
b24bf8b8 BS |
2136 | if (outp->disabled) { |
2137 | nvif_outp_release(&nv_encoder->outp); | |
c0f7b729 | 2138 | outp->disabled = false; |
b24bf8b8 | 2139 | } |
c0f7b729 BS |
2140 | } |
2141 | } | |
2142 | } | |
839ca903 BS |
2143 | } |
2144 | ||
df0c97e2 BS |
2145 | static void |
2146 | nv50_disp_atomic_commit_wndw(struct drm_atomic_state *state, u32 *interlock) | |
2147 | { | |
2148 | struct drm_plane_state *new_plane_state; | |
2149 | struct drm_plane *plane; | |
2150 | int i; | |
2151 | ||
2152 | for_each_new_plane_in_state(state, plane, new_plane_state, i) { | |
2153 | struct nv50_wndw *wndw = nv50_wndw(plane); | |
2154 | if (interlock[wndw->interlock.type] & wndw->interlock.data) { | |
2155 | if (wndw->func->update) | |
2156 | wndw->func->update(wndw, interlock); | |
2157 | } | |
2158 | } | |
2159 | } | |
2160 | ||
839ca903 BS |
2161 | static void |
2162 | nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) | |
2163 | { | |
2164 | struct drm_device *dev = state->dev; | |
efa47935 | 2165 | struct drm_crtc_state *new_crtc_state, *old_crtc_state; |
839ca903 | 2166 | struct drm_crtc *crtc; |
3c847d6c | 2167 | struct drm_plane_state *new_plane_state; |
839ca903 BS |
2168 | struct drm_plane *plane; |
2169 | struct nouveau_drm *drm = nouveau_drm(dev); | |
2170 | struct nv50_disp *disp = nv50_disp(dev); | |
2171 | struct nv50_atom *atom = nv50_atom(state); | |
5bb88d07 | 2172 | struct nv50_core *core = disp->core; |
839ca903 | 2173 | struct nv50_outp_atom *outp, *outt; |
53e0a3e7 | 2174 | u32 interlock[NV50_DISP_INTERLOCK__SIZE] = {}; |
839ca903 | 2175 | int i; |
2d786508 | 2176 | bool flushed = false; |
839ca903 BS |
2177 | |
2178 | NV_ATOMIC(drm, "commit %d %d\n", atom->lock_core, atom->flush_disable); | |
12885ecb | 2179 | nv50_crc_atomic_stop_reporting(state); |
839ca903 BS |
2180 | drm_atomic_helper_wait_for_fences(dev, state, false); |
2181 | drm_atomic_helper_wait_for_dependencies(state); | |
a5c2c0d1 | 2182 | drm_dp_mst_atomic_wait_for_dependencies(state); |
839ca903 | 2183 | drm_atomic_helper_update_legacy_modeset_state(dev, state); |
441959eb | 2184 | drm_atomic_helper_calc_timestamping_constants(state); |
839ca903 BS |
2185 | |
2186 | if (atom->lock_core) | |
2187 | mutex_lock(&disp->mutex); | |
2188 | ||
2189 | /* Disable head(s). */ | |
efa47935 | 2190 | for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { |
3c847d6c | 2191 | struct nv50_head_atom *asyh = nv50_head_atom(new_crtc_state); |
839ca903 BS |
2192 | struct nv50_head *head = nv50_head(crtc); |
2193 | ||
2194 | NV_ATOMIC(drm, "%s: clr %04x (set %04x)\n", crtc->name, | |
2195 | asyh->clr.mask, asyh->set.mask); | |
ed22eb56 LP |
2196 | |
2197 | if (old_crtc_state->active && !new_crtc_state->active) { | |
2198 | pm_runtime_put_noidle(dev->dev); | |
4a5431af | 2199 | drm_crtc_vblank_off(crtc); |
ed22eb56 | 2200 | } |
839ca903 BS |
2201 | |
2202 | if (asyh->clr.mask) { | |
2203 | nv50_head_flush_clr(head, asyh, atom->flush_disable); | |
53e0a3e7 | 2204 | interlock[NV50_DISP_INTERLOCK_CORE] |= 1; |
839ca903 BS |
2205 | } |
2206 | } | |
2207 | ||
2208 | /* Disable plane(s). */ | |
3c847d6c ML |
2209 | for_each_new_plane_in_state(state, plane, new_plane_state, i) { |
2210 | struct nv50_wndw_atom *asyw = nv50_wndw_atom(new_plane_state); | |
839ca903 BS |
2211 | struct nv50_wndw *wndw = nv50_wndw(plane); |
2212 | ||
2213 | NV_ATOMIC(drm, "%s: clr %02x (set %02x)\n", plane->name, | |
2214 | asyw->clr.mask, asyw->set.mask); | |
2215 | if (!asyw->clr.mask) | |
2216 | continue; | |
2217 | ||
53e0a3e7 | 2218 | nv50_wndw_flush_clr(wndw, interlock, atom->flush_disable, asyw); |
839ca903 BS |
2219 | } |
2220 | ||
2221 | /* Disable output path(s). */ | |
2222 | list_for_each_entry(outp, &atom->outp, head) { | |
2223 | const struct drm_encoder_helper_funcs *help; | |
2224 | struct drm_encoder *encoder; | |
2225 | ||
2226 | encoder = outp->encoder; | |
2227 | help = encoder->helper_private; | |
2228 | ||
2229 | NV_ATOMIC(drm, "%s: clr %02x (set %02x)\n", encoder->name, | |
2230 | outp->clr.mask, outp->set.mask); | |
2231 | ||
2232 | if (outp->clr.mask) { | |
09838c4e | 2233 | help->atomic_disable(encoder, state); |
c0f7b729 | 2234 | outp->disabled = true; |
53e0a3e7 | 2235 | interlock[NV50_DISP_INTERLOCK_CORE] |= 1; |
839ca903 BS |
2236 | } |
2237 | } | |
2238 | ||
2239 | /* Flush disable. */ | |
53e0a3e7 | 2240 | if (interlock[NV50_DISP_INTERLOCK_CORE]) { |
839ca903 | 2241 | if (atom->flush_disable) { |
df0c97e2 BS |
2242 | nv50_disp_atomic_commit_wndw(state, interlock); |
2243 | nv50_disp_atomic_commit_core(state, interlock); | |
53e0a3e7 | 2244 | memset(interlock, 0x00, sizeof(interlock)); |
2d786508 LP |
2245 | |
2246 | flushed = true; | |
839ca903 BS |
2247 | } |
2248 | } | |
2249 | ||
2d786508 LP |
2250 | if (flushed) |
2251 | nv50_crc_atomic_release_notifier_contexts(state); | |
2252 | nv50_crc_atomic_init_notifier_contexts(state); | |
12885ecb | 2253 | |
839ca903 | 2254 | /* Update output path(s). */ |
232856e8 | 2255 | list_for_each_entry(outp, &atom->outp, head) { |
839ca903 BS |
2256 | const struct drm_encoder_helper_funcs *help; |
2257 | struct drm_encoder *encoder; | |
2258 | ||
2259 | encoder = outp->encoder; | |
2260 | help = encoder->helper_private; | |
2261 | ||
2262 | NV_ATOMIC(drm, "%s: set %02x (clr %02x)\n", encoder->name, | |
2263 | outp->set.mask, outp->clr.mask); | |
2264 | ||
2265 | if (outp->set.mask) { | |
09838c4e | 2266 | help->atomic_enable(encoder, state); |
c0f7b729 | 2267 | outp->enabled = true; |
53e0a3e7 | 2268 | interlock[NV50_DISP_INTERLOCK_CORE] = 1; |
839ca903 | 2269 | } |
839ca903 BS |
2270 | } |
2271 | ||
2272 | /* Update head(s). */ | |
efa47935 | 2273 | for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { |
3c847d6c | 2274 | struct nv50_head_atom *asyh = nv50_head_atom(new_crtc_state); |
839ca903 BS |
2275 | struct nv50_head *head = nv50_head(crtc); |
2276 | ||
2277 | NV_ATOMIC(drm, "%s: set %04x (clr %04x)\n", crtc->name, | |
2278 | asyh->set.mask, asyh->clr.mask); | |
2279 | ||
2280 | if (asyh->set.mask) { | |
2281 | nv50_head_flush_set(head, asyh); | |
53e0a3e7 | 2282 | interlock[NV50_DISP_INTERLOCK_CORE] = 1; |
839ca903 | 2283 | } |
839ca903 | 2284 | |
efa47935 | 2285 | if (new_crtc_state->active) { |
ed22eb56 | 2286 | if (!old_crtc_state->active) { |
4a5431af | 2287 | drm_crtc_vblank_on(crtc); |
ed22eb56 LP |
2288 | pm_runtime_get_noresume(dev->dev); |
2289 | } | |
efa47935 | 2290 | if (new_crtc_state->event) |
4a5431af BS |
2291 | drm_crtc_vblank_get(crtc); |
2292 | } | |
2b507893 BS |
2293 | } |
2294 | ||
5bb88d07 BS |
2295 | /* Update window->head assignment. |
2296 | * | |
2297 | * This has to happen in an update that's not interlocked with | |
2298 | * any window channels to avoid hitting HW error checks. | |
2299 | * | |
2300 | *TODO: Proper handling of window ownership (Turing apparently | |
2301 | * supports non-fixed mappings). | |
2302 | */ | |
2303 | if (core->assign_windows) { | |
2304 | core->func->wndw.owner(core); | |
705d9d02 | 2305 | nv50_disp_atomic_commit_core(state, interlock); |
5bb88d07 BS |
2306 | core->assign_windows = false; |
2307 | interlock[NV50_DISP_INTERLOCK_CORE] = 0; | |
2308 | } | |
2309 | ||
e78b1b54 BS |
2310 | /* Finish updating head(s)... |
2311 | * | |
2312 | * NVD is rather picky about both where window assignments can change, | |
2313 | * *and* about certain core and window channel states matching. | |
2314 | * | |
2315 | * The EFI GOP driver on newer GPUs configures window channels with a | |
2316 | * different output format to what we do, and the core channel update | |
2317 | * in the assign_windows case above would result in a state mismatch. | |
2318 | * | |
2319 | * Delay some of the head update until after that point to workaround | |
2320 | * the issue. This only affects the initial modeset. | |
2321 | * | |
2322 | * TODO: handle this better when adding flexible window mapping | |
2323 | */ | |
2324 | for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { | |
2325 | struct nv50_head_atom *asyh = nv50_head_atom(new_crtc_state); | |
2326 | struct nv50_head *head = nv50_head(crtc); | |
2327 | ||
2328 | NV_ATOMIC(drm, "%s: set %04x (clr %04x)\n", crtc->name, | |
2329 | asyh->set.mask, asyh->clr.mask); | |
2330 | ||
2331 | if (asyh->set.mask) { | |
2332 | nv50_head_flush_set_wndw(head, asyh); | |
2333 | interlock[NV50_DISP_INTERLOCK_CORE] = 1; | |
2334 | } | |
2335 | } | |
2336 | ||
839ca903 | 2337 | /* Update plane(s). */ |
3c847d6c ML |
2338 | for_each_new_plane_in_state(state, plane, new_plane_state, i) { |
2339 | struct nv50_wndw_atom *asyw = nv50_wndw_atom(new_plane_state); | |
839ca903 BS |
2340 | struct nv50_wndw *wndw = nv50_wndw(plane); |
2341 | ||
2342 | NV_ATOMIC(drm, "%s: set %02x (clr %02x)\n", plane->name, | |
2343 | asyw->set.mask, asyw->clr.mask); | |
2344 | if ( !asyw->set.mask && | |
2345 | (!asyw->clr.mask || atom->flush_disable)) | |
2346 | continue; | |
2347 | ||
53e0a3e7 | 2348 | nv50_wndw_flush_set(wndw, interlock, asyw); |
839ca903 BS |
2349 | } |
2350 | ||
2351 | /* Flush update. */ | |
df0c97e2 | 2352 | nv50_disp_atomic_commit_wndw(state, interlock); |
04fc14be | 2353 | |
53e0a3e7 BS |
2354 | if (interlock[NV50_DISP_INTERLOCK_CORE]) { |
2355 | if (interlock[NV50_DISP_INTERLOCK_BASE] || | |
df0c97e2 BS |
2356 | interlock[NV50_DISP_INTERLOCK_OVLY] || |
2357 | interlock[NV50_DISP_INTERLOCK_WNDW] || | |
53e0a3e7 | 2358 | !atom->state.legacy_cursor_update) |
df0c97e2 | 2359 | nv50_disp_atomic_commit_core(state, interlock); |
09e1b78a | 2360 | else |
53e0a3e7 | 2361 | disp->core->func->update(disp->core, interlock, false); |
839ca903 BS |
2362 | } |
2363 | ||
2364 | if (atom->lock_core) | |
2365 | mutex_unlock(&disp->mutex); | |
2366 | ||
232856e8 BS |
2367 | list_for_each_entry_safe(outp, outt, &atom->outp, head) { |
2368 | list_del(&outp->head); | |
2369 | kfree(outp); | |
2370 | } | |
2371 | ||
839ca903 | 2372 | /* Wait for HW to signal completion. */ |
3c847d6c ML |
2373 | for_each_new_plane_in_state(state, plane, new_plane_state, i) { |
2374 | struct nv50_wndw_atom *asyw = nv50_wndw_atom(new_plane_state); | |
839ca903 BS |
2375 | struct nv50_wndw *wndw = nv50_wndw(plane); |
2376 | int ret = nv50_wndw_wait_armed(wndw, asyw); | |
2377 | if (ret) | |
2378 | NV_ERROR(drm, "%s: timeout\n", plane->name); | |
2379 | } | |
2380 | ||
3c847d6c ML |
2381 | for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { |
2382 | if (new_crtc_state->event) { | |
839ca903 | 2383 | unsigned long flags; |
bd9f6605 | 2384 | /* Get correct count/ts if racing with vblank irq */ |
efa47935 | 2385 | if (new_crtc_state->active) |
0c697faf | 2386 | drm_crtc_accurate_vblank_count(crtc); |
839ca903 | 2387 | spin_lock_irqsave(&crtc->dev->event_lock, flags); |
3c847d6c | 2388 | drm_crtc_send_vblank_event(crtc, new_crtc_state->event); |
839ca903 | 2389 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); |
efa47935 | 2390 | |
3c847d6c | 2391 | new_crtc_state->event = NULL; |
efa47935 | 2392 | if (new_crtc_state->active) |
4a5431af | 2393 | drm_crtc_vblank_put(crtc); |
839ca903 BS |
2394 | } |
2395 | } | |
2396 | ||
12885ecb | 2397 | nv50_crc_atomic_start_reporting(state); |
2d786508 LP |
2398 | if (!flushed) |
2399 | nv50_crc_atomic_release_notifier_contexts(state); | |
6eca310e | 2400 | |
839ca903 BS |
2401 | drm_atomic_helper_commit_hw_done(state); |
2402 | drm_atomic_helper_cleanup_planes(dev, state); | |
2403 | drm_atomic_helper_commit_cleanup_done(state); | |
2404 | drm_atomic_state_put(state); | |
ed22eb56 LP |
2405 | |
2406 | /* Drop the RPM ref we got from nv50_disp_atomic_commit() */ | |
2407 | pm_runtime_mark_last_busy(dev->dev); | |
2408 | pm_runtime_put_autosuspend(dev->dev); | |
839ca903 BS |
2409 | } |
2410 | ||
2411 | static void | |
2412 | nv50_disp_atomic_commit_work(struct work_struct *work) | |
2413 | { | |
2414 | struct drm_atomic_state *state = | |
2415 | container_of(work, typeof(*state), commit_work); | |
2416 | nv50_disp_atomic_commit_tail(state); | |
2417 | } | |
2418 | ||
2419 | static int | |
2420 | nv50_disp_atomic_commit(struct drm_device *dev, | |
2421 | struct drm_atomic_state *state, bool nonblock) | |
2422 | { | |
d324c5bc | 2423 | struct drm_plane_state *new_plane_state; |
839ca903 | 2424 | struct drm_plane *plane; |
839ca903 BS |
2425 | int ret, i; |
2426 | ||
2427 | ret = pm_runtime_get_sync(dev->dev); | |
a2cdf395 AP |
2428 | if (ret < 0 && ret != -EACCES) { |
2429 | pm_runtime_put_autosuspend(dev->dev); | |
839ca903 | 2430 | return ret; |
a2cdf395 | 2431 | } |
839ca903 BS |
2432 | |
2433 | ret = drm_atomic_helper_setup_commit(state, nonblock); | |
2434 | if (ret) | |
2435 | goto done; | |
2436 | ||
2437 | INIT_WORK(&state->commit_work, nv50_disp_atomic_commit_work); | |
2438 | ||
2439 | ret = drm_atomic_helper_prepare_planes(dev, state); | |
2440 | if (ret) | |
2441 | goto done; | |
2442 | ||
2443 | if (!nonblock) { | |
2444 | ret = drm_atomic_helper_wait_for_fences(dev, state, true); | |
2445 | if (ret) | |
813a7e16 | 2446 | goto err_cleanup; |
839ca903 BS |
2447 | } |
2448 | ||
8572636e ML |
2449 | ret = drm_atomic_helper_swap_state(state, true); |
2450 | if (ret) | |
2451 | goto err_cleanup; | |
2452 | ||
d324c5bc BS |
2453 | for_each_new_plane_in_state(state, plane, new_plane_state, i) { |
2454 | struct nv50_wndw_atom *asyw = nv50_wndw_atom(new_plane_state); | |
839ca903 | 2455 | struct nv50_wndw *wndw = nv50_wndw(plane); |
3c847d6c | 2456 | |
ccd27db8 BS |
2457 | if (asyw->set.image) |
2458 | nv50_wndw_ntfy_enable(wndw, asyw); | |
839ca903 BS |
2459 | } |
2460 | ||
839ca903 BS |
2461 | drm_atomic_state_get(state); |
2462 | ||
ed22eb56 LP |
2463 | /* |
2464 | * Grab another RPM ref for the commit tail, which will release the | |
2465 | * ref when it's finished | |
2466 | */ | |
2467 | pm_runtime_get_noresume(dev->dev); | |
2468 | ||
839ca903 BS |
2469 | if (nonblock) |
2470 | queue_work(system_unbound_wq, &state->commit_work); | |
2471 | else | |
2472 | nv50_disp_atomic_commit_tail(state); | |
2473 | ||
813a7e16 ML |
2474 | err_cleanup: |
2475 | if (ret) | |
e0f04e41 | 2476 | drm_atomic_helper_unprepare_planes(dev, state); |
839ca903 BS |
2477 | done: |
2478 | pm_runtime_put_autosuspend(dev->dev); | |
2479 | return ret; | |
2480 | } | |
2481 | ||
2482 | static struct nv50_outp_atom * | |
2483 | nv50_disp_outp_atomic_add(struct nv50_atom *atom, struct drm_encoder *encoder) | |
2484 | { | |
2485 | struct nv50_outp_atom *outp; | |
2486 | ||
2487 | list_for_each_entry(outp, &atom->outp, head) { | |
2488 | if (outp->encoder == encoder) | |
2489 | return outp; | |
2490 | } | |
2491 | ||
2492 | outp = kzalloc(sizeof(*outp), GFP_KERNEL); | |
2493 | if (!outp) | |
2494 | return ERR_PTR(-ENOMEM); | |
2495 | ||
2496 | list_add(&outp->head, &atom->outp); | |
2497 | outp->encoder = encoder; | |
2498 | return outp; | |
2499 | } | |
2500 | ||
2501 | static int | |
2502 | nv50_disp_outp_atomic_check_clr(struct nv50_atom *atom, | |
3c847d6c | 2503 | struct drm_connector_state *old_connector_state) |
839ca903 | 2504 | { |
3c847d6c ML |
2505 | struct drm_encoder *encoder = old_connector_state->best_encoder; |
2506 | struct drm_crtc_state *old_crtc_state, *new_crtc_state; | |
839ca903 BS |
2507 | struct drm_crtc *crtc; |
2508 | struct nv50_outp_atom *outp; | |
2509 | ||
3c847d6c | 2510 | if (!(crtc = old_connector_state->crtc)) |
839ca903 BS |
2511 | return 0; |
2512 | ||
3c847d6c ML |
2513 | old_crtc_state = drm_atomic_get_old_crtc_state(&atom->state, crtc); |
2514 | new_crtc_state = drm_atomic_get_new_crtc_state(&atom->state, crtc); | |
2515 | if (old_crtc_state->active && drm_atomic_crtc_needs_modeset(new_crtc_state)) { | |
839ca903 BS |
2516 | outp = nv50_disp_outp_atomic_add(atom, encoder); |
2517 | if (IS_ERR(outp)) | |
2518 | return PTR_ERR(outp); | |
2519 | ||
a5a7379f | 2520 | if (outp->encoder->encoder_type == DRM_MODE_ENCODER_DPMST || |
625ead3d | 2521 | nouveau_encoder(outp->encoder)->dcb->type == DCB_OUTPUT_DP) |
839ca903 | 2522 | atom->flush_disable = true; |
839ca903 BS |
2523 | outp->clr.ctrl = true; |
2524 | atom->lock_core = true; | |
2525 | } | |
2526 | ||
2527 | return 0; | |
2528 | } | |
2529 | ||
2530 | static int | |
2531 | nv50_disp_outp_atomic_check_set(struct nv50_atom *atom, | |
2532 | struct drm_connector_state *connector_state) | |
2533 | { | |
2534 | struct drm_encoder *encoder = connector_state->best_encoder; | |
3c847d6c | 2535 | struct drm_crtc_state *new_crtc_state; |
839ca903 BS |
2536 | struct drm_crtc *crtc; |
2537 | struct nv50_outp_atom *outp; | |
2538 | ||
2539 | if (!(crtc = connector_state->crtc)) | |
2540 | return 0; | |
2541 | ||
3c847d6c ML |
2542 | new_crtc_state = drm_atomic_get_new_crtc_state(&atom->state, crtc); |
2543 | if (new_crtc_state->active && drm_atomic_crtc_needs_modeset(new_crtc_state)) { | |
839ca903 BS |
2544 | outp = nv50_disp_outp_atomic_add(atom, encoder); |
2545 | if (IS_ERR(outp)) | |
2546 | return PTR_ERR(outp); | |
2547 | ||
2548 | outp->set.ctrl = true; | |
2549 | atom->lock_core = true; | |
2550 | } | |
2551 | ||
2552 | return 0; | |
2553 | } | |
2554 | ||
2555 | static int | |
2556 | nv50_disp_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) | |
2557 | { | |
2558 | struct nv50_atom *atom = nv50_atom(state); | |
dbdaf719 | 2559 | struct nv50_core *core = nv50_disp(dev)->core; |
3c847d6c | 2560 | struct drm_connector_state *old_connector_state, *new_connector_state; |
839ca903 | 2561 | struct drm_connector *connector; |
119608a7 BS |
2562 | struct drm_crtc_state *new_crtc_state; |
2563 | struct drm_crtc *crtc; | |
dbdaf719 LP |
2564 | struct nv50_head *head; |
2565 | struct nv50_head_atom *asyh; | |
839ca903 BS |
2566 | int ret, i; |
2567 | ||
dbdaf719 LP |
2568 | if (core->assign_windows && core->func->head->static_wndw_map) { |
2569 | drm_for_each_crtc(crtc, dev) { | |
2570 | new_crtc_state = drm_atomic_get_crtc_state(state, | |
2571 | crtc); | |
2572 | if (IS_ERR(new_crtc_state)) | |
2573 | return PTR_ERR(new_crtc_state); | |
2574 | ||
2575 | head = nv50_head(crtc); | |
2576 | asyh = nv50_head_atom(new_crtc_state); | |
2577 | core->func->head->static_wndw_map(head, asyh); | |
2578 | } | |
2579 | } | |
2580 | ||
119608a7 BS |
2581 | /* We need to handle colour management on a per-plane basis. */ |
2582 | for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { | |
2583 | if (new_crtc_state->color_mgmt_changed) { | |
2584 | ret = drm_atomic_add_affected_planes(state, crtc); | |
2585 | if (ret) | |
2586 | return ret; | |
2587 | } | |
2588 | } | |
2589 | ||
839ca903 BS |
2590 | ret = drm_atomic_helper_check(dev, state); |
2591 | if (ret) | |
2592 | return ret; | |
2593 | ||
3c847d6c ML |
2594 | for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) { |
2595 | ret = nv50_disp_outp_atomic_check_clr(atom, old_connector_state); | |
839ca903 BS |
2596 | if (ret) |
2597 | return ret; | |
2598 | ||
3c847d6c | 2599 | ret = nv50_disp_outp_atomic_check_set(atom, new_connector_state); |
839ca903 BS |
2600 | if (ret) |
2601 | return ret; | |
2602 | } | |
2603 | ||
232c9eec LP |
2604 | ret = drm_dp_mst_atomic_check(state); |
2605 | if (ret) | |
2606 | return ret; | |
2607 | ||
2d786508 LP |
2608 | nv50_crc_atomic_check_outp(atom); |
2609 | ||
839ca903 BS |
2610 | return 0; |
2611 | } | |
2612 | ||
2613 | static void | |
2614 | nv50_disp_atomic_state_clear(struct drm_atomic_state *state) | |
2615 | { | |
2616 | struct nv50_atom *atom = nv50_atom(state); | |
2617 | struct nv50_outp_atom *outp, *outt; | |
2618 | ||
2619 | list_for_each_entry_safe(outp, outt, &atom->outp, head) { | |
2620 | list_del(&outp->head); | |
2621 | kfree(outp); | |
2622 | } | |
2623 | ||
2624 | drm_atomic_state_default_clear(state); | |
2625 | } | |
2626 | ||
2627 | static void | |
2628 | nv50_disp_atomic_state_free(struct drm_atomic_state *state) | |
2629 | { | |
2630 | struct nv50_atom *atom = nv50_atom(state); | |
2631 | drm_atomic_state_default_release(&atom->state); | |
2632 | kfree(atom); | |
2633 | } | |
2634 | ||
2635 | static struct drm_atomic_state * | |
2636 | nv50_disp_atomic_state_alloc(struct drm_device *dev) | |
2637 | { | |
2638 | struct nv50_atom *atom; | |
2639 | if (!(atom = kzalloc(sizeof(*atom), GFP_KERNEL)) || | |
2640 | drm_atomic_state_init(dev, &atom->state) < 0) { | |
2641 | kfree(atom); | |
2642 | return NULL; | |
2643 | } | |
2644 | INIT_LIST_HEAD(&atom->outp); | |
2645 | return &atom->state; | |
2646 | } | |
2647 | ||
2648 | static const struct drm_mode_config_funcs | |
2649 | nv50_disp_func = { | |
2650 | .fb_create = nouveau_user_framebuffer_create, | |
839ca903 BS |
2651 | .atomic_check = nv50_disp_atomic_check, |
2652 | .atomic_commit = nv50_disp_atomic_commit, | |
2653 | .atomic_state_alloc = nv50_disp_atomic_state_alloc, | |
2654 | .atomic_state_clear = nv50_disp_atomic_state_clear, | |
2655 | .atomic_state_free = nv50_disp_atomic_state_free, | |
2656 | }; | |
2657 | ||
a5c2c0d1 LP |
2658 | static const struct drm_mode_config_helper_funcs |
2659 | nv50_disp_helper_func = { | |
2660 | .atomic_commit_setup = drm_dp_mst_atomic_setup_commit, | |
2661 | }; | |
2662 | ||
26f6d88b BS |
2663 | /****************************************************************************** |
2664 | * Init | |
2665 | *****************************************************************************/ | |
ab0af559 | 2666 | |
ba801ef0 | 2667 | static void |
a0922278 | 2668 | nv50_display_fini(struct drm_device *dev, bool runtime, bool suspend) |
26f6d88b | 2669 | { |
a0922278 | 2670 | struct nouveau_drm *drm = nouveau_drm(dev); |
f479c0ba | 2671 | struct drm_encoder *encoder; |
f479c0ba BS |
2672 | |
2673 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | |
a0922278 LP |
2674 | if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) |
2675 | nv50_mstm_fini(nouveau_encoder(encoder)); | |
f479c0ba | 2676 | } |
a0922278 | 2677 | |
b96a2253 | 2678 | if (!runtime && !drm->headless) |
a0922278 | 2679 | cancel_work_sync(&drm->hpd_work); |
26f6d88b BS |
2680 | } |
2681 | ||
1b477f42 LP |
2682 | static inline void |
2683 | nv50_display_read_hw_or_state(struct drm_device *dev, struct nv50_disp *disp, | |
2684 | struct nouveau_encoder *outp) | |
2685 | { | |
2686 | struct drm_crtc *crtc; | |
2687 | struct drm_connector_list_iter conn_iter; | |
2688 | struct drm_connector *conn; | |
2689 | struct nv50_head_atom *armh; | |
2690 | const u32 encoder_mask = drm_encoder_mask(&outp->base.base); | |
2691 | bool found_conn = false, found_head = false; | |
2692 | u8 proto; | |
2693 | int head_idx; | |
2694 | int ret; | |
2695 | ||
2696 | switch (outp->dcb->type) { | |
2697 | case DCB_OUTPUT_TMDS: | |
2698 | ret = nvif_outp_inherit_tmds(&outp->outp, &proto); | |
2699 | break; | |
2700 | case DCB_OUTPUT_DP: | |
2701 | ret = nvif_outp_inherit_dp(&outp->outp, &proto); | |
2702 | break; | |
2703 | case DCB_OUTPUT_LVDS: | |
2704 | ret = nvif_outp_inherit_lvds(&outp->outp, &proto); | |
2705 | break; | |
2706 | case DCB_OUTPUT_ANALOG: | |
2707 | ret = nvif_outp_inherit_rgb_crt(&outp->outp, &proto); | |
2708 | break; | |
2709 | default: | |
2710 | drm_dbg_kms(dev, "Readback for %s not implemented yet, skipping\n", | |
2711 | outp->base.base.name); | |
2712 | drm_WARN_ON(dev, true); | |
2713 | return; | |
2714 | } | |
2715 | ||
2716 | if (ret < 0) | |
2717 | return; | |
2718 | ||
2719 | head_idx = ret; | |
2720 | ||
2721 | drm_for_each_crtc(crtc, dev) { | |
2722 | if (crtc->index != head_idx) | |
2723 | continue; | |
2724 | ||
2725 | armh = nv50_head_atom(crtc->state); | |
2726 | found_head = true; | |
2727 | break; | |
2728 | } | |
2729 | if (drm_WARN_ON(dev, !found_head)) | |
2730 | return; | |
2731 | ||
2732 | /* Figure out which connector is being used by this encoder */ | |
2733 | drm_connector_list_iter_begin(dev, &conn_iter); | |
2734 | nouveau_for_each_non_mst_connector_iter(conn, &conn_iter) { | |
2735 | if (nouveau_connector(conn)->index == outp->dcb->connector) { | |
2736 | found_conn = true; | |
2737 | break; | |
2738 | } | |
2739 | } | |
2740 | drm_connector_list_iter_end(&conn_iter); | |
2741 | if (drm_WARN_ON(dev, !found_conn)) | |
2742 | return; | |
2743 | ||
2744 | armh->state.encoder_mask = encoder_mask; | |
2745 | armh->state.connector_mask = drm_connector_mask(conn); | |
2746 | armh->state.active = true; | |
2747 | armh->state.enable = true; | |
2748 | pm_runtime_get_noresume(dev->dev); | |
2749 | ||
2750 | outp->crtc = crtc; | |
2751 | outp->ctrl = NVVAL(NV507D, SOR_SET_CONTROL, PROTOCOL, proto) | BIT(crtc->index); | |
2752 | ||
2753 | drm_connector_get(conn); | |
2754 | conn->state->crtc = crtc; | |
2755 | conn->state->best_encoder = &outp->base.base; | |
2756 | } | |
2757 | ||
2758 | /* Read back the currently programmed display state */ | |
2759 | static void | |
2760 | nv50_display_read_hw_state(struct nouveau_drm *drm) | |
2761 | { | |
2762 | struct drm_device *dev = drm->dev; | |
2763 | struct drm_encoder *encoder; | |
2764 | struct drm_modeset_acquire_ctx ctx; | |
2765 | struct nv50_disp *disp = nv50_disp(dev); | |
2766 | int ret; | |
2767 | ||
2768 | DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); | |
2769 | ||
2770 | drm_for_each_encoder(encoder, dev) { | |
2771 | if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) | |
2772 | continue; | |
2773 | ||
2774 | nv50_display_read_hw_or_state(dev, disp, nouveau_encoder(encoder)); | |
2775 | } | |
2776 | ||
2777 | DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); | |
2778 | } | |
2779 | ||
ba801ef0 | 2780 | static int |
0f9976dd | 2781 | nv50_display_init(struct drm_device *dev, bool resume, bool runtime) |
26f6d88b | 2782 | { |
09e1b78a | 2783 | struct nv50_core *core = nv50_disp(dev)->core; |
354d3508 | 2784 | struct drm_encoder *encoder; |
9f9bdaaf | 2785 | |
fa1232ea LP |
2786 | if (resume || runtime) |
2787 | core->func->init(core); | |
973f10c2 | 2788 | |
354d3508 BS |
2789 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
2790 | if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { | |
9c5753bc BS |
2791 | struct nouveau_encoder *nv_encoder = |
2792 | nouveau_encoder(encoder); | |
a0922278 | 2793 | nv50_mstm_init(nv_encoder, runtime); |
354d3508 BS |
2794 | } |
2795 | } | |
2796 | ||
1b477f42 LP |
2797 | if (!resume) |
2798 | nv50_display_read_hw_state(nouveau_drm(dev)); | |
2799 | ||
9f9bdaaf | 2800 | return 0; |
26f6d88b BS |
2801 | } |
2802 | ||
ba801ef0 | 2803 | static void |
e225f446 | 2804 | nv50_display_destroy(struct drm_device *dev) |
26f6d88b | 2805 | { |
e225f446 | 2806 | struct nv50_disp *disp = nv50_disp(dev); |
bdb8c212 | 2807 | |
742db30c TI |
2808 | nv50_audio_component_fini(nouveau_drm(dev)); |
2809 | ||
4a2cb418 | 2810 | nvif_object_unmap(&disp->caps); |
9ac596a4 | 2811 | nvif_object_dtor(&disp->caps); |
9ca6f1eb | 2812 | nv50_core_del(&disp->core); |
26f6d88b | 2813 | |
816af2f2 | 2814 | nouveau_bo_unmap(disp->sync); |
04c8c210 MS |
2815 | if (disp->sync) |
2816 | nouveau_bo_unpin(disp->sync); | |
bf32a3a1 | 2817 | nouveau_bo_fini(disp->sync); |
51beb428 | 2818 | |
77145f1c | 2819 | nouveau_display(dev)->priv = NULL; |
26f6d88b BS |
2820 | kfree(disp); |
2821 | } | |
2822 | ||
2823 | int | |
e225f446 | 2824 | nv50_display_create(struct drm_device *dev) |
26f6d88b | 2825 | { |
77145f1c | 2826 | struct nouveau_drm *drm = nouveau_drm(dev); |
83fc083c | 2827 | struct drm_connector *connector, *tmp; |
e225f446 | 2828 | struct nv50_disp *disp; |
571028c4 | 2829 | int ret, i; |
0a4410a7 | 2830 | bool has_mst = false; |
26f6d88b BS |
2831 | |
2832 | disp = kzalloc(sizeof(*disp), GFP_KERNEL); | |
2833 | if (!disp) | |
2834 | return -ENOMEM; | |
77145f1c | 2835 | |
839ca903 BS |
2836 | mutex_init(&disp->mutex); |
2837 | ||
77145f1c | 2838 | nouveau_display(dev)->priv = disp; |
e225f446 BS |
2839 | nouveau_display(dev)->dtor = nv50_display_destroy; |
2840 | nouveau_display(dev)->init = nv50_display_init; | |
2841 | nouveau_display(dev)->fini = nv50_display_fini; | |
0ad72863 | 2842 | disp->disp = &nouveau_display(dev)->disp; |
839ca903 | 2843 | dev->mode_config.funcs = &nv50_disp_func; |
a5c2c0d1 | 2844 | dev->mode_config.helper_private = &nv50_disp_helper_func; |
0e94043e | 2845 | dev->mode_config.quirk_addfb_prefer_xbgr_30bpp = true; |
7a962f2b | 2846 | dev->mode_config.normalize_zpos = true; |
26f6d88b | 2847 | |
b5a794b0 | 2848 | /* small shared memory area we use for notifiers and semaphores */ |
81b61579 CK |
2849 | ret = nouveau_bo_new(&drm->client, 4096, 0x1000, |
2850 | NOUVEAU_GEM_DOMAIN_VRAM, | |
bb6178b0 | 2851 | 0, 0x0000, NULL, NULL, &disp->sync); |
b5a794b0 | 2852 | if (!ret) { |
81b61579 | 2853 | ret = nouveau_bo_pin(disp->sync, NOUVEAU_GEM_DOMAIN_VRAM, true); |
04c8c210 | 2854 | if (!ret) { |
b5a794b0 | 2855 | ret = nouveau_bo_map(disp->sync); |
04c8c210 MS |
2856 | if (ret) |
2857 | nouveau_bo_unpin(disp->sync); | |
2858 | } | |
b5a794b0 | 2859 | if (ret) |
bf32a3a1 | 2860 | nouveau_bo_fini(disp->sync); |
b5a794b0 BS |
2861 | } |
2862 | ||
b5a794b0 BS |
2863 | if (ret) |
2864 | goto out; | |
2865 | ||
2866 | /* allocate master evo channel */ | |
9ca6f1eb | 2867 | ret = nv50_core_new(drm, &disp->core); |
b5a794b0 BS |
2868 | if (ret) |
2869 | goto out; | |
2870 | ||
fa1232ea | 2871 | disp->core->func->init(disp->core); |
4a2cb418 LP |
2872 | if (disp->core->func->caps_init) { |
2873 | ret = disp->core->func->caps_init(drm, disp); | |
2874 | if (ret) | |
2875 | goto out; | |
2876 | } | |
fa1232ea | 2877 | |
c586f30b JJ |
2878 | /* Assign the correct format modifiers */ |
2879 | if (disp->disp->object.oclass >= TU102_DISP) | |
2880 | nouveau_display(dev)->format_modifiers = wndwc57e_modifiers; | |
2881 | else | |
05088314 | 2882 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_FERMI) |
c586f30b JJ |
2883 | nouveau_display(dev)->format_modifiers = disp90xx_modifiers; |
2884 | else | |
2885 | nouveau_display(dev)->format_modifiers = disp50xx_modifiers; | |
2886 | ||
d3999c1f LP |
2887 | /* FIXME: 256x256 cursors are supported on Kepler, however unlike Maxwell and later |
2888 | * generations Kepler requires that we use small pages (4K) for cursor scanout surfaces. The | |
2889 | * proper fix for this is to teach nouveau to migrate fbs being used for the cursor plane to | |
2890 | * small page allocations in prepare_fb(). When this is implemented, we should also force | |
2891 | * large pages (128K) for ovly fbs in order to fix Kepler ovlys. | |
2892 | * But until then, just limit cursors to 128x128 - which is small enough to avoid ever using | |
2893 | * large pages. | |
2894 | */ | |
2895 | if (disp->disp->object.oclass >= GM107_DISP) { | |
d3b2f0f7 LP |
2896 | dev->mode_config.cursor_width = 256; |
2897 | dev->mode_config.cursor_height = 256; | |
d3999c1f LP |
2898 | } else if (disp->disp->object.oclass >= GK104_DISP) { |
2899 | dev->mode_config.cursor_width = 128; | |
2900 | dev->mode_config.cursor_height = 128; | |
d3b2f0f7 LP |
2901 | } else { |
2902 | dev->mode_config.cursor_width = 64; | |
2903 | dev->mode_config.cursor_height = 64; | |
2904 | } | |
2905 | ||
83fc083c | 2906 | /* create encoder/connector objects based on VBIOS DCB table */ |
0a4410a7 | 2907 | for_each_set_bit(i, &disp->disp->outp_mask, sizeof(disp->disp->outp_mask) * 8) { |
e32de3da BS |
2908 | struct nouveau_encoder *outp; |
2909 | ||
2910 | outp = kzalloc(sizeof(*outp), GFP_KERNEL); | |
2911 | if (!outp) | |
2912 | break; | |
2913 | ||
0a4410a7 | 2914 | ret = nvif_outp_ctor(disp->disp, "kmsOutp", i, &outp->outp); |
e32de3da BS |
2915 | if (ret) { |
2916 | kfree(outp); | |
2917 | continue; | |
2918 | } | |
2919 | ||
0a4410a7 | 2920 | connector = nouveau_connector_create(dev, outp->outp.info.conn); |
e32de3da BS |
2921 | if (IS_ERR(connector)) { |
2922 | nvif_outp_dtor(&outp->outp); | |
2923 | kfree(outp); | |
83fc083c | 2924 | continue; |
e32de3da BS |
2925 | } |
2926 | ||
0a4410a7 | 2927 | outp->base.base.possible_crtcs = outp->outp.info.heads; |
e32de3da | 2928 | outp->base.base.possible_clones = 0; |
e32de3da | 2929 | outp->conn = nouveau_connector(connector); |
83fc083c | 2930 | |
0a4410a7 BS |
2931 | outp->dcb = kzalloc(sizeof(*outp->dcb), GFP_KERNEL); |
2932 | if (!outp->dcb) | |
2933 | break; | |
2934 | ||
2935 | switch (outp->outp.info.proto) { | |
2936 | case NVIF_OUTP_RGB_CRT: | |
2937 | outp->dcb->type = DCB_OUTPUT_ANALOG; | |
2938 | outp->dcb->crtconf.maxfreq = outp->outp.info.rgb_crt.freq_max; | |
2939 | break; | |
2940 | case NVIF_OUTP_TMDS: | |
2941 | outp->dcb->type = DCB_OUTPUT_TMDS; | |
2942 | outp->dcb->duallink_possible = outp->outp.info.tmds.dual; | |
2943 | break; | |
2944 | case NVIF_OUTP_LVDS: | |
2945 | outp->dcb->type = DCB_OUTPUT_LVDS; | |
2946 | outp->dcb->lvdsconf.use_acpi_for_edid = outp->outp.info.lvds.acpi_edid; | |
2947 | break; | |
2948 | case NVIF_OUTP_DP: | |
2949 | outp->dcb->type = DCB_OUTPUT_DP; | |
2950 | outp->dcb->dpconf.link_nr = outp->outp.info.dp.link_nr; | |
2951 | outp->dcb->dpconf.link_bw = outp->outp.info.dp.link_bw; | |
2952 | if (outp->outp.info.dp.mst) | |
2953 | has_mst = true; | |
2954 | break; | |
2955 | default: | |
2956 | WARN_ON(1); | |
2957 | continue; | |
2958 | } | |
2959 | ||
2960 | outp->dcb->heads = outp->outp.info.heads; | |
2961 | outp->dcb->connector = outp->outp.info.conn; | |
2962 | outp->dcb->i2c_index = outp->outp.info.ddc; | |
2963 | ||
2964 | switch (outp->outp.info.type) { | |
2965 | case NVIF_OUTP_DAC : ret = nv50_dac_create(outp); break; | |
2966 | case NVIF_OUTP_SOR : ret = nv50_sor_create(outp); break; | |
2967 | case NVIF_OUTP_PIOR: ret = nv50_pior_create(outp); break; | |
2968 | default: | |
2969 | WARN_ON(1); | |
2970 | continue; | |
83fc083c BS |
2971 | } |
2972 | ||
eb6313ad BS |
2973 | if (ret) { |
2974 | NV_WARN(drm, "failed to create encoder %d/%d/%d: %d\n", | |
0a4410a7 | 2975 | i, outp->outp.info.type, outp->outp.info.proto, ret); |
83fc083c BS |
2976 | } |
2977 | } | |
2978 | ||
2979 | /* cull any connectors we created that don't have an encoder */ | |
2980 | list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) { | |
62afb4ad | 2981 | if (connector->possible_encoders) |
83fc083c BS |
2982 | continue; |
2983 | ||
77145f1c | 2984 | NV_WARN(drm, "%s has no encoders, removing\n", |
8c6c361a | 2985 | connector->name); |
83fc083c BS |
2986 | connector->funcs->destroy(connector); |
2987 | } | |
2988 | ||
0880bf4c BS |
2989 | /* create crtc objects to represent the hw heads */ |
2990 | for_each_set_bit(i, &disp->disp->head_mask, sizeof(disp->disp->head_mask) * 8) { | |
2991 | struct nv50_head *head; | |
2992 | ||
2993 | head = nv50_head_create(dev, i); | |
2994 | if (IS_ERR(head)) { | |
2995 | ret = PTR_ERR(head); | |
2996 | goto out; | |
2997 | } | |
2998 | ||
2999 | if (has_mst) { | |
3000 | head->msto = nv50_msto_new(dev, head, i); | |
3001 | if (IS_ERR(head->msto)) { | |
3002 | ret = PTR_ERR(head->msto); | |
3003 | head->msto = NULL; | |
3004 | goto out; | |
3005 | } | |
3006 | ||
3007 | /* | |
3008 | * FIXME: This is a hack to workaround the following | |
3009 | * issues: | |
3010 | * | |
3011 | * https://gitlab.gnome.org/GNOME/mutter/issues/759 | |
3012 | * https://gitlab.freedesktop.org/xorg/xserver/merge_requests/277 | |
3013 | * | |
3014 | * Once these issues are closed, this should be | |
3015 | * removed | |
3016 | */ | |
3017 | head->msto->encoder.possible_crtcs = disp->disp->head_mask; | |
3018 | } | |
3019 | } | |
3020 | ||
2ae4c5f6 MK |
3021 | /* Disable vblank irqs aggressively for power-saving, safe on nv50+ */ |
3022 | dev->vblank_disable_immediate = true; | |
3023 | ||
742db30c TI |
3024 | nv50_audio_component_init(drm); |
3025 | ||
26f6d88b BS |
3026 | out: |
3027 | if (ret) | |
e225f446 | 3028 | nv50_display_destroy(dev); |
26f6d88b BS |
3029 | return ret; |
3030 | } | |
c586f30b JJ |
3031 | |
3032 | /****************************************************************************** | |
3033 | * Format modifiers | |
3034 | *****************************************************************************/ | |
3035 | ||
3036 | /**************************************************************** | |
3037 | * Log2(block height) ----------------------------+ * | |
3038 | * Page Kind ----------------------------------+ | * | |
3039 | * Gob Height/Page Kind Generation ------+ | | * | |
3040 | * Sector layout -------+ | | | * | |
3041 | * Compression ------+ | | | | */ | |
3042 | const u64 disp50xx_modifiers[] = { /* | | | | | */ | |
3043 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x7a, 0), | |
3044 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x7a, 1), | |
3045 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x7a, 2), | |
3046 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x7a, 3), | |
3047 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x7a, 4), | |
3048 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x7a, 5), | |
3049 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x78, 0), | |
3050 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x78, 1), | |
3051 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x78, 2), | |
3052 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x78, 3), | |
3053 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x78, 4), | |
3054 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x78, 5), | |
3055 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x70, 0), | |
3056 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x70, 1), | |
3057 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x70, 2), | |
3058 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x70, 3), | |
3059 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x70, 4), | |
3060 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 1, 0x70, 5), | |
3061 | DRM_FORMAT_MOD_LINEAR, | |
3062 | DRM_FORMAT_MOD_INVALID | |
3063 | }; | |
3064 | ||
3065 | /**************************************************************** | |
3066 | * Log2(block height) ----------------------------+ * | |
3067 | * Page Kind ----------------------------------+ | * | |
3068 | * Gob Height/Page Kind Generation ------+ | | * | |
3069 | * Sector layout -------+ | | | * | |
3070 | * Compression ------+ | | | | */ | |
3071 | const u64 disp90xx_modifiers[] = { /* | | | | | */ | |
3072 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 0), | |
3073 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 1), | |
3074 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 2), | |
3075 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 3), | |
3076 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 4), | |
3077 | DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 1, 0, 0xfe, 5), | |
3078 | DRM_FORMAT_MOD_LINEAR, | |
3079 | DRM_FORMAT_MOD_INVALID | |
3080 | }; |