blob: 068810b0c15570a41b45eac5e88e9465832ddca4 [file] [log] [blame]
Ben Skeggs56d237d2014-05-19 14:54:33 +10001/*
Ben Skeggs26f6d882011-07-04 16:25:18 +10002 * 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 */
24
Ben Skeggs51beb422011-07-05 10:33:08 +100025#include <linux/dma-mapping.h>
Ben Skeggs83fc0832011-07-05 13:08:40 +100026
David Howells760285e2012-10-02 18:01:07 +010027#include <drm/drmP.h>
Ben Skeggsad633612016-11-04 17:20:36 +100028#include <drm/drm_atomic.h>
Ben Skeggs973f10c2016-11-04 17:20:36 +100029#include <drm/drm_atomic_helper.h>
David Howells760285e2012-10-02 18:01:07 +010030#include <drm/drm_crtc_helper.h>
Ben Skeggs48743222014-05-31 01:48:06 +100031#include <drm/drm_dp_helper.h>
Daniel Vetterb516a9e2015-12-04 09:45:43 +010032#include <drm/drm_fb_helper.h>
Ben Skeggsad633612016-11-04 17:20:36 +100033#include <drm/drm_plane_helper.h>
Ben Skeggs26f6d882011-07-04 16:25:18 +100034
Ben Skeggsfdb751e2014-08-10 04:10:23 +100035#include <nvif/class.h>
Ben Skeggs845f2722015-11-08 12:16:40 +100036#include <nvif/cl0002.h>
Ben Skeggs7568b102015-11-08 10:44:19 +100037#include <nvif/cl5070.h>
38#include <nvif/cl507a.h>
39#include <nvif/cl507b.h>
40#include <nvif/cl507c.h>
41#include <nvif/cl507d.h>
42#include <nvif/cl507e.h>
Ben Skeggs973f10c2016-11-04 17:20:36 +100043#include <nvif/event.h>
Ben Skeggsfdb751e2014-08-10 04:10:23 +100044
Ben Skeggs4dc28132016-05-20 09:22:55 +100045#include "nouveau_drv.h"
Ben Skeggs77145f12012-07-31 16:16:21 +100046#include "nouveau_dma.h"
47#include "nouveau_gem.h"
Ben Skeggs26f6d882011-07-04 16:25:18 +100048#include "nouveau_connector.h"
49#include "nouveau_encoder.h"
50#include "nouveau_crtc.h"
Ben Skeggsf589be82012-07-22 11:55:54 +100051#include "nouveau_fence.h"
Ben Skeggs3a89cd02011-07-07 10:47:10 +100052#include "nv50_display.h"
Ben Skeggs26f6d882011-07-04 16:25:18 +100053
Ben Skeggs8a464382011-11-12 23:52:07 +100054#define EVO_DMA_NR 9
55
Ben Skeggsbdb8c212011-11-12 01:30:24 +100056#define EVO_MASTER (0x00)
Ben Skeggsa63a97e2011-11-16 15:22:34 +100057#define EVO_FLIP(c) (0x01 + (c))
Ben Skeggs8a464382011-11-12 23:52:07 +100058#define EVO_OVLY(c) (0x05 + (c))
59#define EVO_OIMM(c) (0x09 + (c))
Ben Skeggsbdb8c212011-11-12 01:30:24 +100060#define EVO_CURS(c) (0x0d + (c))
61
Ben Skeggs816af2f2011-11-16 15:48:48 +100062/* offsets in shared sync bo of various structures */
63#define EVO_SYNC(c, o) ((c) * 0x0100 + (o))
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +100064#define EVO_MAST_NTFY EVO_SYNC( 0, 0x00)
65#define EVO_FLIP_SEM0(c) EVO_SYNC((c) + 1, 0x00)
66#define EVO_FLIP_SEM1(c) EVO_SYNC((c) + 1, 0x10)
Ben Skeggs973f10c2016-11-04 17:20:36 +100067#define EVO_FLIP_NTFY0(c) EVO_SYNC((c) + 1, 0x20)
68#define EVO_FLIP_NTFY1(c) EVO_SYNC((c) + 1, 0x30)
Ben Skeggs816af2f2011-11-16 15:48:48 +100069
Ben Skeggsb5a794b2012-10-16 14:18:32 +100070/******************************************************************************
Ben Skeggs3dbd0362016-11-04 17:20:36 +100071 * Atomic state
72 *****************************************************************************/
73#define nv50_head_atom(p) container_of((p), struct nv50_head_atom, state)
74
75struct nv50_head_atom {
76 struct drm_crtc_state state;
77
Ben Skeggsc4e68122016-11-04 17:20:36 +100078 struct {
79 u16 iW;
80 u16 iH;
81 u16 oW;
82 u16 oH;
83 } view;
84
Ben Skeggs3dbd0362016-11-04 17:20:36 +100085 struct nv50_head_mode {
86 bool interlace;
87 u32 clock;
88 struct {
89 u16 active;
90 u16 synce;
91 u16 blanke;
92 u16 blanks;
93 } h;
94 struct {
95 u32 active;
96 u16 synce;
97 u16 blanke;
98 u16 blanks;
99 u16 blank2s;
100 u16 blank2e;
101 u16 blankus;
102 } v;
103 } mode;
104
Ben Skeggsad633612016-11-04 17:20:36 +1000105 struct {
Ben Skeggsa7ae1562016-11-04 17:20:36 +1000106 u32 handle;
107 u64 offset:40;
108 } lut;
109
110 struct {
Ben Skeggsad633612016-11-04 17:20:36 +1000111 bool visible;
112 u32 handle;
113 u64 offset:40;
114 u8 format;
115 u8 kind:7;
116 u8 layout:1;
117 u8 block:4;
118 u32 pitch:20;
119 u16 x;
120 u16 y;
121 u16 w;
122 u16 h;
123 } core;
124
125 struct {
Ben Skeggsea8ee392016-11-04 17:20:36 +1000126 bool visible;
127 u32 handle;
128 u64 offset:40;
129 u8 layout:1;
130 u8 format:1;
131 } curs;
132
133 struct {
Ben Skeggsad633612016-11-04 17:20:36 +1000134 u8 depth;
135 u8 cpp;
136 u16 x;
137 u16 y;
138 u16 w;
139 u16 h;
140 } base;
141
Ben Skeggs6bbab3b2016-11-04 17:20:36 +1000142 struct {
143 u8 cpp;
144 } ovly;
145
Ben Skeggs7e918332016-11-04 17:20:36 +1000146 struct {
147 bool enable:1;
148 u8 bits:2;
149 u8 mode:4;
150 } dither;
151
Ben Skeggs7e08d672016-11-04 17:20:36 +1000152 struct {
153 struct {
154 u16 cos:12;
155 u16 sin:12;
156 } sat;
157 } procamp;
158
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000159 union {
160 struct {
Ben Skeggsad633612016-11-04 17:20:36 +1000161 bool core:1;
Ben Skeggsea8ee392016-11-04 17:20:36 +1000162 bool curs:1;
Ben Skeggsad633612016-11-04 17:20:36 +1000163 };
164 u8 mask;
165 } clr;
166
167 union {
168 struct {
169 bool core:1;
Ben Skeggsea8ee392016-11-04 17:20:36 +1000170 bool curs:1;
Ben Skeggsad633612016-11-04 17:20:36 +1000171 bool view:1;
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000172 bool mode:1;
Ben Skeggs6bbab3b2016-11-04 17:20:36 +1000173 bool base:1;
174 bool ovly:1;
Ben Skeggs7e918332016-11-04 17:20:36 +1000175 bool dither:1;
Ben Skeggs7e08d672016-11-04 17:20:36 +1000176 bool procamp:1;
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000177 };
178 u16 mask;
179 } set;
180};
181
Ben Skeggs973f10c2016-11-04 17:20:36 +1000182#define nv50_wndw_atom(p) container_of((p), struct nv50_wndw_atom, state)
183
184struct nv50_wndw_atom {
185 struct drm_plane_state state;
186 u8 interval;
187
188 struct drm_rect clip;
189
190 struct {
191 u32 handle;
192 u16 offset:12;
193 bool awaken:1;
194 } ntfy;
195
196 struct {
197 u32 handle;
198 u16 offset:12;
199 u32 acquire;
200 u32 release;
201 } sema;
202
203 struct {
204 u8 enable:2;
205 } lut;
206
207 struct {
208 u8 mode:2;
209 u8 interval:4;
210
211 u8 format;
212 u8 kind:7;
213 u8 layout:1;
214 u8 block:4;
215 u32 pitch:20;
216 u16 w;
217 u16 h;
218
219 u32 handle;
220 u64 offset;
221 } image;
222
223 struct {
224 u16 x;
225 u16 y;
226 } point;
227
228 union {
229 struct {
230 bool ntfy:1;
231 bool sema:1;
232 bool image:1;
233 };
234 u8 mask;
235 } clr;
236
237 union {
238 struct {
239 bool ntfy:1;
240 bool sema:1;
241 bool image:1;
242 bool lut:1;
243 bool point:1;
244 };
245 u8 mask;
246 } set;
247};
248
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000249/******************************************************************************
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000250 * EVO channel
251 *****************************************************************************/
252
Ben Skeggse225f442012-11-21 14:40:21 +1000253struct nv50_chan {
Ben Skeggs0ad72862014-08-10 04:10:22 +1000254 struct nvif_object user;
Ben Skeggsa01ca782015-08-20 14:54:15 +1000255 struct nvif_device *device;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000256};
257
258static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000259nv50_chan_create(struct nvif_device *device, struct nvif_object *disp,
Ben Skeggs315a8b22015-08-20 14:54:16 +1000260 const s32 *oclass, u8 head, void *data, u32 size,
Ben Skeggsa01ca782015-08-20 14:54:15 +1000261 struct nv50_chan *chan)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000262{
Ben Skeggs41a63402015-08-20 14:54:16 +1000263 struct nvif_sclass *sclass;
264 int ret, i, n;
Ben Skeggs6af52892014-11-03 15:01:33 +1000265
Ben Skeggsa01ca782015-08-20 14:54:15 +1000266 chan->device = device;
267
Ben Skeggs41a63402015-08-20 14:54:16 +1000268 ret = n = nvif_object_sclass_get(disp, &sclass);
Ben Skeggs6af52892014-11-03 15:01:33 +1000269 if (ret < 0)
270 return ret;
271
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000272 while (oclass[0]) {
Ben Skeggs41a63402015-08-20 14:54:16 +1000273 for (i = 0; i < n; i++) {
274 if (sclass[i].oclass == oclass[0]) {
Ben Skeggsfcf3f912015-09-04 14:40:32 +1000275 ret = nvif_object_init(disp, 0, oclass[0],
Ben Skeggsa01ca782015-08-20 14:54:15 +1000276 data, size, &chan->user);
Ben Skeggs6af52892014-11-03 15:01:33 +1000277 if (ret == 0)
278 nvif_object_map(&chan->user);
Ben Skeggs41a63402015-08-20 14:54:16 +1000279 nvif_object_sclass_put(&sclass);
Ben Skeggs6af52892014-11-03 15:01:33 +1000280 return ret;
281 }
Ben Skeggsb76f1522014-08-10 04:10:28 +1000282 }
Ben Skeggs6af52892014-11-03 15:01:33 +1000283 oclass++;
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000284 }
Ben Skeggs6af52892014-11-03 15:01:33 +1000285
Ben Skeggs41a63402015-08-20 14:54:16 +1000286 nvif_object_sclass_put(&sclass);
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000287 return -ENOSYS;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000288}
289
290static void
Ben Skeggs0ad72862014-08-10 04:10:22 +1000291nv50_chan_destroy(struct nv50_chan *chan)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000292{
Ben Skeggs0ad72862014-08-10 04:10:22 +1000293 nvif_object_fini(&chan->user);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000294}
295
296/******************************************************************************
297 * PIO EVO channel
298 *****************************************************************************/
299
Ben Skeggse225f442012-11-21 14:40:21 +1000300struct nv50_pioc {
301 struct nv50_chan base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000302};
303
304static void
Ben Skeggs0ad72862014-08-10 04:10:22 +1000305nv50_pioc_destroy(struct nv50_pioc *pioc)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000306{
Ben Skeggs0ad72862014-08-10 04:10:22 +1000307 nv50_chan_destroy(&pioc->base);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000308}
309
310static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000311nv50_pioc_create(struct nvif_device *device, struct nvif_object *disp,
Ben Skeggs315a8b22015-08-20 14:54:16 +1000312 const s32 *oclass, u8 head, void *data, u32 size,
Ben Skeggsa01ca782015-08-20 14:54:15 +1000313 struct nv50_pioc *pioc)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000314{
Ben Skeggsa01ca782015-08-20 14:54:15 +1000315 return nv50_chan_create(device, disp, oclass, head, data, size,
316 &pioc->base);
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000317}
318
319/******************************************************************************
320 * Cursor Immediate
321 *****************************************************************************/
322
323struct nv50_curs {
324 struct nv50_pioc base;
325};
326
327static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000328nv50_curs_create(struct nvif_device *device, struct nvif_object *disp,
329 int head, struct nv50_curs *curs)
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000330{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000331 struct nv50_disp_cursor_v0 args = {
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000332 .head = head,
333 };
Ben Skeggs315a8b22015-08-20 14:54:16 +1000334 static const s32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000335 GK104_DISP_CURSOR,
336 GF110_DISP_CURSOR,
337 GT214_DISP_CURSOR,
338 G82_DISP_CURSOR,
339 NV50_DISP_CURSOR,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000340 0
341 };
342
Ben Skeggsa01ca782015-08-20 14:54:15 +1000343 return nv50_pioc_create(device, disp, oclass, head, &args, sizeof(args),
344 &curs->base);
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000345}
346
347/******************************************************************************
348 * Overlay Immediate
349 *****************************************************************************/
350
351struct nv50_oimm {
352 struct nv50_pioc base;
353};
354
355static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000356nv50_oimm_create(struct nvif_device *device, struct nvif_object *disp,
357 int head, struct nv50_oimm *oimm)
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000358{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000359 struct nv50_disp_cursor_v0 args = {
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000360 .head = head,
361 };
Ben Skeggs315a8b22015-08-20 14:54:16 +1000362 static const s32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000363 GK104_DISP_OVERLAY,
364 GF110_DISP_OVERLAY,
365 GT214_DISP_OVERLAY,
366 G82_DISP_OVERLAY,
367 NV50_DISP_OVERLAY,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000368 0
369 };
370
Ben Skeggsa01ca782015-08-20 14:54:15 +1000371 return nv50_pioc_create(device, disp, oclass, head, &args, sizeof(args),
372 &oimm->base);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000373}
374
375/******************************************************************************
376 * DMA EVO channel
377 *****************************************************************************/
378
Ben Skeggse225f442012-11-21 14:40:21 +1000379struct nv50_dmac {
380 struct nv50_chan base;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000381 dma_addr_t handle;
382 u32 *ptr;
Daniel Vetter59ad1462012-12-02 14:49:44 +0100383
Ben Skeggs0ad72862014-08-10 04:10:22 +1000384 struct nvif_object sync;
385 struct nvif_object vram;
386
Daniel Vetter59ad1462012-12-02 14:49:44 +0100387 /* Protects against concurrent pushbuf access to this channel, lock is
388 * grabbed by evo_wait (if the pushbuf reservation is successful) and
389 * dropped again by evo_kick. */
390 struct mutex lock;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000391};
392
393static void
Ben Skeggs0ad72862014-08-10 04:10:22 +1000394nv50_dmac_destroy(struct nv50_dmac *dmac, struct nvif_object *disp)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000395{
Ben Skeggsa01ca782015-08-20 14:54:15 +1000396 struct nvif_device *device = dmac->base.device;
397
Ben Skeggs0ad72862014-08-10 04:10:22 +1000398 nvif_object_fini(&dmac->vram);
399 nvif_object_fini(&dmac->sync);
400
401 nv50_chan_destroy(&dmac->base);
402
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000403 if (dmac->ptr) {
Ben Skeggs26c9e8e2015-08-20 14:54:23 +1000404 struct device *dev = nvxx_device(device)->dev;
405 dma_free_coherent(dev, PAGE_SIZE, dmac->ptr, dmac->handle);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000406 }
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000407}
408
409static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000410nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
Ben Skeggs315a8b22015-08-20 14:54:16 +1000411 const s32 *oclass, u8 head, void *data, u32 size, u64 syncbuf,
Ben Skeggse225f442012-11-21 14:40:21 +1000412 struct nv50_dmac *dmac)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000413{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000414 struct nv50_disp_core_channel_dma_v0 *args = data;
Ben Skeggs0ad72862014-08-10 04:10:22 +1000415 struct nvif_object pushbuf;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000416 int ret;
417
Daniel Vetter59ad1462012-12-02 14:49:44 +0100418 mutex_init(&dmac->lock);
419
Ben Skeggs26c9e8e2015-08-20 14:54:23 +1000420 dmac->ptr = dma_alloc_coherent(nvxx_device(device)->dev, PAGE_SIZE,
421 &dmac->handle, GFP_KERNEL);
Ben Skeggs47057302012-11-16 13:58:48 +1000422 if (!dmac->ptr)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000423 return -ENOMEM;
424
Ben Skeggsfcf3f912015-09-04 14:40:32 +1000425 ret = nvif_object_init(&device->object, 0, NV_DMA_FROM_MEMORY,
426 &(struct nv_dma_v0) {
Ben Skeggs4acfd702014-08-10 04:10:24 +1000427 .target = NV_DMA_V0_TARGET_PCI_US,
428 .access = NV_DMA_V0_ACCESS_RD,
Ben Skeggs47057302012-11-16 13:58:48 +1000429 .start = dmac->handle + 0x0000,
430 .limit = dmac->handle + 0x0fff,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000431 }, sizeof(struct nv_dma_v0), &pushbuf);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000432 if (ret)
433 return ret;
434
Ben Skeggsbf81df92015-08-20 14:54:16 +1000435 args->pushbuf = nvif_handle(&pushbuf);
436
Ben Skeggsa01ca782015-08-20 14:54:15 +1000437 ret = nv50_chan_create(device, disp, oclass, head, data, size,
438 &dmac->base);
Ben Skeggs0ad72862014-08-10 04:10:22 +1000439 nvif_object_fini(&pushbuf);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000440 if (ret)
441 return ret;
442
Ben Skeggsa01ca782015-08-20 14:54:15 +1000443 ret = nvif_object_init(&dmac->base.user, 0xf0000000, NV_DMA_IN_MEMORY,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000444 &(struct nv_dma_v0) {
445 .target = NV_DMA_V0_TARGET_VRAM,
446 .access = NV_DMA_V0_ACCESS_RDWR,
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000447 .start = syncbuf + 0x0000,
448 .limit = syncbuf + 0x0fff,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000449 }, sizeof(struct nv_dma_v0),
Ben Skeggs0ad72862014-08-10 04:10:22 +1000450 &dmac->sync);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000451 if (ret)
Ben Skeggs47057302012-11-16 13:58:48 +1000452 return ret;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000453
Ben Skeggsa01ca782015-08-20 14:54:15 +1000454 ret = nvif_object_init(&dmac->base.user, 0xf0000001, NV_DMA_IN_MEMORY,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000455 &(struct nv_dma_v0) {
456 .target = NV_DMA_V0_TARGET_VRAM,
457 .access = NV_DMA_V0_ACCESS_RDWR,
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000458 .start = 0,
Ben Skeggsf392ec42014-08-10 04:10:28 +1000459 .limit = device->info.ram_user - 1,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000460 }, sizeof(struct nv_dma_v0),
Ben Skeggs0ad72862014-08-10 04:10:22 +1000461 &dmac->vram);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000462 if (ret)
Ben Skeggs47057302012-11-16 13:58:48 +1000463 return ret;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000464
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000465 return ret;
466}
467
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000468/******************************************************************************
469 * Core
470 *****************************************************************************/
471
Ben Skeggse225f442012-11-21 14:40:21 +1000472struct nv50_mast {
473 struct nv50_dmac base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000474};
475
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000476static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000477nv50_core_create(struct nvif_device *device, struct nvif_object *disp,
478 u64 syncbuf, struct nv50_mast *core)
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000479{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000480 struct nv50_disp_core_channel_dma_v0 args = {
481 .pushbuf = 0xb0007d00,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000482 };
Ben Skeggs315a8b22015-08-20 14:54:16 +1000483 static const s32 oclass[] = {
Ben Skeggsfd478772016-07-09 10:41:01 +1000484 GP104_DISP_CORE_CHANNEL_DMA,
Ben Skeggsf9d5cbb2016-07-09 10:41:01 +1000485 GP100_DISP_CORE_CHANNEL_DMA,
Ben Skeggsdb1eb522016-02-11 08:35:32 +1000486 GM200_DISP_CORE_CHANNEL_DMA,
Ben Skeggs648d4df2014-08-10 04:10:27 +1000487 GM107_DISP_CORE_CHANNEL_DMA,
488 GK110_DISP_CORE_CHANNEL_DMA,
489 GK104_DISP_CORE_CHANNEL_DMA,
490 GF110_DISP_CORE_CHANNEL_DMA,
491 GT214_DISP_CORE_CHANNEL_DMA,
492 GT206_DISP_CORE_CHANNEL_DMA,
493 GT200_DISP_CORE_CHANNEL_DMA,
494 G82_DISP_CORE_CHANNEL_DMA,
495 NV50_DISP_CORE_CHANNEL_DMA,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000496 0
497 };
498
Ben Skeggsa01ca782015-08-20 14:54:15 +1000499 return nv50_dmac_create(device, disp, oclass, 0, &args, sizeof(args),
500 syncbuf, &core->base);
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000501}
502
503/******************************************************************************
504 * Base
505 *****************************************************************************/
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000506
Ben Skeggse225f442012-11-21 14:40:21 +1000507struct nv50_sync {
508 struct nv50_dmac base;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000509 u32 addr;
510 u32 data;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000511};
512
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000513static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000514nv50_base_create(struct nvif_device *device, struct nvif_object *disp,
515 int head, u64 syncbuf, struct nv50_sync *base)
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000516{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000517 struct nv50_disp_base_channel_dma_v0 args = {
518 .pushbuf = 0xb0007c00 | head,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000519 .head = head,
520 };
Ben Skeggs315a8b22015-08-20 14:54:16 +1000521 static const s32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000522 GK110_DISP_BASE_CHANNEL_DMA,
523 GK104_DISP_BASE_CHANNEL_DMA,
524 GF110_DISP_BASE_CHANNEL_DMA,
525 GT214_DISP_BASE_CHANNEL_DMA,
526 GT200_DISP_BASE_CHANNEL_DMA,
527 G82_DISP_BASE_CHANNEL_DMA,
528 NV50_DISP_BASE_CHANNEL_DMA,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000529 0
530 };
531
Ben Skeggsa01ca782015-08-20 14:54:15 +1000532 return nv50_dmac_create(device, disp, oclass, head, &args, sizeof(args),
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000533 syncbuf, &base->base);
534}
535
536/******************************************************************************
537 * Overlay
538 *****************************************************************************/
539
Ben Skeggse225f442012-11-21 14:40:21 +1000540struct nv50_ovly {
541 struct nv50_dmac base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000542};
Ben Skeggsf20ce962011-07-08 13:17:01 +1000543
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000544static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000545nv50_ovly_create(struct nvif_device *device, struct nvif_object *disp,
546 int head, u64 syncbuf, struct nv50_ovly *ovly)
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000547{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000548 struct nv50_disp_overlay_channel_dma_v0 args = {
549 .pushbuf = 0xb0007e00 | head,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000550 .head = head,
551 };
Ben Skeggs315a8b22015-08-20 14:54:16 +1000552 static const s32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000553 GK104_DISP_OVERLAY_CONTROL_DMA,
554 GF110_DISP_OVERLAY_CONTROL_DMA,
555 GT214_DISP_OVERLAY_CHANNEL_DMA,
556 GT200_DISP_OVERLAY_CHANNEL_DMA,
557 G82_DISP_OVERLAY_CHANNEL_DMA,
558 NV50_DISP_OVERLAY_CHANNEL_DMA,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000559 0
560 };
561
Ben Skeggsa01ca782015-08-20 14:54:15 +1000562 return nv50_dmac_create(device, disp, oclass, head, &args, sizeof(args),
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000563 syncbuf, &ovly->base);
564}
Ben Skeggs26f6d882011-07-04 16:25:18 +1000565
Ben Skeggse225f442012-11-21 14:40:21 +1000566struct nv50_head {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +1000567 struct nouveau_crtc base;
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000568 struct nouveau_bo *image;
Ben Skeggse225f442012-11-21 14:40:21 +1000569 struct nv50_curs curs;
Ben Skeggse225f442012-11-21 14:40:21 +1000570 struct nv50_ovly ovly;
571 struct nv50_oimm oimm;
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000572
573 struct nv50_head_atom arm;
574 struct nv50_head_atom asy;
Ben Skeggs973f10c2016-11-04 17:20:36 +1000575
576 struct nv50_base *_base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000577};
578
Ben Skeggse225f442012-11-21 14:40:21 +1000579#define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c))
580#define nv50_curs(c) (&nv50_head(c)->curs)
Ben Skeggse225f442012-11-21 14:40:21 +1000581#define nv50_ovly(c) (&nv50_head(c)->ovly)
582#define nv50_oimm(c) (&nv50_head(c)->oimm)
583#define nv50_chan(c) (&(c)->base.base)
Ben Skeggs0ad72862014-08-10 04:10:22 +1000584#define nv50_vers(c) nv50_chan(c)->user.oclass
585
586struct nv50_fbdma {
587 struct list_head head;
588 struct nvif_object core;
589 struct nvif_object base[4];
590};
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000591
Ben Skeggse225f442012-11-21 14:40:21 +1000592struct nv50_disp {
Ben Skeggs0ad72862014-08-10 04:10:22 +1000593 struct nvif_object *disp;
Ben Skeggse225f442012-11-21 14:40:21 +1000594 struct nv50_mast mast;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000595
Ben Skeggs8a423642014-08-10 04:10:19 +1000596 struct list_head fbdma;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000597
598 struct nouveau_bo *sync;
Ben Skeggsdd0e3d52012-10-16 14:00:31 +1000599};
600
Ben Skeggse225f442012-11-21 14:40:21 +1000601static struct nv50_disp *
602nv50_disp(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +1000603{
Ben Skeggs77145f12012-07-31 16:16:21 +1000604 return nouveau_display(dev)->priv;
Ben Skeggs26f6d882011-07-04 16:25:18 +1000605}
606
Ben Skeggse225f442012-11-21 14:40:21 +1000607#define nv50_mast(d) (&nv50_disp(d)->mast)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000608
Ben Skeggsbdb8c212011-11-12 01:30:24 +1000609static struct drm_crtc *
Ben Skeggse225f442012-11-21 14:40:21 +1000610nv50_display_crtc_get(struct drm_encoder *encoder)
Ben Skeggsbdb8c212011-11-12 01:30:24 +1000611{
612 return nouveau_encoder(encoder)->crtc;
613}
614
615/******************************************************************************
616 * EVO channel helpers
617 *****************************************************************************/
Ben Skeggs51beb422011-07-05 10:33:08 +1000618static u32 *
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000619evo_wait(void *evoc, int nr)
Ben Skeggs51beb422011-07-05 10:33:08 +1000620{
Ben Skeggse225f442012-11-21 14:40:21 +1000621 struct nv50_dmac *dmac = evoc;
Ben Skeggsa01ca782015-08-20 14:54:15 +1000622 struct nvif_device *device = dmac->base.device;
Ben Skeggs0ad72862014-08-10 04:10:22 +1000623 u32 put = nvif_rd32(&dmac->base.user, 0x0000) / 4;
Ben Skeggs51beb422011-07-05 10:33:08 +1000624
Daniel Vetter59ad1462012-12-02 14:49:44 +0100625 mutex_lock(&dmac->lock);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000626 if (put + nr >= (PAGE_SIZE / 4) - 8) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000627 dmac->ptr[put] = 0x20000000;
Ben Skeggs51beb422011-07-05 10:33:08 +1000628
Ben Skeggs0ad72862014-08-10 04:10:22 +1000629 nvif_wr32(&dmac->base.user, 0x0000, 0x00000000);
Ben Skeggs54442042015-08-20 14:54:11 +1000630 if (nvif_msec(device, 2000,
631 if (!nvif_rd32(&dmac->base.user, 0x0004))
632 break;
633 ) < 0) {
Daniel Vetter59ad1462012-12-02 14:49:44 +0100634 mutex_unlock(&dmac->lock);
Ben Skeggs9ad97ed2015-08-20 14:54:13 +1000635 printk(KERN_ERR "nouveau: evo channel stalled\n");
Ben Skeggs51beb422011-07-05 10:33:08 +1000636 return NULL;
637 }
638
639 put = 0;
640 }
641
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000642 return dmac->ptr + put;
Ben Skeggs51beb422011-07-05 10:33:08 +1000643}
644
645static void
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000646evo_kick(u32 *push, void *evoc)
Ben Skeggs51beb422011-07-05 10:33:08 +1000647{
Ben Skeggse225f442012-11-21 14:40:21 +1000648 struct nv50_dmac *dmac = evoc;
Ben Skeggs0ad72862014-08-10 04:10:22 +1000649 nvif_wr32(&dmac->base.user, 0x0000, (push - dmac->ptr) << 2);
Daniel Vetter59ad1462012-12-02 14:49:44 +0100650 mutex_unlock(&dmac->lock);
Ben Skeggs51beb422011-07-05 10:33:08 +1000651}
652
Ben Skeggs2b1930c2014-11-03 16:43:59 +1000653#define evo_mthd(p,m,s) do { \
654 const u32 _m = (m), _s = (s); \
Ben Skeggs7f55a072016-11-04 17:20:36 +1000655 if (drm_debug & DRM_UT_KMS) \
656 printk(KERN_ERR "%04x %d %s\n", _m, _s, __func__); \
Ben Skeggs2b1930c2014-11-03 16:43:59 +1000657 *((p)++) = ((_s << 18) | _m); \
658} while(0)
Ben Skeggs7f55a072016-11-04 17:20:36 +1000659
Ben Skeggs2b1930c2014-11-03 16:43:59 +1000660#define evo_data(p,d) do { \
661 const u32 _d = (d); \
Ben Skeggs7f55a072016-11-04 17:20:36 +1000662 if (drm_debug & DRM_UT_KMS) \
663 printk(KERN_ERR "\t%08x\n", _d); \
Ben Skeggs2b1930c2014-11-03 16:43:59 +1000664 *((p)++) = _d; \
665} while(0)
Ben Skeggs51beb422011-07-05 10:33:08 +1000666
Ben Skeggs3376ee32011-11-12 14:28:12 +1000667static bool
668evo_sync_wait(void *data)
669{
Ben Skeggs5cc027f2013-02-18 17:50:51 -0500670 if (nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000)
671 return true;
672 usleep_range(1, 2);
673 return false;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000674}
675
676static int
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000677evo_sync(struct drm_device *dev)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000678{
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000679 struct nvif_device *device = &nouveau_drm(dev)->device;
Ben Skeggse225f442012-11-21 14:40:21 +1000680 struct nv50_disp *disp = nv50_disp(dev);
681 struct nv50_mast *mast = nv50_mast(dev);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000682 u32 *push = evo_wait(mast, 8);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000683 if (push) {
Ben Skeggs816af2f2011-11-16 15:48:48 +1000684 nouveau_bo_wr32(disp->sync, EVO_MAST_NTFY, 0x00000000);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000685 evo_mthd(push, 0x0084, 1);
Ben Skeggs816af2f2011-11-16 15:48:48 +1000686 evo_data(push, 0x80000000 | EVO_MAST_NTFY);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000687 evo_mthd(push, 0x0080, 2);
688 evo_data(push, 0x00000000);
689 evo_data(push, 0x00000000);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000690 evo_kick(push, mast);
Ben Skeggs54442042015-08-20 14:54:11 +1000691 if (nvif_msec(device, 2000,
692 if (evo_sync_wait(disp->sync))
693 break;
694 ) >= 0)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000695 return 0;
696 }
697
698 return -EBUSY;
699}
700
701/******************************************************************************
Ben Skeggs973f10c2016-11-04 17:20:36 +1000702 * Plane
703 *****************************************************************************/
704#define nv50_wndw(p) container_of((p), struct nv50_wndw, plane)
705
706struct nv50_wndw {
707 const struct nv50_wndw_func *func;
708 struct nv50_dmac *dmac;
709
710 struct drm_plane plane;
711
712 struct nvif_notify notify;
713 u16 ntfy;
714 u16 sema;
715 u32 data;
716
717 struct nv50_wndw_atom arm;
718 struct nv50_wndw_atom asy;
719};
720
721struct nv50_wndw_func {
722 void *(*dtor)(struct nv50_wndw *);
723 int (*acquire)(struct nv50_wndw *, struct nv50_wndw_atom *asyw,
724 struct nv50_head_atom *asyh);
725 void (*release)(struct nv50_wndw *, struct nv50_wndw_atom *asyw,
726 struct nv50_head_atom *asyh);
727 void (*prepare)(struct nv50_wndw *, struct nv50_head_atom *asyh,
728 struct nv50_wndw_atom *asyw);
729
730 void (*sema_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
731 void (*sema_clr)(struct nv50_wndw *);
732 void (*ntfy_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
733 void (*ntfy_clr)(struct nv50_wndw *);
734 int (*ntfy_wait_begun)(struct nv50_wndw *, struct nv50_wndw_atom *);
735 void (*image_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
736 void (*image_clr)(struct nv50_wndw *);
737 void (*lut)(struct nv50_wndw *, struct nv50_wndw_atom *);
738 void (*point)(struct nv50_wndw *, struct nv50_wndw_atom *);
739
740 u32 (*update)(struct nv50_wndw *, u32 interlock);
741};
742
743static int
744nv50_wndw_wait_armed(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
745{
746 if (asyw->set.ntfy)
747 return wndw->func->ntfy_wait_begun(wndw, asyw);
748 return 0;
749}
750
751static u32
752nv50_wndw_flush_clr(struct nv50_wndw *wndw, u32 interlock, bool flush,
753 struct nv50_wndw_atom *asyw)
754{
755 if (asyw->clr.sema && (!asyw->set.sema || flush))
756 wndw->func->sema_clr(wndw);
757 if (asyw->clr.ntfy && (!asyw->set.ntfy || flush))
758 wndw->func->ntfy_clr(wndw);
759 if (asyw->clr.image && (!asyw->set.image || flush))
760 wndw->func->image_clr(wndw);
761
762 return flush ? wndw->func->update(wndw, interlock) : 0;
763}
764
765static u32
766nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 interlock,
767 struct nv50_wndw_atom *asyw)
768{
769 if (interlock) {
770 asyw->image.mode = 0;
771 asyw->image.interval = 1;
772 }
773
774 if (asyw->set.sema ) wndw->func->sema_set (wndw, asyw);
775 if (asyw->set.ntfy ) wndw->func->ntfy_set (wndw, asyw);
776 if (asyw->set.image) wndw->func->image_set(wndw, asyw);
777 if (asyw->set.lut ) wndw->func->lut (wndw, asyw);
778 if (asyw->set.point) wndw->func->point (wndw, asyw);
779
780 return wndw->func->update(wndw, interlock);
781}
782
783static void
784nv50_wndw_atomic_check_release(struct nv50_wndw *wndw,
785 struct nv50_wndw_atom *asyw,
786 struct nv50_head_atom *asyh)
787{
788 struct nouveau_drm *drm = nouveau_drm(wndw->plane.dev);
789 NV_ATOMIC(drm, "%s release\n", wndw->plane.name);
790 wndw->func->release(wndw, asyw, asyh);
791 asyw->ntfy.handle = 0;
792 asyw->sema.handle = 0;
793}
794
795static int
796nv50_wndw_atomic_check_acquire(struct nv50_wndw *wndw,
797 struct nv50_wndw_atom *asyw,
798 struct nv50_head_atom *asyh)
799{
800 struct nouveau_framebuffer *fb = nouveau_framebuffer(asyw->state.fb);
801 struct nouveau_drm *drm = nouveau_drm(wndw->plane.dev);
802 int ret;
803
804 NV_ATOMIC(drm, "%s acquire\n", wndw->plane.name);
805 asyw->clip.x1 = 0;
806 asyw->clip.y1 = 0;
807 asyw->clip.x2 = asyh->state.mode.hdisplay;
808 asyw->clip.y2 = asyh->state.mode.vdisplay;
809
810 asyw->image.w = fb->base.width;
811 asyw->image.h = fb->base.height;
812 asyw->image.kind = (fb->nvbo->tile_flags & 0x0000ff00) >> 8;
813 if (asyw->image.kind) {
814 asyw->image.layout = 0;
815 if (drm->device.info.chipset >= 0xc0)
816 asyw->image.block = fb->nvbo->tile_mode >> 4;
817 else
818 asyw->image.block = fb->nvbo->tile_mode;
819 asyw->image.pitch = (fb->base.pitches[0] / 4) << 4;
820 } else {
821 asyw->image.layout = 1;
822 asyw->image.block = 0;
823 asyw->image.pitch = fb->base.pitches[0];
824 }
825
826 ret = wndw->func->acquire(wndw, asyw, asyh);
827 if (ret)
828 return ret;
829
830 if (asyw->set.image) {
831 if (!(asyw->image.mode = asyw->interval ? 0 : 1))
832 asyw->image.interval = asyw->interval;
833 else
834 asyw->image.interval = 0;
835 }
836
837 return 0;
838}
839
840static int
841nv50_wndw_atomic_check(struct drm_plane *plane, struct drm_plane_state *state)
842{
843 struct nouveau_drm *drm = nouveau_drm(plane->dev);
844 struct nv50_wndw *wndw = nv50_wndw(plane);
845 struct nv50_wndw_atom *armw = &wndw->arm;
846 struct nv50_wndw_atom *asyw = &wndw->asy;
847 struct nv50_head_atom *harm = NULL, *asyh = NULL;
848 bool varm = false, asyv = false, asym = false;
849 int ret;
850
851 asyw->clr.mask = 0;
852 asyw->set.mask = 0;
853
854 NV_ATOMIC(drm, "%s atomic_check\n", plane->name);
855 if (asyw->state.crtc) {
856 asyh = &nv50_head(asyw->state.crtc)->asy;
857 if (IS_ERR(asyh))
858 return PTR_ERR(asyh);
859 asym = drm_atomic_crtc_needs_modeset(&asyh->state);
860 asyv = asyh->state.active;
861 }
862
863 if (armw->state.crtc) {
864 harm = &nv50_head(armw->state.crtc)->asy;
865 if (IS_ERR(harm))
866 return PTR_ERR(harm);
867 varm = nv50_head(harm->state.crtc)->arm.state.active;
868 }
869
870 if (asyv) {
871 asyw->point.x = asyw->state.crtc_x;
872 asyw->point.y = asyw->state.crtc_y;
873 if (memcmp(&armw->point, &asyw->point, sizeof(asyw->point)))
874 asyw->set.point = true;
875
876 if (!varm || asym || armw->state.fb != asyw->state.fb) {
877 ret = nv50_wndw_atomic_check_acquire(wndw, asyw, asyh);
878 if (ret)
879 return ret;
880 }
881 } else
882 if (varm) {
883 nv50_wndw_atomic_check_release(wndw, asyw, harm);
884 } else {
885 return 0;
886 }
887
888 if (!asyv || asym) {
889 asyw->clr.ntfy = armw->ntfy.handle != 0;
890 asyw->clr.sema = armw->sema.handle != 0;
891 if (wndw->func->image_clr)
892 asyw->clr.image = armw->image.handle != 0;
893 asyw->set.lut = wndw->func->lut && asyv;
894 }
895
896 memcpy(armw, asyw, sizeof(*asyw));
897 return 0;
898}
899
900static void
901nv50_wndw_atomic_destroy_state(struct drm_plane *plane,
902 struct drm_plane_state *state)
903{
904 struct nv50_wndw_atom *asyw = nv50_wndw_atom(state);
905 __drm_atomic_helper_plane_destroy_state(&asyw->state);
906 dma_fence_put(asyw->state.fence);
907 kfree(asyw);
908}
909
910static struct drm_plane_state *
911nv50_wndw_atomic_duplicate_state(struct drm_plane *plane)
912{
913 struct nv50_wndw_atom *armw = nv50_wndw_atom(plane->state);
914 struct nv50_wndw_atom *asyw;
915 if (!(asyw = kmalloc(sizeof(*asyw), GFP_KERNEL)))
916 return NULL;
917 __drm_atomic_helper_plane_duplicate_state(plane, &asyw->state);
918 asyw->state.fence = NULL;
919 asyw->interval = 1;
920 asyw->sema = armw->sema;
921 asyw->ntfy = armw->ntfy;
922 asyw->image = armw->image;
923 asyw->point = armw->point;
924 asyw->lut = armw->lut;
925 asyw->clr.mask = 0;
926 asyw->set.mask = 0;
927 return &asyw->state;
928}
929
930static void
931nv50_wndw_reset(struct drm_plane *plane)
932{
933 struct nv50_wndw_atom *asyw;
934
935 if (WARN_ON(!(asyw = kzalloc(sizeof(*asyw), GFP_KERNEL))))
936 return;
937
938 if (plane->state)
939 plane->funcs->atomic_destroy_state(plane, plane->state);
940 plane->state = &asyw->state;
941 plane->state->plane = plane;
942 plane->state->rotation = DRM_ROTATE_0;
943}
944
945static void
946nv50_wndw_destroy(struct drm_plane *plane)
947{
948 struct nv50_wndw *wndw = nv50_wndw(plane);
949 void *data;
950 nvif_notify_fini(&wndw->notify);
951 data = wndw->func->dtor(wndw);
952 drm_plane_cleanup(&wndw->plane);
953 kfree(data);
954}
955
956static const struct drm_plane_funcs
957nv50_wndw = {
958 .destroy = nv50_wndw_destroy,
959 .reset = nv50_wndw_reset,
960 .set_property = drm_atomic_helper_plane_set_property,
961 .atomic_duplicate_state = nv50_wndw_atomic_duplicate_state,
962 .atomic_destroy_state = nv50_wndw_atomic_destroy_state,
963};
964
965static void
966nv50_wndw_fini(struct nv50_wndw *wndw)
967{
968 nvif_notify_put(&wndw->notify);
969}
970
971static void
972nv50_wndw_init(struct nv50_wndw *wndw)
973{
974 nvif_notify_get(&wndw->notify);
975}
976
977static int
978nv50_wndw_ctor(const struct nv50_wndw_func *func, struct drm_device *dev,
979 enum drm_plane_type type, const char *name, int index,
980 struct nv50_dmac *dmac, const u32 *format, int nformat,
981 struct nv50_wndw *wndw)
982{
983 int ret;
984
985 wndw->func = func;
986 wndw->dmac = dmac;
987
988 ret = drm_universal_plane_init(dev, &wndw->plane, 0, &nv50_wndw, format,
989 nformat, type, "%s-%d", name, index);
990 if (ret)
991 return ret;
992
993 return 0;
994}
995
996/******************************************************************************
997 * Primary plane
998 *****************************************************************************/
999#define nv50_base(p) container_of((p), struct nv50_base, wndw)
1000
1001struct nv50_base {
1002 struct nv50_wndw wndw;
1003 struct nv50_sync chan;
1004 int id;
1005};
1006
1007static int
1008nv50_base_notify(struct nvif_notify *notify)
1009{
1010 return NVIF_NOTIFY_KEEP;
1011}
1012
1013static void
1014nv50_base_lut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
1015{
1016 struct nv50_base *base = nv50_base(wndw);
1017 u32 *push;
1018 if ((push = evo_wait(&base->chan, 2))) {
1019 evo_mthd(push, 0x00e0, 1);
1020 evo_data(push, asyw->lut.enable << 30);
1021 evo_kick(push, &base->chan);
1022 }
1023}
1024
1025static void
1026nv50_base_image_clr(struct nv50_wndw *wndw)
1027{
1028 struct nv50_base *base = nv50_base(wndw);
1029 u32 *push;
1030 if ((push = evo_wait(&base->chan, 4))) {
1031 evo_mthd(push, 0x0084, 1);
1032 evo_data(push, 0x00000000);
1033 evo_mthd(push, 0x00c0, 1);
1034 evo_data(push, 0x00000000);
1035 evo_kick(push, &base->chan);
1036 }
1037}
1038
1039static void
1040nv50_base_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
1041{
1042 struct nv50_base *base = nv50_base(wndw);
1043 const s32 oclass = base->chan.base.base.user.oclass;
1044 u32 *push;
1045 if ((push = evo_wait(&base->chan, 10))) {
1046 evo_mthd(push, 0x0084, 1);
1047 evo_data(push, (asyw->image.mode << 8) |
1048 (asyw->image.interval << 4));
1049 evo_mthd(push, 0x00c0, 1);
1050 evo_data(push, asyw->image.handle);
1051 if (oclass < G82_DISP_BASE_CHANNEL_DMA) {
1052 evo_mthd(push, 0x0800, 5);
1053 evo_data(push, asyw->image.offset >> 8);
1054 evo_data(push, 0x00000000);
1055 evo_data(push, (asyw->image.h << 16) | asyw->image.w);
1056 evo_data(push, (asyw->image.layout << 20) |
1057 asyw->image.pitch |
1058 asyw->image.block);
1059 evo_data(push, (asyw->image.kind << 16) |
1060 (asyw->image.format << 8));
1061 } else
1062 if (oclass < GF110_DISP_BASE_CHANNEL_DMA) {
1063 evo_mthd(push, 0x0800, 5);
1064 evo_data(push, asyw->image.offset >> 8);
1065 evo_data(push, 0x00000000);
1066 evo_data(push, (asyw->image.h << 16) | asyw->image.w);
1067 evo_data(push, (asyw->image.layout << 20) |
1068 asyw->image.pitch |
1069 asyw->image.block);
1070 evo_data(push, asyw->image.format << 8);
1071 } else {
1072 evo_mthd(push, 0x0400, 5);
1073 evo_data(push, asyw->image.offset >> 8);
1074 evo_data(push, 0x00000000);
1075 evo_data(push, (asyw->image.h << 16) | asyw->image.w);
1076 evo_data(push, (asyw->image.layout << 24) |
1077 asyw->image.pitch |
1078 asyw->image.block);
1079 evo_data(push, asyw->image.format << 8);
1080 }
1081 evo_kick(push, &base->chan);
1082 }
1083}
1084
1085static void
1086nv50_base_ntfy_clr(struct nv50_wndw *wndw)
1087{
1088 struct nv50_base *base = nv50_base(wndw);
1089 u32 *push;
1090 if ((push = evo_wait(&base->chan, 2))) {
1091 evo_mthd(push, 0x00a4, 1);
1092 evo_data(push, 0x00000000);
1093 evo_kick(push, &base->chan);
1094 }
1095}
1096
1097static void
1098nv50_base_ntfy_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
1099{
1100 struct nv50_base *base = nv50_base(wndw);
1101 u32 *push;
1102 if ((push = evo_wait(&base->chan, 3))) {
1103 evo_mthd(push, 0x00a0, 2);
1104 evo_data(push, (asyw->ntfy.awaken << 30) | asyw->ntfy.offset);
1105 evo_data(push, asyw->ntfy.handle);
1106 evo_kick(push, &base->chan);
1107 }
1108}
1109
1110static void
1111nv50_base_sema_clr(struct nv50_wndw *wndw)
1112{
1113 struct nv50_base *base = nv50_base(wndw);
1114 u32 *push;
1115 if ((push = evo_wait(&base->chan, 2))) {
1116 evo_mthd(push, 0x0094, 1);
1117 evo_data(push, 0x00000000);
1118 evo_kick(push, &base->chan);
1119 }
1120}
1121
1122static void
1123nv50_base_sema_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
1124{
1125 struct nv50_base *base = nv50_base(wndw);
1126 u32 *push;
1127 if ((push = evo_wait(&base->chan, 5))) {
1128 evo_mthd(push, 0x0088, 4);
1129 evo_data(push, asyw->sema.offset);
1130 evo_data(push, asyw->sema.acquire);
1131 evo_data(push, asyw->sema.release);
1132 evo_data(push, asyw->sema.handle);
1133 evo_kick(push, &base->chan);
1134 }
1135}
1136
1137static u32
1138nv50_base_update(struct nv50_wndw *wndw, u32 interlock)
1139{
1140 struct nv50_base *base = nv50_base(wndw);
1141 u32 *push;
1142
1143 if (!(push = evo_wait(&base->chan, 2)))
1144 return 0;
1145 evo_mthd(push, 0x0080, 1);
1146 evo_data(push, interlock);
1147 evo_kick(push, &base->chan);
1148
1149 if (base->chan.base.base.user.oclass < GF110_DISP_BASE_CHANNEL_DMA)
1150 return interlock ? 2 << (base->id * 8) : 0;
1151 return interlock ? 2 << (base->id * 4) : 0;
1152}
1153
1154static int
1155nv50_base_ntfy_wait_begun(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
1156{
1157 struct nouveau_drm *drm = nouveau_drm(wndw->plane.dev);
1158 struct nv50_disp *disp = nv50_disp(wndw->plane.dev);
1159 if (nvif_msec(&drm->device, 2000ULL,
1160 u32 data = nouveau_bo_rd32(disp->sync, asyw->ntfy.offset / 4);
1161 if ((data & 0xc0000000) == 0x40000000)
1162 break;
1163 usleep_range(1, 2);
1164 ) < 0)
1165 return -ETIMEDOUT;
1166 return 0;
1167}
1168
1169static void
1170nv50_base_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
1171 struct nv50_head_atom *asyh)
1172{
1173 asyh->base.cpp = 0;
1174}
1175
1176static int
1177nv50_base_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
1178 struct nv50_head_atom *asyh)
1179{
1180 const u32 format = asyw->state.fb->pixel_format;
1181 const struct drm_format_info *info;
1182 int ret;
1183
1184 info = drm_format_info(format);
1185 if (!info || !info->depth)
1186 return -EINVAL;
1187
1188 ret = drm_plane_helper_check_state(&asyw->state, &asyw->clip,
1189 DRM_PLANE_HELPER_NO_SCALING,
1190 DRM_PLANE_HELPER_NO_SCALING,
1191 false, true);
1192 if (ret)
1193 return ret;
1194
1195 asyh->base.depth = info->depth;
1196 asyh->base.cpp = info->cpp[0];
1197 asyh->base.x = asyw->state.src.x1 >> 16;
1198 asyh->base.y = asyw->state.src.y1 >> 16;
1199 asyh->base.w = asyw->state.fb->width;
1200 asyh->base.h = asyw->state.fb->height;
1201
1202 switch (format) {
1203 case DRM_FORMAT_C8 : asyw->image.format = 0x1e; break;
1204 case DRM_FORMAT_RGB565 : asyw->image.format = 0xe8; break;
1205 case DRM_FORMAT_XRGB1555 :
1206 case DRM_FORMAT_ARGB1555 : asyw->image.format = 0xe9; break;
1207 case DRM_FORMAT_XRGB8888 :
1208 case DRM_FORMAT_ARGB8888 : asyw->image.format = 0xcf; break;
1209 case DRM_FORMAT_XBGR2101010:
1210 case DRM_FORMAT_ABGR2101010: asyw->image.format = 0xd1; break;
1211 case DRM_FORMAT_XBGR8888 :
1212 case DRM_FORMAT_ABGR8888 : asyw->image.format = 0xd5; break;
1213 default:
1214 WARN_ON(1);
1215 return -EINVAL;
1216 }
1217
1218 asyw->lut.enable = 1;
1219 asyw->set.image = true;
1220 return 0;
1221}
1222
1223static void *
1224nv50_base_dtor(struct nv50_wndw *wndw)
1225{
1226 struct nv50_disp *disp = nv50_disp(wndw->plane.dev);
1227 struct nv50_base *base = nv50_base(wndw);
1228 nv50_dmac_destroy(&base->chan.base, disp->disp);
1229 return base;
1230}
1231
1232static const u32
1233nv50_base_format[] = {
1234 DRM_FORMAT_C8,
1235 DRM_FORMAT_RGB565,
1236 DRM_FORMAT_XRGB1555,
1237 DRM_FORMAT_ARGB1555,
1238 DRM_FORMAT_XRGB8888,
1239 DRM_FORMAT_ARGB8888,
1240 DRM_FORMAT_XBGR2101010,
1241 DRM_FORMAT_ABGR2101010,
1242 DRM_FORMAT_XBGR8888,
1243 DRM_FORMAT_ABGR8888,
1244};
1245
1246static const struct nv50_wndw_func
1247nv50_base = {
1248 .dtor = nv50_base_dtor,
1249 .acquire = nv50_base_acquire,
1250 .release = nv50_base_release,
1251 .sema_set = nv50_base_sema_set,
1252 .sema_clr = nv50_base_sema_clr,
1253 .ntfy_set = nv50_base_ntfy_set,
1254 .ntfy_clr = nv50_base_ntfy_clr,
1255 .ntfy_wait_begun = nv50_base_ntfy_wait_begun,
1256 .image_set = nv50_base_image_set,
1257 .image_clr = nv50_base_image_clr,
1258 .lut = nv50_base_lut,
1259 .update = nv50_base_update,
1260};
1261
1262static int
1263nv50_base_new(struct nouveau_drm *drm, struct nv50_head *head,
1264 struct nv50_base **pbase)
1265{
1266 struct nv50_disp *disp = nv50_disp(drm->dev);
1267 struct nv50_base *base;
1268 int ret;
1269
1270 if (!(base = *pbase = kzalloc(sizeof(*base), GFP_KERNEL)))
1271 return -ENOMEM;
1272 base->id = head->base.index;
1273 base->wndw.ntfy = EVO_FLIP_NTFY0(base->id);
1274 base->wndw.sema = EVO_FLIP_SEM0(base->id);
1275 base->wndw.data = 0x00000000;
1276
1277 ret = nv50_wndw_ctor(&nv50_base, drm->dev, DRM_PLANE_TYPE_PRIMARY,
1278 "base", base->id, &base->chan.base,
1279 nv50_base_format, ARRAY_SIZE(nv50_base_format),
1280 &base->wndw);
1281 if (ret) {
1282 kfree(base);
1283 return ret;
1284 }
1285
1286 ret = nv50_base_create(&drm->device, disp->disp, base->id,
1287 disp->sync->bo.offset, &base->chan);
1288 if (ret)
1289 return ret;
1290
1291 return nvif_notify_init(&base->chan.base.base.user, nv50_base_notify,
1292 false,
1293 NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT,
1294 &(struct nvif_notify_uevent_req) {},
1295 sizeof(struct nvif_notify_uevent_req),
1296 sizeof(struct nvif_notify_uevent_rep),
1297 &base->wndw.notify);
1298}
1299
1300/******************************************************************************
Ben Skeggsa63a97e2011-11-16 15:22:34 +10001301 * Page flipping channel
Ben Skeggs3376ee32011-11-12 14:28:12 +10001302 *****************************************************************************/
1303struct nouveau_bo *
Ben Skeggse225f442012-11-21 14:40:21 +10001304nv50_display_crtc_sema(struct drm_device *dev, int crtc)
Ben Skeggs3376ee32011-11-12 14:28:12 +10001305{
Ben Skeggse225f442012-11-21 14:40:21 +10001306 return nv50_disp(dev)->sync;
Ben Skeggs3376ee32011-11-12 14:28:12 +10001307}
1308
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001309struct nv50_display_flip {
1310 struct nv50_disp *disp;
Ben Skeggs973f10c2016-11-04 17:20:36 +10001311 struct nv50_base *base;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001312};
1313
1314static bool
1315nv50_display_flip_wait(void *data)
1316{
1317 struct nv50_display_flip *flip = data;
Ben Skeggs973f10c2016-11-04 17:20:36 +10001318 if (nouveau_bo_rd32(flip->disp->sync, flip->base->wndw.sema / 4) ==
1319 flip->base->wndw.data)
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001320 return true;
1321 usleep_range(1, 2);
1322 return false;
1323}
1324
Ben Skeggs3376ee32011-11-12 14:28:12 +10001325void
Ben Skeggse225f442012-11-21 14:40:21 +10001326nv50_display_flip_stop(struct drm_crtc *crtc)
Ben Skeggs3376ee32011-11-12 14:28:12 +10001327{
Ben Skeggs967e7bd2014-08-10 04:10:22 +10001328 struct nvif_device *device = &nouveau_drm(crtc->dev)->device;
Ben Skeggs973f10c2016-11-04 17:20:36 +10001329 struct nv50_base *base = nv50_head(crtc)->_base;
1330 struct nv50_wndw *wndw = &base->wndw;
1331 struct nv50_wndw_atom *asyw = &wndw->asy;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001332 struct nv50_display_flip flip = {
1333 .disp = nv50_disp(crtc->dev),
Ben Skeggs973f10c2016-11-04 17:20:36 +10001334 .base = base,
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001335 };
Ben Skeggs3376ee32011-11-12 14:28:12 +10001336
Ben Skeggs973f10c2016-11-04 17:20:36 +10001337 asyw->state.crtc = NULL;
1338 asyw->state.fb = NULL;
1339 nv50_wndw_atomic_check(&wndw->plane, &asyw->state);
1340 nv50_wndw_flush_clr(wndw, 0, true, asyw);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001341
Ben Skeggs54442042015-08-20 14:54:11 +10001342 nvif_msec(device, 2000,
1343 if (nv50_display_flip_wait(&flip))
1344 break;
1345 );
Ben Skeggs3376ee32011-11-12 14:28:12 +10001346}
1347
1348int
Ben Skeggse225f442012-11-21 14:40:21 +10001349nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
Ben Skeggs3376ee32011-11-12 14:28:12 +10001350 struct nouveau_channel *chan, u32 swap_interval)
1351{
1352 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
Ben Skeggs3376ee32011-11-12 14:28:12 +10001353 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001354 struct nv50_head *head = nv50_head(crtc);
Ben Skeggs973f10c2016-11-04 17:20:36 +10001355 struct nv50_base *base = nv50_head(crtc)->_base;
1356 struct nv50_wndw *wndw = &base->wndw;
1357 struct nv50_wndw_atom *asyw = &wndw->asy;
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001358 int ret;
Ben Skeggs3376ee32011-11-12 14:28:12 +10001359
Ben Skeggs9ba83102014-12-22 19:50:23 +10001360 if (crtc->primary->fb->width != fb->width ||
1361 crtc->primary->fb->height != fb->height)
1362 return -EINVAL;
1363
Ben Skeggsf60b6e72013-03-19 15:20:00 +10001364 if (chan == NULL)
1365 evo_sync(crtc->dev);
Ben Skeggs3376ee32011-11-12 14:28:12 +10001366
Ben Skeggsa01ca782015-08-20 14:54:15 +10001367 if (chan && chan->user.oclass < G82_CHANNEL_GPFIFO) {
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001368 ret = RING_SPACE(chan, 8);
1369 if (ret)
1370 return ret;
Ben Skeggs67f97182013-02-26 12:02:54 +10001371
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001372 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001373 OUT_RING (chan, NvEvoSema0 + nv_crtc->index);
Ben Skeggs973f10c2016-11-04 17:20:36 +10001374 OUT_RING (chan, base->wndw.sema ^ 0x10);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001375 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
Ben Skeggs973f10c2016-11-04 17:20:36 +10001376 OUT_RING (chan, base->wndw.data + 1);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001377 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_OFFSET, 2);
Ben Skeggs973f10c2016-11-04 17:20:36 +10001378 OUT_RING (chan, base->wndw.sema);
1379 OUT_RING (chan, base->wndw.data);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001380 } else
Ben Skeggsa01ca782015-08-20 14:54:15 +10001381 if (chan && chan->user.oclass < FERMI_CHANNEL_GPFIFO) {
Ben Skeggs973f10c2016-11-04 17:20:36 +10001382 u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + base->wndw.sema;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001383 ret = RING_SPACE(chan, 12);
1384 if (ret)
1385 return ret;
Ben Skeggsa34caf72013-02-14 09:28:37 +10001386
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001387 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
Ben Skeggs0ad72862014-08-10 04:10:22 +10001388 OUT_RING (chan, chan->vram.handle);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001389 BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
1390 OUT_RING (chan, upper_32_bits(addr ^ 0x10));
1391 OUT_RING (chan, lower_32_bits(addr ^ 0x10));
Ben Skeggs973f10c2016-11-04 17:20:36 +10001392 OUT_RING (chan, base->wndw.data + 1);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001393 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG);
1394 BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
1395 OUT_RING (chan, upper_32_bits(addr));
1396 OUT_RING (chan, lower_32_bits(addr));
Ben Skeggs973f10c2016-11-04 17:20:36 +10001397 OUT_RING (chan, base->wndw.data);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001398 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL);
1399 } else
1400 if (chan) {
Ben Skeggs973f10c2016-11-04 17:20:36 +10001401 u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + base->wndw.sema;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001402 ret = RING_SPACE(chan, 10);
1403 if (ret)
1404 return ret;
Ben Skeggs67f97182013-02-26 12:02:54 +10001405
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001406 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
1407 OUT_RING (chan, upper_32_bits(addr ^ 0x10));
1408 OUT_RING (chan, lower_32_bits(addr ^ 0x10));
Ben Skeggs973f10c2016-11-04 17:20:36 +10001409 OUT_RING (chan, base->wndw.data + 1);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001410 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG |
1411 NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD);
1412 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
1413 OUT_RING (chan, upper_32_bits(addr));
1414 OUT_RING (chan, lower_32_bits(addr));
Ben Skeggs973f10c2016-11-04 17:20:36 +10001415 OUT_RING (chan, base->wndw.data);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001416 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL |
1417 NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD);
1418 }
Ben Skeggs35bcf5d2012-04-30 11:34:10 -05001419
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001420 if (chan) {
Ben Skeggs973f10c2016-11-04 17:20:36 +10001421 base->wndw.sema ^= 0x10;
1422 base->wndw.data++;
Ben Skeggs3376ee32011-11-12 14:28:12 +10001423 FIRE_RING (chan);
Ben Skeggs3376ee32011-11-12 14:28:12 +10001424 }
1425
1426 /* queue the flip */
Ben Skeggs973f10c2016-11-04 17:20:36 +10001427 asyw->state.crtc = &head->base.base;
1428 asyw->state.fb = fb;
1429 asyw->interval = swap_interval;
1430 asyw->image.handle = nv_fb->r_handle;
1431 asyw->image.offset = nv_fb->nvbo->bo.offset;
1432 asyw->sema.handle = base->chan.base.sync.handle;
1433 asyw->sema.offset = base->wndw.sema;
1434 asyw->sema.acquire = base->wndw.data++;
1435 asyw->sema.release = base->wndw.data;
1436 nv50_wndw_atomic_check(&wndw->plane, &asyw->state);
1437 asyw->set.sema = true;
1438 nv50_wndw_flush_set(wndw, 0, asyw);
1439 nv50_wndw_wait_armed(wndw, asyw);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001440
1441 nouveau_bo_ref(nv_fb->nvbo, &head->image);
Ben Skeggs3376ee32011-11-12 14:28:12 +10001442 return 0;
1443}
1444
Ben Skeggs26f6d882011-07-04 16:25:18 +10001445/******************************************************************************
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001446 * Head
1447 *****************************************************************************/
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001448static void
Ben Skeggs7e08d672016-11-04 17:20:36 +10001449nv50_head_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
1450{
1451 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1452 u32 *push;
1453 if ((push = evo_wait(core, 2))) {
1454 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA)
1455 evo_mthd(push, 0x08a8 + (head->base.index * 0x400), 1);
1456 else
1457 evo_mthd(push, 0x0498 + (head->base.index * 0x300), 1);
1458 evo_data(push, (asyh->procamp.sat.sin << 20) |
1459 (asyh->procamp.sat.cos << 8));
1460 evo_kick(push, core);
1461 }
1462}
1463
1464static void
Ben Skeggs7e918332016-11-04 17:20:36 +10001465nv50_head_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
1466{
1467 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1468 u32 *push;
1469 if ((push = evo_wait(core, 2))) {
1470 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA)
1471 evo_mthd(push, 0x08a0 + (head->base.index * 0x0400), 1);
1472 else
1473 if (core->base.user.oclass < GK104_DISP_CORE_CHANNEL_DMA)
1474 evo_mthd(push, 0x0490 + (head->base.index * 0x0300), 1);
1475 else
1476 evo_mthd(push, 0x04a0 + (head->base.index * 0x0300), 1);
1477 evo_data(push, (asyh->dither.mode << 3) |
1478 (asyh->dither.bits << 1) |
1479 asyh->dither.enable);
1480 evo_kick(push, core);
1481 }
1482}
1483
1484static void
Ben Skeggs6bbab3b2016-11-04 17:20:36 +10001485nv50_head_ovly(struct nv50_head *head, struct nv50_head_atom *asyh)
1486{
1487 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1488 u32 bounds = 0;
1489 u32 *push;
1490
1491 if (asyh->base.cpp) {
1492 switch (asyh->base.cpp) {
1493 case 8: bounds |= 0x00000500; break;
1494 case 4: bounds |= 0x00000300; break;
1495 case 2: bounds |= 0x00000100; break;
1496 default:
1497 WARN_ON(1);
1498 break;
1499 }
1500 bounds |= 0x00000001;
1501 }
1502
1503 if ((push = evo_wait(core, 2))) {
1504 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA)
1505 evo_mthd(push, 0x0904 + head->base.index * 0x400, 1);
1506 else
1507 evo_mthd(push, 0x04d4 + head->base.index * 0x300, 1);
1508 evo_data(push, bounds);
1509 evo_kick(push, core);
1510 }
1511}
1512
1513static void
1514nv50_head_base(struct nv50_head *head, struct nv50_head_atom *asyh)
1515{
1516 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1517 u32 bounds = 0;
1518 u32 *push;
1519
1520 if (asyh->base.cpp) {
1521 switch (asyh->base.cpp) {
1522 case 8: bounds |= 0x00000500; break;
1523 case 4: bounds |= 0x00000300; break;
1524 case 2: bounds |= 0x00000100; break;
1525 case 1: bounds |= 0x00000000; break;
1526 default:
1527 WARN_ON(1);
1528 break;
1529 }
1530 bounds |= 0x00000001;
1531 }
1532
1533 if ((push = evo_wait(core, 2))) {
1534 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA)
1535 evo_mthd(push, 0x0900 + head->base.index * 0x400, 1);
1536 else
1537 evo_mthd(push, 0x04d0 + head->base.index * 0x300, 1);
1538 evo_data(push, bounds);
1539 evo_kick(push, core);
1540 }
1541}
1542
1543static void
Ben Skeggsea8ee392016-11-04 17:20:36 +10001544nv50_head_curs_clr(struct nv50_head *head)
1545{
1546 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1547 u32 *push;
1548 if ((push = evo_wait(core, 4))) {
1549 if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) {
1550 evo_mthd(push, 0x0880 + head->base.index * 0x400, 1);
1551 evo_data(push, 0x05000000);
1552 } else
1553 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1554 evo_mthd(push, 0x0880 + head->base.index * 0x400, 1);
1555 evo_data(push, 0x05000000);
1556 evo_mthd(push, 0x089c + head->base.index * 0x400, 1);
1557 evo_data(push, 0x00000000);
1558 } else {
1559 evo_mthd(push, 0x0480 + head->base.index * 0x300, 1);
1560 evo_data(push, 0x05000000);
1561 evo_mthd(push, 0x048c + head->base.index * 0x300, 1);
1562 evo_data(push, 0x00000000);
1563 }
1564 evo_kick(push, core);
1565 }
1566}
1567
1568static void
1569nv50_head_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1570{
1571 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1572 u32 *push;
1573 if ((push = evo_wait(core, 5))) {
1574 if (core->base.user.oclass < G82_DISP_BASE_CHANNEL_DMA) {
1575 evo_mthd(push, 0x0880 + head->base.index * 0x400, 2);
1576 evo_data(push, 0x80000000 | (asyh->curs.layout << 26) |
1577 (asyh->curs.format << 24));
1578 evo_data(push, asyh->curs.offset >> 8);
1579 } else
1580 if (core->base.user.oclass < GF110_DISP_BASE_CHANNEL_DMA) {
1581 evo_mthd(push, 0x0880 + head->base.index * 0x400, 2);
1582 evo_data(push, 0x80000000 | (asyh->curs.layout << 26) |
1583 (asyh->curs.format << 24));
1584 evo_data(push, asyh->curs.offset >> 8);
1585 evo_mthd(push, 0x089c + head->base.index * 0x400, 1);
1586 evo_data(push, asyh->curs.handle);
1587 } else {
1588 evo_mthd(push, 0x0480 + head->base.index * 0x300, 2);
1589 evo_data(push, 0x80000000 | (asyh->curs.layout << 26) |
1590 (asyh->curs.format << 24));
1591 evo_data(push, asyh->curs.offset >> 8);
1592 evo_mthd(push, 0x048c + head->base.index * 0x300, 1);
1593 evo_data(push, asyh->curs.handle);
1594 }
1595 evo_kick(push, core);
1596 }
1597}
1598
1599static void
Ben Skeggsad633612016-11-04 17:20:36 +10001600nv50_head_core_clr(struct nv50_head *head)
1601{
1602 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1603 u32 *push;
1604 if ((push = evo_wait(core, 2))) {
1605 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA)
1606 evo_mthd(push, 0x0874 + head->base.index * 0x400, 1);
1607 else
1608 evo_mthd(push, 0x0474 + head->base.index * 0x300, 1);
1609 evo_data(push, 0x00000000);
1610 evo_kick(push, core);
1611 }
1612}
1613
1614static void
1615nv50_head_core_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1616{
1617 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1618 u32 *push;
1619 if ((push = evo_wait(core, 9))) {
1620 if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) {
1621 evo_mthd(push, 0x0860 + head->base.index * 0x400, 1);
1622 evo_data(push, asyh->core.offset >> 8);
1623 evo_mthd(push, 0x0868 + head->base.index * 0x400, 4);
1624 evo_data(push, (asyh->core.h << 16) | asyh->core.w);
1625 evo_data(push, asyh->core.layout << 20 |
1626 (asyh->core.pitch >> 8) << 8 |
1627 asyh->core.block);
1628 evo_data(push, asyh->core.kind << 16 |
1629 asyh->core.format << 8);
1630 evo_data(push, asyh->core.handle);
1631 evo_mthd(push, 0x08c0 + head->base.index * 0x400, 1);
1632 evo_data(push, (asyh->core.y << 16) | asyh->core.x);
1633 } else
1634 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1635 evo_mthd(push, 0x0860 + head->base.index * 0x400, 1);
1636 evo_data(push, asyh->core.offset >> 8);
1637 evo_mthd(push, 0x0868 + head->base.index * 0x400, 4);
1638 evo_data(push, (asyh->core.h << 16) | asyh->core.w);
1639 evo_data(push, asyh->core.layout << 20 |
1640 (asyh->core.pitch >> 8) << 8 |
1641 asyh->core.block);
1642 evo_data(push, asyh->core.format << 8);
1643 evo_data(push, asyh->core.handle);
1644 evo_mthd(push, 0x08c0 + head->base.index * 0x400, 1);
1645 evo_data(push, (asyh->core.y << 16) | asyh->core.x);
1646 } else {
1647 evo_mthd(push, 0x0460 + head->base.index * 0x300, 1);
1648 evo_data(push, asyh->core.offset >> 8);
1649 evo_mthd(push, 0x0468 + head->base.index * 0x300, 4);
1650 evo_data(push, (asyh->core.h << 16) | asyh->core.w);
1651 evo_data(push, asyh->core.layout << 24 |
1652 (asyh->core.pitch >> 8) << 8 |
1653 asyh->core.block);
1654 evo_data(push, asyh->core.format << 8);
1655 evo_data(push, asyh->core.handle);
1656 evo_mthd(push, 0x04b0 + head->base.index * 0x300, 1);
1657 evo_data(push, (asyh->core.y << 16) | asyh->core.x);
1658 }
1659 evo_kick(push, core);
1660 }
1661}
1662
1663static void
Ben Skeggsa7ae1562016-11-04 17:20:36 +10001664nv50_head_lut_clr(struct nv50_head *head)
1665{
1666 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1667 u32 *push;
1668 if ((push = evo_wait(core, 4))) {
1669 if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) {
1670 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 1);
1671 evo_data(push, 0x40000000);
1672 } else
1673 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1674 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 1);
1675 evo_data(push, 0x40000000);
1676 evo_mthd(push, 0x085c + (head->base.index * 0x400), 1);
1677 evo_data(push, 0x00000000);
1678 } else {
1679 evo_mthd(push, 0x0440 + (head->base.index * 0x300), 1);
1680 evo_data(push, 0x03000000);
1681 evo_mthd(push, 0x045c + (head->base.index * 0x300), 1);
1682 evo_data(push, 0x00000000);
1683 }
1684 evo_kick(push, core);
1685 }
1686}
1687
1688static void
1689nv50_head_lut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1690{
1691 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1692 u32 *push;
1693 if ((push = evo_wait(core, 7))) {
1694 if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) {
1695 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2);
1696 evo_data(push, 0xc0000000);
1697 evo_data(push, asyh->lut.offset >> 8);
1698 } else
1699 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1700 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2);
1701 evo_data(push, 0xc0000000);
1702 evo_data(push, asyh->lut.offset >> 8);
1703 evo_mthd(push, 0x085c + (head->base.index * 0x400), 1);
1704 evo_data(push, asyh->lut.handle);
1705 } else {
1706 evo_mthd(push, 0x0440 + (head->base.index * 0x300), 4);
1707 evo_data(push, 0x83000000);
1708 evo_data(push, asyh->lut.offset >> 8);
1709 evo_data(push, 0x00000000);
1710 evo_data(push, 0x00000000);
1711 evo_mthd(push, 0x045c + (head->base.index * 0x300), 1);
1712 evo_data(push, asyh->lut.handle);
1713 }
1714 evo_kick(push, core);
1715 }
1716}
1717
1718static void
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001719nv50_head_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
1720{
1721 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1722 struct nv50_head_mode *m = &asyh->mode;
1723 u32 *push;
1724 if ((push = evo_wait(core, 14))) {
1725 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1726 evo_mthd(push, 0x0804 + (head->base.index * 0x400), 2);
1727 evo_data(push, 0x00800000 | m->clock);
1728 evo_data(push, m->interlace ? 0x00000002 : 0x00000000);
Ben Skeggs06ab2822016-11-04 17:20:36 +10001729 evo_mthd(push, 0x0810 + (head->base.index * 0x400), 7);
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001730 evo_data(push, 0x00000000);
1731 evo_data(push, (m->v.active << 16) | m->h.active );
1732 evo_data(push, (m->v.synce << 16) | m->h.synce );
1733 evo_data(push, (m->v.blanke << 16) | m->h.blanke );
1734 evo_data(push, (m->v.blanks << 16) | m->h.blanks );
1735 evo_data(push, (m->v.blank2e << 16) | m->v.blank2s);
Ben Skeggs06ab2822016-11-04 17:20:36 +10001736 evo_data(push, asyh->mode.v.blankus);
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001737 evo_mthd(push, 0x082c + (head->base.index * 0x400), 1);
1738 evo_data(push, 0x00000000);
1739 } else {
1740 evo_mthd(push, 0x0410 + (head->base.index * 0x300), 6);
1741 evo_data(push, 0x00000000);
1742 evo_data(push, (m->v.active << 16) | m->h.active );
1743 evo_data(push, (m->v.synce << 16) | m->h.synce );
1744 evo_data(push, (m->v.blanke << 16) | m->h.blanke );
1745 evo_data(push, (m->v.blanks << 16) | m->h.blanks );
1746 evo_data(push, (m->v.blank2e << 16) | m->v.blank2s);
1747 evo_mthd(push, 0x042c + (head->base.index * 0x300), 2);
1748 evo_data(push, 0x00000000); /* ??? */
1749 evo_data(push, 0xffffff00);
1750 evo_mthd(push, 0x0450 + (head->base.index * 0x300), 3);
1751 evo_data(push, m->clock * 1000);
1752 evo_data(push, 0x00200000); /* ??? */
1753 evo_data(push, m->clock * 1000);
1754 }
1755 evo_kick(push, core);
1756 }
1757}
1758
1759static void
Ben Skeggsc4e68122016-11-04 17:20:36 +10001760nv50_head_view(struct nv50_head *head, struct nv50_head_atom *asyh)
1761{
1762 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1763 u32 *push;
1764 if ((push = evo_wait(core, 10))) {
1765 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1766 evo_mthd(push, 0x08a4 + (head->base.index * 0x400), 1);
1767 evo_data(push, 0x00000000);
1768 evo_mthd(push, 0x08c8 + (head->base.index * 0x400), 1);
1769 evo_data(push, (asyh->view.iH << 16) | asyh->view.iW);
1770 evo_mthd(push, 0x08d8 + (head->base.index * 0x400), 2);
1771 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1772 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1773 } else {
1774 evo_mthd(push, 0x0494 + (head->base.index * 0x300), 1);
1775 evo_data(push, 0x00000000);
1776 evo_mthd(push, 0x04b8 + (head->base.index * 0x300), 1);
1777 evo_data(push, (asyh->view.iH << 16) | asyh->view.iW);
1778 evo_mthd(push, 0x04c0 + (head->base.index * 0x300), 3);
1779 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1780 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1781 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1782 }
1783 evo_kick(push, core);
1784 }
1785}
1786
1787static void
Ben Skeggsad633612016-11-04 17:20:36 +10001788nv50_head_flush_clr(struct nv50_head *head, struct nv50_head_atom *asyh, bool y)
1789{
1790 if (asyh->clr.core && (!asyh->set.core || y))
Ben Skeggsa7ae1562016-11-04 17:20:36 +10001791 nv50_head_lut_clr(head);
1792 if (asyh->clr.core && (!asyh->set.core || y))
Ben Skeggsad633612016-11-04 17:20:36 +10001793 nv50_head_core_clr(head);
Ben Skeggsea8ee392016-11-04 17:20:36 +10001794 if (asyh->clr.curs && (!asyh->set.curs || y))
1795 nv50_head_curs_clr(head);
Ben Skeggsad633612016-11-04 17:20:36 +10001796}
1797
1798static void
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001799nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1800{
Ben Skeggsc4e68122016-11-04 17:20:36 +10001801 if (asyh->set.view ) nv50_head_view (head, asyh);
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001802 if (asyh->set.mode ) nv50_head_mode (head, asyh);
Ben Skeggsa7ae1562016-11-04 17:20:36 +10001803 if (asyh->set.core ) nv50_head_lut_set (head, asyh);
Ben Skeggsad633612016-11-04 17:20:36 +10001804 if (asyh->set.core ) nv50_head_core_set(head, asyh);
Ben Skeggsea8ee392016-11-04 17:20:36 +10001805 if (asyh->set.curs ) nv50_head_curs_set(head, asyh);
Ben Skeggs6bbab3b2016-11-04 17:20:36 +10001806 if (asyh->set.base ) nv50_head_base (head, asyh);
1807 if (asyh->set.ovly ) nv50_head_ovly (head, asyh);
Ben Skeggs7e918332016-11-04 17:20:36 +10001808 if (asyh->set.dither ) nv50_head_dither (head, asyh);
Ben Skeggs7e08d672016-11-04 17:20:36 +10001809 if (asyh->set.procamp) nv50_head_procamp (head, asyh);
1810}
1811
1812static void
1813nv50_head_atomic_check_procamp(struct nv50_head_atom *armh,
1814 struct nv50_head_atom *asyh,
1815 struct nouveau_conn_atom *asyc)
1816{
1817 const int vib = asyc->procamp.color_vibrance - 100;
1818 const int hue = asyc->procamp.vibrant_hue - 90;
1819 const int adj = (vib > 0) ? 50 : 0;
1820 asyh->procamp.sat.cos = ((vib * 2047 + adj) / 100) & 0xfff;
1821 asyh->procamp.sat.sin = ((hue * 2047) / 100) & 0xfff;
1822 asyh->set.procamp = true;
Ben Skeggs7e918332016-11-04 17:20:36 +10001823}
1824
1825static void
1826nv50_head_atomic_check_dither(struct nv50_head_atom *armh,
1827 struct nv50_head_atom *asyh,
1828 struct nouveau_conn_atom *asyc)
1829{
1830 struct drm_connector *connector = asyc->state.connector;
1831 u32 mode = 0x00;
1832
1833 if (asyc->dither.mode == DITHERING_MODE_AUTO) {
1834 if (asyh->base.depth > connector->display_info.bpc * 3)
1835 mode = DITHERING_MODE_DYNAMIC2X2;
1836 } else {
1837 mode = asyc->dither.mode;
1838 }
1839
1840 if (asyc->dither.depth == DITHERING_DEPTH_AUTO) {
1841 if (connector->display_info.bpc >= 8)
1842 mode |= DITHERING_DEPTH_8BPC;
1843 } else {
1844 mode |= asyc->dither.depth;
1845 }
1846
1847 asyh->dither.enable = mode;
1848 asyh->dither.bits = mode >> 1;
1849 asyh->dither.mode = mode >> 3;
1850 asyh->set.dither = true;
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001851}
1852
1853static void
Ben Skeggsc4e68122016-11-04 17:20:36 +10001854nv50_head_atomic_check_view(struct nv50_head_atom *armh,
1855 struct nv50_head_atom *asyh,
1856 struct nouveau_conn_atom *asyc)
1857{
1858 struct drm_connector *connector = asyc->state.connector;
1859 struct drm_display_mode *omode = &asyh->state.adjusted_mode;
1860 struct drm_display_mode *umode = &asyh->state.mode;
1861 int mode = asyc->scaler.mode;
1862 struct edid *edid;
1863
1864 if (connector->edid_blob_ptr)
1865 edid = (struct edid *)connector->edid_blob_ptr->data;
1866 else
1867 edid = NULL;
1868
1869 if (!asyc->scaler.full) {
1870 if (mode == DRM_MODE_SCALE_NONE)
1871 omode = umode;
1872 } else {
1873 /* Non-EDID LVDS/eDP mode. */
1874 mode = DRM_MODE_SCALE_FULLSCREEN;
1875 }
1876
1877 asyh->view.iW = umode->hdisplay;
1878 asyh->view.iH = umode->vdisplay;
1879 asyh->view.oW = omode->hdisplay;
1880 asyh->view.oH = omode->vdisplay;
1881 if (omode->flags & DRM_MODE_FLAG_DBLSCAN)
1882 asyh->view.oH *= 2;
1883
1884 /* Add overscan compensation if necessary, will keep the aspect
1885 * ratio the same as the backend mode unless overridden by the
1886 * user setting both hborder and vborder properties.
1887 */
1888 if ((asyc->scaler.underscan.mode == UNDERSCAN_ON ||
1889 (asyc->scaler.underscan.mode == UNDERSCAN_AUTO &&
1890 drm_detect_hdmi_monitor(edid)))) {
1891 u32 bX = asyc->scaler.underscan.hborder;
1892 u32 bY = asyc->scaler.underscan.vborder;
1893 u32 r = (asyh->view.oH << 19) / asyh->view.oW;
1894
1895 if (bX) {
1896 asyh->view.oW -= (bX * 2);
1897 if (bY) asyh->view.oH -= (bY * 2);
1898 else asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19;
1899 } else {
1900 asyh->view.oW -= (asyh->view.oW >> 4) + 32;
1901 if (bY) asyh->view.oH -= (bY * 2);
1902 else asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19;
1903 }
1904 }
1905
1906 /* Handle CENTER/ASPECT scaling, taking into account the areas
1907 * removed already for overscan compensation.
1908 */
1909 switch (mode) {
1910 case DRM_MODE_SCALE_CENTER:
1911 asyh->view.oW = min((u16)umode->hdisplay, asyh->view.oW);
1912 asyh->view.oH = min((u16)umode->vdisplay, asyh->view.oH);
1913 /* fall-through */
1914 case DRM_MODE_SCALE_ASPECT:
1915 if (asyh->view.oH < asyh->view.oW) {
1916 u32 r = (asyh->view.iW << 19) / asyh->view.iH;
1917 asyh->view.oW = ((asyh->view.oH * r) + (r / 2)) >> 19;
1918 } else {
1919 u32 r = (asyh->view.iH << 19) / asyh->view.iW;
1920 asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19;
1921 }
1922 break;
1923 default:
1924 break;
1925 }
1926
1927 asyh->set.view = true;
1928}
1929
1930static void
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001931nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
1932{
1933 struct drm_display_mode *mode = &asyh->state.adjusted_mode;
1934 u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1;
1935 u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
1936 u32 hbackp = mode->htotal - mode->hsync_end;
1937 u32 vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace;
1938 u32 hfrontp = mode->hsync_start - mode->hdisplay;
1939 u32 vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
1940 struct nv50_head_mode *m = &asyh->mode;
1941
1942 m->h.active = mode->htotal;
1943 m->h.synce = mode->hsync_end - mode->hsync_start - 1;
1944 m->h.blanke = m->h.synce + hbackp;
1945 m->h.blanks = mode->htotal - hfrontp - 1;
1946
1947 m->v.active = mode->vtotal * vscan / ilace;
1948 m->v.synce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1;
1949 m->v.blanke = m->v.synce + vbackp;
1950 m->v.blanks = m->v.active - vfrontp - 1;
1951
1952 /*XXX: Safe underestimate, even "0" works */
1953 m->v.blankus = (m->v.active - mode->vdisplay - 2) * m->h.active;
1954 m->v.blankus *= 1000;
1955 m->v.blankus /= mode->clock;
1956
1957 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
1958 m->v.blank2e = m->v.active + m->v.synce + vbackp;
1959 m->v.blank2s = m->v.blank2e + (mode->vdisplay * vscan / ilace);
1960 m->v.active = (m->v.active * 2) + 1;
1961 m->interlace = true;
1962 } else {
1963 m->v.blank2e = 0;
1964 m->v.blank2s = 1;
1965 m->interlace = false;
1966 }
1967 m->clock = mode->clock;
1968
1969 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1970 asyh->set.mode = true;
1971}
1972
1973static int
1974nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
1975{
1976 struct nouveau_drm *drm = nouveau_drm(crtc->dev);
Ben Skeggsad633612016-11-04 17:20:36 +10001977 struct nv50_disp *disp = nv50_disp(crtc->dev);
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001978 struct nv50_head *head = nv50_head(crtc);
1979 struct nv50_head_atom *armh = &head->arm;
1980 struct nv50_head_atom *asyh = nv50_head_atom(state);
1981
1982 NV_ATOMIC(drm, "%s atomic_check %d\n", crtc->name, asyh->state.active);
Ben Skeggsad633612016-11-04 17:20:36 +10001983 asyh->clr.mask = 0;
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001984 asyh->set.mask = 0;
1985
1986 if (asyh->state.active) {
1987 if (asyh->state.mode_changed)
1988 nv50_head_atomic_check_mode(head, asyh);
Ben Skeggsad633612016-11-04 17:20:36 +10001989
1990 if ((asyh->core.visible = (asyh->base.cpp != 0))) {
1991 asyh->core.x = asyh->base.x;
1992 asyh->core.y = asyh->base.y;
1993 asyh->core.w = asyh->base.w;
1994 asyh->core.h = asyh->base.h;
1995 } else
Ben Skeggsea8ee392016-11-04 17:20:36 +10001996 if ((asyh->core.visible = asyh->curs.visible)) {
Ben Skeggsad633612016-11-04 17:20:36 +10001997 /*XXX: We need to either find some way of having the
1998 * primary base layer appear black, while still
1999 * being able to display the other layers, or we
2000 * need to allocate a dummy black surface here.
2001 */
2002 asyh->core.x = 0;
2003 asyh->core.y = 0;
2004 asyh->core.w = asyh->state.mode.hdisplay;
2005 asyh->core.h = asyh->state.mode.vdisplay;
2006 }
2007 asyh->core.handle = disp->mast.base.vram.handle;
2008 asyh->core.offset = 0;
2009 asyh->core.format = 0xcf;
2010 asyh->core.kind = 0;
2011 asyh->core.layout = 1;
2012 asyh->core.block = 0;
2013 asyh->core.pitch = ALIGN(asyh->core.w, 64) * 4;
Ben Skeggsa7ae1562016-11-04 17:20:36 +10002014 asyh->lut.handle = disp->mast.base.vram.handle;
2015 asyh->lut.offset = head->base.lut.nvbo->bo.offset;
Ben Skeggs6bbab3b2016-11-04 17:20:36 +10002016 asyh->set.base = armh->base.cpp != asyh->base.cpp;
2017 asyh->set.ovly = armh->ovly.cpp != asyh->ovly.cpp;
Ben Skeggsad633612016-11-04 17:20:36 +10002018 } else {
2019 asyh->core.visible = false;
Ben Skeggsea8ee392016-11-04 17:20:36 +10002020 asyh->curs.visible = false;
Ben Skeggs6bbab3b2016-11-04 17:20:36 +10002021 asyh->base.cpp = 0;
2022 asyh->ovly.cpp = 0;
Ben Skeggsad633612016-11-04 17:20:36 +10002023 }
2024
2025 if (!drm_atomic_crtc_needs_modeset(&asyh->state)) {
2026 if (asyh->core.visible) {
2027 if (memcmp(&armh->core, &asyh->core, sizeof(asyh->core)))
2028 asyh->set.core = true;
2029 } else
2030 if (armh->core.visible) {
2031 asyh->clr.core = true;
2032 }
Ben Skeggsea8ee392016-11-04 17:20:36 +10002033
2034 if (asyh->curs.visible) {
2035 if (memcmp(&armh->curs, &asyh->curs, sizeof(asyh->curs)))
2036 asyh->set.curs = true;
2037 } else
2038 if (armh->curs.visible) {
2039 asyh->clr.curs = true;
2040 }
Ben Skeggsad633612016-11-04 17:20:36 +10002041 } else {
2042 asyh->clr.core = armh->core.visible;
Ben Skeggsea8ee392016-11-04 17:20:36 +10002043 asyh->clr.curs = armh->curs.visible;
Ben Skeggsad633612016-11-04 17:20:36 +10002044 asyh->set.core = asyh->core.visible;
Ben Skeggsea8ee392016-11-04 17:20:36 +10002045 asyh->set.curs = asyh->curs.visible;
Ben Skeggs3dbd0362016-11-04 17:20:36 +10002046 }
2047
2048 memcpy(armh, asyh, sizeof(*asyh));
2049 asyh->state.mode_changed = 0;
2050 return 0;
2051}
2052
2053/******************************************************************************
Ben Skeggs438d99e2011-07-05 16:48:06 +10002054 * CRTC
2055 *****************************************************************************/
2056static int
Ben Skeggse225f442012-11-21 14:40:21 +10002057nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002058{
Ben Skeggse225f442012-11-21 14:40:21 +10002059 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggs7e918332016-11-04 17:20:36 +10002060 struct nv50_head *head = nv50_head(&nv_crtc->base);
2061 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggsde691852011-10-17 12:23:41 +10002062 struct nouveau_connector *nv_connector;
Ben Skeggs7e918332016-11-04 17:20:36 +10002063 struct nouveau_conn_atom asyc;
2064 u32 *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002065
Ben Skeggs488ff202011-10-17 10:38:10 +10002066 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggsde691852011-10-17 12:23:41 +10002067
Ben Skeggs7e918332016-11-04 17:20:36 +10002068 asyc.state.connector = &nv_connector->base;
2069 asyc.dither.mode = nv_connector->dithering_mode;
2070 asyc.dither.depth = nv_connector->dithering_depth;
2071 asyh->state.crtc = &nv_crtc->base;
2072 nv50_head_atomic_check(&head->base.base, &asyh->state);
2073 nv50_head_atomic_check_dither(&head->arm, asyh, &asyc);
2074 nv50_head_flush_set(head, asyh);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002075
Ben Skeggs7e918332016-11-04 17:20:36 +10002076 if (update) {
2077 if ((push = evo_wait(mast, 2))) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10002078 evo_mthd(push, 0x0080, 1);
2079 evo_data(push, 0x00000000);
Ben Skeggs7e918332016-11-04 17:20:36 +10002080 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002081 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10002082 }
2083
2084 return 0;
2085}
2086
2087static int
Ben Skeggse225f442012-11-21 14:40:21 +10002088nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002089{
Ben Skeggsc4e68122016-11-04 17:20:36 +10002090 struct nv50_head *head = nv50_head(&nv_crtc->base);
2091 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggs3376ee32011-11-12 14:28:12 +10002092 struct drm_crtc *crtc = &nv_crtc->base;
Ben Skeggsf3fdc522011-07-07 16:01:57 +10002093 struct nouveau_connector *nv_connector;
Ben Skeggsc4e68122016-11-04 17:20:36 +10002094 struct nouveau_conn_atom asyc;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002095
Ben Skeggsf3fdc522011-07-07 16:01:57 +10002096 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggsf3fdc522011-07-07 16:01:57 +10002097
Ben Skeggsc4e68122016-11-04 17:20:36 +10002098 asyc.state.connector = &nv_connector->base;
2099 asyc.scaler.mode = nv_connector->scaling_mode;
2100 asyc.scaler.full = nv_connector->scaling_full;
2101 asyc.scaler.underscan.mode = nv_connector->underscan;
2102 asyc.scaler.underscan.hborder = nv_connector->underscan_hborder;
2103 asyc.scaler.underscan.vborder = nv_connector->underscan_vborder;
2104 nv50_head_atomic_check(&head->base.base, &asyh->state);
2105 nv50_head_atomic_check_view(&head->arm, asyh, &asyc);
2106 nv50_head_flush_set(head, asyh);
Ben Skeggs92854622011-11-11 23:49:06 +10002107
Ben Skeggsc4e68122016-11-04 17:20:36 +10002108 if (update) {
2109 nv50_display_flip_stop(crtc);
2110 nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002111 }
2112
2113 return 0;
2114}
2115
2116static int
Ben Skeggse225f442012-11-21 14:40:21 +10002117nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggsf9887d02012-11-21 13:03:42 +10002118{
Ben Skeggse225f442012-11-21 14:40:21 +10002119 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggs7e08d672016-11-04 17:20:36 +10002120 struct nv50_head *head = nv50_head(&nv_crtc->base);
2121 struct nv50_head_atom *asyh = &head->asy;
2122 struct nouveau_conn_atom asyc;
2123 u32 *push;
Ben Skeggsf9887d02012-11-21 13:03:42 +10002124
Ben Skeggs7e08d672016-11-04 17:20:36 +10002125 asyc.procamp.color_vibrance = nv_crtc->color_vibrance + 100;
2126 asyc.procamp.vibrant_hue = nv_crtc->vibrant_hue + 90;
2127 nv50_head_atomic_check(&head->base.base, &asyh->state);
2128 nv50_head_atomic_check_procamp(&head->arm, asyh, &asyc);
2129 nv50_head_flush_set(head, asyh);
Ben Skeggsf9887d02012-11-21 13:03:42 +10002130
Ben Skeggs7e08d672016-11-04 17:20:36 +10002131 if (update) {
2132 if ((push = evo_wait(mast, 2))) {
Ben Skeggsf9887d02012-11-21 13:03:42 +10002133 evo_mthd(push, 0x0080, 1);
2134 evo_data(push, 0x00000000);
Ben Skeggs7e08d672016-11-04 17:20:36 +10002135 evo_kick(push, mast);
Ben Skeggsf9887d02012-11-21 13:03:42 +10002136 }
Ben Skeggsf9887d02012-11-21 13:03:42 +10002137 }
2138
2139 return 0;
2140}
2141
2142static int
Ben Skeggse225f442012-11-21 14:40:21 +10002143nv50_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002144 int x, int y, bool update)
2145{
2146 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb);
Ben Skeggsad633612016-11-04 17:20:36 +10002147 struct nv50_head *head = nv50_head(&nv_crtc->base);
2148 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggs973f10c2016-11-04 17:20:36 +10002149 struct nv50_wndw_atom *asyw = &head->_base->wndw.asy;
Ben Skeggsad633612016-11-04 17:20:36 +10002150 const struct drm_format_info *info;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002151
Ben Skeggsad633612016-11-04 17:20:36 +10002152 info = drm_format_info(nvfb->base.pixel_format);
2153 if (!info || !info->depth)
2154 return -EINVAL;
Ben Skeggsde8268c2012-11-16 10:24:31 +10002155
Ben Skeggsad633612016-11-04 17:20:36 +10002156 asyh->base.depth = info->depth;
2157 asyh->base.cpp = info->cpp[0];
2158 asyh->base.x = x;
2159 asyh->base.y = y;
2160 asyh->base.w = nvfb->base.width;
2161 asyh->base.h = nvfb->base.height;
Ben Skeggs973f10c2016-11-04 17:20:36 +10002162 asyw->state.src_x = x << 16;
2163 asyw->state.src_y = y << 16;
Ben Skeggsad633612016-11-04 17:20:36 +10002164 nv50_head_atomic_check(&head->base.base, &asyh->state);
2165 nv50_head_flush_set(head, asyh);
2166
2167 if (update) {
2168 struct nv50_mast *core = nv50_mast(nv_crtc->base.dev);
2169 u32 *push = evo_wait(core, 2);
2170 if (push) {
Ben Skeggsa46232e2011-07-07 15:23:48 +10002171 evo_mthd(push, 0x0080, 1);
2172 evo_data(push, 0x00000000);
Ben Skeggsad633612016-11-04 17:20:36 +10002173 evo_kick(push, core);
Ben Skeggsa46232e2011-07-07 15:23:48 +10002174 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10002175 }
2176
Ben Skeggs8a423642014-08-10 04:10:19 +10002177 nv_crtc->fb.handle = nvfb->r_handle;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002178 return 0;
2179}
2180
2181static void
Ben Skeggse225f442012-11-21 14:40:21 +10002182nv50_crtc_cursor_show(struct nouveau_crtc *nv_crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002183{
Ben Skeggse225f442012-11-21 14:40:21 +10002184 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsea8ee392016-11-04 17:20:36 +10002185 struct nv50_head *head = nv50_head(&nv_crtc->base);
2186 struct nv50_head_atom *asyh = &head->asy;
2187
2188 asyh->curs.visible = true;
2189 asyh->curs.handle = mast->base.vram.handle;
2190 asyh->curs.offset = nv_crtc->cursor.nvbo->bo.offset;
2191 asyh->curs.layout = 1;
2192 asyh->curs.format = 1;
2193 nv50_head_atomic_check(&head->base.base, &asyh->state);
2194 nv50_head_flush_set(head, asyh);
Ben Skeggsde8268c2012-11-16 10:24:31 +10002195}
2196
2197static void
Ben Skeggse225f442012-11-21 14:40:21 +10002198nv50_crtc_cursor_hide(struct nouveau_crtc *nv_crtc)
Ben Skeggsde8268c2012-11-16 10:24:31 +10002199{
Ben Skeggsea8ee392016-11-04 17:20:36 +10002200 struct nv50_head *head = nv50_head(&nv_crtc->base);
2201 struct nv50_head_atom *asyh = &head->asy;
2202
2203 asyh->curs.visible = false;
2204 nv50_head_atomic_check(&head->base.base, &asyh->state);
2205 nv50_head_flush_clr(head, asyh, false);
Ben Skeggsde8268c2012-11-16 10:24:31 +10002206}
Ben Skeggs438d99e2011-07-05 16:48:06 +10002207
Ben Skeggsde8268c2012-11-16 10:24:31 +10002208static void
Ben Skeggse225f442012-11-21 14:40:21 +10002209nv50_crtc_cursor_show_hide(struct nouveau_crtc *nv_crtc, bool show, bool update)
Ben Skeggsde8268c2012-11-16 10:24:31 +10002210{
Ben Skeggse225f442012-11-21 14:40:21 +10002211 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde8268c2012-11-16 10:24:31 +10002212
Ben Skeggs697bb722015-07-28 17:20:57 +10002213 if (show && nv_crtc->cursor.nvbo && nv_crtc->base.enabled)
Ben Skeggse225f442012-11-21 14:40:21 +10002214 nv50_crtc_cursor_show(nv_crtc);
Ben Skeggsde8268c2012-11-16 10:24:31 +10002215 else
Ben Skeggse225f442012-11-21 14:40:21 +10002216 nv50_crtc_cursor_hide(nv_crtc);
Ben Skeggsde8268c2012-11-16 10:24:31 +10002217
2218 if (update) {
2219 u32 *push = evo_wait(mast, 2);
2220 if (push) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10002221 evo_mthd(push, 0x0080, 1);
2222 evo_data(push, 0x00000000);
Ben Skeggsde8268c2012-11-16 10:24:31 +10002223 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002224 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10002225 }
2226}
2227
2228static void
Ben Skeggse225f442012-11-21 14:40:21 +10002229nv50_crtc_dpms(struct drm_crtc *crtc, int mode)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002230{
2231}
2232
2233static void
Ben Skeggse225f442012-11-21 14:40:21 +10002234nv50_crtc_prepare(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002235{
Ben Skeggsad633612016-11-04 17:20:36 +10002236 struct nv50_head *head = nv50_head(crtc);
2237 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002238
Ben Skeggse225f442012-11-21 14:40:21 +10002239 nv50_display_flip_stop(crtc);
Ben Skeggs3376ee32011-11-12 14:28:12 +10002240
Ben Skeggsad633612016-11-04 17:20:36 +10002241 asyh->state.active = false;
2242 nv50_head_atomic_check(&head->base.base, &asyh->state);
2243 nv50_head_flush_clr(head, asyh, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002244}
2245
2246static void
Ben Skeggse225f442012-11-21 14:40:21 +10002247nv50_crtc_commit(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002248{
Ben Skeggsa7ae1562016-11-04 17:20:36 +10002249 struct nv50_head *head = nv50_head(crtc);
2250 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002251
Ben Skeggsa7ae1562016-11-04 17:20:36 +10002252 asyh->state.active = true;
2253 nv50_head_atomic_check(&head->base.base, &asyh->state);
2254 nv50_head_flush_set(head, asyh);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002255
Matt Roperf4510a22014-04-01 15:22:40 -07002256 nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002257}
2258
2259static bool
Ben Skeggse225f442012-11-21 14:40:21 +10002260nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002261 struct drm_display_mode *adjusted_mode)
2262{
Ben Skeggseb2e9682014-01-24 10:13:23 +10002263 drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002264 return true;
2265}
2266
2267static int
Ben Skeggse225f442012-11-21 14:40:21 +10002268nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002269{
Matt Roperf4510a22014-04-01 15:22:40 -07002270 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002271 struct nv50_head *head = nv50_head(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002272 int ret;
2273
Ben Skeggs547ad072014-11-10 12:35:06 +10002274 ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM, true);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002275 if (ret == 0) {
2276 if (head->image)
2277 nouveau_bo_unpin(head->image);
2278 nouveau_bo_ref(nvfb->nvbo, &head->image);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002279 }
2280
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002281 return ret;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002282}
2283
2284static int
Ben Skeggse225f442012-11-21 14:40:21 +10002285nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002286 struct drm_display_mode *mode, int x, int y,
2287 struct drm_framebuffer *old_fb)
2288{
2289 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
2290 struct nouveau_connector *nv_connector;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002291 int ret;
Ben Skeggs3dbd0362016-11-04 17:20:36 +10002292 struct nv50_head *head = nv50_head(crtc);
2293 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002294
Ben Skeggs3dbd0362016-11-04 17:20:36 +10002295 memcpy(&asyh->state.mode, umode, sizeof(*umode));
2296 memcpy(&asyh->state.adjusted_mode, mode, sizeof(*mode));
2297 asyh->state.active = true;
2298 asyh->state.mode_changed = true;
2299 nv50_head_atomic_check(&head->base.base, &asyh->state);
Ben Skeggs2d1d8982011-11-11 23:39:22 +10002300
Ben Skeggse225f442012-11-21 14:40:21 +10002301 ret = nv50_crtc_swap_fbs(crtc, old_fb);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002302 if (ret)
2303 return ret;
2304
Ben Skeggs3dbd0362016-11-04 17:20:36 +10002305 nv50_head_flush_set(head, asyh);
2306
Ben Skeggs438d99e2011-07-05 16:48:06 +10002307 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10002308 nv50_crtc_set_dither(nv_crtc, false);
2309 nv50_crtc_set_scale(nv_crtc, false);
Roy Splieteae73822014-10-30 22:57:45 +01002310
Ben Skeggse225f442012-11-21 14:40:21 +10002311 nv50_crtc_set_color_vibrance(nv_crtc, false);
Matt Roperf4510a22014-04-01 15:22:40 -07002312 nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002313 return 0;
2314}
2315
2316static int
Ben Skeggse225f442012-11-21 14:40:21 +10002317nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002318 struct drm_framebuffer *old_fb)
2319{
Ben Skeggs77145f12012-07-31 16:16:21 +10002320 struct nouveau_drm *drm = nouveau_drm(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002321 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
2322 int ret;
2323
Matt Roperf4510a22014-04-01 15:22:40 -07002324 if (!crtc->primary->fb) {
Ben Skeggs77145f12012-07-31 16:16:21 +10002325 NV_DEBUG(drm, "No FB bound\n");
Ben Skeggs84e2ad82011-08-26 09:40:39 +10002326 return 0;
2327 }
2328
Ben Skeggse225f442012-11-21 14:40:21 +10002329 ret = nv50_crtc_swap_fbs(crtc, old_fb);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002330 if (ret)
2331 return ret;
2332
Ben Skeggse225f442012-11-21 14:40:21 +10002333 nv50_display_flip_stop(crtc);
Matt Roperf4510a22014-04-01 15:22:40 -07002334 nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, true);
2335 nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002336 return 0;
2337}
2338
2339static int
Ben Skeggse225f442012-11-21 14:40:21 +10002340nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002341 struct drm_framebuffer *fb, int x, int y,
2342 enum mode_set_atomic state)
2343{
2344 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10002345 nv50_display_flip_stop(crtc);
2346 nv50_crtc_set_image(nv_crtc, fb, x, y, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002347 return 0;
2348}
2349
2350static void
Ben Skeggse225f442012-11-21 14:40:21 +10002351nv50_crtc_lut_load(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002352{
Ben Skeggse225f442012-11-21 14:40:21 +10002353 struct nv50_disp *disp = nv50_disp(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002354 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
2355 void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
2356 int i;
2357
2358 for (i = 0; i < 256; i++) {
Ben Skeggsde8268c2012-11-16 10:24:31 +10002359 u16 r = nv_crtc->lut.r[i] >> 2;
2360 u16 g = nv_crtc->lut.g[i] >> 2;
2361 u16 b = nv_crtc->lut.b[i] >> 2;
2362
Ben Skeggs648d4df2014-08-10 04:10:27 +10002363 if (disp->disp->oclass < GF110_DISP) {
Ben Skeggsde8268c2012-11-16 10:24:31 +10002364 writew(r + 0x0000, lut + (i * 0x08) + 0);
2365 writew(g + 0x0000, lut + (i * 0x08) + 2);
2366 writew(b + 0x0000, lut + (i * 0x08) + 4);
2367 } else {
2368 writew(r + 0x6000, lut + (i * 0x20) + 0);
2369 writew(g + 0x6000, lut + (i * 0x20) + 2);
2370 writew(b + 0x6000, lut + (i * 0x20) + 4);
2371 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10002372 }
2373}
2374
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002375static void
2376nv50_crtc_disable(struct drm_crtc *crtc)
2377{
2378 struct nv50_head *head = nv50_head(crtc);
Ben Skeggsefa366f2014-06-05 12:56:35 +10002379 evo_sync(crtc->dev);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002380 if (head->image)
2381 nouveau_bo_unpin(head->image);
2382 nouveau_bo_ref(NULL, &head->image);
2383}
2384
Ben Skeggs438d99e2011-07-05 16:48:06 +10002385static int
Ben Skeggse225f442012-11-21 14:40:21 +10002386nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002387 uint32_t handle, uint32_t width, uint32_t height)
2388{
2389 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggs5a560252014-11-10 15:52:02 +10002390 struct drm_gem_object *gem = NULL;
2391 struct nouveau_bo *nvbo = NULL;
2392 int ret = 0;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002393
Ben Skeggs5a560252014-11-10 15:52:02 +10002394 if (handle) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10002395 if (width != 64 || height != 64)
2396 return -EINVAL;
2397
Chris Wilsona8ad0bd2016-05-09 11:04:54 +01002398 gem = drm_gem_object_lookup(file_priv, handle);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002399 if (unlikely(!gem))
2400 return -ENOENT;
2401 nvbo = nouveau_gem_object(gem);
2402
Ben Skeggs5a560252014-11-10 15:52:02 +10002403 ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002404 }
2405
Ben Skeggs5a560252014-11-10 15:52:02 +10002406 if (ret == 0) {
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01002407 if (nv_crtc->cursor.nvbo)
2408 nouveau_bo_unpin(nv_crtc->cursor.nvbo);
2409 nouveau_bo_ref(nvbo, &nv_crtc->cursor.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002410 }
Ben Skeggs5a560252014-11-10 15:52:02 +10002411 drm_gem_object_unreference_unlocked(gem);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002412
Ben Skeggs5a560252014-11-10 15:52:02 +10002413 nv50_crtc_cursor_show_hide(nv_crtc, true, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002414 return ret;
2415}
2416
2417static int
Ben Skeggse225f442012-11-21 14:40:21 +10002418nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002419{
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01002420 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10002421 struct nv50_curs *curs = nv50_curs(crtc);
2422 struct nv50_chan *chan = nv50_chan(curs);
Ben Skeggs0ad72862014-08-10 04:10:22 +10002423 nvif_wr32(&chan->user, 0x0084, (y << 16) | (x & 0xffff));
2424 nvif_wr32(&chan->user, 0x0080, 0x00000000);
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01002425
2426 nv_crtc->cursor_saved_x = x;
2427 nv_crtc->cursor_saved_y = y;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002428 return 0;
2429}
2430
Maarten Lankhorst7ea77282016-06-07 12:49:30 +02002431static int
Ben Skeggse225f442012-11-21 14:40:21 +10002432nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
Maarten Lankhorst7ea77282016-06-07 12:49:30 +02002433 uint32_t size)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002434{
2435 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002436 u32 i;
2437
Maarten Lankhorst7ea77282016-06-07 12:49:30 +02002438 for (i = 0; i < size; i++) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10002439 nv_crtc->lut.r[i] = r[i];
2440 nv_crtc->lut.g[i] = g[i];
2441 nv_crtc->lut.b[i] = b[i];
2442 }
2443
Ben Skeggse225f442012-11-21 14:40:21 +10002444 nv50_crtc_lut_load(crtc);
Maarten Lankhorst7ea77282016-06-07 12:49:30 +02002445
2446 return 0;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002447}
2448
2449static void
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01002450nv50_crtc_cursor_restore(struct nouveau_crtc *nv_crtc, int x, int y)
2451{
2452 nv50_crtc_cursor_move(&nv_crtc->base, x, y);
2453
2454 nv50_crtc_cursor_show_hide(nv_crtc, true, true);
2455}
2456
2457static void
Ben Skeggse225f442012-11-21 14:40:21 +10002458nv50_crtc_destroy(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002459{
2460 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10002461 struct nv50_disp *disp = nv50_disp(crtc->dev);
2462 struct nv50_head *head = nv50_head(crtc);
Ben Skeggs0ad72862014-08-10 04:10:22 +10002463 struct nv50_fbdma *fbdma;
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002464
Ben Skeggs0ad72862014-08-10 04:10:22 +10002465 list_for_each_entry(fbdma, &disp->fbdma, head) {
2466 nvif_object_fini(&fbdma->base[nv_crtc->index]);
2467 }
2468
2469 nv50_dmac_destroy(&head->ovly.base, disp->disp);
2470 nv50_pioc_destroy(&head->oimm.base);
Ben Skeggs0ad72862014-08-10 04:10:22 +10002471 nv50_pioc_destroy(&head->curs.base);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002472
2473 /*XXX: this shouldn't be necessary, but the core doesn't call
2474 * disconnect() during the cleanup paths
2475 */
2476 if (head->image)
2477 nouveau_bo_unpin(head->image);
2478 nouveau_bo_ref(NULL, &head->image);
2479
Ben Skeggs5a560252014-11-10 15:52:02 +10002480 /*XXX: ditto */
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01002481 if (nv_crtc->cursor.nvbo)
2482 nouveau_bo_unpin(nv_crtc->cursor.nvbo);
2483 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002484
Ben Skeggs438d99e2011-07-05 16:48:06 +10002485 nouveau_bo_unmap(nv_crtc->lut.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01002486 if (nv_crtc->lut.nvbo)
2487 nouveau_bo_unpin(nv_crtc->lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002488 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002489
Ben Skeggs438d99e2011-07-05 16:48:06 +10002490 drm_crtc_cleanup(crtc);
2491 kfree(crtc);
2492}
2493
Ben Skeggse225f442012-11-21 14:40:21 +10002494static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = {
2495 .dpms = nv50_crtc_dpms,
2496 .prepare = nv50_crtc_prepare,
2497 .commit = nv50_crtc_commit,
2498 .mode_fixup = nv50_crtc_mode_fixup,
2499 .mode_set = nv50_crtc_mode_set,
2500 .mode_set_base = nv50_crtc_mode_set_base,
2501 .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
2502 .load_lut = nv50_crtc_lut_load,
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002503 .disable = nv50_crtc_disable,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002504};
2505
Ben Skeggse225f442012-11-21 14:40:21 +10002506static const struct drm_crtc_funcs nv50_crtc_func = {
2507 .cursor_set = nv50_crtc_cursor_set,
2508 .cursor_move = nv50_crtc_cursor_move,
2509 .gamma_set = nv50_crtc_gamma_set,
Dave Airlie5addcf02012-09-10 14:20:51 +10002510 .set_config = nouveau_crtc_set_config,
Ben Skeggse225f442012-11-21 14:40:21 +10002511 .destroy = nv50_crtc_destroy,
Ben Skeggs3376ee32011-11-12 14:28:12 +10002512 .page_flip = nouveau_crtc_page_flip,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002513};
2514
2515static int
Ben Skeggs0ad72862014-08-10 04:10:22 +10002516nv50_crtc_create(struct drm_device *dev, int index)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002517{
Ben Skeggsa01ca782015-08-20 14:54:15 +10002518 struct nouveau_drm *drm = nouveau_drm(dev);
2519 struct nvif_device *device = &drm->device;
Ben Skeggse225f442012-11-21 14:40:21 +10002520 struct nv50_disp *disp = nv50_disp(dev);
2521 struct nv50_head *head;
Ben Skeggs973f10c2016-11-04 17:20:36 +10002522 struct nv50_base *base;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002523 struct drm_crtc *crtc;
2524 int ret, i;
2525
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10002526 head = kzalloc(sizeof(*head), GFP_KERNEL);
2527 if (!head)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002528 return -ENOMEM;
2529
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10002530 head->base.index = index;
Ben Skeggsf9887d02012-11-21 13:03:42 +10002531 head->base.color_vibrance = 50;
2532 head->base.vibrant_hue = 0;
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01002533 head->base.cursor.set_pos = nv50_crtc_cursor_restore;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002534 for (i = 0; i < 256; i++) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10002535 head->base.lut.r[i] = i << 8;
2536 head->base.lut.g[i] = i << 8;
2537 head->base.lut.b[i] = i << 8;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002538 }
2539
Ben Skeggs973f10c2016-11-04 17:20:36 +10002540 ret = nv50_base_new(drm, head, &base);
2541 if (ret) {
2542 kfree(head);
2543 return ret;
2544 }
2545
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10002546 crtc = &head->base.base;
Ben Skeggs973f10c2016-11-04 17:20:36 +10002547 head->_base = base;
2548
Ben Skeggse225f442012-11-21 14:40:21 +10002549 drm_crtc_init(dev, crtc, &nv50_crtc_func);
2550 drm_crtc_helper_add(crtc, &nv50_crtc_hfunc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002551 drm_mode_crtc_set_gamma_size(crtc, 256);
2552
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +10002553 ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
Maarten Lankhorstbb6178b2014-01-09 11:03:15 +01002554 0, 0x0000, NULL, NULL, &head->base.lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002555 if (!ret) {
Ben Skeggs547ad072014-11-10 12:35:06 +10002556 ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM, true);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01002557 if (!ret) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10002558 ret = nouveau_bo_map(head->base.lut.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01002559 if (ret)
2560 nouveau_bo_unpin(head->base.lut.nvbo);
2561 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10002562 if (ret)
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10002563 nouveau_bo_ref(NULL, &head->base.lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002564 }
2565
2566 if (ret)
2567 goto out;
2568
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002569 /* allocate cursor resources */
Ben Skeggsa01ca782015-08-20 14:54:15 +10002570 ret = nv50_curs_create(device, disp->disp, index, &head->curs);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002571 if (ret)
2572 goto out;
2573
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002574 /* allocate overlay resources */
Ben Skeggsa01ca782015-08-20 14:54:15 +10002575 ret = nv50_oimm_create(device, disp->disp, index, &head->oimm);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002576 if (ret)
2577 goto out;
2578
Ben Skeggsa01ca782015-08-20 14:54:15 +10002579 ret = nv50_ovly_create(device, disp->disp, index, disp->sync->bo.offset,
2580 &head->ovly);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002581 if (ret)
2582 goto out;
2583
Ben Skeggs438d99e2011-07-05 16:48:06 +10002584out:
2585 if (ret)
Ben Skeggse225f442012-11-21 14:40:21 +10002586 nv50_crtc_destroy(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002587 return ret;
2588}
2589
2590/******************************************************************************
Ben Skeggsa91d3222014-12-22 16:30:13 +10002591 * Encoder helpers
2592 *****************************************************************************/
2593static bool
2594nv50_encoder_mode_fixup(struct drm_encoder *encoder,
2595 const struct drm_display_mode *mode,
2596 struct drm_display_mode *adjusted_mode)
2597{
2598 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2599 struct nouveau_connector *nv_connector;
2600
2601 nv_connector = nouveau_encoder_connector_get(nv_encoder);
2602 if (nv_connector && nv_connector->native_mode) {
Ben Skeggs576f7912014-12-22 17:19:26 +10002603 nv_connector->scaling_full = false;
2604 if (nv_connector->scaling_mode == DRM_MODE_SCALE_NONE) {
2605 switch (nv_connector->type) {
2606 case DCB_CONNECTOR_LVDS:
2607 case DCB_CONNECTOR_LVDS_SPWG:
2608 case DCB_CONNECTOR_eDP:
2609 /* force use of scaler for non-edid modes */
2610 if (adjusted_mode->type & DRM_MODE_TYPE_DRIVER)
2611 return true;
2612 nv_connector->scaling_full = true;
2613 break;
2614 default:
2615 return true;
2616 }
2617 }
2618
2619 drm_mode_copy(adjusted_mode, nv_connector->native_mode);
Ben Skeggsa91d3222014-12-22 16:30:13 +10002620 }
2621
2622 return true;
2623}
2624
2625/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10002626 * DAC
2627 *****************************************************************************/
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002628static void
Ben Skeggse225f442012-11-21 14:40:21 +10002629nv50_dac_dpms(struct drm_encoder *encoder, int mode)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002630{
2631 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10002632 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggsbf0eb892014-08-10 04:10:26 +10002633 struct {
2634 struct nv50_disp_mthd_v1 base;
2635 struct nv50_disp_dac_pwr_v0 pwr;
2636 } args = {
2637 .base.version = 1,
2638 .base.method = NV50_DISP_MTHD_V1_DAC_PWR,
2639 .base.hasht = nv_encoder->dcb->hasht,
2640 .base.hashm = nv_encoder->dcb->hashm,
2641 .pwr.state = 1,
2642 .pwr.data = 1,
2643 .pwr.vsync = (mode != DRM_MODE_DPMS_SUSPEND &&
2644 mode != DRM_MODE_DPMS_OFF),
2645 .pwr.hsync = (mode != DRM_MODE_DPMS_STANDBY &&
2646 mode != DRM_MODE_DPMS_OFF),
2647 };
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002648
Ben Skeggsbf0eb892014-08-10 04:10:26 +10002649 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002650}
2651
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002652static void
Ben Skeggse225f442012-11-21 14:40:21 +10002653nv50_dac_commit(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002654{
2655}
2656
2657static void
Ben Skeggse225f442012-11-21 14:40:21 +10002658nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002659 struct drm_display_mode *adjusted_mode)
2660{
Ben Skeggse225f442012-11-21 14:40:21 +10002661 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002662 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2663 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs97b19b52012-11-16 11:21:37 +10002664 u32 *push;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002665
Ben Skeggse225f442012-11-21 14:40:21 +10002666 nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002667
Ben Skeggs97b19b52012-11-16 11:21:37 +10002668 push = evo_wait(mast, 8);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002669 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10002670 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggs97b19b52012-11-16 11:21:37 +10002671 u32 syncs = 0x00000000;
2672
2673 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
2674 syncs |= 0x00000001;
2675 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
2676 syncs |= 0x00000002;
2677
2678 evo_mthd(push, 0x0400 + (nv_encoder->or * 0x080), 2);
2679 evo_data(push, 1 << nv_crtc->index);
2680 evo_data(push, syncs);
2681 } else {
2682 u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
2683 u32 syncs = 0x00000001;
2684
2685 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
2686 syncs |= 0x00000008;
2687 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
2688 syncs |= 0x00000010;
2689
2690 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
2691 magic |= 0x00000001;
2692
2693 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
2694 evo_data(push, syncs);
2695 evo_data(push, magic);
2696 evo_mthd(push, 0x0180 + (nv_encoder->or * 0x020), 1);
2697 evo_data(push, 1 << nv_crtc->index);
2698 }
2699
2700 evo_kick(push, mast);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002701 }
2702
2703 nv_encoder->crtc = encoder->crtc;
2704}
2705
2706static void
Ben Skeggse225f442012-11-21 14:40:21 +10002707nv50_dac_disconnect(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002708{
2709 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10002710 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs97b19b52012-11-16 11:21:37 +10002711 const int or = nv_encoder->or;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002712 u32 *push;
2713
2714 if (nv_encoder->crtc) {
Ben Skeggse225f442012-11-21 14:40:21 +10002715 nv50_crtc_prepare(nv_encoder->crtc);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002716
Ben Skeggs97b19b52012-11-16 11:21:37 +10002717 push = evo_wait(mast, 4);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002718 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10002719 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggs97b19b52012-11-16 11:21:37 +10002720 evo_mthd(push, 0x0400 + (or * 0x080), 1);
2721 evo_data(push, 0x00000000);
2722 } else {
2723 evo_mthd(push, 0x0180 + (or * 0x020), 1);
2724 evo_data(push, 0x00000000);
2725 }
Ben Skeggs97b19b52012-11-16 11:21:37 +10002726 evo_kick(push, mast);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002727 }
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002728 }
Ben Skeggs97b19b52012-11-16 11:21:37 +10002729
2730 nv_encoder->crtc = NULL;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002731}
2732
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10002733static enum drm_connector_status
Ben Skeggse225f442012-11-21 14:40:21 +10002734nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10002735{
Ben Skeggsc4abd312014-08-10 04:10:26 +10002736 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10002737 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggsc4abd312014-08-10 04:10:26 +10002738 struct {
2739 struct nv50_disp_mthd_v1 base;
2740 struct nv50_disp_dac_load_v0 load;
2741 } args = {
2742 .base.version = 1,
2743 .base.method = NV50_DISP_MTHD_V1_DAC_LOAD,
2744 .base.hasht = nv_encoder->dcb->hasht,
2745 .base.hashm = nv_encoder->dcb->hashm,
2746 };
2747 int ret;
Ben Skeggsb6819932011-07-08 11:14:50 +10002748
Ben Skeggsc4abd312014-08-10 04:10:26 +10002749 args.load.data = nouveau_drm(encoder->dev)->vbios.dactestval;
2750 if (args.load.data == 0)
2751 args.load.data = 340;
2752
2753 ret = nvif_mthd(disp->disp, 0, &args, sizeof(args));
2754 if (ret || !args.load.load)
Ben Skeggs35b21d32012-11-08 12:08:55 +10002755 return connector_status_disconnected;
Ben Skeggsb6819932011-07-08 11:14:50 +10002756
Ben Skeggs35b21d32012-11-08 12:08:55 +10002757 return connector_status_connected;
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10002758}
2759
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002760static void
Ben Skeggse225f442012-11-21 14:40:21 +10002761nv50_dac_destroy(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002762{
2763 drm_encoder_cleanup(encoder);
2764 kfree(encoder);
2765}
2766
Ben Skeggse225f442012-11-21 14:40:21 +10002767static const struct drm_encoder_helper_funcs nv50_dac_hfunc = {
2768 .dpms = nv50_dac_dpms,
Ben Skeggsa91d3222014-12-22 16:30:13 +10002769 .mode_fixup = nv50_encoder_mode_fixup,
Ben Skeggse225f442012-11-21 14:40:21 +10002770 .prepare = nv50_dac_disconnect,
2771 .commit = nv50_dac_commit,
2772 .mode_set = nv50_dac_mode_set,
2773 .disable = nv50_dac_disconnect,
2774 .get_crtc = nv50_display_crtc_get,
2775 .detect = nv50_dac_detect
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002776};
2777
Ben Skeggse225f442012-11-21 14:40:21 +10002778static const struct drm_encoder_funcs nv50_dac_func = {
2779 .destroy = nv50_dac_destroy,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002780};
2781
2782static int
Ben Skeggse225f442012-11-21 14:40:21 +10002783nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002784{
Ben Skeggs5ed50202013-02-11 20:15:03 +10002785 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +10002786 struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10002787 struct nvkm_i2c_bus *bus;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002788 struct nouveau_encoder *nv_encoder;
2789 struct drm_encoder *encoder;
Ben Skeggs5ed50202013-02-11 20:15:03 +10002790 int type = DRM_MODE_ENCODER_DAC;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002791
2792 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
2793 if (!nv_encoder)
2794 return -ENOMEM;
2795 nv_encoder->dcb = dcbe;
2796 nv_encoder->or = ffs(dcbe->or) - 1;
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10002797
2798 bus = nvkm_i2c_bus_find(i2c, dcbe->i2c_index);
2799 if (bus)
2800 nv_encoder->i2c = &bus->i2c;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002801
2802 encoder = to_drm_encoder(nv_encoder);
2803 encoder->possible_crtcs = dcbe->heads;
2804 encoder->possible_clones = 0;
Ben Skeggs5a223da2016-11-04 17:20:36 +10002805 drm_encoder_init(connector->dev, encoder, &nv50_dac_func, type,
2806 "dac-%04x-%04x", dcbe->hasht, dcbe->hashm);
Ben Skeggse225f442012-11-21 14:40:21 +10002807 drm_encoder_helper_add(encoder, &nv50_dac_hfunc);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002808
2809 drm_mode_connector_attach_encoder(connector, encoder);
2810 return 0;
2811}
Ben Skeggs26f6d882011-07-04 16:25:18 +10002812
2813/******************************************************************************
Ben Skeggs78951d22011-11-11 18:13:13 +10002814 * Audio
2815 *****************************************************************************/
2816static void
Ben Skeggse225f442012-11-21 14:40:21 +10002817nv50_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
Ben Skeggs78951d22011-11-11 18:13:13 +10002818{
2819 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggscc2a9072014-09-15 21:29:05 +10002820 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs78951d22011-11-11 18:13:13 +10002821 struct nouveau_connector *nv_connector;
Ben Skeggse225f442012-11-21 14:40:21 +10002822 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggsd889c522014-09-15 21:11:51 +10002823 struct __packed {
2824 struct {
2825 struct nv50_disp_mthd_v1 mthd;
2826 struct nv50_disp_sor_hda_eld_v0 eld;
2827 } base;
Ben Skeggs120b0c32014-08-10 04:10:26 +10002828 u8 data[sizeof(nv_connector->base.eld)];
2829 } args = {
Ben Skeggsd889c522014-09-15 21:11:51 +10002830 .base.mthd.version = 1,
2831 .base.mthd.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
2832 .base.mthd.hasht = nv_encoder->dcb->hasht,
Ben Skeggscc2a9072014-09-15 21:29:05 +10002833 .base.mthd.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
2834 (0x0100 << nv_crtc->index),
Ben Skeggs120b0c32014-08-10 04:10:26 +10002835 };
Ben Skeggs78951d22011-11-11 18:13:13 +10002836
2837 nv_connector = nouveau_encoder_connector_get(nv_encoder);
2838 if (!drm_detect_monitor_audio(nv_connector->edid))
2839 return;
2840
Ben Skeggs78951d22011-11-11 18:13:13 +10002841 drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
Ben Skeggs120b0c32014-08-10 04:10:26 +10002842 memcpy(args.data, nv_connector->base.eld, sizeof(args.data));
Ben Skeggs78951d22011-11-11 18:13:13 +10002843
Jani Nikula938fd8a2014-10-28 16:20:48 +02002844 nvif_mthd(disp->disp, 0, &args,
2845 sizeof(args.base) + drm_eld_size(args.data));
Ben Skeggs78951d22011-11-11 18:13:13 +10002846}
2847
2848static void
Ben Skeggscc2a9072014-09-15 21:29:05 +10002849nv50_audio_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
Ben Skeggs78951d22011-11-11 18:13:13 +10002850{
2851 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10002852 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs120b0c32014-08-10 04:10:26 +10002853 struct {
2854 struct nv50_disp_mthd_v1 base;
2855 struct nv50_disp_sor_hda_eld_v0 eld;
2856 } args = {
2857 .base.version = 1,
2858 .base.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
2859 .base.hasht = nv_encoder->dcb->hasht,
Ben Skeggscc2a9072014-09-15 21:29:05 +10002860 .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
2861 (0x0100 << nv_crtc->index),
Ben Skeggs120b0c32014-08-10 04:10:26 +10002862 };
Ben Skeggs78951d22011-11-11 18:13:13 +10002863
Ben Skeggs120b0c32014-08-10 04:10:26 +10002864 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs78951d22011-11-11 18:13:13 +10002865}
2866
2867/******************************************************************************
2868 * HDMI
2869 *****************************************************************************/
2870static void
Ben Skeggse225f442012-11-21 14:40:21 +10002871nv50_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
Ben Skeggs78951d22011-11-11 18:13:13 +10002872{
Ben Skeggs64d9cc02011-11-11 19:51:20 +10002873 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2874 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10002875 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggse00f2232014-08-10 04:10:26 +10002876 struct {
2877 struct nv50_disp_mthd_v1 base;
2878 struct nv50_disp_sor_hdmi_pwr_v0 pwr;
2879 } args = {
2880 .base.version = 1,
2881 .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR,
2882 .base.hasht = nv_encoder->dcb->hasht,
2883 .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
2884 (0x0100 << nv_crtc->index),
2885 .pwr.state = 1,
2886 .pwr.rekey = 56, /* binary driver, and tegra, constant */
2887 };
2888 struct nouveau_connector *nv_connector;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10002889 u32 max_ac_packet;
2890
2891 nv_connector = nouveau_encoder_connector_get(nv_encoder);
2892 if (!drm_detect_hdmi_monitor(nv_connector->edid))
2893 return;
2894
2895 max_ac_packet = mode->htotal - mode->hdisplay;
Ben Skeggse00f2232014-08-10 04:10:26 +10002896 max_ac_packet -= args.pwr.rekey;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10002897 max_ac_packet -= 18; /* constant from tegra */
Ben Skeggse00f2232014-08-10 04:10:26 +10002898 args.pwr.max_ac_packet = max_ac_packet / 32;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10002899
Ben Skeggse00f2232014-08-10 04:10:26 +10002900 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggse225f442012-11-21 14:40:21 +10002901 nv50_audio_mode_set(encoder, mode);
Ben Skeggs78951d22011-11-11 18:13:13 +10002902}
2903
2904static void
Ben Skeggse84a35a2014-06-05 10:59:55 +10002905nv50_hdmi_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
Ben Skeggs78951d22011-11-11 18:13:13 +10002906{
Ben Skeggs64d9cc02011-11-11 19:51:20 +10002907 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10002908 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggse00f2232014-08-10 04:10:26 +10002909 struct {
2910 struct nv50_disp_mthd_v1 base;
2911 struct nv50_disp_sor_hdmi_pwr_v0 pwr;
2912 } args = {
2913 .base.version = 1,
2914 .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR,
2915 .base.hasht = nv_encoder->dcb->hasht,
2916 .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
2917 (0x0100 << nv_crtc->index),
2918 };
Ben Skeggs64d9cc02011-11-11 19:51:20 +10002919
Ben Skeggse00f2232014-08-10 04:10:26 +10002920 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs78951d22011-11-11 18:13:13 +10002921}
2922
2923/******************************************************************************
Ben Skeggs52aa30f2016-11-04 17:20:36 +10002924 * MST
2925 *****************************************************************************/
2926struct nv50_mstm {
2927 struct nouveau_encoder *outp;
2928
2929 struct drm_dp_mst_topology_mgr mgr;
2930};
2931
2932static int
2933nv50_mstm_enable(struct nv50_mstm *mstm, u8 dpcd, int state)
2934{
2935 struct nouveau_encoder *outp = mstm->outp;
2936 struct {
2937 struct nv50_disp_mthd_v1 base;
2938 struct nv50_disp_sor_dp_mst_link_v0 mst;
2939 } args = {
2940 .base.version = 1,
2941 .base.method = NV50_DISP_MTHD_V1_SOR_DP_MST_LINK,
2942 .base.hasht = outp->dcb->hasht,
2943 .base.hashm = outp->dcb->hashm,
2944 .mst.state = state,
2945 };
2946 struct nouveau_drm *drm = nouveau_drm(outp->base.base.dev);
2947 struct nvif_object *disp = &drm->display->disp;
2948 int ret;
2949
2950 if (dpcd >= 0x12) {
2951 ret = drm_dp_dpcd_readb(mstm->mgr.aux, DP_MSTM_CTRL, &dpcd);
2952 if (ret < 0)
2953 return ret;
2954
2955 dpcd &= ~DP_MST_EN;
2956 if (state)
2957 dpcd |= DP_MST_EN;
2958
2959 ret = drm_dp_dpcd_writeb(mstm->mgr.aux, DP_MSTM_CTRL, dpcd);
2960 if (ret < 0)
2961 return ret;
2962 }
2963
2964 return nvif_mthd(disp, 0, &args, sizeof(args));
2965}
2966
2967int
2968nv50_mstm_detect(struct nv50_mstm *mstm, u8 dpcd[8], int allow)
2969{
2970 int ret, state = 0;
2971
2972 if (!mstm)
2973 return 0;
2974
2975 if (dpcd[0] >= 0x12 && allow) {
2976 ret = drm_dp_dpcd_readb(mstm->mgr.aux, DP_MSTM_CAP, &dpcd[1]);
2977 if (ret < 0)
2978 return ret;
2979
2980 state = dpcd[1] & DP_MST_CAP;
2981 }
2982
2983 ret = nv50_mstm_enable(mstm, dpcd[0], state);
2984 if (ret)
2985 return ret;
2986
2987 ret = drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, state);
2988 if (ret)
2989 return nv50_mstm_enable(mstm, dpcd[0], 0);
2990
2991 return mstm->mgr.mst_state;
2992}
2993
2994static void
2995nv50_mstm_del(struct nv50_mstm **pmstm)
2996{
2997 struct nv50_mstm *mstm = *pmstm;
2998 if (mstm) {
2999 kfree(*pmstm);
3000 *pmstm = NULL;
3001 }
3002}
3003
3004static int
3005nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max,
3006 int conn_base_id, struct nv50_mstm **pmstm)
3007{
3008 const int max_payloads = hweight8(outp->dcb->heads);
3009 struct drm_device *dev = outp->base.base.dev;
3010 struct nv50_mstm *mstm;
3011 int ret;
3012
3013 if (!(mstm = *pmstm = kzalloc(sizeof(*mstm), GFP_KERNEL)))
3014 return -ENOMEM;
3015 mstm->outp = outp;
3016
3017 ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev->dev, aux, aux_max,
3018 max_payloads, conn_base_id);
3019 if (ret)
3020 return ret;
3021
3022 return 0;
3023}
3024
3025/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10003026 * SOR
3027 *****************************************************************************/
Ben Skeggs6e83fda2012-03-11 01:28:48 +10003028static void
Ben Skeggse225f442012-11-21 14:40:21 +10003029nv50_sor_dpms(struct drm_encoder *encoder, int mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +10003030{
3031 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggsd55b4af2014-08-10 04:10:26 +10003032 struct nv50_disp *disp = nv50_disp(encoder->dev);
3033 struct {
3034 struct nv50_disp_mthd_v1 base;
3035 struct nv50_disp_sor_pwr_v0 pwr;
3036 } args = {
3037 .base.version = 1,
3038 .base.method = NV50_DISP_MTHD_V1_SOR_PWR,
3039 .base.hasht = nv_encoder->dcb->hasht,
3040 .base.hashm = nv_encoder->dcb->hashm,
3041 .pwr.state = mode == DRM_MODE_DPMS_ON,
3042 };
Ben Skeggsc02ed2b2014-08-10 04:10:27 +10003043 struct {
3044 struct nv50_disp_mthd_v1 base;
3045 struct nv50_disp_sor_dp_pwr_v0 pwr;
3046 } link = {
3047 .base.version = 1,
3048 .base.method = NV50_DISP_MTHD_V1_SOR_DP_PWR,
3049 .base.hasht = nv_encoder->dcb->hasht,
3050 .base.hashm = nv_encoder->dcb->hashm,
3051 .pwr.state = mode == DRM_MODE_DPMS_ON,
3052 };
Ben Skeggs83fc0832011-07-05 13:08:40 +10003053 struct drm_device *dev = encoder->dev;
3054 struct drm_encoder *partner;
Ben Skeggs83fc0832011-07-05 13:08:40 +10003055
3056 nv_encoder->last_dpms = mode;
3057
3058 list_for_each_entry(partner, &dev->mode_config.encoder_list, head) {
3059 struct nouveau_encoder *nv_partner = nouveau_encoder(partner);
3060
3061 if (partner->encoder_type != DRM_MODE_ENCODER_TMDS)
3062 continue;
3063
3064 if (nv_partner != nv_encoder &&
Ben Skeggs26cfa812011-11-17 09:10:02 +10003065 nv_partner->dcb->or == nv_encoder->dcb->or) {
Ben Skeggs83fc0832011-07-05 13:08:40 +10003066 if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
3067 return;
3068 break;
3069 }
3070 }
3071
Ben Skeggs48743222014-05-31 01:48:06 +10003072 if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
Ben Skeggsd55b4af2014-08-10 04:10:26 +10003073 args.pwr.state = 1;
3074 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggsc02ed2b2014-08-10 04:10:27 +10003075 nvif_mthd(disp->disp, 0, &link, sizeof(link));
Ben Skeggs48743222014-05-31 01:48:06 +10003076 } else {
Ben Skeggsd55b4af2014-08-10 04:10:26 +10003077 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs48743222014-05-31 01:48:06 +10003078 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10003079}
3080
Ben Skeggs83fc0832011-07-05 13:08:40 +10003081static void
Ben Skeggse84a35a2014-06-05 10:59:55 +10003082nv50_sor_ctrl(struct nouveau_encoder *nv_encoder, u32 mask, u32 data)
3083{
3084 struct nv50_mast *mast = nv50_mast(nv_encoder->base.base.dev);
3085 u32 temp = (nv_encoder->ctrl & ~mask) | (data & mask), *push;
3086 if (temp != nv_encoder->ctrl && (push = evo_wait(mast, 2))) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10003087 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggse84a35a2014-06-05 10:59:55 +10003088 evo_mthd(push, 0x0600 + (nv_encoder->or * 0x40), 1);
3089 evo_data(push, (nv_encoder->ctrl = temp));
3090 } else {
3091 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
3092 evo_data(push, (nv_encoder->ctrl = temp));
3093 }
3094 evo_kick(push, mast);
3095 }
3096}
3097
3098static void
Ben Skeggse225f442012-11-21 14:40:21 +10003099nv50_sor_disconnect(struct drm_encoder *encoder)
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10003100{
3101 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse84a35a2014-06-05 10:59:55 +10003102 struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003103
3104 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
3105 nv_encoder->crtc = NULL;
Ben Skeggse84a35a2014-06-05 10:59:55 +10003106
3107 if (nv_crtc) {
3108 nv50_crtc_prepare(&nv_crtc->base);
3109 nv50_sor_ctrl(nv_encoder, 1 << nv_crtc->index, 0);
Ben Skeggscc2a9072014-09-15 21:29:05 +10003110 nv50_audio_disconnect(encoder, nv_crtc);
Ben Skeggse84a35a2014-06-05 10:59:55 +10003111 nv50_hdmi_disconnect(&nv_encoder->base.base, nv_crtc);
3112 }
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10003113}
3114
3115static void
Ben Skeggse225f442012-11-21 14:40:21 +10003116nv50_sor_commit(struct drm_encoder *encoder)
Ben Skeggs83fc0832011-07-05 13:08:40 +10003117{
3118}
3119
3120static void
Ben Skeggse225f442012-11-21 14:40:21 +10003121nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003122 struct drm_display_mode *mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +10003123{
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003124 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
3125 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
3126 struct {
3127 struct nv50_disp_mthd_v1 base;
3128 struct nv50_disp_sor_lvds_script_v0 lvds;
3129 } lvds = {
3130 .base.version = 1,
3131 .base.method = NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT,
3132 .base.hasht = nv_encoder->dcb->hasht,
3133 .base.hashm = nv_encoder->dcb->hashm,
3134 };
Ben Skeggse225f442012-11-21 14:40:21 +10003135 struct nv50_disp *disp = nv50_disp(encoder->dev);
3136 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs78951d22011-11-11 18:13:13 +10003137 struct drm_device *dev = encoder->dev;
Ben Skeggs77145f12012-07-31 16:16:21 +10003138 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003139 struct nouveau_connector *nv_connector;
Ben Skeggs77145f12012-07-31 16:16:21 +10003140 struct nvbios *bios = &drm->vbios;
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003141 u32 mask, ctrl;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003142 u8 owner = 1 << nv_crtc->index;
3143 u8 proto = 0xf;
3144 u8 depth = 0x0;
Ben Skeggs83fc0832011-07-05 13:08:40 +10003145
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003146 nv_connector = nouveau_encoder_connector_get(nv_encoder);
Ben Skeggse84a35a2014-06-05 10:59:55 +10003147 nv_encoder->crtc = encoder->crtc;
3148
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003149 switch (nv_encoder->dcb->type) {
Ben Skeggscb75d972012-07-11 10:44:20 +10003150 case DCB_OUTPUT_TMDS:
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003151 if (nv_encoder->dcb->sorconf.link & 1) {
Hauke Mehrtens16ef53a92015-11-03 21:00:10 -05003152 proto = 0x1;
3153 /* Only enable dual-link if:
3154 * - Need to (i.e. rate > 165MHz)
3155 * - DCB says we can
3156 * - Not an HDMI monitor, since there's no dual-link
3157 * on HDMI.
3158 */
3159 if (mode->clock >= 165000 &&
3160 nv_encoder->dcb->duallink_possible &&
3161 !drm_detect_hdmi_monitor(nv_connector->edid))
3162 proto |= 0x4;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003163 } else {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003164 proto = 0x2;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003165 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10003166
Ben Skeggse84a35a2014-06-05 10:59:55 +10003167 nv50_hdmi_mode_set(&nv_encoder->base.base, mode);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003168 break;
Ben Skeggscb75d972012-07-11 10:44:20 +10003169 case DCB_OUTPUT_LVDS:
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003170 proto = 0x0;
3171
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003172 if (bios->fp_no_ddc) {
3173 if (bios->fp.dual_link)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003174 lvds.lvds.script |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003175 if (bios->fp.if_is_24bit)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003176 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003177 } else {
Ben Skeggsbefb51e2011-11-18 10:23:59 +10003178 if (nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003179 if (((u8 *)nv_connector->edid)[121] == 2)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003180 lvds.lvds.script |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003181 } else
3182 if (mode->clock >= bios->fp.duallink_transition_clk) {
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003183 lvds.lvds.script |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003184 }
3185
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003186 if (lvds.lvds.script & 0x0100) {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003187 if (bios->fp.strapless_is_24bit & 2)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003188 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003189 } else {
3190 if (bios->fp.strapless_is_24bit & 1)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003191 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003192 }
3193
3194 if (nv_connector->base.display_info.bpc == 8)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003195 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003196 }
Ben Skeggs4a230fa2012-11-09 11:25:37 +10003197
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003198 nvif_mthd(disp->disp, 0, &lvds, sizeof(lvds));
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003199 break;
Ben Skeggscb75d972012-07-11 10:44:20 +10003200 case DCB_OUTPUT_DP:
Ben Skeggs3488c572012-03-12 11:42:20 +10003201 if (nv_connector->base.display_info.bpc == 6) {
Ben Skeggs6e83fda2012-03-11 01:28:48 +10003202 nv_encoder->dp.datarate = mode->clock * 18 / 8;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003203 depth = 0x2;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10003204 } else
3205 if (nv_connector->base.display_info.bpc == 8) {
Ben Skeggs6e83fda2012-03-11 01:28:48 +10003206 nv_encoder->dp.datarate = mode->clock * 24 / 8;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003207 depth = 0x5;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10003208 } else {
3209 nv_encoder->dp.datarate = mode->clock * 30 / 8;
3210 depth = 0x6;
Ben Skeggs3488c572012-03-12 11:42:20 +10003211 }
Ben Skeggs6e83fda2012-03-11 01:28:48 +10003212
3213 if (nv_encoder->dcb->sorconf.link & 1)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003214 proto = 0x8;
Ben Skeggs6e83fda2012-03-11 01:28:48 +10003215 else
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003216 proto = 0x9;
Ben Skeggs3eee8642014-09-15 15:20:47 +10003217 nv50_audio_mode_set(encoder, mode);
Ben Skeggs6e83fda2012-03-11 01:28:48 +10003218 break;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003219 default:
3220 BUG_ON(1);
3221 break;
3222 }
Ben Skeggsff8ff502011-07-08 11:53:37 +10003223
Ben Skeggse84a35a2014-06-05 10:59:55 +10003224 nv50_sor_dpms(&nv_encoder->base.base, DRM_MODE_DPMS_ON);
Ben Skeggs83fc0832011-07-05 13:08:40 +10003225
Ben Skeggs648d4df2014-08-10 04:10:27 +10003226 if (nv50_vers(mast) >= GF110_DISP) {
Ben Skeggse84a35a2014-06-05 10:59:55 +10003227 u32 *push = evo_wait(mast, 3);
3228 if (push) {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003229 u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
3230 u32 syncs = 0x00000001;
3231
3232 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
3233 syncs |= 0x00000008;
3234 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
3235 syncs |= 0x00000010;
3236
3237 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
3238 magic |= 0x00000001;
3239
3240 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
3241 evo_data(push, syncs | (depth << 6));
3242 evo_data(push, magic);
Ben Skeggse84a35a2014-06-05 10:59:55 +10003243 evo_kick(push, mast);
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003244 }
3245
Ben Skeggse84a35a2014-06-05 10:59:55 +10003246 ctrl = proto << 8;
3247 mask = 0x00000f00;
3248 } else {
3249 ctrl = (depth << 16) | (proto << 8);
3250 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
3251 ctrl |= 0x00001000;
3252 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
3253 ctrl |= 0x00002000;
3254 mask = 0x000f3f00;
Ben Skeggs83fc0832011-07-05 13:08:40 +10003255 }
3256
Ben Skeggse84a35a2014-06-05 10:59:55 +10003257 nv50_sor_ctrl(nv_encoder, mask | owner, ctrl | owner);
Ben Skeggs83fc0832011-07-05 13:08:40 +10003258}
3259
3260static void
Ben Skeggse225f442012-11-21 14:40:21 +10003261nv50_sor_destroy(struct drm_encoder *encoder)
Ben Skeggs83fc0832011-07-05 13:08:40 +10003262{
Ben Skeggs52aa30f2016-11-04 17:20:36 +10003263 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
3264 nv50_mstm_del(&nv_encoder->dp.mstm);
Ben Skeggs83fc0832011-07-05 13:08:40 +10003265 drm_encoder_cleanup(encoder);
3266 kfree(encoder);
3267}
3268
Ben Skeggse225f442012-11-21 14:40:21 +10003269static const struct drm_encoder_helper_funcs nv50_sor_hfunc = {
3270 .dpms = nv50_sor_dpms,
Ben Skeggsa91d3222014-12-22 16:30:13 +10003271 .mode_fixup = nv50_encoder_mode_fixup,
Ben Skeggs5a885f02013-02-20 14:34:18 +10003272 .prepare = nv50_sor_disconnect,
Ben Skeggse225f442012-11-21 14:40:21 +10003273 .commit = nv50_sor_commit,
3274 .mode_set = nv50_sor_mode_set,
3275 .disable = nv50_sor_disconnect,
3276 .get_crtc = nv50_display_crtc_get,
Ben Skeggs83fc0832011-07-05 13:08:40 +10003277};
3278
Ben Skeggse225f442012-11-21 14:40:21 +10003279static const struct drm_encoder_funcs nv50_sor_func = {
3280 .destroy = nv50_sor_destroy,
Ben Skeggs83fc0832011-07-05 13:08:40 +10003281};
3282
3283static int
Ben Skeggse225f442012-11-21 14:40:21 +10003284nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
Ben Skeggs83fc0832011-07-05 13:08:40 +10003285{
Ben Skeggs52aa30f2016-11-04 17:20:36 +10003286 struct nouveau_connector *nv_connector = nouveau_connector(connector);
Ben Skeggs5ed50202013-02-11 20:15:03 +10003287 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +10003288 struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
Ben Skeggs83fc0832011-07-05 13:08:40 +10003289 struct nouveau_encoder *nv_encoder;
3290 struct drm_encoder *encoder;
Ben Skeggs52aa30f2016-11-04 17:20:36 +10003291 int type, ret;
Ben Skeggs5ed50202013-02-11 20:15:03 +10003292
3293 switch (dcbe->type) {
3294 case DCB_OUTPUT_LVDS: type = DRM_MODE_ENCODER_LVDS; break;
3295 case DCB_OUTPUT_TMDS:
3296 case DCB_OUTPUT_DP:
3297 default:
3298 type = DRM_MODE_ENCODER_TMDS;
3299 break;
3300 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10003301
3302 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
3303 if (!nv_encoder)
3304 return -ENOMEM;
3305 nv_encoder->dcb = dcbe;
3306 nv_encoder->or = ffs(dcbe->or) - 1;
3307 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
3308
Ben Skeggs52aa30f2016-11-04 17:20:36 +10003309 encoder = to_drm_encoder(nv_encoder);
3310 encoder->possible_crtcs = dcbe->heads;
3311 encoder->possible_clones = 0;
Ben Skeggs5a223da2016-11-04 17:20:36 +10003312 drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type,
3313 "sor-%04x-%04x", dcbe->hasht, dcbe->hashm);
Ben Skeggs52aa30f2016-11-04 17:20:36 +10003314 drm_encoder_helper_add(encoder, &nv50_sor_hfunc);
3315
3316 drm_mode_connector_attach_encoder(connector, encoder);
3317
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10003318 if (dcbe->type == DCB_OUTPUT_DP) {
3319 struct nvkm_i2c_aux *aux =
3320 nvkm_i2c_aux_find(i2c, dcbe->i2c_index);
3321 if (aux) {
3322 nv_encoder->i2c = &aux->i2c;
3323 nv_encoder->aux = aux;
3324 }
Ben Skeggs52aa30f2016-11-04 17:20:36 +10003325
3326 /*TODO: Use DP Info Table to check for support. */
3327 if (nv50_disp(encoder->dev)->disp->oclass >= GF110_DISP) {
3328 ret = nv50_mstm_new(nv_encoder, &nv_connector->aux, 16,
3329 nv_connector->base.base.id,
3330 &nv_encoder->dp.mstm);
3331 if (ret)
3332 return ret;
3333 }
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10003334 } else {
3335 struct nvkm_i2c_bus *bus =
3336 nvkm_i2c_bus_find(i2c, dcbe->i2c_index);
3337 if (bus)
3338 nv_encoder->i2c = &bus->i2c;
3339 }
3340
Ben Skeggs83fc0832011-07-05 13:08:40 +10003341 return 0;
3342}
Ben Skeggs26f6d882011-07-04 16:25:18 +10003343
3344/******************************************************************************
Ben Skeggseb6313a2013-02-11 09:52:58 +10003345 * PIOR
3346 *****************************************************************************/
3347
3348static void
3349nv50_pior_dpms(struct drm_encoder *encoder, int mode)
3350{
3351 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
3352 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs67cb49c2014-08-10 04:10:27 +10003353 struct {
3354 struct nv50_disp_mthd_v1 base;
3355 struct nv50_disp_pior_pwr_v0 pwr;
3356 } args = {
3357 .base.version = 1,
3358 .base.method = NV50_DISP_MTHD_V1_PIOR_PWR,
3359 .base.hasht = nv_encoder->dcb->hasht,
3360 .base.hashm = nv_encoder->dcb->hashm,
3361 .pwr.state = mode == DRM_MODE_DPMS_ON,
3362 .pwr.type = nv_encoder->dcb->type,
3363 };
3364
3365 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggseb6313a2013-02-11 09:52:58 +10003366}
3367
3368static bool
3369nv50_pior_mode_fixup(struct drm_encoder *encoder,
3370 const struct drm_display_mode *mode,
3371 struct drm_display_mode *adjusted_mode)
3372{
Ben Skeggsa91d3222014-12-22 16:30:13 +10003373 if (!nv50_encoder_mode_fixup(encoder, mode, adjusted_mode))
3374 return false;
Ben Skeggseb6313a2013-02-11 09:52:58 +10003375 adjusted_mode->clock *= 2;
3376 return true;
3377}
3378
3379static void
3380nv50_pior_commit(struct drm_encoder *encoder)
3381{
3382}
3383
3384static void
3385nv50_pior_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
3386 struct drm_display_mode *adjusted_mode)
3387{
3388 struct nv50_mast *mast = nv50_mast(encoder->dev);
3389 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
3390 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
3391 struct nouveau_connector *nv_connector;
3392 u8 owner = 1 << nv_crtc->index;
3393 u8 proto, depth;
3394 u32 *push;
3395
3396 nv_connector = nouveau_encoder_connector_get(nv_encoder);
3397 switch (nv_connector->base.display_info.bpc) {
3398 case 10: depth = 0x6; break;
3399 case 8: depth = 0x5; break;
3400 case 6: depth = 0x2; break;
3401 default: depth = 0x0; break;
3402 }
3403
3404 switch (nv_encoder->dcb->type) {
3405 case DCB_OUTPUT_TMDS:
3406 case DCB_OUTPUT_DP:
3407 proto = 0x0;
3408 break;
3409 default:
3410 BUG_ON(1);
3411 break;
3412 }
3413
3414 nv50_pior_dpms(encoder, DRM_MODE_DPMS_ON);
3415
3416 push = evo_wait(mast, 8);
3417 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10003418 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggseb6313a2013-02-11 09:52:58 +10003419 u32 ctrl = (depth << 16) | (proto << 8) | owner;
3420 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
3421 ctrl |= 0x00001000;
3422 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
3423 ctrl |= 0x00002000;
3424 evo_mthd(push, 0x0700 + (nv_encoder->or * 0x040), 1);
3425 evo_data(push, ctrl);
3426 }
3427
3428 evo_kick(push, mast);
3429 }
3430
3431 nv_encoder->crtc = encoder->crtc;
3432}
3433
3434static void
3435nv50_pior_disconnect(struct drm_encoder *encoder)
3436{
3437 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
3438 struct nv50_mast *mast = nv50_mast(encoder->dev);
3439 const int or = nv_encoder->or;
3440 u32 *push;
3441
3442 if (nv_encoder->crtc) {
3443 nv50_crtc_prepare(nv_encoder->crtc);
3444
3445 push = evo_wait(mast, 4);
3446 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10003447 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggseb6313a2013-02-11 09:52:58 +10003448 evo_mthd(push, 0x0700 + (or * 0x040), 1);
3449 evo_data(push, 0x00000000);
3450 }
Ben Skeggseb6313a2013-02-11 09:52:58 +10003451 evo_kick(push, mast);
3452 }
3453 }
3454
3455 nv_encoder->crtc = NULL;
3456}
3457
3458static void
3459nv50_pior_destroy(struct drm_encoder *encoder)
3460{
3461 drm_encoder_cleanup(encoder);
3462 kfree(encoder);
3463}
3464
3465static const struct drm_encoder_helper_funcs nv50_pior_hfunc = {
3466 .dpms = nv50_pior_dpms,
3467 .mode_fixup = nv50_pior_mode_fixup,
3468 .prepare = nv50_pior_disconnect,
3469 .commit = nv50_pior_commit,
3470 .mode_set = nv50_pior_mode_set,
3471 .disable = nv50_pior_disconnect,
3472 .get_crtc = nv50_display_crtc_get,
3473};
3474
3475static const struct drm_encoder_funcs nv50_pior_func = {
3476 .destroy = nv50_pior_destroy,
3477};
3478
3479static int
3480nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
3481{
3482 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +10003483 struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10003484 struct nvkm_i2c_bus *bus = NULL;
3485 struct nvkm_i2c_aux *aux = NULL;
3486 struct i2c_adapter *ddc;
Ben Skeggseb6313a2013-02-11 09:52:58 +10003487 struct nouveau_encoder *nv_encoder;
3488 struct drm_encoder *encoder;
3489 int type;
3490
3491 switch (dcbe->type) {
3492 case DCB_OUTPUT_TMDS:
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10003493 bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_EXT(dcbe->extdev));
3494 ddc = bus ? &bus->i2c : NULL;
Ben Skeggseb6313a2013-02-11 09:52:58 +10003495 type = DRM_MODE_ENCODER_TMDS;
3496 break;
3497 case DCB_OUTPUT_DP:
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10003498 aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbe->extdev));
3499 ddc = aux ? &aux->i2c : NULL;
Ben Skeggseb6313a2013-02-11 09:52:58 +10003500 type = DRM_MODE_ENCODER_TMDS;
3501 break;
3502 default:
3503 return -ENODEV;
3504 }
3505
3506 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
3507 if (!nv_encoder)
3508 return -ENOMEM;
3509 nv_encoder->dcb = dcbe;
3510 nv_encoder->or = ffs(dcbe->or) - 1;
3511 nv_encoder->i2c = ddc;
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10003512 nv_encoder->aux = aux;
Ben Skeggseb6313a2013-02-11 09:52:58 +10003513
3514 encoder = to_drm_encoder(nv_encoder);
3515 encoder->possible_crtcs = dcbe->heads;
3516 encoder->possible_clones = 0;
Ben Skeggs5a223da2016-11-04 17:20:36 +10003517 drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type,
3518 "pior-%04x-%04x", dcbe->hasht, dcbe->hashm);
Ben Skeggseb6313a2013-02-11 09:52:58 +10003519 drm_encoder_helper_add(encoder, &nv50_pior_hfunc);
3520
3521 drm_mode_connector_attach_encoder(connector, encoder);
3522 return 0;
3523}
3524
3525/******************************************************************************
Ben Skeggsab0af552014-08-10 04:10:19 +10003526 * Framebuffer
3527 *****************************************************************************/
3528
Ben Skeggs8a423642014-08-10 04:10:19 +10003529static void
Ben Skeggs0ad72862014-08-10 04:10:22 +10003530nv50_fbdma_fini(struct nv50_fbdma *fbdma)
Ben Skeggs8a423642014-08-10 04:10:19 +10003531{
Ben Skeggs0ad72862014-08-10 04:10:22 +10003532 int i;
3533 for (i = 0; i < ARRAY_SIZE(fbdma->base); i++)
3534 nvif_object_fini(&fbdma->base[i]);
3535 nvif_object_fini(&fbdma->core);
Ben Skeggs8a423642014-08-10 04:10:19 +10003536 list_del(&fbdma->head);
3537 kfree(fbdma);
3538}
3539
3540static int
3541nv50_fbdma_init(struct drm_device *dev, u32 name, u64 offset, u64 length, u8 kind)
3542{
3543 struct nouveau_drm *drm = nouveau_drm(dev);
3544 struct nv50_disp *disp = nv50_disp(dev);
3545 struct nv50_mast *mast = nv50_mast(dev);
Ben Skeggs4acfd702014-08-10 04:10:24 +10003546 struct __attribute__ ((packed)) {
3547 struct nv_dma_v0 base;
3548 union {
3549 struct nv50_dma_v0 nv50;
3550 struct gf100_dma_v0 gf100;
Ben Skeggsbd70563f2015-08-20 14:54:21 +10003551 struct gf119_dma_v0 gf119;
Ben Skeggs4acfd702014-08-10 04:10:24 +10003552 };
3553 } args = {};
Ben Skeggs8a423642014-08-10 04:10:19 +10003554 struct nv50_fbdma *fbdma;
3555 struct drm_crtc *crtc;
Ben Skeggs4acfd702014-08-10 04:10:24 +10003556 u32 size = sizeof(args.base);
Ben Skeggs8a423642014-08-10 04:10:19 +10003557 int ret;
3558
3559 list_for_each_entry(fbdma, &disp->fbdma, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10003560 if (fbdma->core.handle == name)
Ben Skeggs8a423642014-08-10 04:10:19 +10003561 return 0;
3562 }
3563
3564 fbdma = kzalloc(sizeof(*fbdma), GFP_KERNEL);
3565 if (!fbdma)
3566 return -ENOMEM;
3567 list_add(&fbdma->head, &disp->fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10003568
Ben Skeggs4acfd702014-08-10 04:10:24 +10003569 args.base.target = NV_DMA_V0_TARGET_VRAM;
3570 args.base.access = NV_DMA_V0_ACCESS_RDWR;
3571 args.base.start = offset;
3572 args.base.limit = offset + length - 1;
Ben Skeggs8a423642014-08-10 04:10:19 +10003573
Ben Skeggs967e7bd2014-08-10 04:10:22 +10003574 if (drm->device.info.chipset < 0x80) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10003575 args.nv50.part = NV50_DMA_V0_PART_256;
3576 size += sizeof(args.nv50);
Ben Skeggs8a423642014-08-10 04:10:19 +10003577 } else
Ben Skeggs967e7bd2014-08-10 04:10:22 +10003578 if (drm->device.info.chipset < 0xc0) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10003579 args.nv50.part = NV50_DMA_V0_PART_256;
3580 args.nv50.kind = kind;
3581 size += sizeof(args.nv50);
Ben Skeggs8a423642014-08-10 04:10:19 +10003582 } else
Ben Skeggs967e7bd2014-08-10 04:10:22 +10003583 if (drm->device.info.chipset < 0xd0) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10003584 args.gf100.kind = kind;
3585 size += sizeof(args.gf100);
Ben Skeggs8a423642014-08-10 04:10:19 +10003586 } else {
Ben Skeggsbd70563f2015-08-20 14:54:21 +10003587 args.gf119.page = GF119_DMA_V0_PAGE_LP;
3588 args.gf119.kind = kind;
3589 size += sizeof(args.gf119);
Ben Skeggs8a423642014-08-10 04:10:19 +10003590 }
3591
3592 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10003593 struct nv50_head *head = nv50_head(crtc);
Ben Skeggs973f10c2016-11-04 17:20:36 +10003594 int ret = nvif_object_init(&head->_base->chan.base.base.user, name,
Ben Skeggsa01ca782015-08-20 14:54:15 +10003595 NV_DMA_IN_MEMORY, &args, size,
Ben Skeggs0ad72862014-08-10 04:10:22 +10003596 &fbdma->base[head->base.index]);
Ben Skeggs8a423642014-08-10 04:10:19 +10003597 if (ret) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10003598 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10003599 return ret;
3600 }
3601 }
3602
Ben Skeggsa01ca782015-08-20 14:54:15 +10003603 ret = nvif_object_init(&mast->base.base.user, name, NV_DMA_IN_MEMORY,
3604 &args, size, &fbdma->core);
Ben Skeggs8a423642014-08-10 04:10:19 +10003605 if (ret) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10003606 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10003607 return ret;
3608 }
3609
3610 return 0;
3611}
3612
Ben Skeggsab0af552014-08-10 04:10:19 +10003613static void
3614nv50_fb_dtor(struct drm_framebuffer *fb)
3615{
3616}
3617
3618static int
3619nv50_fb_ctor(struct drm_framebuffer *fb)
3620{
3621 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
3622 struct nouveau_drm *drm = nouveau_drm(fb->dev);
3623 struct nouveau_bo *nvbo = nv_fb->nvbo;
Ben Skeggs8a423642014-08-10 04:10:19 +10003624 struct nv50_disp *disp = nv50_disp(fb->dev);
Ben Skeggs8a423642014-08-10 04:10:19 +10003625 u8 kind = nouveau_bo_tile_layout(nvbo) >> 8;
3626 u8 tile = nvbo->tile_mode;
Ben Skeggsab0af552014-08-10 04:10:19 +10003627
Ben Skeggs967e7bd2014-08-10 04:10:22 +10003628 if (drm->device.info.chipset >= 0xc0)
Ben Skeggs8a423642014-08-10 04:10:19 +10003629 tile >>= 4; /* yep.. */
3630
Ben Skeggsab0af552014-08-10 04:10:19 +10003631 switch (fb->depth) {
3632 case 8: nv_fb->r_format = 0x1e00; break;
3633 case 15: nv_fb->r_format = 0xe900; break;
3634 case 16: nv_fb->r_format = 0xe800; break;
3635 case 24:
3636 case 32: nv_fb->r_format = 0xcf00; break;
3637 case 30: nv_fb->r_format = 0xd100; break;
3638 default:
3639 NV_ERROR(drm, "unknown depth %d\n", fb->depth);
3640 return -EINVAL;
3641 }
3642
Ben Skeggs648d4df2014-08-10 04:10:27 +10003643 if (disp->disp->oclass < G82_DISP) {
Ben Skeggs8a423642014-08-10 04:10:19 +10003644 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
3645 (fb->pitches[0] | 0x00100000);
3646 nv_fb->r_format |= kind << 16;
3647 } else
Ben Skeggs648d4df2014-08-10 04:10:27 +10003648 if (disp->disp->oclass < GF110_DISP) {
Ben Skeggs8a423642014-08-10 04:10:19 +10003649 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
3650 (fb->pitches[0] | 0x00100000);
Ben Skeggsab0af552014-08-10 04:10:19 +10003651 } else {
Ben Skeggs8a423642014-08-10 04:10:19 +10003652 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
3653 (fb->pitches[0] | 0x01000000);
Ben Skeggsab0af552014-08-10 04:10:19 +10003654 }
Ben Skeggs8a423642014-08-10 04:10:19 +10003655 nv_fb->r_handle = 0xffff0000 | kind;
Ben Skeggsab0af552014-08-10 04:10:19 +10003656
Ben Skeggsf392ec42014-08-10 04:10:28 +10003657 return nv50_fbdma_init(fb->dev, nv_fb->r_handle, 0,
3658 drm->device.info.ram_user, kind);
Ben Skeggsab0af552014-08-10 04:10:19 +10003659}
3660
3661/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10003662 * Init
3663 *****************************************************************************/
Ben Skeggsab0af552014-08-10 04:10:19 +10003664
Ben Skeggs2a44e492011-11-09 11:36:33 +10003665void
Ben Skeggse225f442012-11-21 14:40:21 +10003666nv50_display_fini(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10003667{
Ben Skeggs973f10c2016-11-04 17:20:36 +10003668 struct drm_plane *plane;
3669
3670 drm_for_each_plane(plane, dev) {
3671 struct nv50_wndw *wndw = nv50_wndw(plane);
3672 if (plane->funcs != &nv50_wndw)
3673 continue;
3674 nv50_wndw_fini(wndw);
3675 }
Ben Skeggs26f6d882011-07-04 16:25:18 +10003676}
3677
3678int
Ben Skeggse225f442012-11-21 14:40:21 +10003679nv50_display_init(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10003680{
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10003681 struct nv50_disp *disp = nv50_disp(dev);
Ben Skeggs973f10c2016-11-04 17:20:36 +10003682 struct drm_plane *plane;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10003683 struct drm_crtc *crtc;
3684 u32 *push;
3685
3686 push = evo_wait(nv50_mast(dev), 32);
3687 if (!push)
3688 return -EBUSY;
3689
3690 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
Ben Skeggs973f10c2016-11-04 17:20:36 +10003691 struct nv50_wndw *wndw = &nv50_head(crtc)->_base->wndw;
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01003692
3693 nv50_crtc_lut_load(crtc);
Ben Skeggs973f10c2016-11-04 17:20:36 +10003694 nouveau_bo_wr32(disp->sync, wndw->sema / 4, wndw->data);
Ben Skeggs26f6d882011-07-04 16:25:18 +10003695 }
3696
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10003697 evo_mthd(push, 0x0088, 1);
Ben Skeggsf45f55c2014-08-10 04:10:23 +10003698 evo_data(push, nv50_mast(dev)->base.sync.handle);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10003699 evo_kick(push, nv50_mast(dev));
Ben Skeggs973f10c2016-11-04 17:20:36 +10003700
3701 drm_for_each_plane(plane, dev) {
3702 struct nv50_wndw *wndw = nv50_wndw(plane);
3703 if (plane->funcs != &nv50_wndw)
3704 continue;
3705 nv50_wndw_init(wndw);
3706 }
3707
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10003708 return 0;
Ben Skeggs26f6d882011-07-04 16:25:18 +10003709}
3710
3711void
Ben Skeggse225f442012-11-21 14:40:21 +10003712nv50_display_destroy(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10003713{
Ben Skeggse225f442012-11-21 14:40:21 +10003714 struct nv50_disp *disp = nv50_disp(dev);
Ben Skeggs8a423642014-08-10 04:10:19 +10003715 struct nv50_fbdma *fbdma, *fbtmp;
3716
3717 list_for_each_entry_safe(fbdma, fbtmp, &disp->fbdma, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10003718 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10003719 }
Ben Skeggs26f6d882011-07-04 16:25:18 +10003720
Ben Skeggs0ad72862014-08-10 04:10:22 +10003721 nv50_dmac_destroy(&disp->mast.base, disp->disp);
Ben Skeggsbdb8c212011-11-12 01:30:24 +10003722
Ben Skeggs816af2f2011-11-16 15:48:48 +10003723 nouveau_bo_unmap(disp->sync);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01003724 if (disp->sync)
3725 nouveau_bo_unpin(disp->sync);
Ben Skeggs816af2f2011-11-16 15:48:48 +10003726 nouveau_bo_ref(NULL, &disp->sync);
Ben Skeggs51beb422011-07-05 10:33:08 +10003727
Ben Skeggs77145f12012-07-31 16:16:21 +10003728 nouveau_display(dev)->priv = NULL;
Ben Skeggs26f6d882011-07-04 16:25:18 +10003729 kfree(disp);
3730}
3731
3732int
Ben Skeggse225f442012-11-21 14:40:21 +10003733nv50_display_create(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10003734{
Ben Skeggs967e7bd2014-08-10 04:10:22 +10003735 struct nvif_device *device = &nouveau_drm(dev)->device;
Ben Skeggs77145f12012-07-31 16:16:21 +10003736 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs77145f12012-07-31 16:16:21 +10003737 struct dcb_table *dcb = &drm->vbios.dcb;
Ben Skeggs83fc0832011-07-05 13:08:40 +10003738 struct drm_connector *connector, *tmp;
Ben Skeggse225f442012-11-21 14:40:21 +10003739 struct nv50_disp *disp;
Ben Skeggscb75d972012-07-11 10:44:20 +10003740 struct dcb_output *dcbe;
Ben Skeggs7c5f6a82012-03-04 16:25:59 +10003741 int crtcs, ret, i;
Ben Skeggs26f6d882011-07-04 16:25:18 +10003742
3743 disp = kzalloc(sizeof(*disp), GFP_KERNEL);
3744 if (!disp)
3745 return -ENOMEM;
Ben Skeggs8a423642014-08-10 04:10:19 +10003746 INIT_LIST_HEAD(&disp->fbdma);
Ben Skeggs77145f12012-07-31 16:16:21 +10003747
3748 nouveau_display(dev)->priv = disp;
Ben Skeggse225f442012-11-21 14:40:21 +10003749 nouveau_display(dev)->dtor = nv50_display_destroy;
3750 nouveau_display(dev)->init = nv50_display_init;
3751 nouveau_display(dev)->fini = nv50_display_fini;
Ben Skeggsab0af552014-08-10 04:10:19 +10003752 nouveau_display(dev)->fb_ctor = nv50_fb_ctor;
3753 nouveau_display(dev)->fb_dtor = nv50_fb_dtor;
Ben Skeggs0ad72862014-08-10 04:10:22 +10003754 disp->disp = &nouveau_display(dev)->disp;
Ben Skeggs26f6d882011-07-04 16:25:18 +10003755
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003756 /* small shared memory area we use for notifiers and semaphores */
3757 ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
Maarten Lankhorstbb6178b2014-01-09 11:03:15 +01003758 0, 0x0000, NULL, NULL, &disp->sync);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003759 if (!ret) {
Ben Skeggs547ad072014-11-10 12:35:06 +10003760 ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM, true);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01003761 if (!ret) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003762 ret = nouveau_bo_map(disp->sync);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01003763 if (ret)
3764 nouveau_bo_unpin(disp->sync);
3765 }
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003766 if (ret)
3767 nouveau_bo_ref(NULL, &disp->sync);
3768 }
3769
3770 if (ret)
3771 goto out;
3772
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003773 /* allocate master evo channel */
Ben Skeggsa01ca782015-08-20 14:54:15 +10003774 ret = nv50_core_create(device, disp->disp, disp->sync->bo.offset,
Ben Skeggs410f3ec2014-08-10 04:10:25 +10003775 &disp->mast);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003776 if (ret)
3777 goto out;
3778
Ben Skeggs438d99e2011-07-05 16:48:06 +10003779 /* create crtc objects to represent the hw heads */
Ben Skeggs648d4df2014-08-10 04:10:27 +10003780 if (disp->disp->oclass >= GF110_DISP)
Ben Skeggsa01ca782015-08-20 14:54:15 +10003781 crtcs = nvif_rd32(&device->object, 0x022448);
Ben Skeggs63718a02012-11-16 11:44:14 +10003782 else
3783 crtcs = 2;
3784
Ben Skeggs7c5f6a82012-03-04 16:25:59 +10003785 for (i = 0; i < crtcs; i++) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10003786 ret = nv50_crtc_create(dev, i);
Ben Skeggs438d99e2011-07-05 16:48:06 +10003787 if (ret)
3788 goto out;
3789 }
3790
Ben Skeggs83fc0832011-07-05 13:08:40 +10003791 /* create encoder/connector objects based on VBIOS DCB table */
3792 for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
3793 connector = nouveau_connector_create(dev, dcbe->connector);
3794 if (IS_ERR(connector))
3795 continue;
3796
Ben Skeggseb6313a2013-02-11 09:52:58 +10003797 if (dcbe->location == DCB_LOC_ON_CHIP) {
3798 switch (dcbe->type) {
3799 case DCB_OUTPUT_TMDS:
3800 case DCB_OUTPUT_LVDS:
3801 case DCB_OUTPUT_DP:
3802 ret = nv50_sor_create(connector, dcbe);
3803 break;
3804 case DCB_OUTPUT_ANALOG:
3805 ret = nv50_dac_create(connector, dcbe);
3806 break;
3807 default:
3808 ret = -ENODEV;
3809 break;
3810 }
3811 } else {
3812 ret = nv50_pior_create(connector, dcbe);
Ben Skeggs83fc0832011-07-05 13:08:40 +10003813 }
3814
Ben Skeggseb6313a2013-02-11 09:52:58 +10003815 if (ret) {
3816 NV_WARN(drm, "failed to create encoder %d/%d/%d: %d\n",
3817 dcbe->location, dcbe->type,
3818 ffs(dcbe->or) - 1, ret);
Ben Skeggs94f54f52013-03-05 22:26:06 +10003819 ret = 0;
Ben Skeggs83fc0832011-07-05 13:08:40 +10003820 }
3821 }
3822
3823 /* cull any connectors we created that don't have an encoder */
3824 list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) {
3825 if (connector->encoder_ids[0])
3826 continue;
3827
Ben Skeggs77145f12012-07-31 16:16:21 +10003828 NV_WARN(drm, "%s has no encoders, removing\n",
Jani Nikula8c6c3612014-06-03 14:56:18 +03003829 connector->name);
Ben Skeggs83fc0832011-07-05 13:08:40 +10003830 connector->funcs->destroy(connector);
3831 }
3832
Ben Skeggs26f6d882011-07-04 16:25:18 +10003833out:
3834 if (ret)
Ben Skeggse225f442012-11-21 14:40:21 +10003835 nv50_display_destroy(dev);
Ben Skeggs26f6d882011-07-04 16:25:18 +10003836 return ret;
3837}