blob: 44de7a3a9f0cc4948e77066efeff81ce9a42ba7b [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>
David Howells760285e2012-10-02 18:01:07 +010029#include <drm/drm_crtc_helper.h>
Ben Skeggs48743222014-05-31 01:48:06 +100030#include <drm/drm_dp_helper.h>
Daniel Vetterb516a9e2015-12-04 09:45:43 +010031#include <drm/drm_fb_helper.h>
Ben Skeggsad633612016-11-04 17:20:36 +100032#include <drm/drm_plane_helper.h>
Ben Skeggs26f6d882011-07-04 16:25:18 +100033
Ben Skeggsfdb751e2014-08-10 04:10:23 +100034#include <nvif/class.h>
Ben Skeggs845f2722015-11-08 12:16:40 +100035#include <nvif/cl0002.h>
Ben Skeggs7568b102015-11-08 10:44:19 +100036#include <nvif/cl5070.h>
37#include <nvif/cl507a.h>
38#include <nvif/cl507b.h>
39#include <nvif/cl507c.h>
40#include <nvif/cl507d.h>
41#include <nvif/cl507e.h>
Ben Skeggsfdb751e2014-08-10 04:10:23 +100042
Ben Skeggs4dc28132016-05-20 09:22:55 +100043#include "nouveau_drv.h"
Ben Skeggs77145f12012-07-31 16:16:21 +100044#include "nouveau_dma.h"
45#include "nouveau_gem.h"
Ben Skeggs26f6d882011-07-04 16:25:18 +100046#include "nouveau_connector.h"
47#include "nouveau_encoder.h"
48#include "nouveau_crtc.h"
Ben Skeggsf589be82012-07-22 11:55:54 +100049#include "nouveau_fence.h"
Ben Skeggs3a89cd02011-07-07 10:47:10 +100050#include "nv50_display.h"
Ben Skeggs26f6d882011-07-04 16:25:18 +100051
Ben Skeggs8a464382011-11-12 23:52:07 +100052#define EVO_DMA_NR 9
53
Ben Skeggsbdb8c212011-11-12 01:30:24 +100054#define EVO_MASTER (0x00)
Ben Skeggsa63a97e2011-11-16 15:22:34 +100055#define EVO_FLIP(c) (0x01 + (c))
Ben Skeggs8a464382011-11-12 23:52:07 +100056#define EVO_OVLY(c) (0x05 + (c))
57#define EVO_OIMM(c) (0x09 + (c))
Ben Skeggsbdb8c212011-11-12 01:30:24 +100058#define EVO_CURS(c) (0x0d + (c))
59
Ben Skeggs816af2f2011-11-16 15:48:48 +100060/* offsets in shared sync bo of various structures */
61#define EVO_SYNC(c, o) ((c) * 0x0100 + (o))
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +100062#define EVO_MAST_NTFY EVO_SYNC( 0, 0x00)
63#define EVO_FLIP_SEM0(c) EVO_SYNC((c) + 1, 0x00)
64#define EVO_FLIP_SEM1(c) EVO_SYNC((c) + 1, 0x10)
Ben Skeggs816af2f2011-11-16 15:48:48 +100065
Ben Skeggsb5a794b2012-10-16 14:18:32 +100066/******************************************************************************
Ben Skeggs3dbd0362016-11-04 17:20:36 +100067 * Atomic state
68 *****************************************************************************/
69#define nv50_head_atom(p) container_of((p), struct nv50_head_atom, state)
70
71struct nv50_head_atom {
72 struct drm_crtc_state state;
73
Ben Skeggsc4e68122016-11-04 17:20:36 +100074 struct {
75 u16 iW;
76 u16 iH;
77 u16 oW;
78 u16 oH;
79 } view;
80
Ben Skeggs3dbd0362016-11-04 17:20:36 +100081 struct nv50_head_mode {
82 bool interlace;
83 u32 clock;
84 struct {
85 u16 active;
86 u16 synce;
87 u16 blanke;
88 u16 blanks;
89 } h;
90 struct {
91 u32 active;
92 u16 synce;
93 u16 blanke;
94 u16 blanks;
95 u16 blank2s;
96 u16 blank2e;
97 u16 blankus;
98 } v;
99 } mode;
100
Ben Skeggsad633612016-11-04 17:20:36 +1000101 struct {
Ben Skeggsa7ae1562016-11-04 17:20:36 +1000102 u32 handle;
103 u64 offset:40;
104 } lut;
105
106 struct {
Ben Skeggsad633612016-11-04 17:20:36 +1000107 bool visible;
108 u32 handle;
109 u64 offset:40;
110 u8 format;
111 u8 kind:7;
112 u8 layout:1;
113 u8 block:4;
114 u32 pitch:20;
115 u16 x;
116 u16 y;
117 u16 w;
118 u16 h;
119 } core;
120
121 struct {
Ben Skeggsea8ee392016-11-04 17:20:36 +1000122 bool visible;
123 u32 handle;
124 u64 offset:40;
125 u8 layout:1;
126 u8 format:1;
127 } curs;
128
129 struct {
Ben Skeggsad633612016-11-04 17:20:36 +1000130 u8 depth;
131 u8 cpp;
132 u16 x;
133 u16 y;
134 u16 w;
135 u16 h;
136 } base;
137
Ben Skeggs6bbab3b2016-11-04 17:20:36 +1000138 struct {
139 u8 cpp;
140 } ovly;
141
Ben Skeggs7e918332016-11-04 17:20:36 +1000142 struct {
143 bool enable:1;
144 u8 bits:2;
145 u8 mode:4;
146 } dither;
147
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000148 union {
149 struct {
Ben Skeggsad633612016-11-04 17:20:36 +1000150 bool core:1;
Ben Skeggsea8ee392016-11-04 17:20:36 +1000151 bool curs:1;
Ben Skeggsad633612016-11-04 17:20:36 +1000152 };
153 u8 mask;
154 } clr;
155
156 union {
157 struct {
158 bool core:1;
Ben Skeggsea8ee392016-11-04 17:20:36 +1000159 bool curs:1;
Ben Skeggsad633612016-11-04 17:20:36 +1000160 bool view:1;
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000161 bool mode:1;
Ben Skeggs6bbab3b2016-11-04 17:20:36 +1000162 bool base:1;
163 bool ovly:1;
Ben Skeggs7e918332016-11-04 17:20:36 +1000164 bool dither:1;
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000165 };
166 u16 mask;
167 } set;
168};
169
170/******************************************************************************
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000171 * EVO channel
172 *****************************************************************************/
173
Ben Skeggse225f442012-11-21 14:40:21 +1000174struct nv50_chan {
Ben Skeggs0ad72862014-08-10 04:10:22 +1000175 struct nvif_object user;
Ben Skeggsa01ca782015-08-20 14:54:15 +1000176 struct nvif_device *device;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000177};
178
179static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000180nv50_chan_create(struct nvif_device *device, struct nvif_object *disp,
Ben Skeggs315a8b22015-08-20 14:54:16 +1000181 const s32 *oclass, u8 head, void *data, u32 size,
Ben Skeggsa01ca782015-08-20 14:54:15 +1000182 struct nv50_chan *chan)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000183{
Ben Skeggs41a63402015-08-20 14:54:16 +1000184 struct nvif_sclass *sclass;
185 int ret, i, n;
Ben Skeggs6af52892014-11-03 15:01:33 +1000186
Ben Skeggsa01ca782015-08-20 14:54:15 +1000187 chan->device = device;
188
Ben Skeggs41a63402015-08-20 14:54:16 +1000189 ret = n = nvif_object_sclass_get(disp, &sclass);
Ben Skeggs6af52892014-11-03 15:01:33 +1000190 if (ret < 0)
191 return ret;
192
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000193 while (oclass[0]) {
Ben Skeggs41a63402015-08-20 14:54:16 +1000194 for (i = 0; i < n; i++) {
195 if (sclass[i].oclass == oclass[0]) {
Ben Skeggsfcf3f912015-09-04 14:40:32 +1000196 ret = nvif_object_init(disp, 0, oclass[0],
Ben Skeggsa01ca782015-08-20 14:54:15 +1000197 data, size, &chan->user);
Ben Skeggs6af52892014-11-03 15:01:33 +1000198 if (ret == 0)
199 nvif_object_map(&chan->user);
Ben Skeggs41a63402015-08-20 14:54:16 +1000200 nvif_object_sclass_put(&sclass);
Ben Skeggs6af52892014-11-03 15:01:33 +1000201 return ret;
202 }
Ben Skeggsb76f1522014-08-10 04:10:28 +1000203 }
Ben Skeggs6af52892014-11-03 15:01:33 +1000204 oclass++;
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000205 }
Ben Skeggs6af52892014-11-03 15:01:33 +1000206
Ben Skeggs41a63402015-08-20 14:54:16 +1000207 nvif_object_sclass_put(&sclass);
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000208 return -ENOSYS;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000209}
210
211static void
Ben Skeggs0ad72862014-08-10 04:10:22 +1000212nv50_chan_destroy(struct nv50_chan *chan)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000213{
Ben Skeggs0ad72862014-08-10 04:10:22 +1000214 nvif_object_fini(&chan->user);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000215}
216
217/******************************************************************************
218 * PIO EVO channel
219 *****************************************************************************/
220
Ben Skeggse225f442012-11-21 14:40:21 +1000221struct nv50_pioc {
222 struct nv50_chan base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000223};
224
225static void
Ben Skeggs0ad72862014-08-10 04:10:22 +1000226nv50_pioc_destroy(struct nv50_pioc *pioc)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000227{
Ben Skeggs0ad72862014-08-10 04:10:22 +1000228 nv50_chan_destroy(&pioc->base);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000229}
230
231static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000232nv50_pioc_create(struct nvif_device *device, struct nvif_object *disp,
Ben Skeggs315a8b22015-08-20 14:54:16 +1000233 const s32 *oclass, u8 head, void *data, u32 size,
Ben Skeggsa01ca782015-08-20 14:54:15 +1000234 struct nv50_pioc *pioc)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000235{
Ben Skeggsa01ca782015-08-20 14:54:15 +1000236 return nv50_chan_create(device, disp, oclass, head, data, size,
237 &pioc->base);
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000238}
239
240/******************************************************************************
241 * Cursor Immediate
242 *****************************************************************************/
243
244struct nv50_curs {
245 struct nv50_pioc base;
246};
247
248static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000249nv50_curs_create(struct nvif_device *device, struct nvif_object *disp,
250 int head, struct nv50_curs *curs)
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000251{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000252 struct nv50_disp_cursor_v0 args = {
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000253 .head = head,
254 };
Ben Skeggs315a8b22015-08-20 14:54:16 +1000255 static const s32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000256 GK104_DISP_CURSOR,
257 GF110_DISP_CURSOR,
258 GT214_DISP_CURSOR,
259 G82_DISP_CURSOR,
260 NV50_DISP_CURSOR,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000261 0
262 };
263
Ben Skeggsa01ca782015-08-20 14:54:15 +1000264 return nv50_pioc_create(device, disp, oclass, head, &args, sizeof(args),
265 &curs->base);
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000266}
267
268/******************************************************************************
269 * Overlay Immediate
270 *****************************************************************************/
271
272struct nv50_oimm {
273 struct nv50_pioc base;
274};
275
276static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000277nv50_oimm_create(struct nvif_device *device, struct nvif_object *disp,
278 int head, struct nv50_oimm *oimm)
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000279{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000280 struct nv50_disp_cursor_v0 args = {
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000281 .head = head,
282 };
Ben Skeggs315a8b22015-08-20 14:54:16 +1000283 static const s32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000284 GK104_DISP_OVERLAY,
285 GF110_DISP_OVERLAY,
286 GT214_DISP_OVERLAY,
287 G82_DISP_OVERLAY,
288 NV50_DISP_OVERLAY,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000289 0
290 };
291
Ben Skeggsa01ca782015-08-20 14:54:15 +1000292 return nv50_pioc_create(device, disp, oclass, head, &args, sizeof(args),
293 &oimm->base);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000294}
295
296/******************************************************************************
297 * DMA EVO channel
298 *****************************************************************************/
299
Ben Skeggse225f442012-11-21 14:40:21 +1000300struct nv50_dmac {
301 struct nv50_chan base;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000302 dma_addr_t handle;
303 u32 *ptr;
Daniel Vetter59ad1462012-12-02 14:49:44 +0100304
Ben Skeggs0ad72862014-08-10 04:10:22 +1000305 struct nvif_object sync;
306 struct nvif_object vram;
307
Daniel Vetter59ad1462012-12-02 14:49:44 +0100308 /* Protects against concurrent pushbuf access to this channel, lock is
309 * grabbed by evo_wait (if the pushbuf reservation is successful) and
310 * dropped again by evo_kick. */
311 struct mutex lock;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000312};
313
314static void
Ben Skeggs0ad72862014-08-10 04:10:22 +1000315nv50_dmac_destroy(struct nv50_dmac *dmac, struct nvif_object *disp)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000316{
Ben Skeggsa01ca782015-08-20 14:54:15 +1000317 struct nvif_device *device = dmac->base.device;
318
Ben Skeggs0ad72862014-08-10 04:10:22 +1000319 nvif_object_fini(&dmac->vram);
320 nvif_object_fini(&dmac->sync);
321
322 nv50_chan_destroy(&dmac->base);
323
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000324 if (dmac->ptr) {
Ben Skeggs26c9e8e2015-08-20 14:54:23 +1000325 struct device *dev = nvxx_device(device)->dev;
326 dma_free_coherent(dev, PAGE_SIZE, dmac->ptr, dmac->handle);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000327 }
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000328}
329
330static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000331nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
Ben Skeggs315a8b22015-08-20 14:54:16 +1000332 const s32 *oclass, u8 head, void *data, u32 size, u64 syncbuf,
Ben Skeggse225f442012-11-21 14:40:21 +1000333 struct nv50_dmac *dmac)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000334{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000335 struct nv50_disp_core_channel_dma_v0 *args = data;
Ben Skeggs0ad72862014-08-10 04:10:22 +1000336 struct nvif_object pushbuf;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000337 int ret;
338
Daniel Vetter59ad1462012-12-02 14:49:44 +0100339 mutex_init(&dmac->lock);
340
Ben Skeggs26c9e8e2015-08-20 14:54:23 +1000341 dmac->ptr = dma_alloc_coherent(nvxx_device(device)->dev, PAGE_SIZE,
342 &dmac->handle, GFP_KERNEL);
Ben Skeggs47057302012-11-16 13:58:48 +1000343 if (!dmac->ptr)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000344 return -ENOMEM;
345
Ben Skeggsfcf3f912015-09-04 14:40:32 +1000346 ret = nvif_object_init(&device->object, 0, NV_DMA_FROM_MEMORY,
347 &(struct nv_dma_v0) {
Ben Skeggs4acfd702014-08-10 04:10:24 +1000348 .target = NV_DMA_V0_TARGET_PCI_US,
349 .access = NV_DMA_V0_ACCESS_RD,
Ben Skeggs47057302012-11-16 13:58:48 +1000350 .start = dmac->handle + 0x0000,
351 .limit = dmac->handle + 0x0fff,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000352 }, sizeof(struct nv_dma_v0), &pushbuf);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000353 if (ret)
354 return ret;
355
Ben Skeggsbf81df92015-08-20 14:54:16 +1000356 args->pushbuf = nvif_handle(&pushbuf);
357
Ben Skeggsa01ca782015-08-20 14:54:15 +1000358 ret = nv50_chan_create(device, disp, oclass, head, data, size,
359 &dmac->base);
Ben Skeggs0ad72862014-08-10 04:10:22 +1000360 nvif_object_fini(&pushbuf);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000361 if (ret)
362 return ret;
363
Ben Skeggsa01ca782015-08-20 14:54:15 +1000364 ret = nvif_object_init(&dmac->base.user, 0xf0000000, NV_DMA_IN_MEMORY,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000365 &(struct nv_dma_v0) {
366 .target = NV_DMA_V0_TARGET_VRAM,
367 .access = NV_DMA_V0_ACCESS_RDWR,
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000368 .start = syncbuf + 0x0000,
369 .limit = syncbuf + 0x0fff,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000370 }, sizeof(struct nv_dma_v0),
Ben Skeggs0ad72862014-08-10 04:10:22 +1000371 &dmac->sync);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000372 if (ret)
Ben Skeggs47057302012-11-16 13:58:48 +1000373 return ret;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000374
Ben Skeggsa01ca782015-08-20 14:54:15 +1000375 ret = nvif_object_init(&dmac->base.user, 0xf0000001, NV_DMA_IN_MEMORY,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000376 &(struct nv_dma_v0) {
377 .target = NV_DMA_V0_TARGET_VRAM,
378 .access = NV_DMA_V0_ACCESS_RDWR,
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000379 .start = 0,
Ben Skeggsf392ec42014-08-10 04:10:28 +1000380 .limit = device->info.ram_user - 1,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000381 }, sizeof(struct nv_dma_v0),
Ben Skeggs0ad72862014-08-10 04:10:22 +1000382 &dmac->vram);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000383 if (ret)
Ben Skeggs47057302012-11-16 13:58:48 +1000384 return ret;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000385
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000386 return ret;
387}
388
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000389/******************************************************************************
390 * Core
391 *****************************************************************************/
392
Ben Skeggse225f442012-11-21 14:40:21 +1000393struct nv50_mast {
394 struct nv50_dmac base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000395};
396
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000397static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000398nv50_core_create(struct nvif_device *device, struct nvif_object *disp,
399 u64 syncbuf, struct nv50_mast *core)
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000400{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000401 struct nv50_disp_core_channel_dma_v0 args = {
402 .pushbuf = 0xb0007d00,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000403 };
Ben Skeggs315a8b22015-08-20 14:54:16 +1000404 static const s32 oclass[] = {
Ben Skeggsfd478772016-07-09 10:41:01 +1000405 GP104_DISP_CORE_CHANNEL_DMA,
Ben Skeggsf9d5cbb2016-07-09 10:41:01 +1000406 GP100_DISP_CORE_CHANNEL_DMA,
Ben Skeggsdb1eb522016-02-11 08:35:32 +1000407 GM200_DISP_CORE_CHANNEL_DMA,
Ben Skeggs648d4df2014-08-10 04:10:27 +1000408 GM107_DISP_CORE_CHANNEL_DMA,
409 GK110_DISP_CORE_CHANNEL_DMA,
410 GK104_DISP_CORE_CHANNEL_DMA,
411 GF110_DISP_CORE_CHANNEL_DMA,
412 GT214_DISP_CORE_CHANNEL_DMA,
413 GT206_DISP_CORE_CHANNEL_DMA,
414 GT200_DISP_CORE_CHANNEL_DMA,
415 G82_DISP_CORE_CHANNEL_DMA,
416 NV50_DISP_CORE_CHANNEL_DMA,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000417 0
418 };
419
Ben Skeggsa01ca782015-08-20 14:54:15 +1000420 return nv50_dmac_create(device, disp, oclass, 0, &args, sizeof(args),
421 syncbuf, &core->base);
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000422}
423
424/******************************************************************************
425 * Base
426 *****************************************************************************/
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000427
Ben Skeggse225f442012-11-21 14:40:21 +1000428struct nv50_sync {
429 struct nv50_dmac base;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000430 u32 addr;
431 u32 data;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000432};
433
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000434static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000435nv50_base_create(struct nvif_device *device, struct nvif_object *disp,
436 int head, u64 syncbuf, struct nv50_sync *base)
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000437{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000438 struct nv50_disp_base_channel_dma_v0 args = {
439 .pushbuf = 0xb0007c00 | head,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000440 .head = head,
441 };
Ben Skeggs315a8b22015-08-20 14:54:16 +1000442 static const s32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000443 GK110_DISP_BASE_CHANNEL_DMA,
444 GK104_DISP_BASE_CHANNEL_DMA,
445 GF110_DISP_BASE_CHANNEL_DMA,
446 GT214_DISP_BASE_CHANNEL_DMA,
447 GT200_DISP_BASE_CHANNEL_DMA,
448 G82_DISP_BASE_CHANNEL_DMA,
449 NV50_DISP_BASE_CHANNEL_DMA,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000450 0
451 };
452
Ben Skeggsa01ca782015-08-20 14:54:15 +1000453 return nv50_dmac_create(device, disp, oclass, head, &args, sizeof(args),
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000454 syncbuf, &base->base);
455}
456
457/******************************************************************************
458 * Overlay
459 *****************************************************************************/
460
Ben Skeggse225f442012-11-21 14:40:21 +1000461struct nv50_ovly {
462 struct nv50_dmac base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000463};
Ben Skeggsf20ce962011-07-08 13:17:01 +1000464
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000465static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000466nv50_ovly_create(struct nvif_device *device, struct nvif_object *disp,
467 int head, u64 syncbuf, struct nv50_ovly *ovly)
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000468{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000469 struct nv50_disp_overlay_channel_dma_v0 args = {
470 .pushbuf = 0xb0007e00 | head,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000471 .head = head,
472 };
Ben Skeggs315a8b22015-08-20 14:54:16 +1000473 static const s32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000474 GK104_DISP_OVERLAY_CONTROL_DMA,
475 GF110_DISP_OVERLAY_CONTROL_DMA,
476 GT214_DISP_OVERLAY_CHANNEL_DMA,
477 GT200_DISP_OVERLAY_CHANNEL_DMA,
478 G82_DISP_OVERLAY_CHANNEL_DMA,
479 NV50_DISP_OVERLAY_CHANNEL_DMA,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000480 0
481 };
482
Ben Skeggsa01ca782015-08-20 14:54:15 +1000483 return nv50_dmac_create(device, disp, oclass, head, &args, sizeof(args),
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000484 syncbuf, &ovly->base);
485}
Ben Skeggs26f6d882011-07-04 16:25:18 +1000486
Ben Skeggse225f442012-11-21 14:40:21 +1000487struct nv50_head {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +1000488 struct nouveau_crtc base;
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000489 struct nouveau_bo *image;
Ben Skeggse225f442012-11-21 14:40:21 +1000490 struct nv50_curs curs;
491 struct nv50_sync sync;
492 struct nv50_ovly ovly;
493 struct nv50_oimm oimm;
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000494
495 struct nv50_head_atom arm;
496 struct nv50_head_atom asy;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000497};
498
Ben Skeggse225f442012-11-21 14:40:21 +1000499#define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c))
500#define nv50_curs(c) (&nv50_head(c)->curs)
501#define nv50_sync(c) (&nv50_head(c)->sync)
502#define nv50_ovly(c) (&nv50_head(c)->ovly)
503#define nv50_oimm(c) (&nv50_head(c)->oimm)
504#define nv50_chan(c) (&(c)->base.base)
Ben Skeggs0ad72862014-08-10 04:10:22 +1000505#define nv50_vers(c) nv50_chan(c)->user.oclass
506
507struct nv50_fbdma {
508 struct list_head head;
509 struct nvif_object core;
510 struct nvif_object base[4];
511};
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000512
Ben Skeggse225f442012-11-21 14:40:21 +1000513struct nv50_disp {
Ben Skeggs0ad72862014-08-10 04:10:22 +1000514 struct nvif_object *disp;
Ben Skeggse225f442012-11-21 14:40:21 +1000515 struct nv50_mast mast;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000516
Ben Skeggs8a423642014-08-10 04:10:19 +1000517 struct list_head fbdma;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000518
519 struct nouveau_bo *sync;
Ben Skeggsdd0e3d52012-10-16 14:00:31 +1000520};
521
Ben Skeggse225f442012-11-21 14:40:21 +1000522static struct nv50_disp *
523nv50_disp(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +1000524{
Ben Skeggs77145f12012-07-31 16:16:21 +1000525 return nouveau_display(dev)->priv;
Ben Skeggs26f6d882011-07-04 16:25:18 +1000526}
527
Ben Skeggse225f442012-11-21 14:40:21 +1000528#define nv50_mast(d) (&nv50_disp(d)->mast)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000529
Ben Skeggsbdb8c212011-11-12 01:30:24 +1000530static struct drm_crtc *
Ben Skeggse225f442012-11-21 14:40:21 +1000531nv50_display_crtc_get(struct drm_encoder *encoder)
Ben Skeggsbdb8c212011-11-12 01:30:24 +1000532{
533 return nouveau_encoder(encoder)->crtc;
534}
535
536/******************************************************************************
537 * EVO channel helpers
538 *****************************************************************************/
Ben Skeggs51beb422011-07-05 10:33:08 +1000539static u32 *
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000540evo_wait(void *evoc, int nr)
Ben Skeggs51beb422011-07-05 10:33:08 +1000541{
Ben Skeggse225f442012-11-21 14:40:21 +1000542 struct nv50_dmac *dmac = evoc;
Ben Skeggsa01ca782015-08-20 14:54:15 +1000543 struct nvif_device *device = dmac->base.device;
Ben Skeggs0ad72862014-08-10 04:10:22 +1000544 u32 put = nvif_rd32(&dmac->base.user, 0x0000) / 4;
Ben Skeggs51beb422011-07-05 10:33:08 +1000545
Daniel Vetter59ad1462012-12-02 14:49:44 +0100546 mutex_lock(&dmac->lock);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000547 if (put + nr >= (PAGE_SIZE / 4) - 8) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000548 dmac->ptr[put] = 0x20000000;
Ben Skeggs51beb422011-07-05 10:33:08 +1000549
Ben Skeggs0ad72862014-08-10 04:10:22 +1000550 nvif_wr32(&dmac->base.user, 0x0000, 0x00000000);
Ben Skeggs54442042015-08-20 14:54:11 +1000551 if (nvif_msec(device, 2000,
552 if (!nvif_rd32(&dmac->base.user, 0x0004))
553 break;
554 ) < 0) {
Daniel Vetter59ad1462012-12-02 14:49:44 +0100555 mutex_unlock(&dmac->lock);
Ben Skeggs9ad97ed2015-08-20 14:54:13 +1000556 printk(KERN_ERR "nouveau: evo channel stalled\n");
Ben Skeggs51beb422011-07-05 10:33:08 +1000557 return NULL;
558 }
559
560 put = 0;
561 }
562
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000563 return dmac->ptr + put;
Ben Skeggs51beb422011-07-05 10:33:08 +1000564}
565
566static void
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000567evo_kick(u32 *push, void *evoc)
Ben Skeggs51beb422011-07-05 10:33:08 +1000568{
Ben Skeggse225f442012-11-21 14:40:21 +1000569 struct nv50_dmac *dmac = evoc;
Ben Skeggs0ad72862014-08-10 04:10:22 +1000570 nvif_wr32(&dmac->base.user, 0x0000, (push - dmac->ptr) << 2);
Daniel Vetter59ad1462012-12-02 14:49:44 +0100571 mutex_unlock(&dmac->lock);
Ben Skeggs51beb422011-07-05 10:33:08 +1000572}
573
Ben Skeggs2b1930c2014-11-03 16:43:59 +1000574#define evo_mthd(p,m,s) do { \
575 const u32 _m = (m), _s = (s); \
Ben Skeggs7f55a072016-11-04 17:20:36 +1000576 if (drm_debug & DRM_UT_KMS) \
577 printk(KERN_ERR "%04x %d %s\n", _m, _s, __func__); \
Ben Skeggs2b1930c2014-11-03 16:43:59 +1000578 *((p)++) = ((_s << 18) | _m); \
579} while(0)
Ben Skeggs7f55a072016-11-04 17:20:36 +1000580
Ben Skeggs2b1930c2014-11-03 16:43:59 +1000581#define evo_data(p,d) do { \
582 const u32 _d = (d); \
Ben Skeggs7f55a072016-11-04 17:20:36 +1000583 if (drm_debug & DRM_UT_KMS) \
584 printk(KERN_ERR "\t%08x\n", _d); \
Ben Skeggs2b1930c2014-11-03 16:43:59 +1000585 *((p)++) = _d; \
586} while(0)
Ben Skeggs51beb422011-07-05 10:33:08 +1000587
Ben Skeggs3376ee32011-11-12 14:28:12 +1000588static bool
589evo_sync_wait(void *data)
590{
Ben Skeggs5cc027f2013-02-18 17:50:51 -0500591 if (nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000)
592 return true;
593 usleep_range(1, 2);
594 return false;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000595}
596
597static int
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000598evo_sync(struct drm_device *dev)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000599{
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000600 struct nvif_device *device = &nouveau_drm(dev)->device;
Ben Skeggse225f442012-11-21 14:40:21 +1000601 struct nv50_disp *disp = nv50_disp(dev);
602 struct nv50_mast *mast = nv50_mast(dev);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000603 u32 *push = evo_wait(mast, 8);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000604 if (push) {
Ben Skeggs816af2f2011-11-16 15:48:48 +1000605 nouveau_bo_wr32(disp->sync, EVO_MAST_NTFY, 0x00000000);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000606 evo_mthd(push, 0x0084, 1);
Ben Skeggs816af2f2011-11-16 15:48:48 +1000607 evo_data(push, 0x80000000 | EVO_MAST_NTFY);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000608 evo_mthd(push, 0x0080, 2);
609 evo_data(push, 0x00000000);
610 evo_data(push, 0x00000000);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000611 evo_kick(push, mast);
Ben Skeggs54442042015-08-20 14:54:11 +1000612 if (nvif_msec(device, 2000,
613 if (evo_sync_wait(disp->sync))
614 break;
615 ) >= 0)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000616 return 0;
617 }
618
619 return -EBUSY;
620}
621
622/******************************************************************************
Ben Skeggsa63a97e2011-11-16 15:22:34 +1000623 * Page flipping channel
Ben Skeggs3376ee32011-11-12 14:28:12 +1000624 *****************************************************************************/
625struct nouveau_bo *
Ben Skeggse225f442012-11-21 14:40:21 +1000626nv50_display_crtc_sema(struct drm_device *dev, int crtc)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000627{
Ben Skeggse225f442012-11-21 14:40:21 +1000628 return nv50_disp(dev)->sync;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000629}
630
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000631struct nv50_display_flip {
632 struct nv50_disp *disp;
633 struct nv50_sync *chan;
634};
635
636static bool
637nv50_display_flip_wait(void *data)
638{
639 struct nv50_display_flip *flip = data;
640 if (nouveau_bo_rd32(flip->disp->sync, flip->chan->addr / 4) ==
Calvin Owensb1ea3e62013-04-07 21:01:19 -0500641 flip->chan->data)
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000642 return true;
643 usleep_range(1, 2);
644 return false;
645}
646
Ben Skeggs3376ee32011-11-12 14:28:12 +1000647void
Ben Skeggse225f442012-11-21 14:40:21 +1000648nv50_display_flip_stop(struct drm_crtc *crtc)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000649{
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000650 struct nvif_device *device = &nouveau_drm(crtc->dev)->device;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000651 struct nv50_display_flip flip = {
652 .disp = nv50_disp(crtc->dev),
653 .chan = nv50_sync(crtc),
654 };
Ben Skeggs3376ee32011-11-12 14:28:12 +1000655 u32 *push;
656
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000657 push = evo_wait(flip.chan, 8);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000658 if (push) {
659 evo_mthd(push, 0x0084, 1);
660 evo_data(push, 0x00000000);
661 evo_mthd(push, 0x0094, 1);
662 evo_data(push, 0x00000000);
663 evo_mthd(push, 0x00c0, 1);
664 evo_data(push, 0x00000000);
665 evo_mthd(push, 0x0080, 1);
666 evo_data(push, 0x00000000);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000667 evo_kick(push, flip.chan);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000668 }
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000669
Ben Skeggs54442042015-08-20 14:54:11 +1000670 nvif_msec(device, 2000,
671 if (nv50_display_flip_wait(&flip))
672 break;
673 );
Ben Skeggs3376ee32011-11-12 14:28:12 +1000674}
675
676int
Ben Skeggse225f442012-11-21 14:40:21 +1000677nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
Ben Skeggs3376ee32011-11-12 14:28:12 +1000678 struct nouveau_channel *chan, u32 swap_interval)
679{
680 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000681 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000682 struct nv50_head *head = nv50_head(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +1000683 struct nv50_sync *sync = nv50_sync(crtc);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000684 u32 *push;
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000685 int ret;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000686
Ben Skeggs9ba83102014-12-22 19:50:23 +1000687 if (crtc->primary->fb->width != fb->width ||
688 crtc->primary->fb->height != fb->height)
689 return -EINVAL;
690
Ben Skeggs3376ee32011-11-12 14:28:12 +1000691 swap_interval <<= 4;
692 if (swap_interval == 0)
693 swap_interval |= 0x100;
Ben Skeggsf60b6e72013-03-19 15:20:00 +1000694 if (chan == NULL)
695 evo_sync(crtc->dev);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000696
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000697 push = evo_wait(sync, 128);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000698 if (unlikely(push == NULL))
699 return -EBUSY;
700
Ben Skeggsa01ca782015-08-20 14:54:15 +1000701 if (chan && chan->user.oclass < G82_CHANNEL_GPFIFO) {
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000702 ret = RING_SPACE(chan, 8);
703 if (ret)
704 return ret;
Ben Skeggs67f97182013-02-26 12:02:54 +1000705
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000706 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000707 OUT_RING (chan, NvEvoSema0 + nv_crtc->index);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000708 OUT_RING (chan, sync->addr ^ 0x10);
709 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
710 OUT_RING (chan, sync->data + 1);
711 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_OFFSET, 2);
712 OUT_RING (chan, sync->addr);
713 OUT_RING (chan, sync->data);
714 } else
Ben Skeggsa01ca782015-08-20 14:54:15 +1000715 if (chan && chan->user.oclass < FERMI_CHANNEL_GPFIFO) {
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000716 u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000717 ret = RING_SPACE(chan, 12);
718 if (ret)
719 return ret;
Ben Skeggsa34caf72013-02-14 09:28:37 +1000720
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000721 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
Ben Skeggs0ad72862014-08-10 04:10:22 +1000722 OUT_RING (chan, chan->vram.handle);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000723 BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
724 OUT_RING (chan, upper_32_bits(addr ^ 0x10));
725 OUT_RING (chan, lower_32_bits(addr ^ 0x10));
726 OUT_RING (chan, sync->data + 1);
727 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG);
728 BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
729 OUT_RING (chan, upper_32_bits(addr));
730 OUT_RING (chan, lower_32_bits(addr));
731 OUT_RING (chan, sync->data);
732 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL);
733 } else
734 if (chan) {
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000735 u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000736 ret = RING_SPACE(chan, 10);
737 if (ret)
738 return ret;
Ben Skeggs67f97182013-02-26 12:02:54 +1000739
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000740 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
741 OUT_RING (chan, upper_32_bits(addr ^ 0x10));
742 OUT_RING (chan, lower_32_bits(addr ^ 0x10));
743 OUT_RING (chan, sync->data + 1);
744 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG |
745 NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD);
746 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
747 OUT_RING (chan, upper_32_bits(addr));
748 OUT_RING (chan, lower_32_bits(addr));
749 OUT_RING (chan, sync->data);
750 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL |
751 NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD);
752 }
Ben Skeggs35bcf5d2012-04-30 11:34:10 -0500753
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000754 if (chan) {
755 sync->addr ^= 0x10;
756 sync->data++;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000757 FIRE_RING (chan);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000758 }
759
760 /* queue the flip */
761 evo_mthd(push, 0x0100, 1);
762 evo_data(push, 0xfffe0000);
763 evo_mthd(push, 0x0084, 1);
764 evo_data(push, swap_interval);
765 if (!(swap_interval & 0x00000100)) {
766 evo_mthd(push, 0x00e0, 1);
767 evo_data(push, 0x40000000);
768 }
769 evo_mthd(push, 0x0088, 4);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000770 evo_data(push, sync->addr);
771 evo_data(push, sync->data++);
772 evo_data(push, sync->data);
Ben Skeggsf45f55c2014-08-10 04:10:23 +1000773 evo_data(push, sync->base.sync.handle);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000774 evo_mthd(push, 0x00a0, 2);
775 evo_data(push, 0x00000000);
776 evo_data(push, 0x00000000);
777 evo_mthd(push, 0x00c0, 1);
Ben Skeggs8a423642014-08-10 04:10:19 +1000778 evo_data(push, nv_fb->r_handle);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000779 evo_mthd(push, 0x0110, 2);
780 evo_data(push, 0x00000000);
781 evo_data(push, 0x00000000);
Ben Skeggs648d4df2014-08-10 04:10:27 +1000782 if (nv50_vers(sync) < GF110_DISP_BASE_CHANNEL_DMA) {
Ben Skeggsed5085a52012-11-16 13:16:51 +1000783 evo_mthd(push, 0x0800, 5);
784 evo_data(push, nv_fb->nvbo->bo.offset >> 8);
785 evo_data(push, 0);
786 evo_data(push, (fb->height << 16) | fb->width);
787 evo_data(push, nv_fb->r_pitch);
788 evo_data(push, nv_fb->r_format);
789 } else {
790 evo_mthd(push, 0x0400, 5);
791 evo_data(push, nv_fb->nvbo->bo.offset >> 8);
792 evo_data(push, 0);
793 evo_data(push, (fb->height << 16) | fb->width);
794 evo_data(push, nv_fb->r_pitch);
795 evo_data(push, nv_fb->r_format);
796 }
Ben Skeggs3376ee32011-11-12 14:28:12 +1000797 evo_mthd(push, 0x0080, 1);
798 evo_data(push, 0x00000000);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000799 evo_kick(push, sync);
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000800
801 nouveau_bo_ref(nv_fb->nvbo, &head->image);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000802 return 0;
803}
804
Ben Skeggs26f6d882011-07-04 16:25:18 +1000805/******************************************************************************
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000806 * Head
807 *****************************************************************************/
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000808static void
Ben Skeggs7e918332016-11-04 17:20:36 +1000809nv50_head_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
810{
811 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
812 u32 *push;
813 if ((push = evo_wait(core, 2))) {
814 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA)
815 evo_mthd(push, 0x08a0 + (head->base.index * 0x0400), 1);
816 else
817 if (core->base.user.oclass < GK104_DISP_CORE_CHANNEL_DMA)
818 evo_mthd(push, 0x0490 + (head->base.index * 0x0300), 1);
819 else
820 evo_mthd(push, 0x04a0 + (head->base.index * 0x0300), 1);
821 evo_data(push, (asyh->dither.mode << 3) |
822 (asyh->dither.bits << 1) |
823 asyh->dither.enable);
824 evo_kick(push, core);
825 }
826}
827
828static void
Ben Skeggs6bbab3b2016-11-04 17:20:36 +1000829nv50_head_ovly(struct nv50_head *head, struct nv50_head_atom *asyh)
830{
831 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
832 u32 bounds = 0;
833 u32 *push;
834
835 if (asyh->base.cpp) {
836 switch (asyh->base.cpp) {
837 case 8: bounds |= 0x00000500; break;
838 case 4: bounds |= 0x00000300; break;
839 case 2: bounds |= 0x00000100; break;
840 default:
841 WARN_ON(1);
842 break;
843 }
844 bounds |= 0x00000001;
845 }
846
847 if ((push = evo_wait(core, 2))) {
848 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA)
849 evo_mthd(push, 0x0904 + head->base.index * 0x400, 1);
850 else
851 evo_mthd(push, 0x04d4 + head->base.index * 0x300, 1);
852 evo_data(push, bounds);
853 evo_kick(push, core);
854 }
855}
856
857static void
858nv50_head_base(struct nv50_head *head, struct nv50_head_atom *asyh)
859{
860 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
861 u32 bounds = 0;
862 u32 *push;
863
864 if (asyh->base.cpp) {
865 switch (asyh->base.cpp) {
866 case 8: bounds |= 0x00000500; break;
867 case 4: bounds |= 0x00000300; break;
868 case 2: bounds |= 0x00000100; break;
869 case 1: bounds |= 0x00000000; break;
870 default:
871 WARN_ON(1);
872 break;
873 }
874 bounds |= 0x00000001;
875 }
876
877 if ((push = evo_wait(core, 2))) {
878 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA)
879 evo_mthd(push, 0x0900 + head->base.index * 0x400, 1);
880 else
881 evo_mthd(push, 0x04d0 + head->base.index * 0x300, 1);
882 evo_data(push, bounds);
883 evo_kick(push, core);
884 }
885}
886
887static void
Ben Skeggsea8ee392016-11-04 17:20:36 +1000888nv50_head_curs_clr(struct nv50_head *head)
889{
890 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
891 u32 *push;
892 if ((push = evo_wait(core, 4))) {
893 if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) {
894 evo_mthd(push, 0x0880 + head->base.index * 0x400, 1);
895 evo_data(push, 0x05000000);
896 } else
897 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
898 evo_mthd(push, 0x0880 + head->base.index * 0x400, 1);
899 evo_data(push, 0x05000000);
900 evo_mthd(push, 0x089c + head->base.index * 0x400, 1);
901 evo_data(push, 0x00000000);
902 } else {
903 evo_mthd(push, 0x0480 + head->base.index * 0x300, 1);
904 evo_data(push, 0x05000000);
905 evo_mthd(push, 0x048c + head->base.index * 0x300, 1);
906 evo_data(push, 0x00000000);
907 }
908 evo_kick(push, core);
909 }
910}
911
912static void
913nv50_head_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
914{
915 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
916 u32 *push;
917 if ((push = evo_wait(core, 5))) {
918 if (core->base.user.oclass < G82_DISP_BASE_CHANNEL_DMA) {
919 evo_mthd(push, 0x0880 + head->base.index * 0x400, 2);
920 evo_data(push, 0x80000000 | (asyh->curs.layout << 26) |
921 (asyh->curs.format << 24));
922 evo_data(push, asyh->curs.offset >> 8);
923 } else
924 if (core->base.user.oclass < GF110_DISP_BASE_CHANNEL_DMA) {
925 evo_mthd(push, 0x0880 + head->base.index * 0x400, 2);
926 evo_data(push, 0x80000000 | (asyh->curs.layout << 26) |
927 (asyh->curs.format << 24));
928 evo_data(push, asyh->curs.offset >> 8);
929 evo_mthd(push, 0x089c + head->base.index * 0x400, 1);
930 evo_data(push, asyh->curs.handle);
931 } else {
932 evo_mthd(push, 0x0480 + head->base.index * 0x300, 2);
933 evo_data(push, 0x80000000 | (asyh->curs.layout << 26) |
934 (asyh->curs.format << 24));
935 evo_data(push, asyh->curs.offset >> 8);
936 evo_mthd(push, 0x048c + head->base.index * 0x300, 1);
937 evo_data(push, asyh->curs.handle);
938 }
939 evo_kick(push, core);
940 }
941}
942
943static void
Ben Skeggsad633612016-11-04 17:20:36 +1000944nv50_head_core_clr(struct nv50_head *head)
945{
946 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
947 u32 *push;
948 if ((push = evo_wait(core, 2))) {
949 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA)
950 evo_mthd(push, 0x0874 + head->base.index * 0x400, 1);
951 else
952 evo_mthd(push, 0x0474 + head->base.index * 0x300, 1);
953 evo_data(push, 0x00000000);
954 evo_kick(push, core);
955 }
956}
957
958static void
959nv50_head_core_set(struct nv50_head *head, struct nv50_head_atom *asyh)
960{
961 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
962 u32 *push;
963 if ((push = evo_wait(core, 9))) {
964 if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) {
965 evo_mthd(push, 0x0860 + head->base.index * 0x400, 1);
966 evo_data(push, asyh->core.offset >> 8);
967 evo_mthd(push, 0x0868 + head->base.index * 0x400, 4);
968 evo_data(push, (asyh->core.h << 16) | asyh->core.w);
969 evo_data(push, asyh->core.layout << 20 |
970 (asyh->core.pitch >> 8) << 8 |
971 asyh->core.block);
972 evo_data(push, asyh->core.kind << 16 |
973 asyh->core.format << 8);
974 evo_data(push, asyh->core.handle);
975 evo_mthd(push, 0x08c0 + head->base.index * 0x400, 1);
976 evo_data(push, (asyh->core.y << 16) | asyh->core.x);
977 } else
978 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
979 evo_mthd(push, 0x0860 + head->base.index * 0x400, 1);
980 evo_data(push, asyh->core.offset >> 8);
981 evo_mthd(push, 0x0868 + head->base.index * 0x400, 4);
982 evo_data(push, (asyh->core.h << 16) | asyh->core.w);
983 evo_data(push, asyh->core.layout << 20 |
984 (asyh->core.pitch >> 8) << 8 |
985 asyh->core.block);
986 evo_data(push, asyh->core.format << 8);
987 evo_data(push, asyh->core.handle);
988 evo_mthd(push, 0x08c0 + head->base.index * 0x400, 1);
989 evo_data(push, (asyh->core.y << 16) | asyh->core.x);
990 } else {
991 evo_mthd(push, 0x0460 + head->base.index * 0x300, 1);
992 evo_data(push, asyh->core.offset >> 8);
993 evo_mthd(push, 0x0468 + head->base.index * 0x300, 4);
994 evo_data(push, (asyh->core.h << 16) | asyh->core.w);
995 evo_data(push, asyh->core.layout << 24 |
996 (asyh->core.pitch >> 8) << 8 |
997 asyh->core.block);
998 evo_data(push, asyh->core.format << 8);
999 evo_data(push, asyh->core.handle);
1000 evo_mthd(push, 0x04b0 + head->base.index * 0x300, 1);
1001 evo_data(push, (asyh->core.y << 16) | asyh->core.x);
1002 }
1003 evo_kick(push, core);
1004 }
1005}
1006
1007static void
Ben Skeggsa7ae1562016-11-04 17:20:36 +10001008nv50_head_lut_clr(struct nv50_head *head)
1009{
1010 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1011 u32 *push;
1012 if ((push = evo_wait(core, 4))) {
1013 if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) {
1014 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 1);
1015 evo_data(push, 0x40000000);
1016 } else
1017 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1018 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 1);
1019 evo_data(push, 0x40000000);
1020 evo_mthd(push, 0x085c + (head->base.index * 0x400), 1);
1021 evo_data(push, 0x00000000);
1022 } else {
1023 evo_mthd(push, 0x0440 + (head->base.index * 0x300), 1);
1024 evo_data(push, 0x03000000);
1025 evo_mthd(push, 0x045c + (head->base.index * 0x300), 1);
1026 evo_data(push, 0x00000000);
1027 }
1028 evo_kick(push, core);
1029 }
1030}
1031
1032static void
1033nv50_head_lut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1034{
1035 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1036 u32 *push;
1037 if ((push = evo_wait(core, 7))) {
1038 if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) {
1039 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2);
1040 evo_data(push, 0xc0000000);
1041 evo_data(push, asyh->lut.offset >> 8);
1042 } else
1043 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1044 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2);
1045 evo_data(push, 0xc0000000);
1046 evo_data(push, asyh->lut.offset >> 8);
1047 evo_mthd(push, 0x085c + (head->base.index * 0x400), 1);
1048 evo_data(push, asyh->lut.handle);
1049 } else {
1050 evo_mthd(push, 0x0440 + (head->base.index * 0x300), 4);
1051 evo_data(push, 0x83000000);
1052 evo_data(push, asyh->lut.offset >> 8);
1053 evo_data(push, 0x00000000);
1054 evo_data(push, 0x00000000);
1055 evo_mthd(push, 0x045c + (head->base.index * 0x300), 1);
1056 evo_data(push, asyh->lut.handle);
1057 }
1058 evo_kick(push, core);
1059 }
1060}
1061
1062static void
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001063nv50_head_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
1064{
1065 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1066 struct nv50_head_mode *m = &asyh->mode;
1067 u32 *push;
1068 if ((push = evo_wait(core, 14))) {
1069 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1070 evo_mthd(push, 0x0804 + (head->base.index * 0x400), 2);
1071 evo_data(push, 0x00800000 | m->clock);
1072 evo_data(push, m->interlace ? 0x00000002 : 0x00000000);
1073 evo_mthd(push, 0x0810 + (head->base.index * 0x400), 6);
1074 evo_data(push, 0x00000000);
1075 evo_data(push, (m->v.active << 16) | m->h.active );
1076 evo_data(push, (m->v.synce << 16) | m->h.synce );
1077 evo_data(push, (m->v.blanke << 16) | m->h.blanke );
1078 evo_data(push, (m->v.blanks << 16) | m->h.blanks );
1079 evo_data(push, (m->v.blank2e << 16) | m->v.blank2s);
1080 evo_mthd(push, 0x082c + (head->base.index * 0x400), 1);
1081 evo_data(push, 0x00000000);
1082 } else {
1083 evo_mthd(push, 0x0410 + (head->base.index * 0x300), 6);
1084 evo_data(push, 0x00000000);
1085 evo_data(push, (m->v.active << 16) | m->h.active );
1086 evo_data(push, (m->v.synce << 16) | m->h.synce );
1087 evo_data(push, (m->v.blanke << 16) | m->h.blanke );
1088 evo_data(push, (m->v.blanks << 16) | m->h.blanks );
1089 evo_data(push, (m->v.blank2e << 16) | m->v.blank2s);
1090 evo_mthd(push, 0x042c + (head->base.index * 0x300), 2);
1091 evo_data(push, 0x00000000); /* ??? */
1092 evo_data(push, 0xffffff00);
1093 evo_mthd(push, 0x0450 + (head->base.index * 0x300), 3);
1094 evo_data(push, m->clock * 1000);
1095 evo_data(push, 0x00200000); /* ??? */
1096 evo_data(push, m->clock * 1000);
1097 }
1098 evo_kick(push, core);
1099 }
1100}
1101
1102static void
Ben Skeggsc4e68122016-11-04 17:20:36 +10001103nv50_head_view(struct nv50_head *head, struct nv50_head_atom *asyh)
1104{
1105 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1106 u32 *push;
1107 if ((push = evo_wait(core, 10))) {
1108 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1109 evo_mthd(push, 0x08a4 + (head->base.index * 0x400), 1);
1110 evo_data(push, 0x00000000);
1111 evo_mthd(push, 0x08c8 + (head->base.index * 0x400), 1);
1112 evo_data(push, (asyh->view.iH << 16) | asyh->view.iW);
1113 evo_mthd(push, 0x08d8 + (head->base.index * 0x400), 2);
1114 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1115 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1116 } else {
1117 evo_mthd(push, 0x0494 + (head->base.index * 0x300), 1);
1118 evo_data(push, 0x00000000);
1119 evo_mthd(push, 0x04b8 + (head->base.index * 0x300), 1);
1120 evo_data(push, (asyh->view.iH << 16) | asyh->view.iW);
1121 evo_mthd(push, 0x04c0 + (head->base.index * 0x300), 3);
1122 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1123 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1124 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1125 }
1126 evo_kick(push, core);
1127 }
1128}
1129
1130static void
Ben Skeggsad633612016-11-04 17:20:36 +10001131nv50_head_flush_clr(struct nv50_head *head, struct nv50_head_atom *asyh, bool y)
1132{
1133 if (asyh->clr.core && (!asyh->set.core || y))
Ben Skeggsa7ae1562016-11-04 17:20:36 +10001134 nv50_head_lut_clr(head);
1135 if (asyh->clr.core && (!asyh->set.core || y))
Ben Skeggsad633612016-11-04 17:20:36 +10001136 nv50_head_core_clr(head);
Ben Skeggsea8ee392016-11-04 17:20:36 +10001137 if (asyh->clr.curs && (!asyh->set.curs || y))
1138 nv50_head_curs_clr(head);
Ben Skeggsad633612016-11-04 17:20:36 +10001139}
1140
1141static void
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001142nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1143{
Ben Skeggsc4e68122016-11-04 17:20:36 +10001144 if (asyh->set.view ) nv50_head_view (head, asyh);
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001145 if (asyh->set.mode ) nv50_head_mode (head, asyh);
Ben Skeggsa7ae1562016-11-04 17:20:36 +10001146 if (asyh->set.core ) nv50_head_lut_set (head, asyh);
Ben Skeggsad633612016-11-04 17:20:36 +10001147 if (asyh->set.core ) nv50_head_core_set(head, asyh);
Ben Skeggsea8ee392016-11-04 17:20:36 +10001148 if (asyh->set.curs ) nv50_head_curs_set(head, asyh);
Ben Skeggs6bbab3b2016-11-04 17:20:36 +10001149 if (asyh->set.base ) nv50_head_base (head, asyh);
1150 if (asyh->set.ovly ) nv50_head_ovly (head, asyh);
Ben Skeggs7e918332016-11-04 17:20:36 +10001151 if (asyh->set.dither ) nv50_head_dither (head, asyh);
1152}
1153
1154static void
1155nv50_head_atomic_check_dither(struct nv50_head_atom *armh,
1156 struct nv50_head_atom *asyh,
1157 struct nouveau_conn_atom *asyc)
1158{
1159 struct drm_connector *connector = asyc->state.connector;
1160 u32 mode = 0x00;
1161
1162 if (asyc->dither.mode == DITHERING_MODE_AUTO) {
1163 if (asyh->base.depth > connector->display_info.bpc * 3)
1164 mode = DITHERING_MODE_DYNAMIC2X2;
1165 } else {
1166 mode = asyc->dither.mode;
1167 }
1168
1169 if (asyc->dither.depth == DITHERING_DEPTH_AUTO) {
1170 if (connector->display_info.bpc >= 8)
1171 mode |= DITHERING_DEPTH_8BPC;
1172 } else {
1173 mode |= asyc->dither.depth;
1174 }
1175
1176 asyh->dither.enable = mode;
1177 asyh->dither.bits = mode >> 1;
1178 asyh->dither.mode = mode >> 3;
1179 asyh->set.dither = true;
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001180}
1181
1182static void
Ben Skeggsc4e68122016-11-04 17:20:36 +10001183nv50_head_atomic_check_view(struct nv50_head_atom *armh,
1184 struct nv50_head_atom *asyh,
1185 struct nouveau_conn_atom *asyc)
1186{
1187 struct drm_connector *connector = asyc->state.connector;
1188 struct drm_display_mode *omode = &asyh->state.adjusted_mode;
1189 struct drm_display_mode *umode = &asyh->state.mode;
1190 int mode = asyc->scaler.mode;
1191 struct edid *edid;
1192
1193 if (connector->edid_blob_ptr)
1194 edid = (struct edid *)connector->edid_blob_ptr->data;
1195 else
1196 edid = NULL;
1197
1198 if (!asyc->scaler.full) {
1199 if (mode == DRM_MODE_SCALE_NONE)
1200 omode = umode;
1201 } else {
1202 /* Non-EDID LVDS/eDP mode. */
1203 mode = DRM_MODE_SCALE_FULLSCREEN;
1204 }
1205
1206 asyh->view.iW = umode->hdisplay;
1207 asyh->view.iH = umode->vdisplay;
1208 asyh->view.oW = omode->hdisplay;
1209 asyh->view.oH = omode->vdisplay;
1210 if (omode->flags & DRM_MODE_FLAG_DBLSCAN)
1211 asyh->view.oH *= 2;
1212
1213 /* Add overscan compensation if necessary, will keep the aspect
1214 * ratio the same as the backend mode unless overridden by the
1215 * user setting both hborder and vborder properties.
1216 */
1217 if ((asyc->scaler.underscan.mode == UNDERSCAN_ON ||
1218 (asyc->scaler.underscan.mode == UNDERSCAN_AUTO &&
1219 drm_detect_hdmi_monitor(edid)))) {
1220 u32 bX = asyc->scaler.underscan.hborder;
1221 u32 bY = asyc->scaler.underscan.vborder;
1222 u32 r = (asyh->view.oH << 19) / asyh->view.oW;
1223
1224 if (bX) {
1225 asyh->view.oW -= (bX * 2);
1226 if (bY) asyh->view.oH -= (bY * 2);
1227 else asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19;
1228 } else {
1229 asyh->view.oW -= (asyh->view.oW >> 4) + 32;
1230 if (bY) asyh->view.oH -= (bY * 2);
1231 else asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19;
1232 }
1233 }
1234
1235 /* Handle CENTER/ASPECT scaling, taking into account the areas
1236 * removed already for overscan compensation.
1237 */
1238 switch (mode) {
1239 case DRM_MODE_SCALE_CENTER:
1240 asyh->view.oW = min((u16)umode->hdisplay, asyh->view.oW);
1241 asyh->view.oH = min((u16)umode->vdisplay, asyh->view.oH);
1242 /* fall-through */
1243 case DRM_MODE_SCALE_ASPECT:
1244 if (asyh->view.oH < asyh->view.oW) {
1245 u32 r = (asyh->view.iW << 19) / asyh->view.iH;
1246 asyh->view.oW = ((asyh->view.oH * r) + (r / 2)) >> 19;
1247 } else {
1248 u32 r = (asyh->view.iH << 19) / asyh->view.iW;
1249 asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19;
1250 }
1251 break;
1252 default:
1253 break;
1254 }
1255
1256 asyh->set.view = true;
1257}
1258
1259static void
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001260nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
1261{
1262 struct drm_display_mode *mode = &asyh->state.adjusted_mode;
1263 u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1;
1264 u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
1265 u32 hbackp = mode->htotal - mode->hsync_end;
1266 u32 vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace;
1267 u32 hfrontp = mode->hsync_start - mode->hdisplay;
1268 u32 vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
1269 struct nv50_head_mode *m = &asyh->mode;
1270
1271 m->h.active = mode->htotal;
1272 m->h.synce = mode->hsync_end - mode->hsync_start - 1;
1273 m->h.blanke = m->h.synce + hbackp;
1274 m->h.blanks = mode->htotal - hfrontp - 1;
1275
1276 m->v.active = mode->vtotal * vscan / ilace;
1277 m->v.synce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1;
1278 m->v.blanke = m->v.synce + vbackp;
1279 m->v.blanks = m->v.active - vfrontp - 1;
1280
1281 /*XXX: Safe underestimate, even "0" works */
1282 m->v.blankus = (m->v.active - mode->vdisplay - 2) * m->h.active;
1283 m->v.blankus *= 1000;
1284 m->v.blankus /= mode->clock;
1285
1286 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
1287 m->v.blank2e = m->v.active + m->v.synce + vbackp;
1288 m->v.blank2s = m->v.blank2e + (mode->vdisplay * vscan / ilace);
1289 m->v.active = (m->v.active * 2) + 1;
1290 m->interlace = true;
1291 } else {
1292 m->v.blank2e = 0;
1293 m->v.blank2s = 1;
1294 m->interlace = false;
1295 }
1296 m->clock = mode->clock;
1297
1298 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1299 asyh->set.mode = true;
1300}
1301
1302static int
1303nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
1304{
1305 struct nouveau_drm *drm = nouveau_drm(crtc->dev);
Ben Skeggsad633612016-11-04 17:20:36 +10001306 struct nv50_disp *disp = nv50_disp(crtc->dev);
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001307 struct nv50_head *head = nv50_head(crtc);
1308 struct nv50_head_atom *armh = &head->arm;
1309 struct nv50_head_atom *asyh = nv50_head_atom(state);
1310
1311 NV_ATOMIC(drm, "%s atomic_check %d\n", crtc->name, asyh->state.active);
Ben Skeggsad633612016-11-04 17:20:36 +10001312 asyh->clr.mask = 0;
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001313 asyh->set.mask = 0;
1314
1315 if (asyh->state.active) {
1316 if (asyh->state.mode_changed)
1317 nv50_head_atomic_check_mode(head, asyh);
Ben Skeggsad633612016-11-04 17:20:36 +10001318
1319 if ((asyh->core.visible = (asyh->base.cpp != 0))) {
1320 asyh->core.x = asyh->base.x;
1321 asyh->core.y = asyh->base.y;
1322 asyh->core.w = asyh->base.w;
1323 asyh->core.h = asyh->base.h;
1324 } else
Ben Skeggsea8ee392016-11-04 17:20:36 +10001325 if ((asyh->core.visible = asyh->curs.visible)) {
Ben Skeggsad633612016-11-04 17:20:36 +10001326 /*XXX: We need to either find some way of having the
1327 * primary base layer appear black, while still
1328 * being able to display the other layers, or we
1329 * need to allocate a dummy black surface here.
1330 */
1331 asyh->core.x = 0;
1332 asyh->core.y = 0;
1333 asyh->core.w = asyh->state.mode.hdisplay;
1334 asyh->core.h = asyh->state.mode.vdisplay;
1335 }
1336 asyh->core.handle = disp->mast.base.vram.handle;
1337 asyh->core.offset = 0;
1338 asyh->core.format = 0xcf;
1339 asyh->core.kind = 0;
1340 asyh->core.layout = 1;
1341 asyh->core.block = 0;
1342 asyh->core.pitch = ALIGN(asyh->core.w, 64) * 4;
Ben Skeggsa7ae1562016-11-04 17:20:36 +10001343 asyh->lut.handle = disp->mast.base.vram.handle;
1344 asyh->lut.offset = head->base.lut.nvbo->bo.offset;
Ben Skeggs6bbab3b2016-11-04 17:20:36 +10001345 asyh->set.base = armh->base.cpp != asyh->base.cpp;
1346 asyh->set.ovly = armh->ovly.cpp != asyh->ovly.cpp;
Ben Skeggsad633612016-11-04 17:20:36 +10001347 } else {
1348 asyh->core.visible = false;
Ben Skeggsea8ee392016-11-04 17:20:36 +10001349 asyh->curs.visible = false;
Ben Skeggs6bbab3b2016-11-04 17:20:36 +10001350 asyh->base.cpp = 0;
1351 asyh->ovly.cpp = 0;
Ben Skeggsad633612016-11-04 17:20:36 +10001352 }
1353
1354 if (!drm_atomic_crtc_needs_modeset(&asyh->state)) {
1355 if (asyh->core.visible) {
1356 if (memcmp(&armh->core, &asyh->core, sizeof(asyh->core)))
1357 asyh->set.core = true;
1358 } else
1359 if (armh->core.visible) {
1360 asyh->clr.core = true;
1361 }
Ben Skeggsea8ee392016-11-04 17:20:36 +10001362
1363 if (asyh->curs.visible) {
1364 if (memcmp(&armh->curs, &asyh->curs, sizeof(asyh->curs)))
1365 asyh->set.curs = true;
1366 } else
1367 if (armh->curs.visible) {
1368 asyh->clr.curs = true;
1369 }
Ben Skeggsad633612016-11-04 17:20:36 +10001370 } else {
1371 asyh->clr.core = armh->core.visible;
Ben Skeggsea8ee392016-11-04 17:20:36 +10001372 asyh->clr.curs = armh->curs.visible;
Ben Skeggsad633612016-11-04 17:20:36 +10001373 asyh->set.core = asyh->core.visible;
Ben Skeggsea8ee392016-11-04 17:20:36 +10001374 asyh->set.curs = asyh->curs.visible;
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001375 }
1376
1377 memcpy(armh, asyh, sizeof(*asyh));
1378 asyh->state.mode_changed = 0;
1379 return 0;
1380}
1381
1382/******************************************************************************
Ben Skeggs438d99e2011-07-05 16:48:06 +10001383 * CRTC
1384 *****************************************************************************/
1385static int
Ben Skeggse225f442012-11-21 14:40:21 +10001386nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001387{
Ben Skeggse225f442012-11-21 14:40:21 +10001388 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggs7e918332016-11-04 17:20:36 +10001389 struct nv50_head *head = nv50_head(&nv_crtc->base);
1390 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggsde691852011-10-17 12:23:41 +10001391 struct nouveau_connector *nv_connector;
Ben Skeggs7e918332016-11-04 17:20:36 +10001392 struct nouveau_conn_atom asyc;
1393 u32 *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001394
Ben Skeggs488ff202011-10-17 10:38:10 +10001395 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggsde691852011-10-17 12:23:41 +10001396
Ben Skeggs7e918332016-11-04 17:20:36 +10001397 asyc.state.connector = &nv_connector->base;
1398 asyc.dither.mode = nv_connector->dithering_mode;
1399 asyc.dither.depth = nv_connector->dithering_depth;
1400 asyh->state.crtc = &nv_crtc->base;
1401 nv50_head_atomic_check(&head->base.base, &asyh->state);
1402 nv50_head_atomic_check_dither(&head->arm, asyh, &asyc);
1403 nv50_head_flush_set(head, asyh);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001404
Ben Skeggs7e918332016-11-04 17:20:36 +10001405 if (update) {
1406 if ((push = evo_wait(mast, 2))) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10001407 evo_mthd(push, 0x0080, 1);
1408 evo_data(push, 0x00000000);
Ben Skeggs7e918332016-11-04 17:20:36 +10001409 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001410 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10001411 }
1412
1413 return 0;
1414}
1415
1416static int
Ben Skeggse225f442012-11-21 14:40:21 +10001417nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001418{
Ben Skeggsc4e68122016-11-04 17:20:36 +10001419 struct nv50_head *head = nv50_head(&nv_crtc->base);
1420 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggs3376ee32011-11-12 14:28:12 +10001421 struct drm_crtc *crtc = &nv_crtc->base;
Ben Skeggsf3fdc522011-07-07 16:01:57 +10001422 struct nouveau_connector *nv_connector;
Ben Skeggsc4e68122016-11-04 17:20:36 +10001423 struct nouveau_conn_atom asyc;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001424
Ben Skeggsf3fdc522011-07-07 16:01:57 +10001425 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggsf3fdc522011-07-07 16:01:57 +10001426
Ben Skeggsc4e68122016-11-04 17:20:36 +10001427 asyc.state.connector = &nv_connector->base;
1428 asyc.scaler.mode = nv_connector->scaling_mode;
1429 asyc.scaler.full = nv_connector->scaling_full;
1430 asyc.scaler.underscan.mode = nv_connector->underscan;
1431 asyc.scaler.underscan.hborder = nv_connector->underscan_hborder;
1432 asyc.scaler.underscan.vborder = nv_connector->underscan_vborder;
1433 nv50_head_atomic_check(&head->base.base, &asyh->state);
1434 nv50_head_atomic_check_view(&head->arm, asyh, &asyc);
1435 nv50_head_flush_set(head, asyh);
Ben Skeggs92854622011-11-11 23:49:06 +10001436
Ben Skeggsc4e68122016-11-04 17:20:36 +10001437 if (update) {
1438 nv50_display_flip_stop(crtc);
1439 nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001440 }
1441
1442 return 0;
1443}
1444
1445static int
Roy Splieteae73822014-10-30 22:57:45 +01001446nv50_crtc_set_raster_vblank_dmi(struct nouveau_crtc *nv_crtc, u32 usec)
1447{
1448 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
1449 u32 *push;
1450
1451 push = evo_wait(mast, 8);
1452 if (!push)
1453 return -ENOMEM;
1454
1455 evo_mthd(push, 0x0828 + (nv_crtc->index * 0x400), 1);
1456 evo_data(push, usec);
1457 evo_kick(push, mast);
1458 return 0;
1459}
1460
1461static int
Ben Skeggse225f442012-11-21 14:40:21 +10001462nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggsf9887d02012-11-21 13:03:42 +10001463{
Ben Skeggse225f442012-11-21 14:40:21 +10001464 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsf9887d02012-11-21 13:03:42 +10001465 u32 *push, hue, vib;
1466 int adj;
1467
1468 adj = (nv_crtc->color_vibrance > 0) ? 50 : 0;
1469 vib = ((nv_crtc->color_vibrance * 2047 + adj) / 100) & 0xfff;
1470 hue = ((nv_crtc->vibrant_hue * 2047) / 100) & 0xfff;
1471
1472 push = evo_wait(mast, 16);
1473 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10001474 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsf9887d02012-11-21 13:03:42 +10001475 evo_mthd(push, 0x08a8 + (nv_crtc->index * 0x400), 1);
1476 evo_data(push, (hue << 20) | (vib << 8));
1477 } else {
1478 evo_mthd(push, 0x0498 + (nv_crtc->index * 0x300), 1);
1479 evo_data(push, (hue << 20) | (vib << 8));
1480 }
1481
1482 if (update) {
1483 evo_mthd(push, 0x0080, 1);
1484 evo_data(push, 0x00000000);
1485 }
1486 evo_kick(push, mast);
1487 }
1488
1489 return 0;
1490}
1491
1492static int
Ben Skeggse225f442012-11-21 14:40:21 +10001493nv50_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001494 int x, int y, bool update)
1495{
1496 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb);
Ben Skeggsad633612016-11-04 17:20:36 +10001497 struct nv50_head *head = nv50_head(&nv_crtc->base);
1498 struct nv50_head_atom *asyh = &head->asy;
1499 const struct drm_format_info *info;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001500
Ben Skeggsad633612016-11-04 17:20:36 +10001501 info = drm_format_info(nvfb->base.pixel_format);
1502 if (!info || !info->depth)
1503 return -EINVAL;
Ben Skeggsde8268c2012-11-16 10:24:31 +10001504
Ben Skeggsad633612016-11-04 17:20:36 +10001505 asyh->base.depth = info->depth;
1506 asyh->base.cpp = info->cpp[0];
1507 asyh->base.x = x;
1508 asyh->base.y = y;
1509 asyh->base.w = nvfb->base.width;
1510 asyh->base.h = nvfb->base.height;
1511 nv50_head_atomic_check(&head->base.base, &asyh->state);
1512 nv50_head_flush_set(head, asyh);
1513
1514 if (update) {
1515 struct nv50_mast *core = nv50_mast(nv_crtc->base.dev);
1516 u32 *push = evo_wait(core, 2);
1517 if (push) {
Ben Skeggsa46232e2011-07-07 15:23:48 +10001518 evo_mthd(push, 0x0080, 1);
1519 evo_data(push, 0x00000000);
Ben Skeggsad633612016-11-04 17:20:36 +10001520 evo_kick(push, core);
Ben Skeggsa46232e2011-07-07 15:23:48 +10001521 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10001522 }
1523
Ben Skeggs8a423642014-08-10 04:10:19 +10001524 nv_crtc->fb.handle = nvfb->r_handle;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001525 return 0;
1526}
1527
1528static void
Ben Skeggse225f442012-11-21 14:40:21 +10001529nv50_crtc_cursor_show(struct nouveau_crtc *nv_crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001530{
Ben Skeggse225f442012-11-21 14:40:21 +10001531 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsea8ee392016-11-04 17:20:36 +10001532 struct nv50_head *head = nv50_head(&nv_crtc->base);
1533 struct nv50_head_atom *asyh = &head->asy;
1534
1535 asyh->curs.visible = true;
1536 asyh->curs.handle = mast->base.vram.handle;
1537 asyh->curs.offset = nv_crtc->cursor.nvbo->bo.offset;
1538 asyh->curs.layout = 1;
1539 asyh->curs.format = 1;
1540 nv50_head_atomic_check(&head->base.base, &asyh->state);
1541 nv50_head_flush_set(head, asyh);
Ben Skeggsde8268c2012-11-16 10:24:31 +10001542}
1543
1544static void
Ben Skeggse225f442012-11-21 14:40:21 +10001545nv50_crtc_cursor_hide(struct nouveau_crtc *nv_crtc)
Ben Skeggsde8268c2012-11-16 10:24:31 +10001546{
Ben Skeggsea8ee392016-11-04 17:20:36 +10001547 struct nv50_head *head = nv50_head(&nv_crtc->base);
1548 struct nv50_head_atom *asyh = &head->asy;
1549
1550 asyh->curs.visible = false;
1551 nv50_head_atomic_check(&head->base.base, &asyh->state);
1552 nv50_head_flush_clr(head, asyh, false);
Ben Skeggsde8268c2012-11-16 10:24:31 +10001553}
Ben Skeggs438d99e2011-07-05 16:48:06 +10001554
Ben Skeggsde8268c2012-11-16 10:24:31 +10001555static void
Ben Skeggse225f442012-11-21 14:40:21 +10001556nv50_crtc_cursor_show_hide(struct nouveau_crtc *nv_crtc, bool show, bool update)
Ben Skeggsde8268c2012-11-16 10:24:31 +10001557{
Ben Skeggse225f442012-11-21 14:40:21 +10001558 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde8268c2012-11-16 10:24:31 +10001559
Ben Skeggs697bb722015-07-28 17:20:57 +10001560 if (show && nv_crtc->cursor.nvbo && nv_crtc->base.enabled)
Ben Skeggse225f442012-11-21 14:40:21 +10001561 nv50_crtc_cursor_show(nv_crtc);
Ben Skeggsde8268c2012-11-16 10:24:31 +10001562 else
Ben Skeggse225f442012-11-21 14:40:21 +10001563 nv50_crtc_cursor_hide(nv_crtc);
Ben Skeggsde8268c2012-11-16 10:24:31 +10001564
1565 if (update) {
1566 u32 *push = evo_wait(mast, 2);
1567 if (push) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10001568 evo_mthd(push, 0x0080, 1);
1569 evo_data(push, 0x00000000);
Ben Skeggsde8268c2012-11-16 10:24:31 +10001570 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001571 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10001572 }
1573}
1574
1575static void
Ben Skeggse225f442012-11-21 14:40:21 +10001576nv50_crtc_dpms(struct drm_crtc *crtc, int mode)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001577{
1578}
1579
1580static void
Ben Skeggse225f442012-11-21 14:40:21 +10001581nv50_crtc_prepare(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001582{
Ben Skeggsad633612016-11-04 17:20:36 +10001583 struct nv50_head *head = nv50_head(crtc);
1584 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001585
Ben Skeggse225f442012-11-21 14:40:21 +10001586 nv50_display_flip_stop(crtc);
Ben Skeggs3376ee32011-11-12 14:28:12 +10001587
Ben Skeggsad633612016-11-04 17:20:36 +10001588 asyh->state.active = false;
1589 nv50_head_atomic_check(&head->base.base, &asyh->state);
1590 nv50_head_flush_clr(head, asyh, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001591}
1592
1593static void
Ben Skeggse225f442012-11-21 14:40:21 +10001594nv50_crtc_commit(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001595{
Ben Skeggsa7ae1562016-11-04 17:20:36 +10001596 struct nv50_head *head = nv50_head(crtc);
1597 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001598
Ben Skeggsa7ae1562016-11-04 17:20:36 +10001599 asyh->state.active = true;
1600 nv50_head_atomic_check(&head->base.base, &asyh->state);
1601 nv50_head_flush_set(head, asyh);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001602
Matt Roperf4510a22014-04-01 15:22:40 -07001603 nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001604}
1605
1606static bool
Ben Skeggse225f442012-11-21 14:40:21 +10001607nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001608 struct drm_display_mode *adjusted_mode)
1609{
Ben Skeggseb2e9682014-01-24 10:13:23 +10001610 drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001611 return true;
1612}
1613
1614static int
Ben Skeggse225f442012-11-21 14:40:21 +10001615nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001616{
Matt Roperf4510a22014-04-01 15:22:40 -07001617 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001618 struct nv50_head *head = nv50_head(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001619 int ret;
1620
Ben Skeggs547ad072014-11-10 12:35:06 +10001621 ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM, true);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001622 if (ret == 0) {
1623 if (head->image)
1624 nouveau_bo_unpin(head->image);
1625 nouveau_bo_ref(nvfb->nvbo, &head->image);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001626 }
1627
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001628 return ret;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001629}
1630
1631static int
Ben Skeggse225f442012-11-21 14:40:21 +10001632nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001633 struct drm_display_mode *mode, int x, int y,
1634 struct drm_framebuffer *old_fb)
1635{
Ben Skeggse225f442012-11-21 14:40:21 +10001636 struct nv50_mast *mast = nv50_mast(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001637 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1638 struct nouveau_connector *nv_connector;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001639 int ret;
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001640 struct nv50_head *head = nv50_head(crtc);
1641 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001642
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001643 memcpy(&asyh->state.mode, umode, sizeof(*umode));
1644 memcpy(&asyh->state.adjusted_mode, mode, sizeof(*mode));
1645 asyh->state.active = true;
1646 asyh->state.mode_changed = true;
1647 nv50_head_atomic_check(&head->base.base, &asyh->state);
Ben Skeggs2d1d8982011-11-11 23:39:22 +10001648
Ben Skeggse225f442012-11-21 14:40:21 +10001649 ret = nv50_crtc_swap_fbs(crtc, old_fb);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001650 if (ret)
1651 return ret;
1652
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001653 nv50_head_flush_set(head, asyh);
1654
Ben Skeggs438d99e2011-07-05 16:48:06 +10001655 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001656 nv50_crtc_set_dither(nv_crtc, false);
1657 nv50_crtc_set_scale(nv_crtc, false);
Roy Splieteae73822014-10-30 22:57:45 +01001658
1659 /* G94 only accepts this after setting scale */
1660 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA)
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001661 nv50_crtc_set_raster_vblank_dmi(nv_crtc, asyh->mode.v.blankus);
Roy Splieteae73822014-10-30 22:57:45 +01001662
Ben Skeggse225f442012-11-21 14:40:21 +10001663 nv50_crtc_set_color_vibrance(nv_crtc, false);
Matt Roperf4510a22014-04-01 15:22:40 -07001664 nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001665 return 0;
1666}
1667
1668static int
Ben Skeggse225f442012-11-21 14:40:21 +10001669nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001670 struct drm_framebuffer *old_fb)
1671{
Ben Skeggs77145f12012-07-31 16:16:21 +10001672 struct nouveau_drm *drm = nouveau_drm(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001673 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1674 int ret;
1675
Matt Roperf4510a22014-04-01 15:22:40 -07001676 if (!crtc->primary->fb) {
Ben Skeggs77145f12012-07-31 16:16:21 +10001677 NV_DEBUG(drm, "No FB bound\n");
Ben Skeggs84e2ad82011-08-26 09:40:39 +10001678 return 0;
1679 }
1680
Ben Skeggse225f442012-11-21 14:40:21 +10001681 ret = nv50_crtc_swap_fbs(crtc, old_fb);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001682 if (ret)
1683 return ret;
1684
Ben Skeggse225f442012-11-21 14:40:21 +10001685 nv50_display_flip_stop(crtc);
Matt Roperf4510a22014-04-01 15:22:40 -07001686 nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, true);
1687 nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001688 return 0;
1689}
1690
1691static int
Ben Skeggse225f442012-11-21 14:40:21 +10001692nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001693 struct drm_framebuffer *fb, int x, int y,
1694 enum mode_set_atomic state)
1695{
1696 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001697 nv50_display_flip_stop(crtc);
1698 nv50_crtc_set_image(nv_crtc, fb, x, y, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001699 return 0;
1700}
1701
1702static void
Ben Skeggse225f442012-11-21 14:40:21 +10001703nv50_crtc_lut_load(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001704{
Ben Skeggse225f442012-11-21 14:40:21 +10001705 struct nv50_disp *disp = nv50_disp(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001706 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1707 void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
1708 int i;
1709
1710 for (i = 0; i < 256; i++) {
Ben Skeggsde8268c2012-11-16 10:24:31 +10001711 u16 r = nv_crtc->lut.r[i] >> 2;
1712 u16 g = nv_crtc->lut.g[i] >> 2;
1713 u16 b = nv_crtc->lut.b[i] >> 2;
1714
Ben Skeggs648d4df2014-08-10 04:10:27 +10001715 if (disp->disp->oclass < GF110_DISP) {
Ben Skeggsde8268c2012-11-16 10:24:31 +10001716 writew(r + 0x0000, lut + (i * 0x08) + 0);
1717 writew(g + 0x0000, lut + (i * 0x08) + 2);
1718 writew(b + 0x0000, lut + (i * 0x08) + 4);
1719 } else {
1720 writew(r + 0x6000, lut + (i * 0x20) + 0);
1721 writew(g + 0x6000, lut + (i * 0x20) + 2);
1722 writew(b + 0x6000, lut + (i * 0x20) + 4);
1723 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10001724 }
1725}
1726
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001727static void
1728nv50_crtc_disable(struct drm_crtc *crtc)
1729{
1730 struct nv50_head *head = nv50_head(crtc);
Ben Skeggsefa366f2014-06-05 12:56:35 +10001731 evo_sync(crtc->dev);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001732 if (head->image)
1733 nouveau_bo_unpin(head->image);
1734 nouveau_bo_ref(NULL, &head->image);
1735}
1736
Ben Skeggs438d99e2011-07-05 16:48:06 +10001737static int
Ben Skeggse225f442012-11-21 14:40:21 +10001738nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001739 uint32_t handle, uint32_t width, uint32_t height)
1740{
1741 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggs5a560252014-11-10 15:52:02 +10001742 struct drm_gem_object *gem = NULL;
1743 struct nouveau_bo *nvbo = NULL;
1744 int ret = 0;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001745
Ben Skeggs5a560252014-11-10 15:52:02 +10001746 if (handle) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10001747 if (width != 64 || height != 64)
1748 return -EINVAL;
1749
Chris Wilsona8ad0bd2016-05-09 11:04:54 +01001750 gem = drm_gem_object_lookup(file_priv, handle);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001751 if (unlikely(!gem))
1752 return -ENOENT;
1753 nvbo = nouveau_gem_object(gem);
1754
Ben Skeggs5a560252014-11-10 15:52:02 +10001755 ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001756 }
1757
Ben Skeggs5a560252014-11-10 15:52:02 +10001758 if (ret == 0) {
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01001759 if (nv_crtc->cursor.nvbo)
1760 nouveau_bo_unpin(nv_crtc->cursor.nvbo);
1761 nouveau_bo_ref(nvbo, &nv_crtc->cursor.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001762 }
Ben Skeggs5a560252014-11-10 15:52:02 +10001763 drm_gem_object_unreference_unlocked(gem);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001764
Ben Skeggs5a560252014-11-10 15:52:02 +10001765 nv50_crtc_cursor_show_hide(nv_crtc, true, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001766 return ret;
1767}
1768
1769static int
Ben Skeggse225f442012-11-21 14:40:21 +10001770nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001771{
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01001772 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001773 struct nv50_curs *curs = nv50_curs(crtc);
1774 struct nv50_chan *chan = nv50_chan(curs);
Ben Skeggs0ad72862014-08-10 04:10:22 +10001775 nvif_wr32(&chan->user, 0x0084, (y << 16) | (x & 0xffff));
1776 nvif_wr32(&chan->user, 0x0080, 0x00000000);
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01001777
1778 nv_crtc->cursor_saved_x = x;
1779 nv_crtc->cursor_saved_y = y;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001780 return 0;
1781}
1782
Maarten Lankhorst7ea77282016-06-07 12:49:30 +02001783static int
Ben Skeggse225f442012-11-21 14:40:21 +10001784nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
Maarten Lankhorst7ea77282016-06-07 12:49:30 +02001785 uint32_t size)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001786{
1787 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001788 u32 i;
1789
Maarten Lankhorst7ea77282016-06-07 12:49:30 +02001790 for (i = 0; i < size; i++) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10001791 nv_crtc->lut.r[i] = r[i];
1792 nv_crtc->lut.g[i] = g[i];
1793 nv_crtc->lut.b[i] = b[i];
1794 }
1795
Ben Skeggse225f442012-11-21 14:40:21 +10001796 nv50_crtc_lut_load(crtc);
Maarten Lankhorst7ea77282016-06-07 12:49:30 +02001797
1798 return 0;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001799}
1800
1801static void
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01001802nv50_crtc_cursor_restore(struct nouveau_crtc *nv_crtc, int x, int y)
1803{
1804 nv50_crtc_cursor_move(&nv_crtc->base, x, y);
1805
1806 nv50_crtc_cursor_show_hide(nv_crtc, true, true);
1807}
1808
1809static void
Ben Skeggse225f442012-11-21 14:40:21 +10001810nv50_crtc_destroy(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001811{
1812 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001813 struct nv50_disp *disp = nv50_disp(crtc->dev);
1814 struct nv50_head *head = nv50_head(crtc);
Ben Skeggs0ad72862014-08-10 04:10:22 +10001815 struct nv50_fbdma *fbdma;
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001816
Ben Skeggs0ad72862014-08-10 04:10:22 +10001817 list_for_each_entry(fbdma, &disp->fbdma, head) {
1818 nvif_object_fini(&fbdma->base[nv_crtc->index]);
1819 }
1820
1821 nv50_dmac_destroy(&head->ovly.base, disp->disp);
1822 nv50_pioc_destroy(&head->oimm.base);
1823 nv50_dmac_destroy(&head->sync.base, disp->disp);
1824 nv50_pioc_destroy(&head->curs.base);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001825
1826 /*XXX: this shouldn't be necessary, but the core doesn't call
1827 * disconnect() during the cleanup paths
1828 */
1829 if (head->image)
1830 nouveau_bo_unpin(head->image);
1831 nouveau_bo_ref(NULL, &head->image);
1832
Ben Skeggs5a560252014-11-10 15:52:02 +10001833 /*XXX: ditto */
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01001834 if (nv_crtc->cursor.nvbo)
1835 nouveau_bo_unpin(nv_crtc->cursor.nvbo);
1836 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001837
Ben Skeggs438d99e2011-07-05 16:48:06 +10001838 nouveau_bo_unmap(nv_crtc->lut.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001839 if (nv_crtc->lut.nvbo)
1840 nouveau_bo_unpin(nv_crtc->lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001841 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001842
Ben Skeggs438d99e2011-07-05 16:48:06 +10001843 drm_crtc_cleanup(crtc);
1844 kfree(crtc);
1845}
1846
Ben Skeggse225f442012-11-21 14:40:21 +10001847static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = {
1848 .dpms = nv50_crtc_dpms,
1849 .prepare = nv50_crtc_prepare,
1850 .commit = nv50_crtc_commit,
1851 .mode_fixup = nv50_crtc_mode_fixup,
1852 .mode_set = nv50_crtc_mode_set,
1853 .mode_set_base = nv50_crtc_mode_set_base,
1854 .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
1855 .load_lut = nv50_crtc_lut_load,
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001856 .disable = nv50_crtc_disable,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001857};
1858
Ben Skeggse225f442012-11-21 14:40:21 +10001859static const struct drm_crtc_funcs nv50_crtc_func = {
1860 .cursor_set = nv50_crtc_cursor_set,
1861 .cursor_move = nv50_crtc_cursor_move,
1862 .gamma_set = nv50_crtc_gamma_set,
Dave Airlie5addcf02012-09-10 14:20:51 +10001863 .set_config = nouveau_crtc_set_config,
Ben Skeggse225f442012-11-21 14:40:21 +10001864 .destroy = nv50_crtc_destroy,
Ben Skeggs3376ee32011-11-12 14:28:12 +10001865 .page_flip = nouveau_crtc_page_flip,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001866};
1867
1868static int
Ben Skeggs0ad72862014-08-10 04:10:22 +10001869nv50_crtc_create(struct drm_device *dev, int index)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001870{
Ben Skeggsa01ca782015-08-20 14:54:15 +10001871 struct nouveau_drm *drm = nouveau_drm(dev);
1872 struct nvif_device *device = &drm->device;
Ben Skeggse225f442012-11-21 14:40:21 +10001873 struct nv50_disp *disp = nv50_disp(dev);
1874 struct nv50_head *head;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001875 struct drm_crtc *crtc;
1876 int ret, i;
1877
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001878 head = kzalloc(sizeof(*head), GFP_KERNEL);
1879 if (!head)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001880 return -ENOMEM;
1881
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001882 head->base.index = index;
Ben Skeggsf9887d02012-11-21 13:03:42 +10001883 head->base.color_vibrance = 50;
1884 head->base.vibrant_hue = 0;
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01001885 head->base.cursor.set_pos = nv50_crtc_cursor_restore;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001886 for (i = 0; i < 256; i++) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001887 head->base.lut.r[i] = i << 8;
1888 head->base.lut.g[i] = i << 8;
1889 head->base.lut.b[i] = i << 8;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001890 }
1891
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001892 crtc = &head->base.base;
Ben Skeggse225f442012-11-21 14:40:21 +10001893 drm_crtc_init(dev, crtc, &nv50_crtc_func);
1894 drm_crtc_helper_add(crtc, &nv50_crtc_hfunc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001895 drm_mode_crtc_set_gamma_size(crtc, 256);
1896
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +10001897 ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
Maarten Lankhorstbb6178b2014-01-09 11:03:15 +01001898 0, 0x0000, NULL, NULL, &head->base.lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001899 if (!ret) {
Ben Skeggs547ad072014-11-10 12:35:06 +10001900 ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM, true);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001901 if (!ret) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001902 ret = nouveau_bo_map(head->base.lut.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001903 if (ret)
1904 nouveau_bo_unpin(head->base.lut.nvbo);
1905 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10001906 if (ret)
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001907 nouveau_bo_ref(NULL, &head->base.lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001908 }
1909
1910 if (ret)
1911 goto out;
1912
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001913 /* allocate cursor resources */
Ben Skeggsa01ca782015-08-20 14:54:15 +10001914 ret = nv50_curs_create(device, disp->disp, index, &head->curs);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001915 if (ret)
1916 goto out;
1917
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001918 /* allocate page flip / sync resources */
Ben Skeggsa01ca782015-08-20 14:54:15 +10001919 ret = nv50_base_create(device, disp->disp, index, disp->sync->bo.offset,
1920 &head->sync);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001921 if (ret)
1922 goto out;
1923
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001924 head->sync.addr = EVO_FLIP_SEM0(index);
1925 head->sync.data = 0x00000000;
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001926
1927 /* allocate overlay resources */
Ben Skeggsa01ca782015-08-20 14:54:15 +10001928 ret = nv50_oimm_create(device, disp->disp, index, &head->oimm);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001929 if (ret)
1930 goto out;
1931
Ben Skeggsa01ca782015-08-20 14:54:15 +10001932 ret = nv50_ovly_create(device, disp->disp, index, disp->sync->bo.offset,
1933 &head->ovly);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001934 if (ret)
1935 goto out;
1936
Ben Skeggs438d99e2011-07-05 16:48:06 +10001937out:
1938 if (ret)
Ben Skeggse225f442012-11-21 14:40:21 +10001939 nv50_crtc_destroy(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001940 return ret;
1941}
1942
1943/******************************************************************************
Ben Skeggsa91d3222014-12-22 16:30:13 +10001944 * Encoder helpers
1945 *****************************************************************************/
1946static bool
1947nv50_encoder_mode_fixup(struct drm_encoder *encoder,
1948 const struct drm_display_mode *mode,
1949 struct drm_display_mode *adjusted_mode)
1950{
1951 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1952 struct nouveau_connector *nv_connector;
1953
1954 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1955 if (nv_connector && nv_connector->native_mode) {
Ben Skeggs576f7912014-12-22 17:19:26 +10001956 nv_connector->scaling_full = false;
1957 if (nv_connector->scaling_mode == DRM_MODE_SCALE_NONE) {
1958 switch (nv_connector->type) {
1959 case DCB_CONNECTOR_LVDS:
1960 case DCB_CONNECTOR_LVDS_SPWG:
1961 case DCB_CONNECTOR_eDP:
1962 /* force use of scaler for non-edid modes */
1963 if (adjusted_mode->type & DRM_MODE_TYPE_DRIVER)
1964 return true;
1965 nv_connector->scaling_full = true;
1966 break;
1967 default:
1968 return true;
1969 }
1970 }
1971
1972 drm_mode_copy(adjusted_mode, nv_connector->native_mode);
Ben Skeggsa91d3222014-12-22 16:30:13 +10001973 }
1974
1975 return true;
1976}
1977
1978/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10001979 * DAC
1980 *****************************************************************************/
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001981static void
Ben Skeggse225f442012-11-21 14:40:21 +10001982nv50_dac_dpms(struct drm_encoder *encoder, int mode)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001983{
1984 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10001985 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggsbf0eb892014-08-10 04:10:26 +10001986 struct {
1987 struct nv50_disp_mthd_v1 base;
1988 struct nv50_disp_dac_pwr_v0 pwr;
1989 } args = {
1990 .base.version = 1,
1991 .base.method = NV50_DISP_MTHD_V1_DAC_PWR,
1992 .base.hasht = nv_encoder->dcb->hasht,
1993 .base.hashm = nv_encoder->dcb->hashm,
1994 .pwr.state = 1,
1995 .pwr.data = 1,
1996 .pwr.vsync = (mode != DRM_MODE_DPMS_SUSPEND &&
1997 mode != DRM_MODE_DPMS_OFF),
1998 .pwr.hsync = (mode != DRM_MODE_DPMS_STANDBY &&
1999 mode != DRM_MODE_DPMS_OFF),
2000 };
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002001
Ben Skeggsbf0eb892014-08-10 04:10:26 +10002002 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002003}
2004
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002005static void
Ben Skeggse225f442012-11-21 14:40:21 +10002006nv50_dac_commit(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002007{
2008}
2009
2010static void
Ben Skeggse225f442012-11-21 14:40:21 +10002011nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002012 struct drm_display_mode *adjusted_mode)
2013{
Ben Skeggse225f442012-11-21 14:40:21 +10002014 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002015 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2016 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs97b19b52012-11-16 11:21:37 +10002017 u32 *push;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002018
Ben Skeggse225f442012-11-21 14:40:21 +10002019 nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002020
Ben Skeggs97b19b52012-11-16 11:21:37 +10002021 push = evo_wait(mast, 8);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002022 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10002023 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggs97b19b52012-11-16 11:21:37 +10002024 u32 syncs = 0x00000000;
2025
2026 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
2027 syncs |= 0x00000001;
2028 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
2029 syncs |= 0x00000002;
2030
2031 evo_mthd(push, 0x0400 + (nv_encoder->or * 0x080), 2);
2032 evo_data(push, 1 << nv_crtc->index);
2033 evo_data(push, syncs);
2034 } else {
2035 u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
2036 u32 syncs = 0x00000001;
2037
2038 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
2039 syncs |= 0x00000008;
2040 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
2041 syncs |= 0x00000010;
2042
2043 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
2044 magic |= 0x00000001;
2045
2046 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
2047 evo_data(push, syncs);
2048 evo_data(push, magic);
2049 evo_mthd(push, 0x0180 + (nv_encoder->or * 0x020), 1);
2050 evo_data(push, 1 << nv_crtc->index);
2051 }
2052
2053 evo_kick(push, mast);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002054 }
2055
2056 nv_encoder->crtc = encoder->crtc;
2057}
2058
2059static void
Ben Skeggse225f442012-11-21 14:40:21 +10002060nv50_dac_disconnect(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002061{
2062 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10002063 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs97b19b52012-11-16 11:21:37 +10002064 const int or = nv_encoder->or;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002065 u32 *push;
2066
2067 if (nv_encoder->crtc) {
Ben Skeggse225f442012-11-21 14:40:21 +10002068 nv50_crtc_prepare(nv_encoder->crtc);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002069
Ben Skeggs97b19b52012-11-16 11:21:37 +10002070 push = evo_wait(mast, 4);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002071 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10002072 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggs97b19b52012-11-16 11:21:37 +10002073 evo_mthd(push, 0x0400 + (or * 0x080), 1);
2074 evo_data(push, 0x00000000);
2075 } else {
2076 evo_mthd(push, 0x0180 + (or * 0x020), 1);
2077 evo_data(push, 0x00000000);
2078 }
Ben Skeggs97b19b52012-11-16 11:21:37 +10002079 evo_kick(push, mast);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002080 }
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002081 }
Ben Skeggs97b19b52012-11-16 11:21:37 +10002082
2083 nv_encoder->crtc = NULL;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002084}
2085
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10002086static enum drm_connector_status
Ben Skeggse225f442012-11-21 14:40:21 +10002087nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10002088{
Ben Skeggsc4abd312014-08-10 04:10:26 +10002089 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10002090 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggsc4abd312014-08-10 04:10:26 +10002091 struct {
2092 struct nv50_disp_mthd_v1 base;
2093 struct nv50_disp_dac_load_v0 load;
2094 } args = {
2095 .base.version = 1,
2096 .base.method = NV50_DISP_MTHD_V1_DAC_LOAD,
2097 .base.hasht = nv_encoder->dcb->hasht,
2098 .base.hashm = nv_encoder->dcb->hashm,
2099 };
2100 int ret;
Ben Skeggsb6819932011-07-08 11:14:50 +10002101
Ben Skeggsc4abd312014-08-10 04:10:26 +10002102 args.load.data = nouveau_drm(encoder->dev)->vbios.dactestval;
2103 if (args.load.data == 0)
2104 args.load.data = 340;
2105
2106 ret = nvif_mthd(disp->disp, 0, &args, sizeof(args));
2107 if (ret || !args.load.load)
Ben Skeggs35b21d32012-11-08 12:08:55 +10002108 return connector_status_disconnected;
Ben Skeggsb6819932011-07-08 11:14:50 +10002109
Ben Skeggs35b21d32012-11-08 12:08:55 +10002110 return connector_status_connected;
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10002111}
2112
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002113static void
Ben Skeggse225f442012-11-21 14:40:21 +10002114nv50_dac_destroy(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002115{
2116 drm_encoder_cleanup(encoder);
2117 kfree(encoder);
2118}
2119
Ben Skeggse225f442012-11-21 14:40:21 +10002120static const struct drm_encoder_helper_funcs nv50_dac_hfunc = {
2121 .dpms = nv50_dac_dpms,
Ben Skeggsa91d3222014-12-22 16:30:13 +10002122 .mode_fixup = nv50_encoder_mode_fixup,
Ben Skeggse225f442012-11-21 14:40:21 +10002123 .prepare = nv50_dac_disconnect,
2124 .commit = nv50_dac_commit,
2125 .mode_set = nv50_dac_mode_set,
2126 .disable = nv50_dac_disconnect,
2127 .get_crtc = nv50_display_crtc_get,
2128 .detect = nv50_dac_detect
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002129};
2130
Ben Skeggse225f442012-11-21 14:40:21 +10002131static const struct drm_encoder_funcs nv50_dac_func = {
2132 .destroy = nv50_dac_destroy,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002133};
2134
2135static int
Ben Skeggse225f442012-11-21 14:40:21 +10002136nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002137{
Ben Skeggs5ed50202013-02-11 20:15:03 +10002138 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +10002139 struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10002140 struct nvkm_i2c_bus *bus;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002141 struct nouveau_encoder *nv_encoder;
2142 struct drm_encoder *encoder;
Ben Skeggs5ed50202013-02-11 20:15:03 +10002143 int type = DRM_MODE_ENCODER_DAC;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002144
2145 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
2146 if (!nv_encoder)
2147 return -ENOMEM;
2148 nv_encoder->dcb = dcbe;
2149 nv_encoder->or = ffs(dcbe->or) - 1;
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10002150
2151 bus = nvkm_i2c_bus_find(i2c, dcbe->i2c_index);
2152 if (bus)
2153 nv_encoder->i2c = &bus->i2c;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002154
2155 encoder = to_drm_encoder(nv_encoder);
2156 encoder->possible_crtcs = dcbe->heads;
2157 encoder->possible_clones = 0;
Ben Skeggs5a223da2016-11-04 17:20:36 +10002158 drm_encoder_init(connector->dev, encoder, &nv50_dac_func, type,
2159 "dac-%04x-%04x", dcbe->hasht, dcbe->hashm);
Ben Skeggse225f442012-11-21 14:40:21 +10002160 drm_encoder_helper_add(encoder, &nv50_dac_hfunc);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002161
2162 drm_mode_connector_attach_encoder(connector, encoder);
2163 return 0;
2164}
Ben Skeggs26f6d882011-07-04 16:25:18 +10002165
2166/******************************************************************************
Ben Skeggs78951d22011-11-11 18:13:13 +10002167 * Audio
2168 *****************************************************************************/
2169static void
Ben Skeggse225f442012-11-21 14:40:21 +10002170nv50_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
Ben Skeggs78951d22011-11-11 18:13:13 +10002171{
2172 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggscc2a9072014-09-15 21:29:05 +10002173 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs78951d22011-11-11 18:13:13 +10002174 struct nouveau_connector *nv_connector;
Ben Skeggse225f442012-11-21 14:40:21 +10002175 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggsd889c522014-09-15 21:11:51 +10002176 struct __packed {
2177 struct {
2178 struct nv50_disp_mthd_v1 mthd;
2179 struct nv50_disp_sor_hda_eld_v0 eld;
2180 } base;
Ben Skeggs120b0c32014-08-10 04:10:26 +10002181 u8 data[sizeof(nv_connector->base.eld)];
2182 } args = {
Ben Skeggsd889c522014-09-15 21:11:51 +10002183 .base.mthd.version = 1,
2184 .base.mthd.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
2185 .base.mthd.hasht = nv_encoder->dcb->hasht,
Ben Skeggscc2a9072014-09-15 21:29:05 +10002186 .base.mthd.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
2187 (0x0100 << nv_crtc->index),
Ben Skeggs120b0c32014-08-10 04:10:26 +10002188 };
Ben Skeggs78951d22011-11-11 18:13:13 +10002189
2190 nv_connector = nouveau_encoder_connector_get(nv_encoder);
2191 if (!drm_detect_monitor_audio(nv_connector->edid))
2192 return;
2193
Ben Skeggs78951d22011-11-11 18:13:13 +10002194 drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
Ben Skeggs120b0c32014-08-10 04:10:26 +10002195 memcpy(args.data, nv_connector->base.eld, sizeof(args.data));
Ben Skeggs78951d22011-11-11 18:13:13 +10002196
Jani Nikula938fd8a2014-10-28 16:20:48 +02002197 nvif_mthd(disp->disp, 0, &args,
2198 sizeof(args.base) + drm_eld_size(args.data));
Ben Skeggs78951d22011-11-11 18:13:13 +10002199}
2200
2201static void
Ben Skeggscc2a9072014-09-15 21:29:05 +10002202nv50_audio_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
Ben Skeggs78951d22011-11-11 18:13:13 +10002203{
2204 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10002205 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs120b0c32014-08-10 04:10:26 +10002206 struct {
2207 struct nv50_disp_mthd_v1 base;
2208 struct nv50_disp_sor_hda_eld_v0 eld;
2209 } args = {
2210 .base.version = 1,
2211 .base.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
2212 .base.hasht = nv_encoder->dcb->hasht,
Ben Skeggscc2a9072014-09-15 21:29:05 +10002213 .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
2214 (0x0100 << nv_crtc->index),
Ben Skeggs120b0c32014-08-10 04:10:26 +10002215 };
Ben Skeggs78951d22011-11-11 18:13:13 +10002216
Ben Skeggs120b0c32014-08-10 04:10:26 +10002217 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs78951d22011-11-11 18:13:13 +10002218}
2219
2220/******************************************************************************
2221 * HDMI
2222 *****************************************************************************/
2223static void
Ben Skeggse225f442012-11-21 14:40:21 +10002224nv50_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
Ben Skeggs78951d22011-11-11 18:13:13 +10002225{
Ben Skeggs64d9cc02011-11-11 19:51:20 +10002226 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2227 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10002228 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggse00f2232014-08-10 04:10:26 +10002229 struct {
2230 struct nv50_disp_mthd_v1 base;
2231 struct nv50_disp_sor_hdmi_pwr_v0 pwr;
2232 } args = {
2233 .base.version = 1,
2234 .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR,
2235 .base.hasht = nv_encoder->dcb->hasht,
2236 .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
2237 (0x0100 << nv_crtc->index),
2238 .pwr.state = 1,
2239 .pwr.rekey = 56, /* binary driver, and tegra, constant */
2240 };
2241 struct nouveau_connector *nv_connector;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10002242 u32 max_ac_packet;
2243
2244 nv_connector = nouveau_encoder_connector_get(nv_encoder);
2245 if (!drm_detect_hdmi_monitor(nv_connector->edid))
2246 return;
2247
2248 max_ac_packet = mode->htotal - mode->hdisplay;
Ben Skeggse00f2232014-08-10 04:10:26 +10002249 max_ac_packet -= args.pwr.rekey;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10002250 max_ac_packet -= 18; /* constant from tegra */
Ben Skeggse00f2232014-08-10 04:10:26 +10002251 args.pwr.max_ac_packet = max_ac_packet / 32;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10002252
Ben Skeggse00f2232014-08-10 04:10:26 +10002253 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggse225f442012-11-21 14:40:21 +10002254 nv50_audio_mode_set(encoder, mode);
Ben Skeggs78951d22011-11-11 18:13:13 +10002255}
2256
2257static void
Ben Skeggse84a35a2014-06-05 10:59:55 +10002258nv50_hdmi_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
Ben Skeggs78951d22011-11-11 18:13:13 +10002259{
Ben Skeggs64d9cc02011-11-11 19:51:20 +10002260 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10002261 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggse00f2232014-08-10 04:10:26 +10002262 struct {
2263 struct nv50_disp_mthd_v1 base;
2264 struct nv50_disp_sor_hdmi_pwr_v0 pwr;
2265 } args = {
2266 .base.version = 1,
2267 .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR,
2268 .base.hasht = nv_encoder->dcb->hasht,
2269 .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
2270 (0x0100 << nv_crtc->index),
2271 };
Ben Skeggs64d9cc02011-11-11 19:51:20 +10002272
Ben Skeggse00f2232014-08-10 04:10:26 +10002273 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs78951d22011-11-11 18:13:13 +10002274}
2275
2276/******************************************************************************
Ben Skeggs52aa30f2016-11-04 17:20:36 +10002277 * MST
2278 *****************************************************************************/
2279struct nv50_mstm {
2280 struct nouveau_encoder *outp;
2281
2282 struct drm_dp_mst_topology_mgr mgr;
2283};
2284
2285static int
2286nv50_mstm_enable(struct nv50_mstm *mstm, u8 dpcd, int state)
2287{
2288 struct nouveau_encoder *outp = mstm->outp;
2289 struct {
2290 struct nv50_disp_mthd_v1 base;
2291 struct nv50_disp_sor_dp_mst_link_v0 mst;
2292 } args = {
2293 .base.version = 1,
2294 .base.method = NV50_DISP_MTHD_V1_SOR_DP_MST_LINK,
2295 .base.hasht = outp->dcb->hasht,
2296 .base.hashm = outp->dcb->hashm,
2297 .mst.state = state,
2298 };
2299 struct nouveau_drm *drm = nouveau_drm(outp->base.base.dev);
2300 struct nvif_object *disp = &drm->display->disp;
2301 int ret;
2302
2303 if (dpcd >= 0x12) {
2304 ret = drm_dp_dpcd_readb(mstm->mgr.aux, DP_MSTM_CTRL, &dpcd);
2305 if (ret < 0)
2306 return ret;
2307
2308 dpcd &= ~DP_MST_EN;
2309 if (state)
2310 dpcd |= DP_MST_EN;
2311
2312 ret = drm_dp_dpcd_writeb(mstm->mgr.aux, DP_MSTM_CTRL, dpcd);
2313 if (ret < 0)
2314 return ret;
2315 }
2316
2317 return nvif_mthd(disp, 0, &args, sizeof(args));
2318}
2319
2320int
2321nv50_mstm_detect(struct nv50_mstm *mstm, u8 dpcd[8], int allow)
2322{
2323 int ret, state = 0;
2324
2325 if (!mstm)
2326 return 0;
2327
2328 if (dpcd[0] >= 0x12 && allow) {
2329 ret = drm_dp_dpcd_readb(mstm->mgr.aux, DP_MSTM_CAP, &dpcd[1]);
2330 if (ret < 0)
2331 return ret;
2332
2333 state = dpcd[1] & DP_MST_CAP;
2334 }
2335
2336 ret = nv50_mstm_enable(mstm, dpcd[0], state);
2337 if (ret)
2338 return ret;
2339
2340 ret = drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, state);
2341 if (ret)
2342 return nv50_mstm_enable(mstm, dpcd[0], 0);
2343
2344 return mstm->mgr.mst_state;
2345}
2346
2347static void
2348nv50_mstm_del(struct nv50_mstm **pmstm)
2349{
2350 struct nv50_mstm *mstm = *pmstm;
2351 if (mstm) {
2352 kfree(*pmstm);
2353 *pmstm = NULL;
2354 }
2355}
2356
2357static int
2358nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max,
2359 int conn_base_id, struct nv50_mstm **pmstm)
2360{
2361 const int max_payloads = hweight8(outp->dcb->heads);
2362 struct drm_device *dev = outp->base.base.dev;
2363 struct nv50_mstm *mstm;
2364 int ret;
2365
2366 if (!(mstm = *pmstm = kzalloc(sizeof(*mstm), GFP_KERNEL)))
2367 return -ENOMEM;
2368 mstm->outp = outp;
2369
2370 ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev->dev, aux, aux_max,
2371 max_payloads, conn_base_id);
2372 if (ret)
2373 return ret;
2374
2375 return 0;
2376}
2377
2378/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10002379 * SOR
2380 *****************************************************************************/
Ben Skeggs6e83fda2012-03-11 01:28:48 +10002381static void
Ben Skeggse225f442012-11-21 14:40:21 +10002382nv50_sor_dpms(struct drm_encoder *encoder, int mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +10002383{
2384 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggsd55b4af2014-08-10 04:10:26 +10002385 struct nv50_disp *disp = nv50_disp(encoder->dev);
2386 struct {
2387 struct nv50_disp_mthd_v1 base;
2388 struct nv50_disp_sor_pwr_v0 pwr;
2389 } args = {
2390 .base.version = 1,
2391 .base.method = NV50_DISP_MTHD_V1_SOR_PWR,
2392 .base.hasht = nv_encoder->dcb->hasht,
2393 .base.hashm = nv_encoder->dcb->hashm,
2394 .pwr.state = mode == DRM_MODE_DPMS_ON,
2395 };
Ben Skeggsc02ed2b2014-08-10 04:10:27 +10002396 struct {
2397 struct nv50_disp_mthd_v1 base;
2398 struct nv50_disp_sor_dp_pwr_v0 pwr;
2399 } link = {
2400 .base.version = 1,
2401 .base.method = NV50_DISP_MTHD_V1_SOR_DP_PWR,
2402 .base.hasht = nv_encoder->dcb->hasht,
2403 .base.hashm = nv_encoder->dcb->hashm,
2404 .pwr.state = mode == DRM_MODE_DPMS_ON,
2405 };
Ben Skeggs83fc0832011-07-05 13:08:40 +10002406 struct drm_device *dev = encoder->dev;
2407 struct drm_encoder *partner;
Ben Skeggs83fc0832011-07-05 13:08:40 +10002408
2409 nv_encoder->last_dpms = mode;
2410
2411 list_for_each_entry(partner, &dev->mode_config.encoder_list, head) {
2412 struct nouveau_encoder *nv_partner = nouveau_encoder(partner);
2413
2414 if (partner->encoder_type != DRM_MODE_ENCODER_TMDS)
2415 continue;
2416
2417 if (nv_partner != nv_encoder &&
Ben Skeggs26cfa812011-11-17 09:10:02 +10002418 nv_partner->dcb->or == nv_encoder->dcb->or) {
Ben Skeggs83fc0832011-07-05 13:08:40 +10002419 if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
2420 return;
2421 break;
2422 }
2423 }
2424
Ben Skeggs48743222014-05-31 01:48:06 +10002425 if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
Ben Skeggsd55b4af2014-08-10 04:10:26 +10002426 args.pwr.state = 1;
2427 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggsc02ed2b2014-08-10 04:10:27 +10002428 nvif_mthd(disp->disp, 0, &link, sizeof(link));
Ben Skeggs48743222014-05-31 01:48:06 +10002429 } else {
Ben Skeggsd55b4af2014-08-10 04:10:26 +10002430 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs48743222014-05-31 01:48:06 +10002431 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10002432}
2433
Ben Skeggs83fc0832011-07-05 13:08:40 +10002434static void
Ben Skeggse84a35a2014-06-05 10:59:55 +10002435nv50_sor_ctrl(struct nouveau_encoder *nv_encoder, u32 mask, u32 data)
2436{
2437 struct nv50_mast *mast = nv50_mast(nv_encoder->base.base.dev);
2438 u32 temp = (nv_encoder->ctrl & ~mask) | (data & mask), *push;
2439 if (temp != nv_encoder->ctrl && (push = evo_wait(mast, 2))) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10002440 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggse84a35a2014-06-05 10:59:55 +10002441 evo_mthd(push, 0x0600 + (nv_encoder->or * 0x40), 1);
2442 evo_data(push, (nv_encoder->ctrl = temp));
2443 } else {
2444 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
2445 evo_data(push, (nv_encoder->ctrl = temp));
2446 }
2447 evo_kick(push, mast);
2448 }
2449}
2450
2451static void
Ben Skeggse225f442012-11-21 14:40:21 +10002452nv50_sor_disconnect(struct drm_encoder *encoder)
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10002453{
2454 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse84a35a2014-06-05 10:59:55 +10002455 struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
Ben Skeggs419e8dc2012-11-16 11:40:34 +10002456
2457 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
2458 nv_encoder->crtc = NULL;
Ben Skeggse84a35a2014-06-05 10:59:55 +10002459
2460 if (nv_crtc) {
2461 nv50_crtc_prepare(&nv_crtc->base);
2462 nv50_sor_ctrl(nv_encoder, 1 << nv_crtc->index, 0);
Ben Skeggscc2a9072014-09-15 21:29:05 +10002463 nv50_audio_disconnect(encoder, nv_crtc);
Ben Skeggse84a35a2014-06-05 10:59:55 +10002464 nv50_hdmi_disconnect(&nv_encoder->base.base, nv_crtc);
2465 }
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10002466}
2467
2468static void
Ben Skeggse225f442012-11-21 14:40:21 +10002469nv50_sor_commit(struct drm_encoder *encoder)
Ben Skeggs83fc0832011-07-05 13:08:40 +10002470{
2471}
2472
2473static void
Ben Skeggse225f442012-11-21 14:40:21 +10002474nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002475 struct drm_display_mode *mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +10002476{
Ben Skeggsa3761fa2014-08-10 04:10:27 +10002477 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2478 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
2479 struct {
2480 struct nv50_disp_mthd_v1 base;
2481 struct nv50_disp_sor_lvds_script_v0 lvds;
2482 } lvds = {
2483 .base.version = 1,
2484 .base.method = NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT,
2485 .base.hasht = nv_encoder->dcb->hasht,
2486 .base.hashm = nv_encoder->dcb->hashm,
2487 };
Ben Skeggse225f442012-11-21 14:40:21 +10002488 struct nv50_disp *disp = nv50_disp(encoder->dev);
2489 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs78951d22011-11-11 18:13:13 +10002490 struct drm_device *dev = encoder->dev;
Ben Skeggs77145f12012-07-31 16:16:21 +10002491 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002492 struct nouveau_connector *nv_connector;
Ben Skeggs77145f12012-07-31 16:16:21 +10002493 struct nvbios *bios = &drm->vbios;
Ben Skeggsa3761fa2014-08-10 04:10:27 +10002494 u32 mask, ctrl;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10002495 u8 owner = 1 << nv_crtc->index;
2496 u8 proto = 0xf;
2497 u8 depth = 0x0;
Ben Skeggs83fc0832011-07-05 13:08:40 +10002498
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002499 nv_connector = nouveau_encoder_connector_get(nv_encoder);
Ben Skeggse84a35a2014-06-05 10:59:55 +10002500 nv_encoder->crtc = encoder->crtc;
2501
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002502 switch (nv_encoder->dcb->type) {
Ben Skeggscb75d972012-07-11 10:44:20 +10002503 case DCB_OUTPUT_TMDS:
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002504 if (nv_encoder->dcb->sorconf.link & 1) {
Hauke Mehrtens16ef53a92015-11-03 21:00:10 -05002505 proto = 0x1;
2506 /* Only enable dual-link if:
2507 * - Need to (i.e. rate > 165MHz)
2508 * - DCB says we can
2509 * - Not an HDMI monitor, since there's no dual-link
2510 * on HDMI.
2511 */
2512 if (mode->clock >= 165000 &&
2513 nv_encoder->dcb->duallink_possible &&
2514 !drm_detect_hdmi_monitor(nv_connector->edid))
2515 proto |= 0x4;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002516 } else {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10002517 proto = 0x2;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002518 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10002519
Ben Skeggse84a35a2014-06-05 10:59:55 +10002520 nv50_hdmi_mode_set(&nv_encoder->base.base, mode);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002521 break;
Ben Skeggscb75d972012-07-11 10:44:20 +10002522 case DCB_OUTPUT_LVDS:
Ben Skeggs419e8dc2012-11-16 11:40:34 +10002523 proto = 0x0;
2524
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002525 if (bios->fp_no_ddc) {
2526 if (bios->fp.dual_link)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10002527 lvds.lvds.script |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002528 if (bios->fp.if_is_24bit)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10002529 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002530 } else {
Ben Skeggsbefb51e2011-11-18 10:23:59 +10002531 if (nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002532 if (((u8 *)nv_connector->edid)[121] == 2)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10002533 lvds.lvds.script |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002534 } else
2535 if (mode->clock >= bios->fp.duallink_transition_clk) {
Ben Skeggsa3761fa2014-08-10 04:10:27 +10002536 lvds.lvds.script |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002537 }
2538
Ben Skeggsa3761fa2014-08-10 04:10:27 +10002539 if (lvds.lvds.script & 0x0100) {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002540 if (bios->fp.strapless_is_24bit & 2)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10002541 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002542 } else {
2543 if (bios->fp.strapless_is_24bit & 1)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10002544 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002545 }
2546
2547 if (nv_connector->base.display_info.bpc == 8)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10002548 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002549 }
Ben Skeggs4a230fa2012-11-09 11:25:37 +10002550
Ben Skeggsa3761fa2014-08-10 04:10:27 +10002551 nvif_mthd(disp->disp, 0, &lvds, sizeof(lvds));
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002552 break;
Ben Skeggscb75d972012-07-11 10:44:20 +10002553 case DCB_OUTPUT_DP:
Ben Skeggs3488c572012-03-12 11:42:20 +10002554 if (nv_connector->base.display_info.bpc == 6) {
Ben Skeggs6e83fda2012-03-11 01:28:48 +10002555 nv_encoder->dp.datarate = mode->clock * 18 / 8;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10002556 depth = 0x2;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10002557 } else
2558 if (nv_connector->base.display_info.bpc == 8) {
Ben Skeggs6e83fda2012-03-11 01:28:48 +10002559 nv_encoder->dp.datarate = mode->clock * 24 / 8;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10002560 depth = 0x5;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10002561 } else {
2562 nv_encoder->dp.datarate = mode->clock * 30 / 8;
2563 depth = 0x6;
Ben Skeggs3488c572012-03-12 11:42:20 +10002564 }
Ben Skeggs6e83fda2012-03-11 01:28:48 +10002565
2566 if (nv_encoder->dcb->sorconf.link & 1)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10002567 proto = 0x8;
Ben Skeggs6e83fda2012-03-11 01:28:48 +10002568 else
Ben Skeggs419e8dc2012-11-16 11:40:34 +10002569 proto = 0x9;
Ben Skeggs3eee8642014-09-15 15:20:47 +10002570 nv50_audio_mode_set(encoder, mode);
Ben Skeggs6e83fda2012-03-11 01:28:48 +10002571 break;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10002572 default:
2573 BUG_ON(1);
2574 break;
2575 }
Ben Skeggsff8ff502011-07-08 11:53:37 +10002576
Ben Skeggse84a35a2014-06-05 10:59:55 +10002577 nv50_sor_dpms(&nv_encoder->base.base, DRM_MODE_DPMS_ON);
Ben Skeggs83fc0832011-07-05 13:08:40 +10002578
Ben Skeggs648d4df2014-08-10 04:10:27 +10002579 if (nv50_vers(mast) >= GF110_DISP) {
Ben Skeggse84a35a2014-06-05 10:59:55 +10002580 u32 *push = evo_wait(mast, 3);
2581 if (push) {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10002582 u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
2583 u32 syncs = 0x00000001;
2584
2585 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
2586 syncs |= 0x00000008;
2587 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
2588 syncs |= 0x00000010;
2589
2590 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
2591 magic |= 0x00000001;
2592
2593 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
2594 evo_data(push, syncs | (depth << 6));
2595 evo_data(push, magic);
Ben Skeggse84a35a2014-06-05 10:59:55 +10002596 evo_kick(push, mast);
Ben Skeggs419e8dc2012-11-16 11:40:34 +10002597 }
2598
Ben Skeggse84a35a2014-06-05 10:59:55 +10002599 ctrl = proto << 8;
2600 mask = 0x00000f00;
2601 } else {
2602 ctrl = (depth << 16) | (proto << 8);
2603 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
2604 ctrl |= 0x00001000;
2605 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
2606 ctrl |= 0x00002000;
2607 mask = 0x000f3f00;
Ben Skeggs83fc0832011-07-05 13:08:40 +10002608 }
2609
Ben Skeggse84a35a2014-06-05 10:59:55 +10002610 nv50_sor_ctrl(nv_encoder, mask | owner, ctrl | owner);
Ben Skeggs83fc0832011-07-05 13:08:40 +10002611}
2612
2613static void
Ben Skeggse225f442012-11-21 14:40:21 +10002614nv50_sor_destroy(struct drm_encoder *encoder)
Ben Skeggs83fc0832011-07-05 13:08:40 +10002615{
Ben Skeggs52aa30f2016-11-04 17:20:36 +10002616 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2617 nv50_mstm_del(&nv_encoder->dp.mstm);
Ben Skeggs83fc0832011-07-05 13:08:40 +10002618 drm_encoder_cleanup(encoder);
2619 kfree(encoder);
2620}
2621
Ben Skeggse225f442012-11-21 14:40:21 +10002622static const struct drm_encoder_helper_funcs nv50_sor_hfunc = {
2623 .dpms = nv50_sor_dpms,
Ben Skeggsa91d3222014-12-22 16:30:13 +10002624 .mode_fixup = nv50_encoder_mode_fixup,
Ben Skeggs5a885f02013-02-20 14:34:18 +10002625 .prepare = nv50_sor_disconnect,
Ben Skeggse225f442012-11-21 14:40:21 +10002626 .commit = nv50_sor_commit,
2627 .mode_set = nv50_sor_mode_set,
2628 .disable = nv50_sor_disconnect,
2629 .get_crtc = nv50_display_crtc_get,
Ben Skeggs83fc0832011-07-05 13:08:40 +10002630};
2631
Ben Skeggse225f442012-11-21 14:40:21 +10002632static const struct drm_encoder_funcs nv50_sor_func = {
2633 .destroy = nv50_sor_destroy,
Ben Skeggs83fc0832011-07-05 13:08:40 +10002634};
2635
2636static int
Ben Skeggse225f442012-11-21 14:40:21 +10002637nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
Ben Skeggs83fc0832011-07-05 13:08:40 +10002638{
Ben Skeggs52aa30f2016-11-04 17:20:36 +10002639 struct nouveau_connector *nv_connector = nouveau_connector(connector);
Ben Skeggs5ed50202013-02-11 20:15:03 +10002640 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +10002641 struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
Ben Skeggs83fc0832011-07-05 13:08:40 +10002642 struct nouveau_encoder *nv_encoder;
2643 struct drm_encoder *encoder;
Ben Skeggs52aa30f2016-11-04 17:20:36 +10002644 int type, ret;
Ben Skeggs5ed50202013-02-11 20:15:03 +10002645
2646 switch (dcbe->type) {
2647 case DCB_OUTPUT_LVDS: type = DRM_MODE_ENCODER_LVDS; break;
2648 case DCB_OUTPUT_TMDS:
2649 case DCB_OUTPUT_DP:
2650 default:
2651 type = DRM_MODE_ENCODER_TMDS;
2652 break;
2653 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10002654
2655 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
2656 if (!nv_encoder)
2657 return -ENOMEM;
2658 nv_encoder->dcb = dcbe;
2659 nv_encoder->or = ffs(dcbe->or) - 1;
2660 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
2661
Ben Skeggs52aa30f2016-11-04 17:20:36 +10002662 encoder = to_drm_encoder(nv_encoder);
2663 encoder->possible_crtcs = dcbe->heads;
2664 encoder->possible_clones = 0;
Ben Skeggs5a223da2016-11-04 17:20:36 +10002665 drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type,
2666 "sor-%04x-%04x", dcbe->hasht, dcbe->hashm);
Ben Skeggs52aa30f2016-11-04 17:20:36 +10002667 drm_encoder_helper_add(encoder, &nv50_sor_hfunc);
2668
2669 drm_mode_connector_attach_encoder(connector, encoder);
2670
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10002671 if (dcbe->type == DCB_OUTPUT_DP) {
2672 struct nvkm_i2c_aux *aux =
2673 nvkm_i2c_aux_find(i2c, dcbe->i2c_index);
2674 if (aux) {
2675 nv_encoder->i2c = &aux->i2c;
2676 nv_encoder->aux = aux;
2677 }
Ben Skeggs52aa30f2016-11-04 17:20:36 +10002678
2679 /*TODO: Use DP Info Table to check for support. */
2680 if (nv50_disp(encoder->dev)->disp->oclass >= GF110_DISP) {
2681 ret = nv50_mstm_new(nv_encoder, &nv_connector->aux, 16,
2682 nv_connector->base.base.id,
2683 &nv_encoder->dp.mstm);
2684 if (ret)
2685 return ret;
2686 }
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10002687 } else {
2688 struct nvkm_i2c_bus *bus =
2689 nvkm_i2c_bus_find(i2c, dcbe->i2c_index);
2690 if (bus)
2691 nv_encoder->i2c = &bus->i2c;
2692 }
2693
Ben Skeggs83fc0832011-07-05 13:08:40 +10002694 return 0;
2695}
Ben Skeggs26f6d882011-07-04 16:25:18 +10002696
2697/******************************************************************************
Ben Skeggseb6313a2013-02-11 09:52:58 +10002698 * PIOR
2699 *****************************************************************************/
2700
2701static void
2702nv50_pior_dpms(struct drm_encoder *encoder, int mode)
2703{
2704 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2705 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs67cb49c2014-08-10 04:10:27 +10002706 struct {
2707 struct nv50_disp_mthd_v1 base;
2708 struct nv50_disp_pior_pwr_v0 pwr;
2709 } args = {
2710 .base.version = 1,
2711 .base.method = NV50_DISP_MTHD_V1_PIOR_PWR,
2712 .base.hasht = nv_encoder->dcb->hasht,
2713 .base.hashm = nv_encoder->dcb->hashm,
2714 .pwr.state = mode == DRM_MODE_DPMS_ON,
2715 .pwr.type = nv_encoder->dcb->type,
2716 };
2717
2718 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggseb6313a2013-02-11 09:52:58 +10002719}
2720
2721static bool
2722nv50_pior_mode_fixup(struct drm_encoder *encoder,
2723 const struct drm_display_mode *mode,
2724 struct drm_display_mode *adjusted_mode)
2725{
Ben Skeggsa91d3222014-12-22 16:30:13 +10002726 if (!nv50_encoder_mode_fixup(encoder, mode, adjusted_mode))
2727 return false;
Ben Skeggseb6313a2013-02-11 09:52:58 +10002728 adjusted_mode->clock *= 2;
2729 return true;
2730}
2731
2732static void
2733nv50_pior_commit(struct drm_encoder *encoder)
2734{
2735}
2736
2737static void
2738nv50_pior_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
2739 struct drm_display_mode *adjusted_mode)
2740{
2741 struct nv50_mast *mast = nv50_mast(encoder->dev);
2742 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2743 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
2744 struct nouveau_connector *nv_connector;
2745 u8 owner = 1 << nv_crtc->index;
2746 u8 proto, depth;
2747 u32 *push;
2748
2749 nv_connector = nouveau_encoder_connector_get(nv_encoder);
2750 switch (nv_connector->base.display_info.bpc) {
2751 case 10: depth = 0x6; break;
2752 case 8: depth = 0x5; break;
2753 case 6: depth = 0x2; break;
2754 default: depth = 0x0; break;
2755 }
2756
2757 switch (nv_encoder->dcb->type) {
2758 case DCB_OUTPUT_TMDS:
2759 case DCB_OUTPUT_DP:
2760 proto = 0x0;
2761 break;
2762 default:
2763 BUG_ON(1);
2764 break;
2765 }
2766
2767 nv50_pior_dpms(encoder, DRM_MODE_DPMS_ON);
2768
2769 push = evo_wait(mast, 8);
2770 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10002771 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggseb6313a2013-02-11 09:52:58 +10002772 u32 ctrl = (depth << 16) | (proto << 8) | owner;
2773 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
2774 ctrl |= 0x00001000;
2775 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
2776 ctrl |= 0x00002000;
2777 evo_mthd(push, 0x0700 + (nv_encoder->or * 0x040), 1);
2778 evo_data(push, ctrl);
2779 }
2780
2781 evo_kick(push, mast);
2782 }
2783
2784 nv_encoder->crtc = encoder->crtc;
2785}
2786
2787static void
2788nv50_pior_disconnect(struct drm_encoder *encoder)
2789{
2790 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2791 struct nv50_mast *mast = nv50_mast(encoder->dev);
2792 const int or = nv_encoder->or;
2793 u32 *push;
2794
2795 if (nv_encoder->crtc) {
2796 nv50_crtc_prepare(nv_encoder->crtc);
2797
2798 push = evo_wait(mast, 4);
2799 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10002800 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggseb6313a2013-02-11 09:52:58 +10002801 evo_mthd(push, 0x0700 + (or * 0x040), 1);
2802 evo_data(push, 0x00000000);
2803 }
Ben Skeggseb6313a2013-02-11 09:52:58 +10002804 evo_kick(push, mast);
2805 }
2806 }
2807
2808 nv_encoder->crtc = NULL;
2809}
2810
2811static void
2812nv50_pior_destroy(struct drm_encoder *encoder)
2813{
2814 drm_encoder_cleanup(encoder);
2815 kfree(encoder);
2816}
2817
2818static const struct drm_encoder_helper_funcs nv50_pior_hfunc = {
2819 .dpms = nv50_pior_dpms,
2820 .mode_fixup = nv50_pior_mode_fixup,
2821 .prepare = nv50_pior_disconnect,
2822 .commit = nv50_pior_commit,
2823 .mode_set = nv50_pior_mode_set,
2824 .disable = nv50_pior_disconnect,
2825 .get_crtc = nv50_display_crtc_get,
2826};
2827
2828static const struct drm_encoder_funcs nv50_pior_func = {
2829 .destroy = nv50_pior_destroy,
2830};
2831
2832static int
2833nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
2834{
2835 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +10002836 struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10002837 struct nvkm_i2c_bus *bus = NULL;
2838 struct nvkm_i2c_aux *aux = NULL;
2839 struct i2c_adapter *ddc;
Ben Skeggseb6313a2013-02-11 09:52:58 +10002840 struct nouveau_encoder *nv_encoder;
2841 struct drm_encoder *encoder;
2842 int type;
2843
2844 switch (dcbe->type) {
2845 case DCB_OUTPUT_TMDS:
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10002846 bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_EXT(dcbe->extdev));
2847 ddc = bus ? &bus->i2c : NULL;
Ben Skeggseb6313a2013-02-11 09:52:58 +10002848 type = DRM_MODE_ENCODER_TMDS;
2849 break;
2850 case DCB_OUTPUT_DP:
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10002851 aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbe->extdev));
2852 ddc = aux ? &aux->i2c : NULL;
Ben Skeggseb6313a2013-02-11 09:52:58 +10002853 type = DRM_MODE_ENCODER_TMDS;
2854 break;
2855 default:
2856 return -ENODEV;
2857 }
2858
2859 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
2860 if (!nv_encoder)
2861 return -ENOMEM;
2862 nv_encoder->dcb = dcbe;
2863 nv_encoder->or = ffs(dcbe->or) - 1;
2864 nv_encoder->i2c = ddc;
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10002865 nv_encoder->aux = aux;
Ben Skeggseb6313a2013-02-11 09:52:58 +10002866
2867 encoder = to_drm_encoder(nv_encoder);
2868 encoder->possible_crtcs = dcbe->heads;
2869 encoder->possible_clones = 0;
Ben Skeggs5a223da2016-11-04 17:20:36 +10002870 drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type,
2871 "pior-%04x-%04x", dcbe->hasht, dcbe->hashm);
Ben Skeggseb6313a2013-02-11 09:52:58 +10002872 drm_encoder_helper_add(encoder, &nv50_pior_hfunc);
2873
2874 drm_mode_connector_attach_encoder(connector, encoder);
2875 return 0;
2876}
2877
2878/******************************************************************************
Ben Skeggsab0af552014-08-10 04:10:19 +10002879 * Framebuffer
2880 *****************************************************************************/
2881
Ben Skeggs8a423642014-08-10 04:10:19 +10002882static void
Ben Skeggs0ad72862014-08-10 04:10:22 +10002883nv50_fbdma_fini(struct nv50_fbdma *fbdma)
Ben Skeggs8a423642014-08-10 04:10:19 +10002884{
Ben Skeggs0ad72862014-08-10 04:10:22 +10002885 int i;
2886 for (i = 0; i < ARRAY_SIZE(fbdma->base); i++)
2887 nvif_object_fini(&fbdma->base[i]);
2888 nvif_object_fini(&fbdma->core);
Ben Skeggs8a423642014-08-10 04:10:19 +10002889 list_del(&fbdma->head);
2890 kfree(fbdma);
2891}
2892
2893static int
2894nv50_fbdma_init(struct drm_device *dev, u32 name, u64 offset, u64 length, u8 kind)
2895{
2896 struct nouveau_drm *drm = nouveau_drm(dev);
2897 struct nv50_disp *disp = nv50_disp(dev);
2898 struct nv50_mast *mast = nv50_mast(dev);
Ben Skeggs4acfd702014-08-10 04:10:24 +10002899 struct __attribute__ ((packed)) {
2900 struct nv_dma_v0 base;
2901 union {
2902 struct nv50_dma_v0 nv50;
2903 struct gf100_dma_v0 gf100;
Ben Skeggsbd70563f2015-08-20 14:54:21 +10002904 struct gf119_dma_v0 gf119;
Ben Skeggs4acfd702014-08-10 04:10:24 +10002905 };
2906 } args = {};
Ben Skeggs8a423642014-08-10 04:10:19 +10002907 struct nv50_fbdma *fbdma;
2908 struct drm_crtc *crtc;
Ben Skeggs4acfd702014-08-10 04:10:24 +10002909 u32 size = sizeof(args.base);
Ben Skeggs8a423642014-08-10 04:10:19 +10002910 int ret;
2911
2912 list_for_each_entry(fbdma, &disp->fbdma, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002913 if (fbdma->core.handle == name)
Ben Skeggs8a423642014-08-10 04:10:19 +10002914 return 0;
2915 }
2916
2917 fbdma = kzalloc(sizeof(*fbdma), GFP_KERNEL);
2918 if (!fbdma)
2919 return -ENOMEM;
2920 list_add(&fbdma->head, &disp->fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10002921
Ben Skeggs4acfd702014-08-10 04:10:24 +10002922 args.base.target = NV_DMA_V0_TARGET_VRAM;
2923 args.base.access = NV_DMA_V0_ACCESS_RDWR;
2924 args.base.start = offset;
2925 args.base.limit = offset + length - 1;
Ben Skeggs8a423642014-08-10 04:10:19 +10002926
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002927 if (drm->device.info.chipset < 0x80) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10002928 args.nv50.part = NV50_DMA_V0_PART_256;
2929 size += sizeof(args.nv50);
Ben Skeggs8a423642014-08-10 04:10:19 +10002930 } else
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002931 if (drm->device.info.chipset < 0xc0) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10002932 args.nv50.part = NV50_DMA_V0_PART_256;
2933 args.nv50.kind = kind;
2934 size += sizeof(args.nv50);
Ben Skeggs8a423642014-08-10 04:10:19 +10002935 } else
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002936 if (drm->device.info.chipset < 0xd0) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10002937 args.gf100.kind = kind;
2938 size += sizeof(args.gf100);
Ben Skeggs8a423642014-08-10 04:10:19 +10002939 } else {
Ben Skeggsbd70563f2015-08-20 14:54:21 +10002940 args.gf119.page = GF119_DMA_V0_PAGE_LP;
2941 args.gf119.kind = kind;
2942 size += sizeof(args.gf119);
Ben Skeggs8a423642014-08-10 04:10:19 +10002943 }
2944
2945 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002946 struct nv50_head *head = nv50_head(crtc);
Ben Skeggsa01ca782015-08-20 14:54:15 +10002947 int ret = nvif_object_init(&head->sync.base.base.user, name,
2948 NV_DMA_IN_MEMORY, &args, size,
Ben Skeggs0ad72862014-08-10 04:10:22 +10002949 &fbdma->base[head->base.index]);
Ben Skeggs8a423642014-08-10 04:10:19 +10002950 if (ret) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002951 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10002952 return ret;
2953 }
2954 }
2955
Ben Skeggsa01ca782015-08-20 14:54:15 +10002956 ret = nvif_object_init(&mast->base.base.user, name, NV_DMA_IN_MEMORY,
2957 &args, size, &fbdma->core);
Ben Skeggs8a423642014-08-10 04:10:19 +10002958 if (ret) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002959 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10002960 return ret;
2961 }
2962
2963 return 0;
2964}
2965
Ben Skeggsab0af552014-08-10 04:10:19 +10002966static void
2967nv50_fb_dtor(struct drm_framebuffer *fb)
2968{
2969}
2970
2971static int
2972nv50_fb_ctor(struct drm_framebuffer *fb)
2973{
2974 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
2975 struct nouveau_drm *drm = nouveau_drm(fb->dev);
2976 struct nouveau_bo *nvbo = nv_fb->nvbo;
Ben Skeggs8a423642014-08-10 04:10:19 +10002977 struct nv50_disp *disp = nv50_disp(fb->dev);
Ben Skeggs8a423642014-08-10 04:10:19 +10002978 u8 kind = nouveau_bo_tile_layout(nvbo) >> 8;
2979 u8 tile = nvbo->tile_mode;
Ben Skeggsab0af552014-08-10 04:10:19 +10002980
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002981 if (drm->device.info.chipset >= 0xc0)
Ben Skeggs8a423642014-08-10 04:10:19 +10002982 tile >>= 4; /* yep.. */
2983
Ben Skeggsab0af552014-08-10 04:10:19 +10002984 switch (fb->depth) {
2985 case 8: nv_fb->r_format = 0x1e00; break;
2986 case 15: nv_fb->r_format = 0xe900; break;
2987 case 16: nv_fb->r_format = 0xe800; break;
2988 case 24:
2989 case 32: nv_fb->r_format = 0xcf00; break;
2990 case 30: nv_fb->r_format = 0xd100; break;
2991 default:
2992 NV_ERROR(drm, "unknown depth %d\n", fb->depth);
2993 return -EINVAL;
2994 }
2995
Ben Skeggs648d4df2014-08-10 04:10:27 +10002996 if (disp->disp->oclass < G82_DISP) {
Ben Skeggs8a423642014-08-10 04:10:19 +10002997 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
2998 (fb->pitches[0] | 0x00100000);
2999 nv_fb->r_format |= kind << 16;
3000 } else
Ben Skeggs648d4df2014-08-10 04:10:27 +10003001 if (disp->disp->oclass < GF110_DISP) {
Ben Skeggs8a423642014-08-10 04:10:19 +10003002 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
3003 (fb->pitches[0] | 0x00100000);
Ben Skeggsab0af552014-08-10 04:10:19 +10003004 } else {
Ben Skeggs8a423642014-08-10 04:10:19 +10003005 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
3006 (fb->pitches[0] | 0x01000000);
Ben Skeggsab0af552014-08-10 04:10:19 +10003007 }
Ben Skeggs8a423642014-08-10 04:10:19 +10003008 nv_fb->r_handle = 0xffff0000 | kind;
Ben Skeggsab0af552014-08-10 04:10:19 +10003009
Ben Skeggsf392ec42014-08-10 04:10:28 +10003010 return nv50_fbdma_init(fb->dev, nv_fb->r_handle, 0,
3011 drm->device.info.ram_user, kind);
Ben Skeggsab0af552014-08-10 04:10:19 +10003012}
3013
3014/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10003015 * Init
3016 *****************************************************************************/
Ben Skeggsab0af552014-08-10 04:10:19 +10003017
Ben Skeggs2a44e492011-11-09 11:36:33 +10003018void
Ben Skeggse225f442012-11-21 14:40:21 +10003019nv50_display_fini(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10003020{
Ben Skeggs26f6d882011-07-04 16:25:18 +10003021}
3022
3023int
Ben Skeggse225f442012-11-21 14:40:21 +10003024nv50_display_init(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10003025{
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10003026 struct nv50_disp *disp = nv50_disp(dev);
3027 struct drm_crtc *crtc;
3028 u32 *push;
3029
3030 push = evo_wait(nv50_mast(dev), 32);
3031 if (!push)
3032 return -EBUSY;
3033
3034 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
3035 struct nv50_sync *sync = nv50_sync(crtc);
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01003036
3037 nv50_crtc_lut_load(crtc);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10003038 nouveau_bo_wr32(disp->sync, sync->addr / 4, sync->data);
Ben Skeggs26f6d882011-07-04 16:25:18 +10003039 }
3040
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10003041 evo_mthd(push, 0x0088, 1);
Ben Skeggsf45f55c2014-08-10 04:10:23 +10003042 evo_data(push, nv50_mast(dev)->base.sync.handle);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10003043 evo_kick(push, nv50_mast(dev));
3044 return 0;
Ben Skeggs26f6d882011-07-04 16:25:18 +10003045}
3046
3047void
Ben Skeggse225f442012-11-21 14:40:21 +10003048nv50_display_destroy(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10003049{
Ben Skeggse225f442012-11-21 14:40:21 +10003050 struct nv50_disp *disp = nv50_disp(dev);
Ben Skeggs8a423642014-08-10 04:10:19 +10003051 struct nv50_fbdma *fbdma, *fbtmp;
3052
3053 list_for_each_entry_safe(fbdma, fbtmp, &disp->fbdma, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10003054 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10003055 }
Ben Skeggs26f6d882011-07-04 16:25:18 +10003056
Ben Skeggs0ad72862014-08-10 04:10:22 +10003057 nv50_dmac_destroy(&disp->mast.base, disp->disp);
Ben Skeggsbdb8c212011-11-12 01:30:24 +10003058
Ben Skeggs816af2f2011-11-16 15:48:48 +10003059 nouveau_bo_unmap(disp->sync);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01003060 if (disp->sync)
3061 nouveau_bo_unpin(disp->sync);
Ben Skeggs816af2f2011-11-16 15:48:48 +10003062 nouveau_bo_ref(NULL, &disp->sync);
Ben Skeggs51beb422011-07-05 10:33:08 +10003063
Ben Skeggs77145f12012-07-31 16:16:21 +10003064 nouveau_display(dev)->priv = NULL;
Ben Skeggs26f6d882011-07-04 16:25:18 +10003065 kfree(disp);
3066}
3067
3068int
Ben Skeggse225f442012-11-21 14:40:21 +10003069nv50_display_create(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10003070{
Ben Skeggs967e7bd2014-08-10 04:10:22 +10003071 struct nvif_device *device = &nouveau_drm(dev)->device;
Ben Skeggs77145f12012-07-31 16:16:21 +10003072 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs77145f12012-07-31 16:16:21 +10003073 struct dcb_table *dcb = &drm->vbios.dcb;
Ben Skeggs83fc0832011-07-05 13:08:40 +10003074 struct drm_connector *connector, *tmp;
Ben Skeggse225f442012-11-21 14:40:21 +10003075 struct nv50_disp *disp;
Ben Skeggscb75d972012-07-11 10:44:20 +10003076 struct dcb_output *dcbe;
Ben Skeggs7c5f6a82012-03-04 16:25:59 +10003077 int crtcs, ret, i;
Ben Skeggs26f6d882011-07-04 16:25:18 +10003078
3079 disp = kzalloc(sizeof(*disp), GFP_KERNEL);
3080 if (!disp)
3081 return -ENOMEM;
Ben Skeggs8a423642014-08-10 04:10:19 +10003082 INIT_LIST_HEAD(&disp->fbdma);
Ben Skeggs77145f12012-07-31 16:16:21 +10003083
3084 nouveau_display(dev)->priv = disp;
Ben Skeggse225f442012-11-21 14:40:21 +10003085 nouveau_display(dev)->dtor = nv50_display_destroy;
3086 nouveau_display(dev)->init = nv50_display_init;
3087 nouveau_display(dev)->fini = nv50_display_fini;
Ben Skeggsab0af552014-08-10 04:10:19 +10003088 nouveau_display(dev)->fb_ctor = nv50_fb_ctor;
3089 nouveau_display(dev)->fb_dtor = nv50_fb_dtor;
Ben Skeggs0ad72862014-08-10 04:10:22 +10003090 disp->disp = &nouveau_display(dev)->disp;
Ben Skeggs26f6d882011-07-04 16:25:18 +10003091
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003092 /* small shared memory area we use for notifiers and semaphores */
3093 ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
Maarten Lankhorstbb6178b2014-01-09 11:03:15 +01003094 0, 0x0000, NULL, NULL, &disp->sync);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003095 if (!ret) {
Ben Skeggs547ad072014-11-10 12:35:06 +10003096 ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM, true);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01003097 if (!ret) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003098 ret = nouveau_bo_map(disp->sync);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01003099 if (ret)
3100 nouveau_bo_unpin(disp->sync);
3101 }
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003102 if (ret)
3103 nouveau_bo_ref(NULL, &disp->sync);
3104 }
3105
3106 if (ret)
3107 goto out;
3108
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003109 /* allocate master evo channel */
Ben Skeggsa01ca782015-08-20 14:54:15 +10003110 ret = nv50_core_create(device, disp->disp, disp->sync->bo.offset,
Ben Skeggs410f3ec2014-08-10 04:10:25 +10003111 &disp->mast);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003112 if (ret)
3113 goto out;
3114
Ben Skeggs438d99e2011-07-05 16:48:06 +10003115 /* create crtc objects to represent the hw heads */
Ben Skeggs648d4df2014-08-10 04:10:27 +10003116 if (disp->disp->oclass >= GF110_DISP)
Ben Skeggsa01ca782015-08-20 14:54:15 +10003117 crtcs = nvif_rd32(&device->object, 0x022448);
Ben Skeggs63718a02012-11-16 11:44:14 +10003118 else
3119 crtcs = 2;
3120
Ben Skeggs7c5f6a82012-03-04 16:25:59 +10003121 for (i = 0; i < crtcs; i++) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10003122 ret = nv50_crtc_create(dev, i);
Ben Skeggs438d99e2011-07-05 16:48:06 +10003123 if (ret)
3124 goto out;
3125 }
3126
Ben Skeggs83fc0832011-07-05 13:08:40 +10003127 /* create encoder/connector objects based on VBIOS DCB table */
3128 for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
3129 connector = nouveau_connector_create(dev, dcbe->connector);
3130 if (IS_ERR(connector))
3131 continue;
3132
Ben Skeggseb6313a2013-02-11 09:52:58 +10003133 if (dcbe->location == DCB_LOC_ON_CHIP) {
3134 switch (dcbe->type) {
3135 case DCB_OUTPUT_TMDS:
3136 case DCB_OUTPUT_LVDS:
3137 case DCB_OUTPUT_DP:
3138 ret = nv50_sor_create(connector, dcbe);
3139 break;
3140 case DCB_OUTPUT_ANALOG:
3141 ret = nv50_dac_create(connector, dcbe);
3142 break;
3143 default:
3144 ret = -ENODEV;
3145 break;
3146 }
3147 } else {
3148 ret = nv50_pior_create(connector, dcbe);
Ben Skeggs83fc0832011-07-05 13:08:40 +10003149 }
3150
Ben Skeggseb6313a2013-02-11 09:52:58 +10003151 if (ret) {
3152 NV_WARN(drm, "failed to create encoder %d/%d/%d: %d\n",
3153 dcbe->location, dcbe->type,
3154 ffs(dcbe->or) - 1, ret);
Ben Skeggs94f54f52013-03-05 22:26:06 +10003155 ret = 0;
Ben Skeggs83fc0832011-07-05 13:08:40 +10003156 }
3157 }
3158
3159 /* cull any connectors we created that don't have an encoder */
3160 list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) {
3161 if (connector->encoder_ids[0])
3162 continue;
3163
Ben Skeggs77145f12012-07-31 16:16:21 +10003164 NV_WARN(drm, "%s has no encoders, removing\n",
Jani Nikula8c6c3612014-06-03 14:56:18 +03003165 connector->name);
Ben Skeggs83fc0832011-07-05 13:08:40 +10003166 connector->funcs->destroy(connector);
3167 }
3168
Ben Skeggs26f6d882011-07-04 16:25:18 +10003169out:
3170 if (ret)
Ben Skeggse225f442012-11-21 14:40:21 +10003171 nv50_display_destroy(dev);
Ben Skeggs26f6d882011-07-04 16:25:18 +10003172 return ret;
3173}