blob: da1ae6997f8a9a37d152e89a6a4db33e9f3db946 [file] [log] [blame]
Ben Skeggs56d237d2014-05-19 14:54:33 +10001/*
Ben Skeggs26f6d882011-07-04 16:25:18 +10002 * Copyright 2011 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24
Ben Skeggs51beb422011-07-05 10:33:08 +100025#include <linux/dma-mapping.h>
Ben Skeggs83fc0832011-07-05 13:08:40 +100026
David Howells760285e2012-10-02 18:01:07 +010027#include <drm/drmP.h>
Ben Skeggsad633612016-11-04 17:20:36 +100028#include <drm/drm_atomic.h>
Ben Skeggs973f10c2016-11-04 17:20:36 +100029#include <drm/drm_atomic_helper.h>
David Howells760285e2012-10-02 18:01:07 +010030#include <drm/drm_crtc_helper.h>
Ben Skeggs48743222014-05-31 01:48:06 +100031#include <drm/drm_dp_helper.h>
Daniel Vetterb516a9e2015-12-04 09:45:43 +010032#include <drm/drm_fb_helper.h>
Ben Skeggsad633612016-11-04 17:20:36 +100033#include <drm/drm_plane_helper.h>
Ben Skeggs26f6d882011-07-04 16:25:18 +100034
Ben Skeggsfdb751e2014-08-10 04:10:23 +100035#include <nvif/class.h>
Ben Skeggs845f2722015-11-08 12:16:40 +100036#include <nvif/cl0002.h>
Ben Skeggs7568b102015-11-08 10:44:19 +100037#include <nvif/cl5070.h>
38#include <nvif/cl507a.h>
39#include <nvif/cl507b.h>
40#include <nvif/cl507c.h>
41#include <nvif/cl507d.h>
42#include <nvif/cl507e.h>
Ben Skeggs973f10c2016-11-04 17:20:36 +100043#include <nvif/event.h>
Ben Skeggsfdb751e2014-08-10 04:10:23 +100044
Ben Skeggs4dc28132016-05-20 09:22:55 +100045#include "nouveau_drv.h"
Ben Skeggs77145f12012-07-31 16:16:21 +100046#include "nouveau_dma.h"
47#include "nouveau_gem.h"
Ben Skeggs26f6d882011-07-04 16:25:18 +100048#include "nouveau_connector.h"
49#include "nouveau_encoder.h"
50#include "nouveau_crtc.h"
Ben Skeggsf589be82012-07-22 11:55:54 +100051#include "nouveau_fence.h"
Ben Skeggs3a89cd02011-07-07 10:47:10 +100052#include "nv50_display.h"
Ben Skeggs26f6d882011-07-04 16:25:18 +100053
Ben Skeggs8a464382011-11-12 23:52:07 +100054#define EVO_DMA_NR 9
55
Ben Skeggsbdb8c212011-11-12 01:30:24 +100056#define EVO_MASTER (0x00)
Ben Skeggsa63a97e2011-11-16 15:22:34 +100057#define EVO_FLIP(c) (0x01 + (c))
Ben Skeggs8a464382011-11-12 23:52:07 +100058#define EVO_OVLY(c) (0x05 + (c))
59#define EVO_OIMM(c) (0x09 + (c))
Ben Skeggsbdb8c212011-11-12 01:30:24 +100060#define EVO_CURS(c) (0x0d + (c))
61
Ben Skeggs816af2f2011-11-16 15:48:48 +100062/* offsets in shared sync bo of various structures */
63#define EVO_SYNC(c, o) ((c) * 0x0100 + (o))
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +100064#define EVO_MAST_NTFY EVO_SYNC( 0, 0x00)
65#define EVO_FLIP_SEM0(c) EVO_SYNC((c) + 1, 0x00)
66#define EVO_FLIP_SEM1(c) EVO_SYNC((c) + 1, 0x10)
Ben Skeggs973f10c2016-11-04 17:20:36 +100067#define EVO_FLIP_NTFY0(c) EVO_SYNC((c) + 1, 0x20)
68#define EVO_FLIP_NTFY1(c) EVO_SYNC((c) + 1, 0x30)
Ben Skeggs816af2f2011-11-16 15:48:48 +100069
Ben Skeggsb5a794b2012-10-16 14:18:32 +100070/******************************************************************************
Ben Skeggs3dbd0362016-11-04 17:20:36 +100071 * Atomic state
72 *****************************************************************************/
73#define nv50_head_atom(p) container_of((p), struct nv50_head_atom, state)
74
75struct nv50_head_atom {
76 struct drm_crtc_state state;
77
Ben Skeggsc4e68122016-11-04 17:20:36 +100078 struct {
79 u16 iW;
80 u16 iH;
81 u16 oW;
82 u16 oH;
83 } view;
84
Ben Skeggs3dbd0362016-11-04 17:20:36 +100085 struct nv50_head_mode {
86 bool interlace;
87 u32 clock;
88 struct {
89 u16 active;
90 u16 synce;
91 u16 blanke;
92 u16 blanks;
93 } h;
94 struct {
95 u32 active;
96 u16 synce;
97 u16 blanke;
98 u16 blanks;
99 u16 blank2s;
100 u16 blank2e;
101 u16 blankus;
102 } v;
103 } mode;
104
Ben Skeggsad633612016-11-04 17:20:36 +1000105 struct {
Ben Skeggsa7ae1562016-11-04 17:20:36 +1000106 u32 handle;
107 u64 offset:40;
108 } lut;
109
110 struct {
Ben Skeggsad633612016-11-04 17:20:36 +1000111 bool visible;
112 u32 handle;
113 u64 offset:40;
114 u8 format;
115 u8 kind:7;
116 u8 layout:1;
117 u8 block:4;
118 u32 pitch:20;
119 u16 x;
120 u16 y;
121 u16 w;
122 u16 h;
123 } core;
124
125 struct {
Ben Skeggsea8ee392016-11-04 17:20:36 +1000126 bool visible;
127 u32 handle;
128 u64 offset:40;
129 u8 layout:1;
130 u8 format:1;
131 } curs;
132
133 struct {
Ben Skeggsad633612016-11-04 17:20:36 +1000134 u8 depth;
135 u8 cpp;
136 u16 x;
137 u16 y;
138 u16 w;
139 u16 h;
140 } base;
141
Ben Skeggs6bbab3b2016-11-04 17:20:36 +1000142 struct {
143 u8 cpp;
144 } ovly;
145
Ben Skeggs7e918332016-11-04 17:20:36 +1000146 struct {
147 bool enable:1;
148 u8 bits:2;
149 u8 mode:4;
150 } dither;
151
Ben Skeggs7e08d672016-11-04 17:20:36 +1000152 struct {
153 struct {
154 u16 cos:12;
155 u16 sin:12;
156 } sat;
157 } procamp;
158
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000159 union {
160 struct {
Ben Skeggsad633612016-11-04 17:20:36 +1000161 bool core:1;
Ben Skeggsea8ee392016-11-04 17:20:36 +1000162 bool curs:1;
Ben Skeggsad633612016-11-04 17:20:36 +1000163 };
164 u8 mask;
165 } clr;
166
167 union {
168 struct {
169 bool core:1;
Ben Skeggsea8ee392016-11-04 17:20:36 +1000170 bool curs:1;
Ben Skeggsad633612016-11-04 17:20:36 +1000171 bool view:1;
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000172 bool mode:1;
Ben Skeggs6bbab3b2016-11-04 17:20:36 +1000173 bool base:1;
174 bool ovly:1;
Ben Skeggs7e918332016-11-04 17:20:36 +1000175 bool dither:1;
Ben Skeggs7e08d672016-11-04 17:20:36 +1000176 bool procamp:1;
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000177 };
178 u16 mask;
179 } set;
180};
181
Ben Skeggs973f10c2016-11-04 17:20:36 +1000182#define nv50_wndw_atom(p) container_of((p), struct nv50_wndw_atom, state)
183
184struct nv50_wndw_atom {
185 struct drm_plane_state state;
186 u8 interval;
187
188 struct drm_rect clip;
189
190 struct {
191 u32 handle;
192 u16 offset:12;
193 bool awaken:1;
194 } ntfy;
195
196 struct {
197 u32 handle;
198 u16 offset:12;
199 u32 acquire;
200 u32 release;
201 } sema;
202
203 struct {
204 u8 enable:2;
205 } lut;
206
207 struct {
208 u8 mode:2;
209 u8 interval:4;
210
211 u8 format;
212 u8 kind:7;
213 u8 layout:1;
214 u8 block:4;
215 u32 pitch:20;
216 u16 w;
217 u16 h;
218
219 u32 handle;
220 u64 offset;
221 } image;
222
223 struct {
224 u16 x;
225 u16 y;
226 } point;
227
228 union {
229 struct {
230 bool ntfy:1;
231 bool sema:1;
232 bool image:1;
233 };
234 u8 mask;
235 } clr;
236
237 union {
238 struct {
239 bool ntfy:1;
240 bool sema:1;
241 bool image:1;
242 bool lut:1;
243 bool point:1;
244 };
245 u8 mask;
246 } set;
247};
248
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000249/******************************************************************************
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000250 * EVO channel
251 *****************************************************************************/
252
Ben Skeggse225f442012-11-21 14:40:21 +1000253struct nv50_chan {
Ben Skeggs0ad72862014-08-10 04:10:22 +1000254 struct nvif_object user;
Ben Skeggsa01ca782015-08-20 14:54:15 +1000255 struct nvif_device *device;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000256};
257
258static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000259nv50_chan_create(struct nvif_device *device, struct nvif_object *disp,
Ben Skeggs315a8b22015-08-20 14:54:16 +1000260 const s32 *oclass, u8 head, void *data, u32 size,
Ben Skeggsa01ca782015-08-20 14:54:15 +1000261 struct nv50_chan *chan)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000262{
Ben Skeggs41a63402015-08-20 14:54:16 +1000263 struct nvif_sclass *sclass;
264 int ret, i, n;
Ben Skeggs6af52892014-11-03 15:01:33 +1000265
Ben Skeggsa01ca782015-08-20 14:54:15 +1000266 chan->device = device;
267
Ben Skeggs41a63402015-08-20 14:54:16 +1000268 ret = n = nvif_object_sclass_get(disp, &sclass);
Ben Skeggs6af52892014-11-03 15:01:33 +1000269 if (ret < 0)
270 return ret;
271
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000272 while (oclass[0]) {
Ben Skeggs41a63402015-08-20 14:54:16 +1000273 for (i = 0; i < n; i++) {
274 if (sclass[i].oclass == oclass[0]) {
Ben Skeggsfcf3f912015-09-04 14:40:32 +1000275 ret = nvif_object_init(disp, 0, oclass[0],
Ben Skeggsa01ca782015-08-20 14:54:15 +1000276 data, size, &chan->user);
Ben Skeggs6af52892014-11-03 15:01:33 +1000277 if (ret == 0)
278 nvif_object_map(&chan->user);
Ben Skeggs41a63402015-08-20 14:54:16 +1000279 nvif_object_sclass_put(&sclass);
Ben Skeggs6af52892014-11-03 15:01:33 +1000280 return ret;
281 }
Ben Skeggsb76f1522014-08-10 04:10:28 +1000282 }
Ben Skeggs6af52892014-11-03 15:01:33 +1000283 oclass++;
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000284 }
Ben Skeggs6af52892014-11-03 15:01:33 +1000285
Ben Skeggs41a63402015-08-20 14:54:16 +1000286 nvif_object_sclass_put(&sclass);
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000287 return -ENOSYS;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000288}
289
290static void
Ben Skeggs0ad72862014-08-10 04:10:22 +1000291nv50_chan_destroy(struct nv50_chan *chan)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000292{
Ben Skeggs0ad72862014-08-10 04:10:22 +1000293 nvif_object_fini(&chan->user);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000294}
295
296/******************************************************************************
297 * PIO EVO channel
298 *****************************************************************************/
299
Ben Skeggse225f442012-11-21 14:40:21 +1000300struct nv50_pioc {
301 struct nv50_chan base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000302};
303
304static void
Ben Skeggs0ad72862014-08-10 04:10:22 +1000305nv50_pioc_destroy(struct nv50_pioc *pioc)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000306{
Ben Skeggs0ad72862014-08-10 04:10:22 +1000307 nv50_chan_destroy(&pioc->base);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000308}
309
310static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000311nv50_pioc_create(struct nvif_device *device, struct nvif_object *disp,
Ben Skeggs315a8b22015-08-20 14:54:16 +1000312 const s32 *oclass, u8 head, void *data, u32 size,
Ben Skeggsa01ca782015-08-20 14:54:15 +1000313 struct nv50_pioc *pioc)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000314{
Ben Skeggsa01ca782015-08-20 14:54:15 +1000315 return nv50_chan_create(device, disp, oclass, head, data, size,
316 &pioc->base);
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000317}
318
319/******************************************************************************
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000320 * Overlay Immediate
321 *****************************************************************************/
322
323struct nv50_oimm {
324 struct nv50_pioc base;
325};
326
327static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000328nv50_oimm_create(struct nvif_device *device, struct nvif_object *disp,
329 int head, struct nv50_oimm *oimm)
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000330{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000331 struct nv50_disp_cursor_v0 args = {
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000332 .head = head,
333 };
Ben Skeggs315a8b22015-08-20 14:54:16 +1000334 static const s32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000335 GK104_DISP_OVERLAY,
336 GF110_DISP_OVERLAY,
337 GT214_DISP_OVERLAY,
338 G82_DISP_OVERLAY,
339 NV50_DISP_OVERLAY,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000340 0
341 };
342
Ben Skeggsa01ca782015-08-20 14:54:15 +1000343 return nv50_pioc_create(device, disp, oclass, head, &args, sizeof(args),
344 &oimm->base);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000345}
346
347/******************************************************************************
348 * DMA EVO channel
349 *****************************************************************************/
350
Ben Skeggse225f442012-11-21 14:40:21 +1000351struct nv50_dmac {
352 struct nv50_chan base;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000353 dma_addr_t handle;
354 u32 *ptr;
Daniel Vetter59ad1462012-12-02 14:49:44 +0100355
Ben Skeggs0ad72862014-08-10 04:10:22 +1000356 struct nvif_object sync;
357 struct nvif_object vram;
358
Daniel Vetter59ad1462012-12-02 14:49:44 +0100359 /* Protects against concurrent pushbuf access to this channel, lock is
360 * grabbed by evo_wait (if the pushbuf reservation is successful) and
361 * dropped again by evo_kick. */
362 struct mutex lock;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000363};
364
365static void
Ben Skeggs0ad72862014-08-10 04:10:22 +1000366nv50_dmac_destroy(struct nv50_dmac *dmac, struct nvif_object *disp)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000367{
Ben Skeggsa01ca782015-08-20 14:54:15 +1000368 struct nvif_device *device = dmac->base.device;
369
Ben Skeggs0ad72862014-08-10 04:10:22 +1000370 nvif_object_fini(&dmac->vram);
371 nvif_object_fini(&dmac->sync);
372
373 nv50_chan_destroy(&dmac->base);
374
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000375 if (dmac->ptr) {
Ben Skeggs26c9e8e2015-08-20 14:54:23 +1000376 struct device *dev = nvxx_device(device)->dev;
377 dma_free_coherent(dev, PAGE_SIZE, dmac->ptr, dmac->handle);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000378 }
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000379}
380
381static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000382nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
Ben Skeggs315a8b22015-08-20 14:54:16 +1000383 const s32 *oclass, u8 head, void *data, u32 size, u64 syncbuf,
Ben Skeggse225f442012-11-21 14:40:21 +1000384 struct nv50_dmac *dmac)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000385{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000386 struct nv50_disp_core_channel_dma_v0 *args = data;
Ben Skeggs0ad72862014-08-10 04:10:22 +1000387 struct nvif_object pushbuf;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000388 int ret;
389
Daniel Vetter59ad1462012-12-02 14:49:44 +0100390 mutex_init(&dmac->lock);
391
Ben Skeggs26c9e8e2015-08-20 14:54:23 +1000392 dmac->ptr = dma_alloc_coherent(nvxx_device(device)->dev, PAGE_SIZE,
393 &dmac->handle, GFP_KERNEL);
Ben Skeggs47057302012-11-16 13:58:48 +1000394 if (!dmac->ptr)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000395 return -ENOMEM;
396
Ben Skeggsfcf3f912015-09-04 14:40:32 +1000397 ret = nvif_object_init(&device->object, 0, NV_DMA_FROM_MEMORY,
398 &(struct nv_dma_v0) {
Ben Skeggs4acfd702014-08-10 04:10:24 +1000399 .target = NV_DMA_V0_TARGET_PCI_US,
400 .access = NV_DMA_V0_ACCESS_RD,
Ben Skeggs47057302012-11-16 13:58:48 +1000401 .start = dmac->handle + 0x0000,
402 .limit = dmac->handle + 0x0fff,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000403 }, sizeof(struct nv_dma_v0), &pushbuf);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000404 if (ret)
405 return ret;
406
Ben Skeggsbf81df92015-08-20 14:54:16 +1000407 args->pushbuf = nvif_handle(&pushbuf);
408
Ben Skeggsa01ca782015-08-20 14:54:15 +1000409 ret = nv50_chan_create(device, disp, oclass, head, data, size,
410 &dmac->base);
Ben Skeggs0ad72862014-08-10 04:10:22 +1000411 nvif_object_fini(&pushbuf);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000412 if (ret)
413 return ret;
414
Ben Skeggsa01ca782015-08-20 14:54:15 +1000415 ret = nvif_object_init(&dmac->base.user, 0xf0000000, NV_DMA_IN_MEMORY,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000416 &(struct nv_dma_v0) {
417 .target = NV_DMA_V0_TARGET_VRAM,
418 .access = NV_DMA_V0_ACCESS_RDWR,
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000419 .start = syncbuf + 0x0000,
420 .limit = syncbuf + 0x0fff,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000421 }, sizeof(struct nv_dma_v0),
Ben Skeggs0ad72862014-08-10 04:10:22 +1000422 &dmac->sync);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000423 if (ret)
Ben Skeggs47057302012-11-16 13:58:48 +1000424 return ret;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000425
Ben Skeggsa01ca782015-08-20 14:54:15 +1000426 ret = nvif_object_init(&dmac->base.user, 0xf0000001, NV_DMA_IN_MEMORY,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000427 &(struct nv_dma_v0) {
428 .target = NV_DMA_V0_TARGET_VRAM,
429 .access = NV_DMA_V0_ACCESS_RDWR,
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000430 .start = 0,
Ben Skeggsf392ec42014-08-10 04:10:28 +1000431 .limit = device->info.ram_user - 1,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000432 }, sizeof(struct nv_dma_v0),
Ben Skeggs0ad72862014-08-10 04:10:22 +1000433 &dmac->vram);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000434 if (ret)
Ben Skeggs47057302012-11-16 13:58:48 +1000435 return ret;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000436
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000437 return ret;
438}
439
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000440/******************************************************************************
441 * Core
442 *****************************************************************************/
443
Ben Skeggse225f442012-11-21 14:40:21 +1000444struct nv50_mast {
445 struct nv50_dmac base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000446};
447
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000448static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000449nv50_core_create(struct nvif_device *device, struct nvif_object *disp,
450 u64 syncbuf, struct nv50_mast *core)
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000451{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000452 struct nv50_disp_core_channel_dma_v0 args = {
453 .pushbuf = 0xb0007d00,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000454 };
Ben Skeggs315a8b22015-08-20 14:54:16 +1000455 static const s32 oclass[] = {
Ben Skeggsfd478772016-07-09 10:41:01 +1000456 GP104_DISP_CORE_CHANNEL_DMA,
Ben Skeggsf9d5cbb2016-07-09 10:41:01 +1000457 GP100_DISP_CORE_CHANNEL_DMA,
Ben Skeggsdb1eb522016-02-11 08:35:32 +1000458 GM200_DISP_CORE_CHANNEL_DMA,
Ben Skeggs648d4df2014-08-10 04:10:27 +1000459 GM107_DISP_CORE_CHANNEL_DMA,
460 GK110_DISP_CORE_CHANNEL_DMA,
461 GK104_DISP_CORE_CHANNEL_DMA,
462 GF110_DISP_CORE_CHANNEL_DMA,
463 GT214_DISP_CORE_CHANNEL_DMA,
464 GT206_DISP_CORE_CHANNEL_DMA,
465 GT200_DISP_CORE_CHANNEL_DMA,
466 G82_DISP_CORE_CHANNEL_DMA,
467 NV50_DISP_CORE_CHANNEL_DMA,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000468 0
469 };
470
Ben Skeggsa01ca782015-08-20 14:54:15 +1000471 return nv50_dmac_create(device, disp, oclass, 0, &args, sizeof(args),
472 syncbuf, &core->base);
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000473}
474
475/******************************************************************************
476 * Base
477 *****************************************************************************/
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000478
Ben Skeggse225f442012-11-21 14:40:21 +1000479struct nv50_sync {
480 struct nv50_dmac base;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000481 u32 addr;
482 u32 data;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000483};
484
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000485static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000486nv50_base_create(struct nvif_device *device, struct nvif_object *disp,
487 int head, u64 syncbuf, struct nv50_sync *base)
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000488{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000489 struct nv50_disp_base_channel_dma_v0 args = {
490 .pushbuf = 0xb0007c00 | head,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000491 .head = head,
492 };
Ben Skeggs315a8b22015-08-20 14:54:16 +1000493 static const s32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000494 GK110_DISP_BASE_CHANNEL_DMA,
495 GK104_DISP_BASE_CHANNEL_DMA,
496 GF110_DISP_BASE_CHANNEL_DMA,
497 GT214_DISP_BASE_CHANNEL_DMA,
498 GT200_DISP_BASE_CHANNEL_DMA,
499 G82_DISP_BASE_CHANNEL_DMA,
500 NV50_DISP_BASE_CHANNEL_DMA,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000501 0
502 };
503
Ben Skeggsa01ca782015-08-20 14:54:15 +1000504 return nv50_dmac_create(device, disp, oclass, head, &args, sizeof(args),
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000505 syncbuf, &base->base);
506}
507
508/******************************************************************************
509 * Overlay
510 *****************************************************************************/
511
Ben Skeggse225f442012-11-21 14:40:21 +1000512struct nv50_ovly {
513 struct nv50_dmac base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000514};
Ben Skeggsf20ce962011-07-08 13:17:01 +1000515
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000516static int
Ben Skeggsa01ca782015-08-20 14:54:15 +1000517nv50_ovly_create(struct nvif_device *device, struct nvif_object *disp,
518 int head, u64 syncbuf, struct nv50_ovly *ovly)
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000519{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000520 struct nv50_disp_overlay_channel_dma_v0 args = {
521 .pushbuf = 0xb0007e00 | head,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000522 .head = head,
523 };
Ben Skeggs315a8b22015-08-20 14:54:16 +1000524 static const s32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000525 GK104_DISP_OVERLAY_CONTROL_DMA,
526 GF110_DISP_OVERLAY_CONTROL_DMA,
527 GT214_DISP_OVERLAY_CHANNEL_DMA,
528 GT200_DISP_OVERLAY_CHANNEL_DMA,
529 G82_DISP_OVERLAY_CHANNEL_DMA,
530 NV50_DISP_OVERLAY_CHANNEL_DMA,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000531 0
532 };
533
Ben Skeggsa01ca782015-08-20 14:54:15 +1000534 return nv50_dmac_create(device, disp, oclass, head, &args, sizeof(args),
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000535 syncbuf, &ovly->base);
536}
Ben Skeggs26f6d882011-07-04 16:25:18 +1000537
Ben Skeggse225f442012-11-21 14:40:21 +1000538struct nv50_head {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +1000539 struct nouveau_crtc base;
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000540 struct nouveau_bo *image;
Ben Skeggse225f442012-11-21 14:40:21 +1000541 struct nv50_ovly ovly;
542 struct nv50_oimm oimm;
Ben Skeggs3dbd0362016-11-04 17:20:36 +1000543
544 struct nv50_head_atom arm;
545 struct nv50_head_atom asy;
Ben Skeggs973f10c2016-11-04 17:20:36 +1000546
547 struct nv50_base *_base;
Ben Skeggs22e927d2016-11-04 17:20:36 +1000548 struct nv50_curs *_curs;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000549};
550
Ben Skeggse225f442012-11-21 14:40:21 +1000551#define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c))
Ben Skeggse225f442012-11-21 14:40:21 +1000552#define nv50_ovly(c) (&nv50_head(c)->ovly)
553#define nv50_oimm(c) (&nv50_head(c)->oimm)
554#define nv50_chan(c) (&(c)->base.base)
Ben Skeggs0ad72862014-08-10 04:10:22 +1000555#define nv50_vers(c) nv50_chan(c)->user.oclass
556
557struct nv50_fbdma {
558 struct list_head head;
559 struct nvif_object core;
560 struct nvif_object base[4];
561};
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000562
Ben Skeggse225f442012-11-21 14:40:21 +1000563struct nv50_disp {
Ben Skeggs0ad72862014-08-10 04:10:22 +1000564 struct nvif_object *disp;
Ben Skeggse225f442012-11-21 14:40:21 +1000565 struct nv50_mast mast;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000566
Ben Skeggs8a423642014-08-10 04:10:19 +1000567 struct list_head fbdma;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000568
569 struct nouveau_bo *sync;
Ben Skeggsdd0e3d52012-10-16 14:00:31 +1000570};
571
Ben Skeggse225f442012-11-21 14:40:21 +1000572static struct nv50_disp *
573nv50_disp(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +1000574{
Ben Skeggs77145f12012-07-31 16:16:21 +1000575 return nouveau_display(dev)->priv;
Ben Skeggs26f6d882011-07-04 16:25:18 +1000576}
577
Ben Skeggse225f442012-11-21 14:40:21 +1000578#define nv50_mast(d) (&nv50_disp(d)->mast)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000579
Ben Skeggsbdb8c212011-11-12 01:30:24 +1000580static struct drm_crtc *
Ben Skeggse225f442012-11-21 14:40:21 +1000581nv50_display_crtc_get(struct drm_encoder *encoder)
Ben Skeggsbdb8c212011-11-12 01:30:24 +1000582{
583 return nouveau_encoder(encoder)->crtc;
584}
585
586/******************************************************************************
587 * EVO channel helpers
588 *****************************************************************************/
Ben Skeggs51beb422011-07-05 10:33:08 +1000589static u32 *
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000590evo_wait(void *evoc, int nr)
Ben Skeggs51beb422011-07-05 10:33:08 +1000591{
Ben Skeggse225f442012-11-21 14:40:21 +1000592 struct nv50_dmac *dmac = evoc;
Ben Skeggsa01ca782015-08-20 14:54:15 +1000593 struct nvif_device *device = dmac->base.device;
Ben Skeggs0ad72862014-08-10 04:10:22 +1000594 u32 put = nvif_rd32(&dmac->base.user, 0x0000) / 4;
Ben Skeggs51beb422011-07-05 10:33:08 +1000595
Daniel Vetter59ad1462012-12-02 14:49:44 +0100596 mutex_lock(&dmac->lock);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000597 if (put + nr >= (PAGE_SIZE / 4) - 8) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000598 dmac->ptr[put] = 0x20000000;
Ben Skeggs51beb422011-07-05 10:33:08 +1000599
Ben Skeggs0ad72862014-08-10 04:10:22 +1000600 nvif_wr32(&dmac->base.user, 0x0000, 0x00000000);
Ben Skeggs54442042015-08-20 14:54:11 +1000601 if (nvif_msec(device, 2000,
602 if (!nvif_rd32(&dmac->base.user, 0x0004))
603 break;
604 ) < 0) {
Daniel Vetter59ad1462012-12-02 14:49:44 +0100605 mutex_unlock(&dmac->lock);
Ben Skeggs9ad97ed2015-08-20 14:54:13 +1000606 printk(KERN_ERR "nouveau: evo channel stalled\n");
Ben Skeggs51beb422011-07-05 10:33:08 +1000607 return NULL;
608 }
609
610 put = 0;
611 }
612
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000613 return dmac->ptr + put;
Ben Skeggs51beb422011-07-05 10:33:08 +1000614}
615
616static void
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000617evo_kick(u32 *push, void *evoc)
Ben Skeggs51beb422011-07-05 10:33:08 +1000618{
Ben Skeggse225f442012-11-21 14:40:21 +1000619 struct nv50_dmac *dmac = evoc;
Ben Skeggs0ad72862014-08-10 04:10:22 +1000620 nvif_wr32(&dmac->base.user, 0x0000, (push - dmac->ptr) << 2);
Daniel Vetter59ad1462012-12-02 14:49:44 +0100621 mutex_unlock(&dmac->lock);
Ben Skeggs51beb422011-07-05 10:33:08 +1000622}
623
Ben Skeggs2b1930c2014-11-03 16:43:59 +1000624#define evo_mthd(p,m,s) do { \
625 const u32 _m = (m), _s = (s); \
Ben Skeggs7f55a072016-11-04 17:20:36 +1000626 if (drm_debug & DRM_UT_KMS) \
627 printk(KERN_ERR "%04x %d %s\n", _m, _s, __func__); \
Ben Skeggs2b1930c2014-11-03 16:43:59 +1000628 *((p)++) = ((_s << 18) | _m); \
629} while(0)
Ben Skeggs7f55a072016-11-04 17:20:36 +1000630
Ben Skeggs2b1930c2014-11-03 16:43:59 +1000631#define evo_data(p,d) do { \
632 const u32 _d = (d); \
Ben Skeggs7f55a072016-11-04 17:20:36 +1000633 if (drm_debug & DRM_UT_KMS) \
634 printk(KERN_ERR "\t%08x\n", _d); \
Ben Skeggs2b1930c2014-11-03 16:43:59 +1000635 *((p)++) = _d; \
636} while(0)
Ben Skeggs51beb422011-07-05 10:33:08 +1000637
Ben Skeggs3376ee32011-11-12 14:28:12 +1000638static bool
639evo_sync_wait(void *data)
640{
Ben Skeggs5cc027f2013-02-18 17:50:51 -0500641 if (nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000)
642 return true;
643 usleep_range(1, 2);
644 return false;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000645}
646
647static int
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000648evo_sync(struct drm_device *dev)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000649{
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000650 struct nvif_device *device = &nouveau_drm(dev)->device;
Ben Skeggse225f442012-11-21 14:40:21 +1000651 struct nv50_disp *disp = nv50_disp(dev);
652 struct nv50_mast *mast = nv50_mast(dev);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000653 u32 *push = evo_wait(mast, 8);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000654 if (push) {
Ben Skeggs816af2f2011-11-16 15:48:48 +1000655 nouveau_bo_wr32(disp->sync, EVO_MAST_NTFY, 0x00000000);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000656 evo_mthd(push, 0x0084, 1);
Ben Skeggs816af2f2011-11-16 15:48:48 +1000657 evo_data(push, 0x80000000 | EVO_MAST_NTFY);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000658 evo_mthd(push, 0x0080, 2);
659 evo_data(push, 0x00000000);
660 evo_data(push, 0x00000000);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000661 evo_kick(push, mast);
Ben Skeggs54442042015-08-20 14:54:11 +1000662 if (nvif_msec(device, 2000,
663 if (evo_sync_wait(disp->sync))
664 break;
665 ) >= 0)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000666 return 0;
667 }
668
669 return -EBUSY;
670}
671
672/******************************************************************************
Ben Skeggs973f10c2016-11-04 17:20:36 +1000673 * Plane
674 *****************************************************************************/
675#define nv50_wndw(p) container_of((p), struct nv50_wndw, plane)
676
677struct nv50_wndw {
678 const struct nv50_wndw_func *func;
679 struct nv50_dmac *dmac;
680
681 struct drm_plane plane;
682
683 struct nvif_notify notify;
684 u16 ntfy;
685 u16 sema;
686 u32 data;
687
688 struct nv50_wndw_atom arm;
689 struct nv50_wndw_atom asy;
690};
691
692struct nv50_wndw_func {
693 void *(*dtor)(struct nv50_wndw *);
694 int (*acquire)(struct nv50_wndw *, struct nv50_wndw_atom *asyw,
695 struct nv50_head_atom *asyh);
696 void (*release)(struct nv50_wndw *, struct nv50_wndw_atom *asyw,
697 struct nv50_head_atom *asyh);
698 void (*prepare)(struct nv50_wndw *, struct nv50_head_atom *asyh,
699 struct nv50_wndw_atom *asyw);
700
701 void (*sema_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
702 void (*sema_clr)(struct nv50_wndw *);
703 void (*ntfy_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
704 void (*ntfy_clr)(struct nv50_wndw *);
705 int (*ntfy_wait_begun)(struct nv50_wndw *, struct nv50_wndw_atom *);
706 void (*image_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
707 void (*image_clr)(struct nv50_wndw *);
708 void (*lut)(struct nv50_wndw *, struct nv50_wndw_atom *);
709 void (*point)(struct nv50_wndw *, struct nv50_wndw_atom *);
710
711 u32 (*update)(struct nv50_wndw *, u32 interlock);
712};
713
714static int
715nv50_wndw_wait_armed(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
716{
717 if (asyw->set.ntfy)
718 return wndw->func->ntfy_wait_begun(wndw, asyw);
719 return 0;
720}
721
722static u32
723nv50_wndw_flush_clr(struct nv50_wndw *wndw, u32 interlock, bool flush,
724 struct nv50_wndw_atom *asyw)
725{
726 if (asyw->clr.sema && (!asyw->set.sema || flush))
727 wndw->func->sema_clr(wndw);
728 if (asyw->clr.ntfy && (!asyw->set.ntfy || flush))
729 wndw->func->ntfy_clr(wndw);
730 if (asyw->clr.image && (!asyw->set.image || flush))
731 wndw->func->image_clr(wndw);
732
733 return flush ? wndw->func->update(wndw, interlock) : 0;
734}
735
736static u32
737nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 interlock,
738 struct nv50_wndw_atom *asyw)
739{
740 if (interlock) {
741 asyw->image.mode = 0;
742 asyw->image.interval = 1;
743 }
744
745 if (asyw->set.sema ) wndw->func->sema_set (wndw, asyw);
746 if (asyw->set.ntfy ) wndw->func->ntfy_set (wndw, asyw);
747 if (asyw->set.image) wndw->func->image_set(wndw, asyw);
748 if (asyw->set.lut ) wndw->func->lut (wndw, asyw);
749 if (asyw->set.point) wndw->func->point (wndw, asyw);
750
751 return wndw->func->update(wndw, interlock);
752}
753
754static void
755nv50_wndw_atomic_check_release(struct nv50_wndw *wndw,
756 struct nv50_wndw_atom *asyw,
757 struct nv50_head_atom *asyh)
758{
759 struct nouveau_drm *drm = nouveau_drm(wndw->plane.dev);
760 NV_ATOMIC(drm, "%s release\n", wndw->plane.name);
761 wndw->func->release(wndw, asyw, asyh);
762 asyw->ntfy.handle = 0;
763 asyw->sema.handle = 0;
764}
765
766static int
767nv50_wndw_atomic_check_acquire(struct nv50_wndw *wndw,
768 struct nv50_wndw_atom *asyw,
769 struct nv50_head_atom *asyh)
770{
771 struct nouveau_framebuffer *fb = nouveau_framebuffer(asyw->state.fb);
772 struct nouveau_drm *drm = nouveau_drm(wndw->plane.dev);
773 int ret;
774
775 NV_ATOMIC(drm, "%s acquire\n", wndw->plane.name);
776 asyw->clip.x1 = 0;
777 asyw->clip.y1 = 0;
778 asyw->clip.x2 = asyh->state.mode.hdisplay;
779 asyw->clip.y2 = asyh->state.mode.vdisplay;
780
781 asyw->image.w = fb->base.width;
782 asyw->image.h = fb->base.height;
783 asyw->image.kind = (fb->nvbo->tile_flags & 0x0000ff00) >> 8;
784 if (asyw->image.kind) {
785 asyw->image.layout = 0;
786 if (drm->device.info.chipset >= 0xc0)
787 asyw->image.block = fb->nvbo->tile_mode >> 4;
788 else
789 asyw->image.block = fb->nvbo->tile_mode;
790 asyw->image.pitch = (fb->base.pitches[0] / 4) << 4;
791 } else {
792 asyw->image.layout = 1;
793 asyw->image.block = 0;
794 asyw->image.pitch = fb->base.pitches[0];
795 }
796
797 ret = wndw->func->acquire(wndw, asyw, asyh);
798 if (ret)
799 return ret;
800
801 if (asyw->set.image) {
802 if (!(asyw->image.mode = asyw->interval ? 0 : 1))
803 asyw->image.interval = asyw->interval;
804 else
805 asyw->image.interval = 0;
806 }
807
808 return 0;
809}
810
811static int
812nv50_wndw_atomic_check(struct drm_plane *plane, struct drm_plane_state *state)
813{
814 struct nouveau_drm *drm = nouveau_drm(plane->dev);
815 struct nv50_wndw *wndw = nv50_wndw(plane);
816 struct nv50_wndw_atom *armw = &wndw->arm;
817 struct nv50_wndw_atom *asyw = &wndw->asy;
818 struct nv50_head_atom *harm = NULL, *asyh = NULL;
819 bool varm = false, asyv = false, asym = false;
820 int ret;
821
822 asyw->clr.mask = 0;
823 asyw->set.mask = 0;
824
825 NV_ATOMIC(drm, "%s atomic_check\n", plane->name);
826 if (asyw->state.crtc) {
827 asyh = &nv50_head(asyw->state.crtc)->asy;
828 if (IS_ERR(asyh))
829 return PTR_ERR(asyh);
830 asym = drm_atomic_crtc_needs_modeset(&asyh->state);
831 asyv = asyh->state.active;
832 }
833
834 if (armw->state.crtc) {
835 harm = &nv50_head(armw->state.crtc)->asy;
836 if (IS_ERR(harm))
837 return PTR_ERR(harm);
838 varm = nv50_head(harm->state.crtc)->arm.state.active;
839 }
840
841 if (asyv) {
842 asyw->point.x = asyw->state.crtc_x;
843 asyw->point.y = asyw->state.crtc_y;
844 if (memcmp(&armw->point, &asyw->point, sizeof(asyw->point)))
845 asyw->set.point = true;
846
847 if (!varm || asym || armw->state.fb != asyw->state.fb) {
848 ret = nv50_wndw_atomic_check_acquire(wndw, asyw, asyh);
849 if (ret)
850 return ret;
851 }
852 } else
853 if (varm) {
854 nv50_wndw_atomic_check_release(wndw, asyw, harm);
855 } else {
856 return 0;
857 }
858
859 if (!asyv || asym) {
860 asyw->clr.ntfy = armw->ntfy.handle != 0;
861 asyw->clr.sema = armw->sema.handle != 0;
862 if (wndw->func->image_clr)
863 asyw->clr.image = armw->image.handle != 0;
864 asyw->set.lut = wndw->func->lut && asyv;
865 }
866
867 memcpy(armw, asyw, sizeof(*asyw));
868 return 0;
869}
870
871static void
872nv50_wndw_atomic_destroy_state(struct drm_plane *plane,
873 struct drm_plane_state *state)
874{
875 struct nv50_wndw_atom *asyw = nv50_wndw_atom(state);
876 __drm_atomic_helper_plane_destroy_state(&asyw->state);
877 dma_fence_put(asyw->state.fence);
878 kfree(asyw);
879}
880
881static struct drm_plane_state *
882nv50_wndw_atomic_duplicate_state(struct drm_plane *plane)
883{
884 struct nv50_wndw_atom *armw = nv50_wndw_atom(plane->state);
885 struct nv50_wndw_atom *asyw;
886 if (!(asyw = kmalloc(sizeof(*asyw), GFP_KERNEL)))
887 return NULL;
888 __drm_atomic_helper_plane_duplicate_state(plane, &asyw->state);
889 asyw->state.fence = NULL;
890 asyw->interval = 1;
891 asyw->sema = armw->sema;
892 asyw->ntfy = armw->ntfy;
893 asyw->image = armw->image;
894 asyw->point = armw->point;
895 asyw->lut = armw->lut;
896 asyw->clr.mask = 0;
897 asyw->set.mask = 0;
898 return &asyw->state;
899}
900
901static void
902nv50_wndw_reset(struct drm_plane *plane)
903{
904 struct nv50_wndw_atom *asyw;
905
906 if (WARN_ON(!(asyw = kzalloc(sizeof(*asyw), GFP_KERNEL))))
907 return;
908
909 if (plane->state)
910 plane->funcs->atomic_destroy_state(plane, plane->state);
911 plane->state = &asyw->state;
912 plane->state->plane = plane;
913 plane->state->rotation = DRM_ROTATE_0;
914}
915
916static void
917nv50_wndw_destroy(struct drm_plane *plane)
918{
919 struct nv50_wndw *wndw = nv50_wndw(plane);
920 void *data;
921 nvif_notify_fini(&wndw->notify);
922 data = wndw->func->dtor(wndw);
923 drm_plane_cleanup(&wndw->plane);
924 kfree(data);
925}
926
927static const struct drm_plane_funcs
928nv50_wndw = {
929 .destroy = nv50_wndw_destroy,
930 .reset = nv50_wndw_reset,
931 .set_property = drm_atomic_helper_plane_set_property,
932 .atomic_duplicate_state = nv50_wndw_atomic_duplicate_state,
933 .atomic_destroy_state = nv50_wndw_atomic_destroy_state,
934};
935
936static void
937nv50_wndw_fini(struct nv50_wndw *wndw)
938{
939 nvif_notify_put(&wndw->notify);
940}
941
942static void
943nv50_wndw_init(struct nv50_wndw *wndw)
944{
945 nvif_notify_get(&wndw->notify);
946}
947
948static int
949nv50_wndw_ctor(const struct nv50_wndw_func *func, struct drm_device *dev,
950 enum drm_plane_type type, const char *name, int index,
951 struct nv50_dmac *dmac, const u32 *format, int nformat,
952 struct nv50_wndw *wndw)
953{
954 int ret;
955
956 wndw->func = func;
957 wndw->dmac = dmac;
958
959 ret = drm_universal_plane_init(dev, &wndw->plane, 0, &nv50_wndw, format,
960 nformat, type, "%s-%d", name, index);
961 if (ret)
962 return ret;
963
964 return 0;
965}
966
967/******************************************************************************
Ben Skeggs22e927d2016-11-04 17:20:36 +1000968 * Cursor plane
969 *****************************************************************************/
970#define nv50_curs(p) container_of((p), struct nv50_curs, wndw)
971
972struct nv50_curs {
973 struct nv50_wndw wndw;
974 struct nvif_object chan;
975};
976
977static u32
978nv50_curs_update(struct nv50_wndw *wndw, u32 interlock)
979{
980 struct nv50_curs *curs = nv50_curs(wndw);
981 nvif_wr32(&curs->chan, 0x0080, 0x00000000);
982 return 0;
983}
984
985static void
986nv50_curs_point(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
987{
988 struct nv50_curs *curs = nv50_curs(wndw);
989 nvif_wr32(&curs->chan, 0x0084, (asyw->point.y << 16) | asyw->point.x);
990}
991
992static void
993nv50_curs_prepare(struct nv50_wndw *wndw, struct nv50_head_atom *asyh,
994 struct nv50_wndw_atom *asyw)
995{
996 asyh->curs.handle = nv50_disp(wndw->plane.dev)->mast.base.vram.handle;
997 asyh->curs.offset = asyw->image.offset;
998 asyh->set.curs = asyh->curs.visible;
999}
1000
1001static void
1002nv50_curs_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
1003 struct nv50_head_atom *asyh)
1004{
1005 asyh->curs.visible = false;
1006}
1007
1008static int
1009nv50_curs_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
1010 struct nv50_head_atom *asyh)
1011{
1012 int ret;
1013
1014 ret = drm_plane_helper_check_state(&asyw->state, &asyw->clip,
1015 DRM_PLANE_HELPER_NO_SCALING,
1016 DRM_PLANE_HELPER_NO_SCALING,
1017 true, true);
1018 asyh->curs.visible = asyw->state.visible;
1019 if (ret || !asyh->curs.visible)
1020 return ret;
1021
1022 switch (asyw->state.fb->width) {
1023 case 32: asyh->curs.layout = 0; break;
1024 case 64: asyh->curs.layout = 1; break;
1025 default:
1026 return -EINVAL;
1027 }
1028
1029 if (asyw->state.fb->width != asyw->state.fb->height)
1030 return -EINVAL;
1031
1032 switch (asyw->state.fb->pixel_format) {
1033 case DRM_FORMAT_ARGB8888: asyh->curs.format = 1; break;
1034 default:
1035 WARN_ON(1);
1036 return -EINVAL;
1037 }
1038
1039 return 0;
1040}
1041
1042static void *
1043nv50_curs_dtor(struct nv50_wndw *wndw)
1044{
1045 struct nv50_curs *curs = nv50_curs(wndw);
1046 nvif_object_fini(&curs->chan);
1047 return curs;
1048}
1049
1050static const u32
1051nv50_curs_format[] = {
1052 DRM_FORMAT_ARGB8888,
1053};
1054
1055static const struct nv50_wndw_func
1056nv50_curs = {
1057 .dtor = nv50_curs_dtor,
1058 .acquire = nv50_curs_acquire,
1059 .release = nv50_curs_release,
1060 .prepare = nv50_curs_prepare,
1061 .point = nv50_curs_point,
1062 .update = nv50_curs_update,
1063};
1064
1065static int
1066nv50_curs_new(struct nouveau_drm *drm, struct nv50_head *head,
1067 struct nv50_curs **pcurs)
1068{
1069 static const struct nvif_mclass curses[] = {
1070 { GK104_DISP_CURSOR, 0 },
1071 { GF110_DISP_CURSOR, 0 },
1072 { GT214_DISP_CURSOR, 0 },
1073 { G82_DISP_CURSOR, 0 },
1074 { NV50_DISP_CURSOR, 0 },
1075 {}
1076 };
1077 struct nv50_disp_cursor_v0 args = {
1078 .head = head->base.index,
1079 };
1080 struct nv50_disp *disp = nv50_disp(drm->dev);
1081 struct nv50_curs *curs;
1082 int cid, ret;
1083
1084 cid = nvif_mclass(disp->disp, curses);
1085 if (cid < 0) {
1086 NV_ERROR(drm, "No supported cursor immediate class\n");
1087 return cid;
1088 }
1089
1090 if (!(curs = *pcurs = kzalloc(sizeof(*curs), GFP_KERNEL)))
1091 return -ENOMEM;
1092
1093 ret = nv50_wndw_ctor(&nv50_curs, drm->dev, DRM_PLANE_TYPE_CURSOR,
1094 "curs", head->base.index, &disp->mast.base,
1095 nv50_curs_format, ARRAY_SIZE(nv50_curs_format),
1096 &curs->wndw);
1097 if (ret) {
1098 kfree(curs);
1099 return ret;
1100 }
1101
1102 ret = nvif_object_init(disp->disp, 0, curses[cid].oclass, &args,
1103 sizeof(args), &curs->chan);
1104 if (ret) {
1105 NV_ERROR(drm, "curs%04x allocation failed: %d\n",
1106 curses[cid].oclass, ret);
1107 return ret;
1108 }
1109
1110 return 0;
1111}
1112
1113/******************************************************************************
Ben Skeggs973f10c2016-11-04 17:20:36 +10001114 * Primary plane
1115 *****************************************************************************/
1116#define nv50_base(p) container_of((p), struct nv50_base, wndw)
1117
1118struct nv50_base {
1119 struct nv50_wndw wndw;
1120 struct nv50_sync chan;
1121 int id;
1122};
1123
1124static int
1125nv50_base_notify(struct nvif_notify *notify)
1126{
1127 return NVIF_NOTIFY_KEEP;
1128}
1129
1130static void
1131nv50_base_lut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
1132{
1133 struct nv50_base *base = nv50_base(wndw);
1134 u32 *push;
1135 if ((push = evo_wait(&base->chan, 2))) {
1136 evo_mthd(push, 0x00e0, 1);
1137 evo_data(push, asyw->lut.enable << 30);
1138 evo_kick(push, &base->chan);
1139 }
1140}
1141
1142static void
1143nv50_base_image_clr(struct nv50_wndw *wndw)
1144{
1145 struct nv50_base *base = nv50_base(wndw);
1146 u32 *push;
1147 if ((push = evo_wait(&base->chan, 4))) {
1148 evo_mthd(push, 0x0084, 1);
1149 evo_data(push, 0x00000000);
1150 evo_mthd(push, 0x00c0, 1);
1151 evo_data(push, 0x00000000);
1152 evo_kick(push, &base->chan);
1153 }
1154}
1155
1156static void
1157nv50_base_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
1158{
1159 struct nv50_base *base = nv50_base(wndw);
1160 const s32 oclass = base->chan.base.base.user.oclass;
1161 u32 *push;
1162 if ((push = evo_wait(&base->chan, 10))) {
1163 evo_mthd(push, 0x0084, 1);
1164 evo_data(push, (asyw->image.mode << 8) |
1165 (asyw->image.interval << 4));
1166 evo_mthd(push, 0x00c0, 1);
1167 evo_data(push, asyw->image.handle);
1168 if (oclass < G82_DISP_BASE_CHANNEL_DMA) {
1169 evo_mthd(push, 0x0800, 5);
1170 evo_data(push, asyw->image.offset >> 8);
1171 evo_data(push, 0x00000000);
1172 evo_data(push, (asyw->image.h << 16) | asyw->image.w);
1173 evo_data(push, (asyw->image.layout << 20) |
1174 asyw->image.pitch |
1175 asyw->image.block);
1176 evo_data(push, (asyw->image.kind << 16) |
1177 (asyw->image.format << 8));
1178 } else
1179 if (oclass < GF110_DISP_BASE_CHANNEL_DMA) {
1180 evo_mthd(push, 0x0800, 5);
1181 evo_data(push, asyw->image.offset >> 8);
1182 evo_data(push, 0x00000000);
1183 evo_data(push, (asyw->image.h << 16) | asyw->image.w);
1184 evo_data(push, (asyw->image.layout << 20) |
1185 asyw->image.pitch |
1186 asyw->image.block);
1187 evo_data(push, asyw->image.format << 8);
1188 } else {
1189 evo_mthd(push, 0x0400, 5);
1190 evo_data(push, asyw->image.offset >> 8);
1191 evo_data(push, 0x00000000);
1192 evo_data(push, (asyw->image.h << 16) | asyw->image.w);
1193 evo_data(push, (asyw->image.layout << 24) |
1194 asyw->image.pitch |
1195 asyw->image.block);
1196 evo_data(push, asyw->image.format << 8);
1197 }
1198 evo_kick(push, &base->chan);
1199 }
1200}
1201
1202static void
1203nv50_base_ntfy_clr(struct nv50_wndw *wndw)
1204{
1205 struct nv50_base *base = nv50_base(wndw);
1206 u32 *push;
1207 if ((push = evo_wait(&base->chan, 2))) {
1208 evo_mthd(push, 0x00a4, 1);
1209 evo_data(push, 0x00000000);
1210 evo_kick(push, &base->chan);
1211 }
1212}
1213
1214static void
1215nv50_base_ntfy_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
1216{
1217 struct nv50_base *base = nv50_base(wndw);
1218 u32 *push;
1219 if ((push = evo_wait(&base->chan, 3))) {
1220 evo_mthd(push, 0x00a0, 2);
1221 evo_data(push, (asyw->ntfy.awaken << 30) | asyw->ntfy.offset);
1222 evo_data(push, asyw->ntfy.handle);
1223 evo_kick(push, &base->chan);
1224 }
1225}
1226
1227static void
1228nv50_base_sema_clr(struct nv50_wndw *wndw)
1229{
1230 struct nv50_base *base = nv50_base(wndw);
1231 u32 *push;
1232 if ((push = evo_wait(&base->chan, 2))) {
1233 evo_mthd(push, 0x0094, 1);
1234 evo_data(push, 0x00000000);
1235 evo_kick(push, &base->chan);
1236 }
1237}
1238
1239static void
1240nv50_base_sema_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
1241{
1242 struct nv50_base *base = nv50_base(wndw);
1243 u32 *push;
1244 if ((push = evo_wait(&base->chan, 5))) {
1245 evo_mthd(push, 0x0088, 4);
1246 evo_data(push, asyw->sema.offset);
1247 evo_data(push, asyw->sema.acquire);
1248 evo_data(push, asyw->sema.release);
1249 evo_data(push, asyw->sema.handle);
1250 evo_kick(push, &base->chan);
1251 }
1252}
1253
1254static u32
1255nv50_base_update(struct nv50_wndw *wndw, u32 interlock)
1256{
1257 struct nv50_base *base = nv50_base(wndw);
1258 u32 *push;
1259
1260 if (!(push = evo_wait(&base->chan, 2)))
1261 return 0;
1262 evo_mthd(push, 0x0080, 1);
1263 evo_data(push, interlock);
1264 evo_kick(push, &base->chan);
1265
1266 if (base->chan.base.base.user.oclass < GF110_DISP_BASE_CHANNEL_DMA)
1267 return interlock ? 2 << (base->id * 8) : 0;
1268 return interlock ? 2 << (base->id * 4) : 0;
1269}
1270
1271static int
1272nv50_base_ntfy_wait_begun(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
1273{
1274 struct nouveau_drm *drm = nouveau_drm(wndw->plane.dev);
1275 struct nv50_disp *disp = nv50_disp(wndw->plane.dev);
1276 if (nvif_msec(&drm->device, 2000ULL,
1277 u32 data = nouveau_bo_rd32(disp->sync, asyw->ntfy.offset / 4);
1278 if ((data & 0xc0000000) == 0x40000000)
1279 break;
1280 usleep_range(1, 2);
1281 ) < 0)
1282 return -ETIMEDOUT;
1283 return 0;
1284}
1285
1286static void
1287nv50_base_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
1288 struct nv50_head_atom *asyh)
1289{
1290 asyh->base.cpp = 0;
1291}
1292
1293static int
1294nv50_base_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
1295 struct nv50_head_atom *asyh)
1296{
1297 const u32 format = asyw->state.fb->pixel_format;
1298 const struct drm_format_info *info;
1299 int ret;
1300
1301 info = drm_format_info(format);
1302 if (!info || !info->depth)
1303 return -EINVAL;
1304
1305 ret = drm_plane_helper_check_state(&asyw->state, &asyw->clip,
1306 DRM_PLANE_HELPER_NO_SCALING,
1307 DRM_PLANE_HELPER_NO_SCALING,
1308 false, true);
1309 if (ret)
1310 return ret;
1311
1312 asyh->base.depth = info->depth;
1313 asyh->base.cpp = info->cpp[0];
1314 asyh->base.x = asyw->state.src.x1 >> 16;
1315 asyh->base.y = asyw->state.src.y1 >> 16;
1316 asyh->base.w = asyw->state.fb->width;
1317 asyh->base.h = asyw->state.fb->height;
1318
1319 switch (format) {
1320 case DRM_FORMAT_C8 : asyw->image.format = 0x1e; break;
1321 case DRM_FORMAT_RGB565 : asyw->image.format = 0xe8; break;
1322 case DRM_FORMAT_XRGB1555 :
1323 case DRM_FORMAT_ARGB1555 : asyw->image.format = 0xe9; break;
1324 case DRM_FORMAT_XRGB8888 :
1325 case DRM_FORMAT_ARGB8888 : asyw->image.format = 0xcf; break;
1326 case DRM_FORMAT_XBGR2101010:
1327 case DRM_FORMAT_ABGR2101010: asyw->image.format = 0xd1; break;
1328 case DRM_FORMAT_XBGR8888 :
1329 case DRM_FORMAT_ABGR8888 : asyw->image.format = 0xd5; break;
1330 default:
1331 WARN_ON(1);
1332 return -EINVAL;
1333 }
1334
1335 asyw->lut.enable = 1;
1336 asyw->set.image = true;
1337 return 0;
1338}
1339
1340static void *
1341nv50_base_dtor(struct nv50_wndw *wndw)
1342{
1343 struct nv50_disp *disp = nv50_disp(wndw->plane.dev);
1344 struct nv50_base *base = nv50_base(wndw);
1345 nv50_dmac_destroy(&base->chan.base, disp->disp);
1346 return base;
1347}
1348
1349static const u32
1350nv50_base_format[] = {
1351 DRM_FORMAT_C8,
1352 DRM_FORMAT_RGB565,
1353 DRM_FORMAT_XRGB1555,
1354 DRM_FORMAT_ARGB1555,
1355 DRM_FORMAT_XRGB8888,
1356 DRM_FORMAT_ARGB8888,
1357 DRM_FORMAT_XBGR2101010,
1358 DRM_FORMAT_ABGR2101010,
1359 DRM_FORMAT_XBGR8888,
1360 DRM_FORMAT_ABGR8888,
1361};
1362
1363static const struct nv50_wndw_func
1364nv50_base = {
1365 .dtor = nv50_base_dtor,
1366 .acquire = nv50_base_acquire,
1367 .release = nv50_base_release,
1368 .sema_set = nv50_base_sema_set,
1369 .sema_clr = nv50_base_sema_clr,
1370 .ntfy_set = nv50_base_ntfy_set,
1371 .ntfy_clr = nv50_base_ntfy_clr,
1372 .ntfy_wait_begun = nv50_base_ntfy_wait_begun,
1373 .image_set = nv50_base_image_set,
1374 .image_clr = nv50_base_image_clr,
1375 .lut = nv50_base_lut,
1376 .update = nv50_base_update,
1377};
1378
1379static int
1380nv50_base_new(struct nouveau_drm *drm, struct nv50_head *head,
1381 struct nv50_base **pbase)
1382{
1383 struct nv50_disp *disp = nv50_disp(drm->dev);
1384 struct nv50_base *base;
1385 int ret;
1386
1387 if (!(base = *pbase = kzalloc(sizeof(*base), GFP_KERNEL)))
1388 return -ENOMEM;
1389 base->id = head->base.index;
1390 base->wndw.ntfy = EVO_FLIP_NTFY0(base->id);
1391 base->wndw.sema = EVO_FLIP_SEM0(base->id);
1392 base->wndw.data = 0x00000000;
1393
1394 ret = nv50_wndw_ctor(&nv50_base, drm->dev, DRM_PLANE_TYPE_PRIMARY,
1395 "base", base->id, &base->chan.base,
1396 nv50_base_format, ARRAY_SIZE(nv50_base_format),
1397 &base->wndw);
1398 if (ret) {
1399 kfree(base);
1400 return ret;
1401 }
1402
1403 ret = nv50_base_create(&drm->device, disp->disp, base->id,
1404 disp->sync->bo.offset, &base->chan);
1405 if (ret)
1406 return ret;
1407
1408 return nvif_notify_init(&base->chan.base.base.user, nv50_base_notify,
1409 false,
1410 NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT,
1411 &(struct nvif_notify_uevent_req) {},
1412 sizeof(struct nvif_notify_uevent_req),
1413 sizeof(struct nvif_notify_uevent_rep),
1414 &base->wndw.notify);
1415}
1416
1417/******************************************************************************
Ben Skeggsa63a97e2011-11-16 15:22:34 +10001418 * Page flipping channel
Ben Skeggs3376ee32011-11-12 14:28:12 +10001419 *****************************************************************************/
1420struct nouveau_bo *
Ben Skeggse225f442012-11-21 14:40:21 +10001421nv50_display_crtc_sema(struct drm_device *dev, int crtc)
Ben Skeggs3376ee32011-11-12 14:28:12 +10001422{
Ben Skeggse225f442012-11-21 14:40:21 +10001423 return nv50_disp(dev)->sync;
Ben Skeggs3376ee32011-11-12 14:28:12 +10001424}
1425
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001426struct nv50_display_flip {
1427 struct nv50_disp *disp;
Ben Skeggs973f10c2016-11-04 17:20:36 +10001428 struct nv50_base *base;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001429};
1430
1431static bool
1432nv50_display_flip_wait(void *data)
1433{
1434 struct nv50_display_flip *flip = data;
Ben Skeggs973f10c2016-11-04 17:20:36 +10001435 if (nouveau_bo_rd32(flip->disp->sync, flip->base->wndw.sema / 4) ==
1436 flip->base->wndw.data)
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001437 return true;
1438 usleep_range(1, 2);
1439 return false;
1440}
1441
Ben Skeggs3376ee32011-11-12 14:28:12 +10001442void
Ben Skeggse225f442012-11-21 14:40:21 +10001443nv50_display_flip_stop(struct drm_crtc *crtc)
Ben Skeggs3376ee32011-11-12 14:28:12 +10001444{
Ben Skeggs967e7bd2014-08-10 04:10:22 +10001445 struct nvif_device *device = &nouveau_drm(crtc->dev)->device;
Ben Skeggs973f10c2016-11-04 17:20:36 +10001446 struct nv50_base *base = nv50_head(crtc)->_base;
1447 struct nv50_wndw *wndw = &base->wndw;
1448 struct nv50_wndw_atom *asyw = &wndw->asy;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001449 struct nv50_display_flip flip = {
1450 .disp = nv50_disp(crtc->dev),
Ben Skeggs973f10c2016-11-04 17:20:36 +10001451 .base = base,
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001452 };
Ben Skeggs3376ee32011-11-12 14:28:12 +10001453
Ben Skeggs973f10c2016-11-04 17:20:36 +10001454 asyw->state.crtc = NULL;
1455 asyw->state.fb = NULL;
1456 nv50_wndw_atomic_check(&wndw->plane, &asyw->state);
1457 nv50_wndw_flush_clr(wndw, 0, true, asyw);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001458
Ben Skeggs54442042015-08-20 14:54:11 +10001459 nvif_msec(device, 2000,
1460 if (nv50_display_flip_wait(&flip))
1461 break;
1462 );
Ben Skeggs3376ee32011-11-12 14:28:12 +10001463}
1464
1465int
Ben Skeggse225f442012-11-21 14:40:21 +10001466nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
Ben Skeggs3376ee32011-11-12 14:28:12 +10001467 struct nouveau_channel *chan, u32 swap_interval)
1468{
1469 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
Ben Skeggs3376ee32011-11-12 14:28:12 +10001470 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001471 struct nv50_head *head = nv50_head(crtc);
Ben Skeggs973f10c2016-11-04 17:20:36 +10001472 struct nv50_base *base = nv50_head(crtc)->_base;
1473 struct nv50_wndw *wndw = &base->wndw;
1474 struct nv50_wndw_atom *asyw = &wndw->asy;
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001475 int ret;
Ben Skeggs3376ee32011-11-12 14:28:12 +10001476
Ben Skeggs9ba83102014-12-22 19:50:23 +10001477 if (crtc->primary->fb->width != fb->width ||
1478 crtc->primary->fb->height != fb->height)
1479 return -EINVAL;
1480
Ben Skeggsf60b6e72013-03-19 15:20:00 +10001481 if (chan == NULL)
1482 evo_sync(crtc->dev);
Ben Skeggs3376ee32011-11-12 14:28:12 +10001483
Ben Skeggsa01ca782015-08-20 14:54:15 +10001484 if (chan && chan->user.oclass < G82_CHANNEL_GPFIFO) {
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001485 ret = RING_SPACE(chan, 8);
1486 if (ret)
1487 return ret;
Ben Skeggs67f97182013-02-26 12:02:54 +10001488
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001489 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001490 OUT_RING (chan, NvEvoSema0 + nv_crtc->index);
Ben Skeggs973f10c2016-11-04 17:20:36 +10001491 OUT_RING (chan, base->wndw.sema ^ 0x10);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001492 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
Ben Skeggs973f10c2016-11-04 17:20:36 +10001493 OUT_RING (chan, base->wndw.data + 1);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001494 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_OFFSET, 2);
Ben Skeggs973f10c2016-11-04 17:20:36 +10001495 OUT_RING (chan, base->wndw.sema);
1496 OUT_RING (chan, base->wndw.data);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001497 } else
Ben Skeggsa01ca782015-08-20 14:54:15 +10001498 if (chan && chan->user.oclass < FERMI_CHANNEL_GPFIFO) {
Ben Skeggs973f10c2016-11-04 17:20:36 +10001499 u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + base->wndw.sema;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001500 ret = RING_SPACE(chan, 12);
1501 if (ret)
1502 return ret;
Ben Skeggsa34caf72013-02-14 09:28:37 +10001503
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001504 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
Ben Skeggs0ad72862014-08-10 04:10:22 +10001505 OUT_RING (chan, chan->vram.handle);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001506 BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
1507 OUT_RING (chan, upper_32_bits(addr ^ 0x10));
1508 OUT_RING (chan, lower_32_bits(addr ^ 0x10));
Ben Skeggs973f10c2016-11-04 17:20:36 +10001509 OUT_RING (chan, base->wndw.data + 1);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001510 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG);
1511 BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
1512 OUT_RING (chan, upper_32_bits(addr));
1513 OUT_RING (chan, lower_32_bits(addr));
Ben Skeggs973f10c2016-11-04 17:20:36 +10001514 OUT_RING (chan, base->wndw.data);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001515 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL);
1516 } else
1517 if (chan) {
Ben Skeggs973f10c2016-11-04 17:20:36 +10001518 u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + base->wndw.sema;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001519 ret = RING_SPACE(chan, 10);
1520 if (ret)
1521 return ret;
Ben Skeggs67f97182013-02-26 12:02:54 +10001522
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001523 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
1524 OUT_RING (chan, upper_32_bits(addr ^ 0x10));
1525 OUT_RING (chan, lower_32_bits(addr ^ 0x10));
Ben Skeggs973f10c2016-11-04 17:20:36 +10001526 OUT_RING (chan, base->wndw.data + 1);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001527 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG |
1528 NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD);
1529 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
1530 OUT_RING (chan, upper_32_bits(addr));
1531 OUT_RING (chan, lower_32_bits(addr));
Ben Skeggs973f10c2016-11-04 17:20:36 +10001532 OUT_RING (chan, base->wndw.data);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001533 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL |
1534 NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD);
1535 }
Ben Skeggs35bcf5d2012-04-30 11:34:10 -05001536
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001537 if (chan) {
Ben Skeggs973f10c2016-11-04 17:20:36 +10001538 base->wndw.sema ^= 0x10;
1539 base->wndw.data++;
Ben Skeggs3376ee32011-11-12 14:28:12 +10001540 FIRE_RING (chan);
Ben Skeggs3376ee32011-11-12 14:28:12 +10001541 }
1542
1543 /* queue the flip */
Ben Skeggs973f10c2016-11-04 17:20:36 +10001544 asyw->state.crtc = &head->base.base;
1545 asyw->state.fb = fb;
1546 asyw->interval = swap_interval;
1547 asyw->image.handle = nv_fb->r_handle;
1548 asyw->image.offset = nv_fb->nvbo->bo.offset;
1549 asyw->sema.handle = base->chan.base.sync.handle;
1550 asyw->sema.offset = base->wndw.sema;
1551 asyw->sema.acquire = base->wndw.data++;
1552 asyw->sema.release = base->wndw.data;
1553 nv50_wndw_atomic_check(&wndw->plane, &asyw->state);
1554 asyw->set.sema = true;
1555 nv50_wndw_flush_set(wndw, 0, asyw);
1556 nv50_wndw_wait_armed(wndw, asyw);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001557
1558 nouveau_bo_ref(nv_fb->nvbo, &head->image);
Ben Skeggs3376ee32011-11-12 14:28:12 +10001559 return 0;
1560}
1561
Ben Skeggs26f6d882011-07-04 16:25:18 +10001562/******************************************************************************
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001563 * Head
1564 *****************************************************************************/
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001565static void
Ben Skeggs7e08d672016-11-04 17:20:36 +10001566nv50_head_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
1567{
1568 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1569 u32 *push;
1570 if ((push = evo_wait(core, 2))) {
1571 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA)
1572 evo_mthd(push, 0x08a8 + (head->base.index * 0x400), 1);
1573 else
1574 evo_mthd(push, 0x0498 + (head->base.index * 0x300), 1);
1575 evo_data(push, (asyh->procamp.sat.sin << 20) |
1576 (asyh->procamp.sat.cos << 8));
1577 evo_kick(push, core);
1578 }
1579}
1580
1581static void
Ben Skeggs7e918332016-11-04 17:20:36 +10001582nv50_head_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
1583{
1584 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1585 u32 *push;
1586 if ((push = evo_wait(core, 2))) {
1587 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA)
1588 evo_mthd(push, 0x08a0 + (head->base.index * 0x0400), 1);
1589 else
1590 if (core->base.user.oclass < GK104_DISP_CORE_CHANNEL_DMA)
1591 evo_mthd(push, 0x0490 + (head->base.index * 0x0300), 1);
1592 else
1593 evo_mthd(push, 0x04a0 + (head->base.index * 0x0300), 1);
1594 evo_data(push, (asyh->dither.mode << 3) |
1595 (asyh->dither.bits << 1) |
1596 asyh->dither.enable);
1597 evo_kick(push, core);
1598 }
1599}
1600
1601static void
Ben Skeggs6bbab3b2016-11-04 17:20:36 +10001602nv50_head_ovly(struct nv50_head *head, struct nv50_head_atom *asyh)
1603{
1604 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1605 u32 bounds = 0;
1606 u32 *push;
1607
1608 if (asyh->base.cpp) {
1609 switch (asyh->base.cpp) {
1610 case 8: bounds |= 0x00000500; break;
1611 case 4: bounds |= 0x00000300; break;
1612 case 2: bounds |= 0x00000100; break;
1613 default:
1614 WARN_ON(1);
1615 break;
1616 }
1617 bounds |= 0x00000001;
1618 }
1619
1620 if ((push = evo_wait(core, 2))) {
1621 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA)
1622 evo_mthd(push, 0x0904 + head->base.index * 0x400, 1);
1623 else
1624 evo_mthd(push, 0x04d4 + head->base.index * 0x300, 1);
1625 evo_data(push, bounds);
1626 evo_kick(push, core);
1627 }
1628}
1629
1630static void
1631nv50_head_base(struct nv50_head *head, struct nv50_head_atom *asyh)
1632{
1633 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1634 u32 bounds = 0;
1635 u32 *push;
1636
1637 if (asyh->base.cpp) {
1638 switch (asyh->base.cpp) {
1639 case 8: bounds |= 0x00000500; break;
1640 case 4: bounds |= 0x00000300; break;
1641 case 2: bounds |= 0x00000100; break;
1642 case 1: bounds |= 0x00000000; break;
1643 default:
1644 WARN_ON(1);
1645 break;
1646 }
1647 bounds |= 0x00000001;
1648 }
1649
1650 if ((push = evo_wait(core, 2))) {
1651 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA)
1652 evo_mthd(push, 0x0900 + head->base.index * 0x400, 1);
1653 else
1654 evo_mthd(push, 0x04d0 + head->base.index * 0x300, 1);
1655 evo_data(push, bounds);
1656 evo_kick(push, core);
1657 }
1658}
1659
1660static void
Ben Skeggsea8ee392016-11-04 17:20:36 +10001661nv50_head_curs_clr(struct nv50_head *head)
1662{
1663 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1664 u32 *push;
1665 if ((push = evo_wait(core, 4))) {
1666 if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) {
1667 evo_mthd(push, 0x0880 + head->base.index * 0x400, 1);
1668 evo_data(push, 0x05000000);
1669 } else
1670 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1671 evo_mthd(push, 0x0880 + head->base.index * 0x400, 1);
1672 evo_data(push, 0x05000000);
1673 evo_mthd(push, 0x089c + head->base.index * 0x400, 1);
1674 evo_data(push, 0x00000000);
1675 } else {
1676 evo_mthd(push, 0x0480 + head->base.index * 0x300, 1);
1677 evo_data(push, 0x05000000);
1678 evo_mthd(push, 0x048c + head->base.index * 0x300, 1);
1679 evo_data(push, 0x00000000);
1680 }
1681 evo_kick(push, core);
1682 }
1683}
1684
1685static void
1686nv50_head_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1687{
1688 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1689 u32 *push;
1690 if ((push = evo_wait(core, 5))) {
1691 if (core->base.user.oclass < G82_DISP_BASE_CHANNEL_DMA) {
1692 evo_mthd(push, 0x0880 + head->base.index * 0x400, 2);
1693 evo_data(push, 0x80000000 | (asyh->curs.layout << 26) |
1694 (asyh->curs.format << 24));
1695 evo_data(push, asyh->curs.offset >> 8);
1696 } else
1697 if (core->base.user.oclass < GF110_DISP_BASE_CHANNEL_DMA) {
1698 evo_mthd(push, 0x0880 + head->base.index * 0x400, 2);
1699 evo_data(push, 0x80000000 | (asyh->curs.layout << 26) |
1700 (asyh->curs.format << 24));
1701 evo_data(push, asyh->curs.offset >> 8);
1702 evo_mthd(push, 0x089c + head->base.index * 0x400, 1);
1703 evo_data(push, asyh->curs.handle);
1704 } else {
1705 evo_mthd(push, 0x0480 + head->base.index * 0x300, 2);
1706 evo_data(push, 0x80000000 | (asyh->curs.layout << 26) |
1707 (asyh->curs.format << 24));
1708 evo_data(push, asyh->curs.offset >> 8);
1709 evo_mthd(push, 0x048c + head->base.index * 0x300, 1);
1710 evo_data(push, asyh->curs.handle);
1711 }
1712 evo_kick(push, core);
1713 }
1714}
1715
1716static void
Ben Skeggsad633612016-11-04 17:20:36 +10001717nv50_head_core_clr(struct nv50_head *head)
1718{
1719 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1720 u32 *push;
1721 if ((push = evo_wait(core, 2))) {
1722 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA)
1723 evo_mthd(push, 0x0874 + head->base.index * 0x400, 1);
1724 else
1725 evo_mthd(push, 0x0474 + head->base.index * 0x300, 1);
1726 evo_data(push, 0x00000000);
1727 evo_kick(push, core);
1728 }
1729}
1730
1731static void
1732nv50_head_core_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1733{
1734 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1735 u32 *push;
1736 if ((push = evo_wait(core, 9))) {
1737 if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) {
1738 evo_mthd(push, 0x0860 + head->base.index * 0x400, 1);
1739 evo_data(push, asyh->core.offset >> 8);
1740 evo_mthd(push, 0x0868 + head->base.index * 0x400, 4);
1741 evo_data(push, (asyh->core.h << 16) | asyh->core.w);
1742 evo_data(push, asyh->core.layout << 20 |
1743 (asyh->core.pitch >> 8) << 8 |
1744 asyh->core.block);
1745 evo_data(push, asyh->core.kind << 16 |
1746 asyh->core.format << 8);
1747 evo_data(push, asyh->core.handle);
1748 evo_mthd(push, 0x08c0 + head->base.index * 0x400, 1);
1749 evo_data(push, (asyh->core.y << 16) | asyh->core.x);
1750 } else
1751 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1752 evo_mthd(push, 0x0860 + head->base.index * 0x400, 1);
1753 evo_data(push, asyh->core.offset >> 8);
1754 evo_mthd(push, 0x0868 + head->base.index * 0x400, 4);
1755 evo_data(push, (asyh->core.h << 16) | asyh->core.w);
1756 evo_data(push, asyh->core.layout << 20 |
1757 (asyh->core.pitch >> 8) << 8 |
1758 asyh->core.block);
1759 evo_data(push, asyh->core.format << 8);
1760 evo_data(push, asyh->core.handle);
1761 evo_mthd(push, 0x08c0 + head->base.index * 0x400, 1);
1762 evo_data(push, (asyh->core.y << 16) | asyh->core.x);
1763 } else {
1764 evo_mthd(push, 0x0460 + head->base.index * 0x300, 1);
1765 evo_data(push, asyh->core.offset >> 8);
1766 evo_mthd(push, 0x0468 + head->base.index * 0x300, 4);
1767 evo_data(push, (asyh->core.h << 16) | asyh->core.w);
1768 evo_data(push, asyh->core.layout << 24 |
1769 (asyh->core.pitch >> 8) << 8 |
1770 asyh->core.block);
1771 evo_data(push, asyh->core.format << 8);
1772 evo_data(push, asyh->core.handle);
1773 evo_mthd(push, 0x04b0 + head->base.index * 0x300, 1);
1774 evo_data(push, (asyh->core.y << 16) | asyh->core.x);
1775 }
1776 evo_kick(push, core);
1777 }
1778}
1779
1780static void
Ben Skeggsa7ae1562016-11-04 17:20:36 +10001781nv50_head_lut_clr(struct nv50_head *head)
1782{
1783 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1784 u32 *push;
1785 if ((push = evo_wait(core, 4))) {
1786 if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) {
1787 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 1);
1788 evo_data(push, 0x40000000);
1789 } else
1790 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1791 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 1);
1792 evo_data(push, 0x40000000);
1793 evo_mthd(push, 0x085c + (head->base.index * 0x400), 1);
1794 evo_data(push, 0x00000000);
1795 } else {
1796 evo_mthd(push, 0x0440 + (head->base.index * 0x300), 1);
1797 evo_data(push, 0x03000000);
1798 evo_mthd(push, 0x045c + (head->base.index * 0x300), 1);
1799 evo_data(push, 0x00000000);
1800 }
1801 evo_kick(push, core);
1802 }
1803}
1804
1805static void
1806nv50_head_lut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1807{
1808 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1809 u32 *push;
1810 if ((push = evo_wait(core, 7))) {
1811 if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) {
1812 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2);
1813 evo_data(push, 0xc0000000);
1814 evo_data(push, asyh->lut.offset >> 8);
1815 } else
1816 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1817 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2);
1818 evo_data(push, 0xc0000000);
1819 evo_data(push, asyh->lut.offset >> 8);
1820 evo_mthd(push, 0x085c + (head->base.index * 0x400), 1);
1821 evo_data(push, asyh->lut.handle);
1822 } else {
1823 evo_mthd(push, 0x0440 + (head->base.index * 0x300), 4);
1824 evo_data(push, 0x83000000);
1825 evo_data(push, asyh->lut.offset >> 8);
1826 evo_data(push, 0x00000000);
1827 evo_data(push, 0x00000000);
1828 evo_mthd(push, 0x045c + (head->base.index * 0x300), 1);
1829 evo_data(push, asyh->lut.handle);
1830 }
1831 evo_kick(push, core);
1832 }
1833}
1834
1835static void
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001836nv50_head_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
1837{
1838 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1839 struct nv50_head_mode *m = &asyh->mode;
1840 u32 *push;
1841 if ((push = evo_wait(core, 14))) {
1842 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1843 evo_mthd(push, 0x0804 + (head->base.index * 0x400), 2);
1844 evo_data(push, 0x00800000 | m->clock);
1845 evo_data(push, m->interlace ? 0x00000002 : 0x00000000);
Ben Skeggs06ab2822016-11-04 17:20:36 +10001846 evo_mthd(push, 0x0810 + (head->base.index * 0x400), 7);
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001847 evo_data(push, 0x00000000);
1848 evo_data(push, (m->v.active << 16) | m->h.active );
1849 evo_data(push, (m->v.synce << 16) | m->h.synce );
1850 evo_data(push, (m->v.blanke << 16) | m->h.blanke );
1851 evo_data(push, (m->v.blanks << 16) | m->h.blanks );
1852 evo_data(push, (m->v.blank2e << 16) | m->v.blank2s);
Ben Skeggs06ab2822016-11-04 17:20:36 +10001853 evo_data(push, asyh->mode.v.blankus);
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001854 evo_mthd(push, 0x082c + (head->base.index * 0x400), 1);
1855 evo_data(push, 0x00000000);
1856 } else {
1857 evo_mthd(push, 0x0410 + (head->base.index * 0x300), 6);
1858 evo_data(push, 0x00000000);
1859 evo_data(push, (m->v.active << 16) | m->h.active );
1860 evo_data(push, (m->v.synce << 16) | m->h.synce );
1861 evo_data(push, (m->v.blanke << 16) | m->h.blanke );
1862 evo_data(push, (m->v.blanks << 16) | m->h.blanks );
1863 evo_data(push, (m->v.blank2e << 16) | m->v.blank2s);
1864 evo_mthd(push, 0x042c + (head->base.index * 0x300), 2);
1865 evo_data(push, 0x00000000); /* ??? */
1866 evo_data(push, 0xffffff00);
1867 evo_mthd(push, 0x0450 + (head->base.index * 0x300), 3);
1868 evo_data(push, m->clock * 1000);
1869 evo_data(push, 0x00200000); /* ??? */
1870 evo_data(push, m->clock * 1000);
1871 }
1872 evo_kick(push, core);
1873 }
1874}
1875
1876static void
Ben Skeggsc4e68122016-11-04 17:20:36 +10001877nv50_head_view(struct nv50_head *head, struct nv50_head_atom *asyh)
1878{
1879 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
1880 u32 *push;
1881 if ((push = evo_wait(core, 10))) {
1882 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1883 evo_mthd(push, 0x08a4 + (head->base.index * 0x400), 1);
1884 evo_data(push, 0x00000000);
1885 evo_mthd(push, 0x08c8 + (head->base.index * 0x400), 1);
1886 evo_data(push, (asyh->view.iH << 16) | asyh->view.iW);
1887 evo_mthd(push, 0x08d8 + (head->base.index * 0x400), 2);
1888 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1889 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1890 } else {
1891 evo_mthd(push, 0x0494 + (head->base.index * 0x300), 1);
1892 evo_data(push, 0x00000000);
1893 evo_mthd(push, 0x04b8 + (head->base.index * 0x300), 1);
1894 evo_data(push, (asyh->view.iH << 16) | asyh->view.iW);
1895 evo_mthd(push, 0x04c0 + (head->base.index * 0x300), 3);
1896 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1897 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1898 evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
1899 }
1900 evo_kick(push, core);
1901 }
1902}
1903
1904static void
Ben Skeggsad633612016-11-04 17:20:36 +10001905nv50_head_flush_clr(struct nv50_head *head, struct nv50_head_atom *asyh, bool y)
1906{
1907 if (asyh->clr.core && (!asyh->set.core || y))
Ben Skeggsa7ae1562016-11-04 17:20:36 +10001908 nv50_head_lut_clr(head);
1909 if (asyh->clr.core && (!asyh->set.core || y))
Ben Skeggsad633612016-11-04 17:20:36 +10001910 nv50_head_core_clr(head);
Ben Skeggsea8ee392016-11-04 17:20:36 +10001911 if (asyh->clr.curs && (!asyh->set.curs || y))
1912 nv50_head_curs_clr(head);
Ben Skeggsad633612016-11-04 17:20:36 +10001913}
1914
1915static void
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001916nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1917{
Ben Skeggsc4e68122016-11-04 17:20:36 +10001918 if (asyh->set.view ) nv50_head_view (head, asyh);
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001919 if (asyh->set.mode ) nv50_head_mode (head, asyh);
Ben Skeggsa7ae1562016-11-04 17:20:36 +10001920 if (asyh->set.core ) nv50_head_lut_set (head, asyh);
Ben Skeggsad633612016-11-04 17:20:36 +10001921 if (asyh->set.core ) nv50_head_core_set(head, asyh);
Ben Skeggsea8ee392016-11-04 17:20:36 +10001922 if (asyh->set.curs ) nv50_head_curs_set(head, asyh);
Ben Skeggs6bbab3b2016-11-04 17:20:36 +10001923 if (asyh->set.base ) nv50_head_base (head, asyh);
1924 if (asyh->set.ovly ) nv50_head_ovly (head, asyh);
Ben Skeggs7e918332016-11-04 17:20:36 +10001925 if (asyh->set.dither ) nv50_head_dither (head, asyh);
Ben Skeggs7e08d672016-11-04 17:20:36 +10001926 if (asyh->set.procamp) nv50_head_procamp (head, asyh);
1927}
1928
1929static void
1930nv50_head_atomic_check_procamp(struct nv50_head_atom *armh,
1931 struct nv50_head_atom *asyh,
1932 struct nouveau_conn_atom *asyc)
1933{
1934 const int vib = asyc->procamp.color_vibrance - 100;
1935 const int hue = asyc->procamp.vibrant_hue - 90;
1936 const int adj = (vib > 0) ? 50 : 0;
1937 asyh->procamp.sat.cos = ((vib * 2047 + adj) / 100) & 0xfff;
1938 asyh->procamp.sat.sin = ((hue * 2047) / 100) & 0xfff;
1939 asyh->set.procamp = true;
Ben Skeggs7e918332016-11-04 17:20:36 +10001940}
1941
1942static void
1943nv50_head_atomic_check_dither(struct nv50_head_atom *armh,
1944 struct nv50_head_atom *asyh,
1945 struct nouveau_conn_atom *asyc)
1946{
1947 struct drm_connector *connector = asyc->state.connector;
1948 u32 mode = 0x00;
1949
1950 if (asyc->dither.mode == DITHERING_MODE_AUTO) {
1951 if (asyh->base.depth > connector->display_info.bpc * 3)
1952 mode = DITHERING_MODE_DYNAMIC2X2;
1953 } else {
1954 mode = asyc->dither.mode;
1955 }
1956
1957 if (asyc->dither.depth == DITHERING_DEPTH_AUTO) {
1958 if (connector->display_info.bpc >= 8)
1959 mode |= DITHERING_DEPTH_8BPC;
1960 } else {
1961 mode |= asyc->dither.depth;
1962 }
1963
1964 asyh->dither.enable = mode;
1965 asyh->dither.bits = mode >> 1;
1966 asyh->dither.mode = mode >> 3;
1967 asyh->set.dither = true;
Ben Skeggs3dbd0362016-11-04 17:20:36 +10001968}
1969
1970static void
Ben Skeggsc4e68122016-11-04 17:20:36 +10001971nv50_head_atomic_check_view(struct nv50_head_atom *armh,
1972 struct nv50_head_atom *asyh,
1973 struct nouveau_conn_atom *asyc)
1974{
1975 struct drm_connector *connector = asyc->state.connector;
1976 struct drm_display_mode *omode = &asyh->state.adjusted_mode;
1977 struct drm_display_mode *umode = &asyh->state.mode;
1978 int mode = asyc->scaler.mode;
1979 struct edid *edid;
1980
1981 if (connector->edid_blob_ptr)
1982 edid = (struct edid *)connector->edid_blob_ptr->data;
1983 else
1984 edid = NULL;
1985
1986 if (!asyc->scaler.full) {
1987 if (mode == DRM_MODE_SCALE_NONE)
1988 omode = umode;
1989 } else {
1990 /* Non-EDID LVDS/eDP mode. */
1991 mode = DRM_MODE_SCALE_FULLSCREEN;
1992 }
1993
1994 asyh->view.iW = umode->hdisplay;
1995 asyh->view.iH = umode->vdisplay;
1996 asyh->view.oW = omode->hdisplay;
1997 asyh->view.oH = omode->vdisplay;
1998 if (omode->flags & DRM_MODE_FLAG_DBLSCAN)
1999 asyh->view.oH *= 2;
2000
2001 /* Add overscan compensation if necessary, will keep the aspect
2002 * ratio the same as the backend mode unless overridden by the
2003 * user setting both hborder and vborder properties.
2004 */
2005 if ((asyc->scaler.underscan.mode == UNDERSCAN_ON ||
2006 (asyc->scaler.underscan.mode == UNDERSCAN_AUTO &&
2007 drm_detect_hdmi_monitor(edid)))) {
2008 u32 bX = asyc->scaler.underscan.hborder;
2009 u32 bY = asyc->scaler.underscan.vborder;
2010 u32 r = (asyh->view.oH << 19) / asyh->view.oW;
2011
2012 if (bX) {
2013 asyh->view.oW -= (bX * 2);
2014 if (bY) asyh->view.oH -= (bY * 2);
2015 else asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19;
2016 } else {
2017 asyh->view.oW -= (asyh->view.oW >> 4) + 32;
2018 if (bY) asyh->view.oH -= (bY * 2);
2019 else asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19;
2020 }
2021 }
2022
2023 /* Handle CENTER/ASPECT scaling, taking into account the areas
2024 * removed already for overscan compensation.
2025 */
2026 switch (mode) {
2027 case DRM_MODE_SCALE_CENTER:
2028 asyh->view.oW = min((u16)umode->hdisplay, asyh->view.oW);
2029 asyh->view.oH = min((u16)umode->vdisplay, asyh->view.oH);
2030 /* fall-through */
2031 case DRM_MODE_SCALE_ASPECT:
2032 if (asyh->view.oH < asyh->view.oW) {
2033 u32 r = (asyh->view.iW << 19) / asyh->view.iH;
2034 asyh->view.oW = ((asyh->view.oH * r) + (r / 2)) >> 19;
2035 } else {
2036 u32 r = (asyh->view.iH << 19) / asyh->view.iW;
2037 asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19;
2038 }
2039 break;
2040 default:
2041 break;
2042 }
2043
2044 asyh->set.view = true;
2045}
2046
2047static void
Ben Skeggs3dbd0362016-11-04 17:20:36 +10002048nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
2049{
2050 struct drm_display_mode *mode = &asyh->state.adjusted_mode;
2051 u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1;
2052 u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
2053 u32 hbackp = mode->htotal - mode->hsync_end;
2054 u32 vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace;
2055 u32 hfrontp = mode->hsync_start - mode->hdisplay;
2056 u32 vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
2057 struct nv50_head_mode *m = &asyh->mode;
2058
2059 m->h.active = mode->htotal;
2060 m->h.synce = mode->hsync_end - mode->hsync_start - 1;
2061 m->h.blanke = m->h.synce + hbackp;
2062 m->h.blanks = mode->htotal - hfrontp - 1;
2063
2064 m->v.active = mode->vtotal * vscan / ilace;
2065 m->v.synce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1;
2066 m->v.blanke = m->v.synce + vbackp;
2067 m->v.blanks = m->v.active - vfrontp - 1;
2068
2069 /*XXX: Safe underestimate, even "0" works */
2070 m->v.blankus = (m->v.active - mode->vdisplay - 2) * m->h.active;
2071 m->v.blankus *= 1000;
2072 m->v.blankus /= mode->clock;
2073
2074 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
2075 m->v.blank2e = m->v.active + m->v.synce + vbackp;
2076 m->v.blank2s = m->v.blank2e + (mode->vdisplay * vscan / ilace);
2077 m->v.active = (m->v.active * 2) + 1;
2078 m->interlace = true;
2079 } else {
2080 m->v.blank2e = 0;
2081 m->v.blank2s = 1;
2082 m->interlace = false;
2083 }
2084 m->clock = mode->clock;
2085
2086 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
2087 asyh->set.mode = true;
2088}
2089
2090static int
2091nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
2092{
2093 struct nouveau_drm *drm = nouveau_drm(crtc->dev);
Ben Skeggsad633612016-11-04 17:20:36 +10002094 struct nv50_disp *disp = nv50_disp(crtc->dev);
Ben Skeggs3dbd0362016-11-04 17:20:36 +10002095 struct nv50_head *head = nv50_head(crtc);
2096 struct nv50_head_atom *armh = &head->arm;
2097 struct nv50_head_atom *asyh = nv50_head_atom(state);
2098
2099 NV_ATOMIC(drm, "%s atomic_check %d\n", crtc->name, asyh->state.active);
Ben Skeggsad633612016-11-04 17:20:36 +10002100 asyh->clr.mask = 0;
Ben Skeggs3dbd0362016-11-04 17:20:36 +10002101 asyh->set.mask = 0;
2102
2103 if (asyh->state.active) {
2104 if (asyh->state.mode_changed)
2105 nv50_head_atomic_check_mode(head, asyh);
Ben Skeggsad633612016-11-04 17:20:36 +10002106
2107 if ((asyh->core.visible = (asyh->base.cpp != 0))) {
2108 asyh->core.x = asyh->base.x;
2109 asyh->core.y = asyh->base.y;
2110 asyh->core.w = asyh->base.w;
2111 asyh->core.h = asyh->base.h;
2112 } else
Ben Skeggsea8ee392016-11-04 17:20:36 +10002113 if ((asyh->core.visible = asyh->curs.visible)) {
Ben Skeggsad633612016-11-04 17:20:36 +10002114 /*XXX: We need to either find some way of having the
2115 * primary base layer appear black, while still
2116 * being able to display the other layers, or we
2117 * need to allocate a dummy black surface here.
2118 */
2119 asyh->core.x = 0;
2120 asyh->core.y = 0;
2121 asyh->core.w = asyh->state.mode.hdisplay;
2122 asyh->core.h = asyh->state.mode.vdisplay;
2123 }
2124 asyh->core.handle = disp->mast.base.vram.handle;
2125 asyh->core.offset = 0;
2126 asyh->core.format = 0xcf;
2127 asyh->core.kind = 0;
2128 asyh->core.layout = 1;
2129 asyh->core.block = 0;
2130 asyh->core.pitch = ALIGN(asyh->core.w, 64) * 4;
Ben Skeggsa7ae1562016-11-04 17:20:36 +10002131 asyh->lut.handle = disp->mast.base.vram.handle;
2132 asyh->lut.offset = head->base.lut.nvbo->bo.offset;
Ben Skeggs6bbab3b2016-11-04 17:20:36 +10002133 asyh->set.base = armh->base.cpp != asyh->base.cpp;
2134 asyh->set.ovly = armh->ovly.cpp != asyh->ovly.cpp;
Ben Skeggsad633612016-11-04 17:20:36 +10002135 } else {
2136 asyh->core.visible = false;
Ben Skeggsea8ee392016-11-04 17:20:36 +10002137 asyh->curs.visible = false;
Ben Skeggs6bbab3b2016-11-04 17:20:36 +10002138 asyh->base.cpp = 0;
2139 asyh->ovly.cpp = 0;
Ben Skeggsad633612016-11-04 17:20:36 +10002140 }
2141
2142 if (!drm_atomic_crtc_needs_modeset(&asyh->state)) {
2143 if (asyh->core.visible) {
2144 if (memcmp(&armh->core, &asyh->core, sizeof(asyh->core)))
2145 asyh->set.core = true;
2146 } else
2147 if (armh->core.visible) {
2148 asyh->clr.core = true;
2149 }
Ben Skeggsea8ee392016-11-04 17:20:36 +10002150
2151 if (asyh->curs.visible) {
2152 if (memcmp(&armh->curs, &asyh->curs, sizeof(asyh->curs)))
2153 asyh->set.curs = true;
2154 } else
2155 if (armh->curs.visible) {
2156 asyh->clr.curs = true;
2157 }
Ben Skeggsad633612016-11-04 17:20:36 +10002158 } else {
2159 asyh->clr.core = armh->core.visible;
Ben Skeggsea8ee392016-11-04 17:20:36 +10002160 asyh->clr.curs = armh->curs.visible;
Ben Skeggsad633612016-11-04 17:20:36 +10002161 asyh->set.core = asyh->core.visible;
Ben Skeggsea8ee392016-11-04 17:20:36 +10002162 asyh->set.curs = asyh->curs.visible;
Ben Skeggs3dbd0362016-11-04 17:20:36 +10002163 }
2164
2165 memcpy(armh, asyh, sizeof(*asyh));
2166 asyh->state.mode_changed = 0;
2167 return 0;
2168}
2169
2170/******************************************************************************
Ben Skeggs438d99e2011-07-05 16:48:06 +10002171 * CRTC
2172 *****************************************************************************/
2173static int
Ben Skeggse225f442012-11-21 14:40:21 +10002174nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002175{
Ben Skeggse225f442012-11-21 14:40:21 +10002176 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggs7e918332016-11-04 17:20:36 +10002177 struct nv50_head *head = nv50_head(&nv_crtc->base);
2178 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggsde691852011-10-17 12:23:41 +10002179 struct nouveau_connector *nv_connector;
Ben Skeggs7e918332016-11-04 17:20:36 +10002180 struct nouveau_conn_atom asyc;
2181 u32 *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002182
Ben Skeggs488ff202011-10-17 10:38:10 +10002183 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggsde691852011-10-17 12:23:41 +10002184
Ben Skeggs7e918332016-11-04 17:20:36 +10002185 asyc.state.connector = &nv_connector->base;
2186 asyc.dither.mode = nv_connector->dithering_mode;
2187 asyc.dither.depth = nv_connector->dithering_depth;
2188 asyh->state.crtc = &nv_crtc->base;
2189 nv50_head_atomic_check(&head->base.base, &asyh->state);
2190 nv50_head_atomic_check_dither(&head->arm, asyh, &asyc);
2191 nv50_head_flush_set(head, asyh);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002192
Ben Skeggs7e918332016-11-04 17:20:36 +10002193 if (update) {
2194 if ((push = evo_wait(mast, 2))) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10002195 evo_mthd(push, 0x0080, 1);
2196 evo_data(push, 0x00000000);
Ben Skeggs7e918332016-11-04 17:20:36 +10002197 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002198 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10002199 }
2200
2201 return 0;
2202}
2203
2204static int
Ben Skeggse225f442012-11-21 14:40:21 +10002205nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002206{
Ben Skeggsc4e68122016-11-04 17:20:36 +10002207 struct nv50_head *head = nv50_head(&nv_crtc->base);
2208 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggs3376ee32011-11-12 14:28:12 +10002209 struct drm_crtc *crtc = &nv_crtc->base;
Ben Skeggsf3fdc522011-07-07 16:01:57 +10002210 struct nouveau_connector *nv_connector;
Ben Skeggsc4e68122016-11-04 17:20:36 +10002211 struct nouveau_conn_atom asyc;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002212
Ben Skeggsf3fdc522011-07-07 16:01:57 +10002213 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggsf3fdc522011-07-07 16:01:57 +10002214
Ben Skeggsc4e68122016-11-04 17:20:36 +10002215 asyc.state.connector = &nv_connector->base;
2216 asyc.scaler.mode = nv_connector->scaling_mode;
2217 asyc.scaler.full = nv_connector->scaling_full;
2218 asyc.scaler.underscan.mode = nv_connector->underscan;
2219 asyc.scaler.underscan.hborder = nv_connector->underscan_hborder;
2220 asyc.scaler.underscan.vborder = nv_connector->underscan_vborder;
2221 nv50_head_atomic_check(&head->base.base, &asyh->state);
2222 nv50_head_atomic_check_view(&head->arm, asyh, &asyc);
2223 nv50_head_flush_set(head, asyh);
Ben Skeggs92854622011-11-11 23:49:06 +10002224
Ben Skeggsc4e68122016-11-04 17:20:36 +10002225 if (update) {
2226 nv50_display_flip_stop(crtc);
2227 nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002228 }
2229
2230 return 0;
2231}
2232
2233static int
Ben Skeggse225f442012-11-21 14:40:21 +10002234nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggsf9887d02012-11-21 13:03:42 +10002235{
Ben Skeggse225f442012-11-21 14:40:21 +10002236 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggs7e08d672016-11-04 17:20:36 +10002237 struct nv50_head *head = nv50_head(&nv_crtc->base);
2238 struct nv50_head_atom *asyh = &head->asy;
2239 struct nouveau_conn_atom asyc;
2240 u32 *push;
Ben Skeggsf9887d02012-11-21 13:03:42 +10002241
Ben Skeggs7e08d672016-11-04 17:20:36 +10002242 asyc.procamp.color_vibrance = nv_crtc->color_vibrance + 100;
2243 asyc.procamp.vibrant_hue = nv_crtc->vibrant_hue + 90;
2244 nv50_head_atomic_check(&head->base.base, &asyh->state);
2245 nv50_head_atomic_check_procamp(&head->arm, asyh, &asyc);
2246 nv50_head_flush_set(head, asyh);
Ben Skeggsf9887d02012-11-21 13:03:42 +10002247
Ben Skeggs7e08d672016-11-04 17:20:36 +10002248 if (update) {
2249 if ((push = evo_wait(mast, 2))) {
Ben Skeggsf9887d02012-11-21 13:03:42 +10002250 evo_mthd(push, 0x0080, 1);
2251 evo_data(push, 0x00000000);
Ben Skeggs7e08d672016-11-04 17:20:36 +10002252 evo_kick(push, mast);
Ben Skeggsf9887d02012-11-21 13:03:42 +10002253 }
Ben Skeggsf9887d02012-11-21 13:03:42 +10002254 }
2255
2256 return 0;
2257}
2258
2259static int
Ben Skeggse225f442012-11-21 14:40:21 +10002260nv50_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002261 int x, int y, bool update)
2262{
2263 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb);
Ben Skeggsad633612016-11-04 17:20:36 +10002264 struct nv50_head *head = nv50_head(&nv_crtc->base);
2265 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggs973f10c2016-11-04 17:20:36 +10002266 struct nv50_wndw_atom *asyw = &head->_base->wndw.asy;
Ben Skeggsad633612016-11-04 17:20:36 +10002267 const struct drm_format_info *info;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002268
Ben Skeggsad633612016-11-04 17:20:36 +10002269 info = drm_format_info(nvfb->base.pixel_format);
2270 if (!info || !info->depth)
2271 return -EINVAL;
Ben Skeggsde8268c2012-11-16 10:24:31 +10002272
Ben Skeggsad633612016-11-04 17:20:36 +10002273 asyh->base.depth = info->depth;
2274 asyh->base.cpp = info->cpp[0];
2275 asyh->base.x = x;
2276 asyh->base.y = y;
2277 asyh->base.w = nvfb->base.width;
2278 asyh->base.h = nvfb->base.height;
Ben Skeggs973f10c2016-11-04 17:20:36 +10002279 asyw->state.src_x = x << 16;
2280 asyw->state.src_y = y << 16;
Ben Skeggsad633612016-11-04 17:20:36 +10002281 nv50_head_atomic_check(&head->base.base, &asyh->state);
2282 nv50_head_flush_set(head, asyh);
2283
2284 if (update) {
2285 struct nv50_mast *core = nv50_mast(nv_crtc->base.dev);
2286 u32 *push = evo_wait(core, 2);
2287 if (push) {
Ben Skeggsa46232e2011-07-07 15:23:48 +10002288 evo_mthd(push, 0x0080, 1);
2289 evo_data(push, 0x00000000);
Ben Skeggsad633612016-11-04 17:20:36 +10002290 evo_kick(push, core);
Ben Skeggsa46232e2011-07-07 15:23:48 +10002291 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10002292 }
2293
Ben Skeggs8a423642014-08-10 04:10:19 +10002294 nv_crtc->fb.handle = nvfb->r_handle;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002295 return 0;
2296}
2297
2298static void
Ben Skeggse225f442012-11-21 14:40:21 +10002299nv50_crtc_cursor_show(struct nouveau_crtc *nv_crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002300{
Ben Skeggse225f442012-11-21 14:40:21 +10002301 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsea8ee392016-11-04 17:20:36 +10002302 struct nv50_head *head = nv50_head(&nv_crtc->base);
2303 struct nv50_head_atom *asyh = &head->asy;
2304
2305 asyh->curs.visible = true;
2306 asyh->curs.handle = mast->base.vram.handle;
2307 asyh->curs.offset = nv_crtc->cursor.nvbo->bo.offset;
2308 asyh->curs.layout = 1;
2309 asyh->curs.format = 1;
2310 nv50_head_atomic_check(&head->base.base, &asyh->state);
2311 nv50_head_flush_set(head, asyh);
Ben Skeggsde8268c2012-11-16 10:24:31 +10002312}
2313
2314static void
Ben Skeggse225f442012-11-21 14:40:21 +10002315nv50_crtc_cursor_hide(struct nouveau_crtc *nv_crtc)
Ben Skeggsde8268c2012-11-16 10:24:31 +10002316{
Ben Skeggsea8ee392016-11-04 17:20:36 +10002317 struct nv50_head *head = nv50_head(&nv_crtc->base);
2318 struct nv50_head_atom *asyh = &head->asy;
2319
2320 asyh->curs.visible = false;
2321 nv50_head_atomic_check(&head->base.base, &asyh->state);
2322 nv50_head_flush_clr(head, asyh, false);
Ben Skeggsde8268c2012-11-16 10:24:31 +10002323}
Ben Skeggs438d99e2011-07-05 16:48:06 +10002324
Ben Skeggsde8268c2012-11-16 10:24:31 +10002325static void
Ben Skeggse225f442012-11-21 14:40:21 +10002326nv50_crtc_cursor_show_hide(struct nouveau_crtc *nv_crtc, bool show, bool update)
Ben Skeggsde8268c2012-11-16 10:24:31 +10002327{
Ben Skeggse225f442012-11-21 14:40:21 +10002328 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde8268c2012-11-16 10:24:31 +10002329
Ben Skeggs697bb722015-07-28 17:20:57 +10002330 if (show && nv_crtc->cursor.nvbo && nv_crtc->base.enabled)
Ben Skeggse225f442012-11-21 14:40:21 +10002331 nv50_crtc_cursor_show(nv_crtc);
Ben Skeggsde8268c2012-11-16 10:24:31 +10002332 else
Ben Skeggse225f442012-11-21 14:40:21 +10002333 nv50_crtc_cursor_hide(nv_crtc);
Ben Skeggsde8268c2012-11-16 10:24:31 +10002334
2335 if (update) {
2336 u32 *push = evo_wait(mast, 2);
2337 if (push) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10002338 evo_mthd(push, 0x0080, 1);
2339 evo_data(push, 0x00000000);
Ben Skeggsde8268c2012-11-16 10:24:31 +10002340 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002341 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10002342 }
2343}
2344
2345static void
Ben Skeggse225f442012-11-21 14:40:21 +10002346nv50_crtc_dpms(struct drm_crtc *crtc, int mode)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002347{
2348}
2349
2350static void
Ben Skeggse225f442012-11-21 14:40:21 +10002351nv50_crtc_prepare(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002352{
Ben Skeggsad633612016-11-04 17:20:36 +10002353 struct nv50_head *head = nv50_head(crtc);
2354 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002355
Ben Skeggse225f442012-11-21 14:40:21 +10002356 nv50_display_flip_stop(crtc);
Ben Skeggs3376ee32011-11-12 14:28:12 +10002357
Ben Skeggsad633612016-11-04 17:20:36 +10002358 asyh->state.active = false;
2359 nv50_head_atomic_check(&head->base.base, &asyh->state);
2360 nv50_head_flush_clr(head, asyh, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002361}
2362
2363static void
Ben Skeggse225f442012-11-21 14:40:21 +10002364nv50_crtc_commit(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002365{
Ben Skeggsa7ae1562016-11-04 17:20:36 +10002366 struct nv50_head *head = nv50_head(crtc);
2367 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002368
Ben Skeggsa7ae1562016-11-04 17:20:36 +10002369 asyh->state.active = true;
2370 nv50_head_atomic_check(&head->base.base, &asyh->state);
2371 nv50_head_flush_set(head, asyh);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002372
Matt Roperf4510a22014-04-01 15:22:40 -07002373 nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002374}
2375
2376static bool
Ben Skeggse225f442012-11-21 14:40:21 +10002377nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002378 struct drm_display_mode *adjusted_mode)
2379{
Ben Skeggseb2e9682014-01-24 10:13:23 +10002380 drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002381 return true;
2382}
2383
2384static int
Ben Skeggse225f442012-11-21 14:40:21 +10002385nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002386{
Matt Roperf4510a22014-04-01 15:22:40 -07002387 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002388 struct nv50_head *head = nv50_head(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002389 int ret;
2390
Ben Skeggs547ad072014-11-10 12:35:06 +10002391 ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM, true);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002392 if (ret == 0) {
2393 if (head->image)
2394 nouveau_bo_unpin(head->image);
2395 nouveau_bo_ref(nvfb->nvbo, &head->image);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002396 }
2397
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002398 return ret;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002399}
2400
2401static int
Ben Skeggse225f442012-11-21 14:40:21 +10002402nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002403 struct drm_display_mode *mode, int x, int y,
2404 struct drm_framebuffer *old_fb)
2405{
2406 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
2407 struct nouveau_connector *nv_connector;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002408 int ret;
Ben Skeggs3dbd0362016-11-04 17:20:36 +10002409 struct nv50_head *head = nv50_head(crtc);
2410 struct nv50_head_atom *asyh = &head->asy;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002411
Ben Skeggs3dbd0362016-11-04 17:20:36 +10002412 memcpy(&asyh->state.mode, umode, sizeof(*umode));
2413 memcpy(&asyh->state.adjusted_mode, mode, sizeof(*mode));
2414 asyh->state.active = true;
2415 asyh->state.mode_changed = true;
2416 nv50_head_atomic_check(&head->base.base, &asyh->state);
Ben Skeggs2d1d8982011-11-11 23:39:22 +10002417
Ben Skeggse225f442012-11-21 14:40:21 +10002418 ret = nv50_crtc_swap_fbs(crtc, old_fb);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002419 if (ret)
2420 return ret;
2421
Ben Skeggs3dbd0362016-11-04 17:20:36 +10002422 nv50_head_flush_set(head, asyh);
2423
Ben Skeggs438d99e2011-07-05 16:48:06 +10002424 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10002425 nv50_crtc_set_dither(nv_crtc, false);
2426 nv50_crtc_set_scale(nv_crtc, false);
Roy Splieteae73822014-10-30 22:57:45 +01002427
Ben Skeggse225f442012-11-21 14:40:21 +10002428 nv50_crtc_set_color_vibrance(nv_crtc, false);
Matt Roperf4510a22014-04-01 15:22:40 -07002429 nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002430 return 0;
2431}
2432
2433static int
Ben Skeggse225f442012-11-21 14:40:21 +10002434nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002435 struct drm_framebuffer *old_fb)
2436{
Ben Skeggs77145f12012-07-31 16:16:21 +10002437 struct nouveau_drm *drm = nouveau_drm(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002438 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
2439 int ret;
2440
Matt Roperf4510a22014-04-01 15:22:40 -07002441 if (!crtc->primary->fb) {
Ben Skeggs77145f12012-07-31 16:16:21 +10002442 NV_DEBUG(drm, "No FB bound\n");
Ben Skeggs84e2ad82011-08-26 09:40:39 +10002443 return 0;
2444 }
2445
Ben Skeggse225f442012-11-21 14:40:21 +10002446 ret = nv50_crtc_swap_fbs(crtc, old_fb);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002447 if (ret)
2448 return ret;
2449
Ben Skeggse225f442012-11-21 14:40:21 +10002450 nv50_display_flip_stop(crtc);
Matt Roperf4510a22014-04-01 15:22:40 -07002451 nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, true);
2452 nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002453 return 0;
2454}
2455
2456static int
Ben Skeggse225f442012-11-21 14:40:21 +10002457nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002458 struct drm_framebuffer *fb, int x, int y,
2459 enum mode_set_atomic state)
2460{
2461 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10002462 nv50_display_flip_stop(crtc);
2463 nv50_crtc_set_image(nv_crtc, fb, x, y, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002464 return 0;
2465}
2466
2467static void
Ben Skeggse225f442012-11-21 14:40:21 +10002468nv50_crtc_lut_load(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002469{
Ben Skeggse225f442012-11-21 14:40:21 +10002470 struct nv50_disp *disp = nv50_disp(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002471 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
2472 void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
2473 int i;
2474
2475 for (i = 0; i < 256; i++) {
Ben Skeggsde8268c2012-11-16 10:24:31 +10002476 u16 r = nv_crtc->lut.r[i] >> 2;
2477 u16 g = nv_crtc->lut.g[i] >> 2;
2478 u16 b = nv_crtc->lut.b[i] >> 2;
2479
Ben Skeggs648d4df2014-08-10 04:10:27 +10002480 if (disp->disp->oclass < GF110_DISP) {
Ben Skeggsde8268c2012-11-16 10:24:31 +10002481 writew(r + 0x0000, lut + (i * 0x08) + 0);
2482 writew(g + 0x0000, lut + (i * 0x08) + 2);
2483 writew(b + 0x0000, lut + (i * 0x08) + 4);
2484 } else {
2485 writew(r + 0x6000, lut + (i * 0x20) + 0);
2486 writew(g + 0x6000, lut + (i * 0x20) + 2);
2487 writew(b + 0x6000, lut + (i * 0x20) + 4);
2488 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10002489 }
2490}
2491
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002492static void
2493nv50_crtc_disable(struct drm_crtc *crtc)
2494{
2495 struct nv50_head *head = nv50_head(crtc);
Ben Skeggsefa366f2014-06-05 12:56:35 +10002496 evo_sync(crtc->dev);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002497 if (head->image)
2498 nouveau_bo_unpin(head->image);
2499 nouveau_bo_ref(NULL, &head->image);
2500}
2501
Ben Skeggs438d99e2011-07-05 16:48:06 +10002502static int
Ben Skeggse225f442012-11-21 14:40:21 +10002503nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002504 uint32_t handle, uint32_t width, uint32_t height)
2505{
2506 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggs5a560252014-11-10 15:52:02 +10002507 struct drm_gem_object *gem = NULL;
2508 struct nouveau_bo *nvbo = NULL;
2509 int ret = 0;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002510
Ben Skeggs5a560252014-11-10 15:52:02 +10002511 if (handle) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10002512 if (width != 64 || height != 64)
2513 return -EINVAL;
2514
Chris Wilsona8ad0bd2016-05-09 11:04:54 +01002515 gem = drm_gem_object_lookup(file_priv, handle);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002516 if (unlikely(!gem))
2517 return -ENOENT;
2518 nvbo = nouveau_gem_object(gem);
2519
Ben Skeggs5a560252014-11-10 15:52:02 +10002520 ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002521 }
2522
Ben Skeggs5a560252014-11-10 15:52:02 +10002523 if (ret == 0) {
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01002524 if (nv_crtc->cursor.nvbo)
2525 nouveau_bo_unpin(nv_crtc->cursor.nvbo);
2526 nouveau_bo_ref(nvbo, &nv_crtc->cursor.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002527 }
Ben Skeggs5a560252014-11-10 15:52:02 +10002528 drm_gem_object_unreference_unlocked(gem);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002529
Ben Skeggs5a560252014-11-10 15:52:02 +10002530 nv50_crtc_cursor_show_hide(nv_crtc, true, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002531 return ret;
2532}
2533
2534static int
Ben Skeggse225f442012-11-21 14:40:21 +10002535nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002536{
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01002537 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggs22e927d2016-11-04 17:20:36 +10002538 struct nv50_wndw *wndw = &nv50_head(crtc)->_curs->wndw;
2539 struct nv50_wndw_atom *asyw = &wndw->asy;
2540
2541 asyw->point.x = x;
2542 asyw->point.y = y;
2543 asyw->set.point = true;
2544 nv50_wndw_flush_set(wndw, 0, asyw);
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01002545
2546 nv_crtc->cursor_saved_x = x;
2547 nv_crtc->cursor_saved_y = y;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002548 return 0;
2549}
2550
Maarten Lankhorst7ea77282016-06-07 12:49:30 +02002551static int
Ben Skeggse225f442012-11-21 14:40:21 +10002552nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
Maarten Lankhorst7ea77282016-06-07 12:49:30 +02002553 uint32_t size)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002554{
2555 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002556 u32 i;
2557
Maarten Lankhorst7ea77282016-06-07 12:49:30 +02002558 for (i = 0; i < size; i++) {
Ben Skeggs438d99e2011-07-05 16:48:06 +10002559 nv_crtc->lut.r[i] = r[i];
2560 nv_crtc->lut.g[i] = g[i];
2561 nv_crtc->lut.b[i] = b[i];
2562 }
2563
Ben Skeggse225f442012-11-21 14:40:21 +10002564 nv50_crtc_lut_load(crtc);
Maarten Lankhorst7ea77282016-06-07 12:49:30 +02002565
2566 return 0;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002567}
2568
2569static void
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01002570nv50_crtc_cursor_restore(struct nouveau_crtc *nv_crtc, int x, int y)
2571{
2572 nv50_crtc_cursor_move(&nv_crtc->base, x, y);
2573
2574 nv50_crtc_cursor_show_hide(nv_crtc, true, true);
2575}
2576
2577static void
Ben Skeggse225f442012-11-21 14:40:21 +10002578nv50_crtc_destroy(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002579{
2580 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10002581 struct nv50_disp *disp = nv50_disp(crtc->dev);
2582 struct nv50_head *head = nv50_head(crtc);
Ben Skeggs0ad72862014-08-10 04:10:22 +10002583 struct nv50_fbdma *fbdma;
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002584
Ben Skeggs0ad72862014-08-10 04:10:22 +10002585 list_for_each_entry(fbdma, &disp->fbdma, head) {
2586 nvif_object_fini(&fbdma->base[nv_crtc->index]);
2587 }
2588
2589 nv50_dmac_destroy(&head->ovly.base, disp->disp);
2590 nv50_pioc_destroy(&head->oimm.base);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002591
2592 /*XXX: this shouldn't be necessary, but the core doesn't call
2593 * disconnect() during the cleanup paths
2594 */
2595 if (head->image)
2596 nouveau_bo_unpin(head->image);
2597 nouveau_bo_ref(NULL, &head->image);
2598
Ben Skeggs5a560252014-11-10 15:52:02 +10002599 /*XXX: ditto */
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01002600 if (nv_crtc->cursor.nvbo)
2601 nouveau_bo_unpin(nv_crtc->cursor.nvbo);
2602 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002603
Ben Skeggs438d99e2011-07-05 16:48:06 +10002604 nouveau_bo_unmap(nv_crtc->lut.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01002605 if (nv_crtc->lut.nvbo)
2606 nouveau_bo_unpin(nv_crtc->lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002607 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002608
Ben Skeggs438d99e2011-07-05 16:48:06 +10002609 drm_crtc_cleanup(crtc);
2610 kfree(crtc);
2611}
2612
Ben Skeggse225f442012-11-21 14:40:21 +10002613static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = {
2614 .dpms = nv50_crtc_dpms,
2615 .prepare = nv50_crtc_prepare,
2616 .commit = nv50_crtc_commit,
2617 .mode_fixup = nv50_crtc_mode_fixup,
2618 .mode_set = nv50_crtc_mode_set,
2619 .mode_set_base = nv50_crtc_mode_set_base,
2620 .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
2621 .load_lut = nv50_crtc_lut_load,
Ben Skeggs8dda53f2013-07-09 12:35:55 +10002622 .disable = nv50_crtc_disable,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002623};
2624
Ben Skeggse225f442012-11-21 14:40:21 +10002625static const struct drm_crtc_funcs nv50_crtc_func = {
2626 .cursor_set = nv50_crtc_cursor_set,
2627 .cursor_move = nv50_crtc_cursor_move,
2628 .gamma_set = nv50_crtc_gamma_set,
Dave Airlie5addcf02012-09-10 14:20:51 +10002629 .set_config = nouveau_crtc_set_config,
Ben Skeggse225f442012-11-21 14:40:21 +10002630 .destroy = nv50_crtc_destroy,
Ben Skeggs3376ee32011-11-12 14:28:12 +10002631 .page_flip = nouveau_crtc_page_flip,
Ben Skeggs438d99e2011-07-05 16:48:06 +10002632};
2633
2634static int
Ben Skeggs0ad72862014-08-10 04:10:22 +10002635nv50_crtc_create(struct drm_device *dev, int index)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002636{
Ben Skeggsa01ca782015-08-20 14:54:15 +10002637 struct nouveau_drm *drm = nouveau_drm(dev);
2638 struct nvif_device *device = &drm->device;
Ben Skeggse225f442012-11-21 14:40:21 +10002639 struct nv50_disp *disp = nv50_disp(dev);
2640 struct nv50_head *head;
Ben Skeggs973f10c2016-11-04 17:20:36 +10002641 struct nv50_base *base;
Ben Skeggs22e927d2016-11-04 17:20:36 +10002642 struct nv50_curs *curs;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002643 struct drm_crtc *crtc;
2644 int ret, i;
2645
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10002646 head = kzalloc(sizeof(*head), GFP_KERNEL);
2647 if (!head)
Ben Skeggs438d99e2011-07-05 16:48:06 +10002648 return -ENOMEM;
2649
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10002650 head->base.index = index;
Ben Skeggsf9887d02012-11-21 13:03:42 +10002651 head->base.color_vibrance = 50;
2652 head->base.vibrant_hue = 0;
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01002653 head->base.cursor.set_pos = nv50_crtc_cursor_restore;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002654 for (i = 0; i < 256; i++) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10002655 head->base.lut.r[i] = i << 8;
2656 head->base.lut.g[i] = i << 8;
2657 head->base.lut.b[i] = i << 8;
Ben Skeggs438d99e2011-07-05 16:48:06 +10002658 }
2659
Ben Skeggs973f10c2016-11-04 17:20:36 +10002660 ret = nv50_base_new(drm, head, &base);
Ben Skeggs22e927d2016-11-04 17:20:36 +10002661 if (ret == 0)
2662 ret = nv50_curs_new(drm, head, &curs);
Ben Skeggs973f10c2016-11-04 17:20:36 +10002663 if (ret) {
2664 kfree(head);
2665 return ret;
2666 }
2667
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10002668 crtc = &head->base.base;
Ben Skeggs973f10c2016-11-04 17:20:36 +10002669 head->_base = base;
Ben Skeggs22e927d2016-11-04 17:20:36 +10002670 head->_curs = curs;
Ben Skeggs973f10c2016-11-04 17:20:36 +10002671
Ben Skeggse225f442012-11-21 14:40:21 +10002672 drm_crtc_init(dev, crtc, &nv50_crtc_func);
2673 drm_crtc_helper_add(crtc, &nv50_crtc_hfunc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002674 drm_mode_crtc_set_gamma_size(crtc, 256);
2675
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +10002676 ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
Maarten Lankhorstbb6178b2014-01-09 11:03:15 +01002677 0, 0x0000, NULL, NULL, &head->base.lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002678 if (!ret) {
Ben Skeggs547ad072014-11-10 12:35:06 +10002679 ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM, true);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01002680 if (!ret) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10002681 ret = nouveau_bo_map(head->base.lut.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01002682 if (ret)
2683 nouveau_bo_unpin(head->base.lut.nvbo);
2684 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10002685 if (ret)
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10002686 nouveau_bo_ref(NULL, &head->base.lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002687 }
2688
2689 if (ret)
2690 goto out;
2691
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002692 /* allocate overlay resources */
Ben Skeggsa01ca782015-08-20 14:54:15 +10002693 ret = nv50_oimm_create(device, disp->disp, index, &head->oimm);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002694 if (ret)
2695 goto out;
2696
Ben Skeggsa01ca782015-08-20 14:54:15 +10002697 ret = nv50_ovly_create(device, disp->disp, index, disp->sync->bo.offset,
2698 &head->ovly);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002699 if (ret)
2700 goto out;
2701
Ben Skeggs438d99e2011-07-05 16:48:06 +10002702out:
2703 if (ret)
Ben Skeggse225f442012-11-21 14:40:21 +10002704 nv50_crtc_destroy(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002705 return ret;
2706}
2707
2708/******************************************************************************
Ben Skeggsa91d3222014-12-22 16:30:13 +10002709 * Encoder helpers
2710 *****************************************************************************/
2711static bool
2712nv50_encoder_mode_fixup(struct drm_encoder *encoder,
2713 const struct drm_display_mode *mode,
2714 struct drm_display_mode *adjusted_mode)
2715{
2716 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2717 struct nouveau_connector *nv_connector;
2718
2719 nv_connector = nouveau_encoder_connector_get(nv_encoder);
2720 if (nv_connector && nv_connector->native_mode) {
Ben Skeggs576f7912014-12-22 17:19:26 +10002721 nv_connector->scaling_full = false;
2722 if (nv_connector->scaling_mode == DRM_MODE_SCALE_NONE) {
2723 switch (nv_connector->type) {
2724 case DCB_CONNECTOR_LVDS:
2725 case DCB_CONNECTOR_LVDS_SPWG:
2726 case DCB_CONNECTOR_eDP:
2727 /* force use of scaler for non-edid modes */
2728 if (adjusted_mode->type & DRM_MODE_TYPE_DRIVER)
2729 return true;
2730 nv_connector->scaling_full = true;
2731 break;
2732 default:
2733 return true;
2734 }
2735 }
2736
2737 drm_mode_copy(adjusted_mode, nv_connector->native_mode);
Ben Skeggsa91d3222014-12-22 16:30:13 +10002738 }
2739
2740 return true;
2741}
2742
2743/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10002744 * DAC
2745 *****************************************************************************/
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002746static void
Ben Skeggse225f442012-11-21 14:40:21 +10002747nv50_dac_dpms(struct drm_encoder *encoder, int mode)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002748{
2749 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10002750 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggsbf0eb892014-08-10 04:10:26 +10002751 struct {
2752 struct nv50_disp_mthd_v1 base;
2753 struct nv50_disp_dac_pwr_v0 pwr;
2754 } args = {
2755 .base.version = 1,
2756 .base.method = NV50_DISP_MTHD_V1_DAC_PWR,
2757 .base.hasht = nv_encoder->dcb->hasht,
2758 .base.hashm = nv_encoder->dcb->hashm,
2759 .pwr.state = 1,
2760 .pwr.data = 1,
2761 .pwr.vsync = (mode != DRM_MODE_DPMS_SUSPEND &&
2762 mode != DRM_MODE_DPMS_OFF),
2763 .pwr.hsync = (mode != DRM_MODE_DPMS_STANDBY &&
2764 mode != DRM_MODE_DPMS_OFF),
2765 };
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002766
Ben Skeggsbf0eb892014-08-10 04:10:26 +10002767 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002768}
2769
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002770static void
Ben Skeggse225f442012-11-21 14:40:21 +10002771nv50_dac_commit(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002772{
2773}
2774
2775static void
Ben Skeggse225f442012-11-21 14:40:21 +10002776nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002777 struct drm_display_mode *adjusted_mode)
2778{
Ben Skeggse225f442012-11-21 14:40:21 +10002779 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002780 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2781 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs97b19b52012-11-16 11:21:37 +10002782 u32 *push;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002783
Ben Skeggse225f442012-11-21 14:40:21 +10002784 nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002785
Ben Skeggs97b19b52012-11-16 11:21:37 +10002786 push = evo_wait(mast, 8);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002787 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10002788 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggs97b19b52012-11-16 11:21:37 +10002789 u32 syncs = 0x00000000;
2790
2791 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
2792 syncs |= 0x00000001;
2793 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
2794 syncs |= 0x00000002;
2795
2796 evo_mthd(push, 0x0400 + (nv_encoder->or * 0x080), 2);
2797 evo_data(push, 1 << nv_crtc->index);
2798 evo_data(push, syncs);
2799 } else {
2800 u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
2801 u32 syncs = 0x00000001;
2802
2803 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
2804 syncs |= 0x00000008;
2805 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
2806 syncs |= 0x00000010;
2807
2808 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
2809 magic |= 0x00000001;
2810
2811 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
2812 evo_data(push, syncs);
2813 evo_data(push, magic);
2814 evo_mthd(push, 0x0180 + (nv_encoder->or * 0x020), 1);
2815 evo_data(push, 1 << nv_crtc->index);
2816 }
2817
2818 evo_kick(push, mast);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002819 }
2820
2821 nv_encoder->crtc = encoder->crtc;
2822}
2823
2824static void
Ben Skeggse225f442012-11-21 14:40:21 +10002825nv50_dac_disconnect(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002826{
2827 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10002828 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs97b19b52012-11-16 11:21:37 +10002829 const int or = nv_encoder->or;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002830 u32 *push;
2831
2832 if (nv_encoder->crtc) {
Ben Skeggse225f442012-11-21 14:40:21 +10002833 nv50_crtc_prepare(nv_encoder->crtc);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002834
Ben Skeggs97b19b52012-11-16 11:21:37 +10002835 push = evo_wait(mast, 4);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002836 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10002837 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggs97b19b52012-11-16 11:21:37 +10002838 evo_mthd(push, 0x0400 + (or * 0x080), 1);
2839 evo_data(push, 0x00000000);
2840 } else {
2841 evo_mthd(push, 0x0180 + (or * 0x020), 1);
2842 evo_data(push, 0x00000000);
2843 }
Ben Skeggs97b19b52012-11-16 11:21:37 +10002844 evo_kick(push, mast);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002845 }
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002846 }
Ben Skeggs97b19b52012-11-16 11:21:37 +10002847
2848 nv_encoder->crtc = NULL;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002849}
2850
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10002851static enum drm_connector_status
Ben Skeggse225f442012-11-21 14:40:21 +10002852nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10002853{
Ben Skeggsc4abd312014-08-10 04:10:26 +10002854 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10002855 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggsc4abd312014-08-10 04:10:26 +10002856 struct {
2857 struct nv50_disp_mthd_v1 base;
2858 struct nv50_disp_dac_load_v0 load;
2859 } args = {
2860 .base.version = 1,
2861 .base.method = NV50_DISP_MTHD_V1_DAC_LOAD,
2862 .base.hasht = nv_encoder->dcb->hasht,
2863 .base.hashm = nv_encoder->dcb->hashm,
2864 };
2865 int ret;
Ben Skeggsb6819932011-07-08 11:14:50 +10002866
Ben Skeggsc4abd312014-08-10 04:10:26 +10002867 args.load.data = nouveau_drm(encoder->dev)->vbios.dactestval;
2868 if (args.load.data == 0)
2869 args.load.data = 340;
2870
2871 ret = nvif_mthd(disp->disp, 0, &args, sizeof(args));
2872 if (ret || !args.load.load)
Ben Skeggs35b21d32012-11-08 12:08:55 +10002873 return connector_status_disconnected;
Ben Skeggsb6819932011-07-08 11:14:50 +10002874
Ben Skeggs35b21d32012-11-08 12:08:55 +10002875 return connector_status_connected;
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10002876}
2877
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002878static void
Ben Skeggse225f442012-11-21 14:40:21 +10002879nv50_dac_destroy(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002880{
2881 drm_encoder_cleanup(encoder);
2882 kfree(encoder);
2883}
2884
Ben Skeggse225f442012-11-21 14:40:21 +10002885static const struct drm_encoder_helper_funcs nv50_dac_hfunc = {
2886 .dpms = nv50_dac_dpms,
Ben Skeggsa91d3222014-12-22 16:30:13 +10002887 .mode_fixup = nv50_encoder_mode_fixup,
Ben Skeggse225f442012-11-21 14:40:21 +10002888 .prepare = nv50_dac_disconnect,
2889 .commit = nv50_dac_commit,
2890 .mode_set = nv50_dac_mode_set,
2891 .disable = nv50_dac_disconnect,
2892 .get_crtc = nv50_display_crtc_get,
2893 .detect = nv50_dac_detect
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002894};
2895
Ben Skeggse225f442012-11-21 14:40:21 +10002896static const struct drm_encoder_funcs nv50_dac_func = {
2897 .destroy = nv50_dac_destroy,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002898};
2899
2900static int
Ben Skeggse225f442012-11-21 14:40:21 +10002901nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002902{
Ben Skeggs5ed50202013-02-11 20:15:03 +10002903 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +10002904 struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10002905 struct nvkm_i2c_bus *bus;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002906 struct nouveau_encoder *nv_encoder;
2907 struct drm_encoder *encoder;
Ben Skeggs5ed50202013-02-11 20:15:03 +10002908 int type = DRM_MODE_ENCODER_DAC;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002909
2910 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
2911 if (!nv_encoder)
2912 return -ENOMEM;
2913 nv_encoder->dcb = dcbe;
2914 nv_encoder->or = ffs(dcbe->or) - 1;
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10002915
2916 bus = nvkm_i2c_bus_find(i2c, dcbe->i2c_index);
2917 if (bus)
2918 nv_encoder->i2c = &bus->i2c;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002919
2920 encoder = to_drm_encoder(nv_encoder);
2921 encoder->possible_crtcs = dcbe->heads;
2922 encoder->possible_clones = 0;
Ben Skeggs5a223da2016-11-04 17:20:36 +10002923 drm_encoder_init(connector->dev, encoder, &nv50_dac_func, type,
2924 "dac-%04x-%04x", dcbe->hasht, dcbe->hashm);
Ben Skeggse225f442012-11-21 14:40:21 +10002925 drm_encoder_helper_add(encoder, &nv50_dac_hfunc);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002926
2927 drm_mode_connector_attach_encoder(connector, encoder);
2928 return 0;
2929}
Ben Skeggs26f6d882011-07-04 16:25:18 +10002930
2931/******************************************************************************
Ben Skeggs78951d22011-11-11 18:13:13 +10002932 * Audio
2933 *****************************************************************************/
2934static void
Ben Skeggse225f442012-11-21 14:40:21 +10002935nv50_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
Ben Skeggs78951d22011-11-11 18:13:13 +10002936{
2937 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggscc2a9072014-09-15 21:29:05 +10002938 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs78951d22011-11-11 18:13:13 +10002939 struct nouveau_connector *nv_connector;
Ben Skeggse225f442012-11-21 14:40:21 +10002940 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggsd889c522014-09-15 21:11:51 +10002941 struct __packed {
2942 struct {
2943 struct nv50_disp_mthd_v1 mthd;
2944 struct nv50_disp_sor_hda_eld_v0 eld;
2945 } base;
Ben Skeggs120b0c32014-08-10 04:10:26 +10002946 u8 data[sizeof(nv_connector->base.eld)];
2947 } args = {
Ben Skeggsd889c522014-09-15 21:11:51 +10002948 .base.mthd.version = 1,
2949 .base.mthd.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
2950 .base.mthd.hasht = nv_encoder->dcb->hasht,
Ben Skeggscc2a9072014-09-15 21:29:05 +10002951 .base.mthd.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
2952 (0x0100 << nv_crtc->index),
Ben Skeggs120b0c32014-08-10 04:10:26 +10002953 };
Ben Skeggs78951d22011-11-11 18:13:13 +10002954
2955 nv_connector = nouveau_encoder_connector_get(nv_encoder);
2956 if (!drm_detect_monitor_audio(nv_connector->edid))
2957 return;
2958
Ben Skeggs78951d22011-11-11 18:13:13 +10002959 drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
Ben Skeggs120b0c32014-08-10 04:10:26 +10002960 memcpy(args.data, nv_connector->base.eld, sizeof(args.data));
Ben Skeggs78951d22011-11-11 18:13:13 +10002961
Jani Nikula938fd8a2014-10-28 16:20:48 +02002962 nvif_mthd(disp->disp, 0, &args,
2963 sizeof(args.base) + drm_eld_size(args.data));
Ben Skeggs78951d22011-11-11 18:13:13 +10002964}
2965
2966static void
Ben Skeggscc2a9072014-09-15 21:29:05 +10002967nv50_audio_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
Ben Skeggs78951d22011-11-11 18:13:13 +10002968{
2969 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10002970 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs120b0c32014-08-10 04:10:26 +10002971 struct {
2972 struct nv50_disp_mthd_v1 base;
2973 struct nv50_disp_sor_hda_eld_v0 eld;
2974 } args = {
2975 .base.version = 1,
2976 .base.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
2977 .base.hasht = nv_encoder->dcb->hasht,
Ben Skeggscc2a9072014-09-15 21:29:05 +10002978 .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
2979 (0x0100 << nv_crtc->index),
Ben Skeggs120b0c32014-08-10 04:10:26 +10002980 };
Ben Skeggs78951d22011-11-11 18:13:13 +10002981
Ben Skeggs120b0c32014-08-10 04:10:26 +10002982 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs78951d22011-11-11 18:13:13 +10002983}
2984
2985/******************************************************************************
2986 * HDMI
2987 *****************************************************************************/
2988static void
Ben Skeggse225f442012-11-21 14:40:21 +10002989nv50_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
Ben Skeggs78951d22011-11-11 18:13:13 +10002990{
Ben Skeggs64d9cc02011-11-11 19:51:20 +10002991 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2992 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10002993 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggse00f2232014-08-10 04:10:26 +10002994 struct {
2995 struct nv50_disp_mthd_v1 base;
2996 struct nv50_disp_sor_hdmi_pwr_v0 pwr;
2997 } args = {
2998 .base.version = 1,
2999 .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR,
3000 .base.hasht = nv_encoder->dcb->hasht,
3001 .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
3002 (0x0100 << nv_crtc->index),
3003 .pwr.state = 1,
3004 .pwr.rekey = 56, /* binary driver, and tegra, constant */
3005 };
3006 struct nouveau_connector *nv_connector;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10003007 u32 max_ac_packet;
3008
3009 nv_connector = nouveau_encoder_connector_get(nv_encoder);
3010 if (!drm_detect_hdmi_monitor(nv_connector->edid))
3011 return;
3012
3013 max_ac_packet = mode->htotal - mode->hdisplay;
Ben Skeggse00f2232014-08-10 04:10:26 +10003014 max_ac_packet -= args.pwr.rekey;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10003015 max_ac_packet -= 18; /* constant from tegra */
Ben Skeggse00f2232014-08-10 04:10:26 +10003016 args.pwr.max_ac_packet = max_ac_packet / 32;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10003017
Ben Skeggse00f2232014-08-10 04:10:26 +10003018 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggse225f442012-11-21 14:40:21 +10003019 nv50_audio_mode_set(encoder, mode);
Ben Skeggs78951d22011-11-11 18:13:13 +10003020}
3021
3022static void
Ben Skeggse84a35a2014-06-05 10:59:55 +10003023nv50_hdmi_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
Ben Skeggs78951d22011-11-11 18:13:13 +10003024{
Ben Skeggs64d9cc02011-11-11 19:51:20 +10003025 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10003026 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggse00f2232014-08-10 04:10:26 +10003027 struct {
3028 struct nv50_disp_mthd_v1 base;
3029 struct nv50_disp_sor_hdmi_pwr_v0 pwr;
3030 } args = {
3031 .base.version = 1,
3032 .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR,
3033 .base.hasht = nv_encoder->dcb->hasht,
3034 .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
3035 (0x0100 << nv_crtc->index),
3036 };
Ben Skeggs64d9cc02011-11-11 19:51:20 +10003037
Ben Skeggse00f2232014-08-10 04:10:26 +10003038 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs78951d22011-11-11 18:13:13 +10003039}
3040
3041/******************************************************************************
Ben Skeggs52aa30f2016-11-04 17:20:36 +10003042 * MST
3043 *****************************************************************************/
3044struct nv50_mstm {
3045 struct nouveau_encoder *outp;
3046
3047 struct drm_dp_mst_topology_mgr mgr;
3048};
3049
3050static int
3051nv50_mstm_enable(struct nv50_mstm *mstm, u8 dpcd, int state)
3052{
3053 struct nouveau_encoder *outp = mstm->outp;
3054 struct {
3055 struct nv50_disp_mthd_v1 base;
3056 struct nv50_disp_sor_dp_mst_link_v0 mst;
3057 } args = {
3058 .base.version = 1,
3059 .base.method = NV50_DISP_MTHD_V1_SOR_DP_MST_LINK,
3060 .base.hasht = outp->dcb->hasht,
3061 .base.hashm = outp->dcb->hashm,
3062 .mst.state = state,
3063 };
3064 struct nouveau_drm *drm = nouveau_drm(outp->base.base.dev);
3065 struct nvif_object *disp = &drm->display->disp;
3066 int ret;
3067
3068 if (dpcd >= 0x12) {
3069 ret = drm_dp_dpcd_readb(mstm->mgr.aux, DP_MSTM_CTRL, &dpcd);
3070 if (ret < 0)
3071 return ret;
3072
3073 dpcd &= ~DP_MST_EN;
3074 if (state)
3075 dpcd |= DP_MST_EN;
3076
3077 ret = drm_dp_dpcd_writeb(mstm->mgr.aux, DP_MSTM_CTRL, dpcd);
3078 if (ret < 0)
3079 return ret;
3080 }
3081
3082 return nvif_mthd(disp, 0, &args, sizeof(args));
3083}
3084
3085int
3086nv50_mstm_detect(struct nv50_mstm *mstm, u8 dpcd[8], int allow)
3087{
3088 int ret, state = 0;
3089
3090 if (!mstm)
3091 return 0;
3092
3093 if (dpcd[0] >= 0x12 && allow) {
3094 ret = drm_dp_dpcd_readb(mstm->mgr.aux, DP_MSTM_CAP, &dpcd[1]);
3095 if (ret < 0)
3096 return ret;
3097
3098 state = dpcd[1] & DP_MST_CAP;
3099 }
3100
3101 ret = nv50_mstm_enable(mstm, dpcd[0], state);
3102 if (ret)
3103 return ret;
3104
3105 ret = drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, state);
3106 if (ret)
3107 return nv50_mstm_enable(mstm, dpcd[0], 0);
3108
3109 return mstm->mgr.mst_state;
3110}
3111
3112static void
3113nv50_mstm_del(struct nv50_mstm **pmstm)
3114{
3115 struct nv50_mstm *mstm = *pmstm;
3116 if (mstm) {
3117 kfree(*pmstm);
3118 *pmstm = NULL;
3119 }
3120}
3121
3122static int
3123nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max,
3124 int conn_base_id, struct nv50_mstm **pmstm)
3125{
3126 const int max_payloads = hweight8(outp->dcb->heads);
3127 struct drm_device *dev = outp->base.base.dev;
3128 struct nv50_mstm *mstm;
3129 int ret;
3130
3131 if (!(mstm = *pmstm = kzalloc(sizeof(*mstm), GFP_KERNEL)))
3132 return -ENOMEM;
3133 mstm->outp = outp;
3134
3135 ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev->dev, aux, aux_max,
3136 max_payloads, conn_base_id);
3137 if (ret)
3138 return ret;
3139
3140 return 0;
3141}
3142
3143/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10003144 * SOR
3145 *****************************************************************************/
Ben Skeggs6e83fda2012-03-11 01:28:48 +10003146static void
Ben Skeggse225f442012-11-21 14:40:21 +10003147nv50_sor_dpms(struct drm_encoder *encoder, int mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +10003148{
3149 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggsd55b4af2014-08-10 04:10:26 +10003150 struct nv50_disp *disp = nv50_disp(encoder->dev);
3151 struct {
3152 struct nv50_disp_mthd_v1 base;
3153 struct nv50_disp_sor_pwr_v0 pwr;
3154 } args = {
3155 .base.version = 1,
3156 .base.method = NV50_DISP_MTHD_V1_SOR_PWR,
3157 .base.hasht = nv_encoder->dcb->hasht,
3158 .base.hashm = nv_encoder->dcb->hashm,
3159 .pwr.state = mode == DRM_MODE_DPMS_ON,
3160 };
Ben Skeggsc02ed2b2014-08-10 04:10:27 +10003161 struct {
3162 struct nv50_disp_mthd_v1 base;
3163 struct nv50_disp_sor_dp_pwr_v0 pwr;
3164 } link = {
3165 .base.version = 1,
3166 .base.method = NV50_DISP_MTHD_V1_SOR_DP_PWR,
3167 .base.hasht = nv_encoder->dcb->hasht,
3168 .base.hashm = nv_encoder->dcb->hashm,
3169 .pwr.state = mode == DRM_MODE_DPMS_ON,
3170 };
Ben Skeggs83fc0832011-07-05 13:08:40 +10003171 struct drm_device *dev = encoder->dev;
3172 struct drm_encoder *partner;
Ben Skeggs83fc0832011-07-05 13:08:40 +10003173
3174 nv_encoder->last_dpms = mode;
3175
3176 list_for_each_entry(partner, &dev->mode_config.encoder_list, head) {
3177 struct nouveau_encoder *nv_partner = nouveau_encoder(partner);
3178
3179 if (partner->encoder_type != DRM_MODE_ENCODER_TMDS)
3180 continue;
3181
3182 if (nv_partner != nv_encoder &&
Ben Skeggs26cfa812011-11-17 09:10:02 +10003183 nv_partner->dcb->or == nv_encoder->dcb->or) {
Ben Skeggs83fc0832011-07-05 13:08:40 +10003184 if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
3185 return;
3186 break;
3187 }
3188 }
3189
Ben Skeggs48743222014-05-31 01:48:06 +10003190 if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
Ben Skeggsd55b4af2014-08-10 04:10:26 +10003191 args.pwr.state = 1;
3192 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggsc02ed2b2014-08-10 04:10:27 +10003193 nvif_mthd(disp->disp, 0, &link, sizeof(link));
Ben Skeggs48743222014-05-31 01:48:06 +10003194 } else {
Ben Skeggsd55b4af2014-08-10 04:10:26 +10003195 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs48743222014-05-31 01:48:06 +10003196 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10003197}
3198
Ben Skeggs83fc0832011-07-05 13:08:40 +10003199static void
Ben Skeggse84a35a2014-06-05 10:59:55 +10003200nv50_sor_ctrl(struct nouveau_encoder *nv_encoder, u32 mask, u32 data)
3201{
3202 struct nv50_mast *mast = nv50_mast(nv_encoder->base.base.dev);
3203 u32 temp = (nv_encoder->ctrl & ~mask) | (data & mask), *push;
3204 if (temp != nv_encoder->ctrl && (push = evo_wait(mast, 2))) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10003205 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggse84a35a2014-06-05 10:59:55 +10003206 evo_mthd(push, 0x0600 + (nv_encoder->or * 0x40), 1);
3207 evo_data(push, (nv_encoder->ctrl = temp));
3208 } else {
3209 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
3210 evo_data(push, (nv_encoder->ctrl = temp));
3211 }
3212 evo_kick(push, mast);
3213 }
3214}
3215
3216static void
Ben Skeggse225f442012-11-21 14:40:21 +10003217nv50_sor_disconnect(struct drm_encoder *encoder)
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10003218{
3219 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse84a35a2014-06-05 10:59:55 +10003220 struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003221
3222 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
3223 nv_encoder->crtc = NULL;
Ben Skeggse84a35a2014-06-05 10:59:55 +10003224
3225 if (nv_crtc) {
3226 nv50_crtc_prepare(&nv_crtc->base);
3227 nv50_sor_ctrl(nv_encoder, 1 << nv_crtc->index, 0);
Ben Skeggscc2a9072014-09-15 21:29:05 +10003228 nv50_audio_disconnect(encoder, nv_crtc);
Ben Skeggse84a35a2014-06-05 10:59:55 +10003229 nv50_hdmi_disconnect(&nv_encoder->base.base, nv_crtc);
3230 }
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10003231}
3232
3233static void
Ben Skeggse225f442012-11-21 14:40:21 +10003234nv50_sor_commit(struct drm_encoder *encoder)
Ben Skeggs83fc0832011-07-05 13:08:40 +10003235{
3236}
3237
3238static void
Ben Skeggse225f442012-11-21 14:40:21 +10003239nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003240 struct drm_display_mode *mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +10003241{
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003242 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
3243 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
3244 struct {
3245 struct nv50_disp_mthd_v1 base;
3246 struct nv50_disp_sor_lvds_script_v0 lvds;
3247 } lvds = {
3248 .base.version = 1,
3249 .base.method = NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT,
3250 .base.hasht = nv_encoder->dcb->hasht,
3251 .base.hashm = nv_encoder->dcb->hashm,
3252 };
Ben Skeggse225f442012-11-21 14:40:21 +10003253 struct nv50_disp *disp = nv50_disp(encoder->dev);
3254 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs78951d22011-11-11 18:13:13 +10003255 struct drm_device *dev = encoder->dev;
Ben Skeggs77145f12012-07-31 16:16:21 +10003256 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003257 struct nouveau_connector *nv_connector;
Ben Skeggs77145f12012-07-31 16:16:21 +10003258 struct nvbios *bios = &drm->vbios;
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003259 u32 mask, ctrl;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003260 u8 owner = 1 << nv_crtc->index;
3261 u8 proto = 0xf;
3262 u8 depth = 0x0;
Ben Skeggs83fc0832011-07-05 13:08:40 +10003263
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003264 nv_connector = nouveau_encoder_connector_get(nv_encoder);
Ben Skeggse84a35a2014-06-05 10:59:55 +10003265 nv_encoder->crtc = encoder->crtc;
3266
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003267 switch (nv_encoder->dcb->type) {
Ben Skeggscb75d972012-07-11 10:44:20 +10003268 case DCB_OUTPUT_TMDS:
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003269 if (nv_encoder->dcb->sorconf.link & 1) {
Hauke Mehrtens16ef53a92015-11-03 21:00:10 -05003270 proto = 0x1;
3271 /* Only enable dual-link if:
3272 * - Need to (i.e. rate > 165MHz)
3273 * - DCB says we can
3274 * - Not an HDMI monitor, since there's no dual-link
3275 * on HDMI.
3276 */
3277 if (mode->clock >= 165000 &&
3278 nv_encoder->dcb->duallink_possible &&
3279 !drm_detect_hdmi_monitor(nv_connector->edid))
3280 proto |= 0x4;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003281 } else {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003282 proto = 0x2;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003283 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10003284
Ben Skeggse84a35a2014-06-05 10:59:55 +10003285 nv50_hdmi_mode_set(&nv_encoder->base.base, mode);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003286 break;
Ben Skeggscb75d972012-07-11 10:44:20 +10003287 case DCB_OUTPUT_LVDS:
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003288 proto = 0x0;
3289
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003290 if (bios->fp_no_ddc) {
3291 if (bios->fp.dual_link)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003292 lvds.lvds.script |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003293 if (bios->fp.if_is_24bit)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003294 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003295 } else {
Ben Skeggsbefb51e2011-11-18 10:23:59 +10003296 if (nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003297 if (((u8 *)nv_connector->edid)[121] == 2)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003298 lvds.lvds.script |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003299 } else
3300 if (mode->clock >= bios->fp.duallink_transition_clk) {
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003301 lvds.lvds.script |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003302 }
3303
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003304 if (lvds.lvds.script & 0x0100) {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003305 if (bios->fp.strapless_is_24bit & 2)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003306 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003307 } else {
3308 if (bios->fp.strapless_is_24bit & 1)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003309 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003310 }
3311
3312 if (nv_connector->base.display_info.bpc == 8)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003313 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003314 }
Ben Skeggs4a230fa2012-11-09 11:25:37 +10003315
Ben Skeggsa3761fa2014-08-10 04:10:27 +10003316 nvif_mthd(disp->disp, 0, &lvds, sizeof(lvds));
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003317 break;
Ben Skeggscb75d972012-07-11 10:44:20 +10003318 case DCB_OUTPUT_DP:
Ben Skeggs3488c572012-03-12 11:42:20 +10003319 if (nv_connector->base.display_info.bpc == 6) {
Ben Skeggs6e83fda2012-03-11 01:28:48 +10003320 nv_encoder->dp.datarate = mode->clock * 18 / 8;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003321 depth = 0x2;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10003322 } else
3323 if (nv_connector->base.display_info.bpc == 8) {
Ben Skeggs6e83fda2012-03-11 01:28:48 +10003324 nv_encoder->dp.datarate = mode->clock * 24 / 8;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003325 depth = 0x5;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10003326 } else {
3327 nv_encoder->dp.datarate = mode->clock * 30 / 8;
3328 depth = 0x6;
Ben Skeggs3488c572012-03-12 11:42:20 +10003329 }
Ben Skeggs6e83fda2012-03-11 01:28:48 +10003330
3331 if (nv_encoder->dcb->sorconf.link & 1)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003332 proto = 0x8;
Ben Skeggs6e83fda2012-03-11 01:28:48 +10003333 else
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003334 proto = 0x9;
Ben Skeggs3eee8642014-09-15 15:20:47 +10003335 nv50_audio_mode_set(encoder, mode);
Ben Skeggs6e83fda2012-03-11 01:28:48 +10003336 break;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10003337 default:
3338 BUG_ON(1);
3339 break;
3340 }
Ben Skeggsff8ff502011-07-08 11:53:37 +10003341
Ben Skeggse84a35a2014-06-05 10:59:55 +10003342 nv50_sor_dpms(&nv_encoder->base.base, DRM_MODE_DPMS_ON);
Ben Skeggs83fc0832011-07-05 13:08:40 +10003343
Ben Skeggs648d4df2014-08-10 04:10:27 +10003344 if (nv50_vers(mast) >= GF110_DISP) {
Ben Skeggse84a35a2014-06-05 10:59:55 +10003345 u32 *push = evo_wait(mast, 3);
3346 if (push) {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003347 u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
3348 u32 syncs = 0x00000001;
3349
3350 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
3351 syncs |= 0x00000008;
3352 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
3353 syncs |= 0x00000010;
3354
3355 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
3356 magic |= 0x00000001;
3357
3358 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
3359 evo_data(push, syncs | (depth << 6));
3360 evo_data(push, magic);
Ben Skeggse84a35a2014-06-05 10:59:55 +10003361 evo_kick(push, mast);
Ben Skeggs419e8dc2012-11-16 11:40:34 +10003362 }
3363
Ben Skeggse84a35a2014-06-05 10:59:55 +10003364 ctrl = proto << 8;
3365 mask = 0x00000f00;
3366 } else {
3367 ctrl = (depth << 16) | (proto << 8);
3368 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
3369 ctrl |= 0x00001000;
3370 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
3371 ctrl |= 0x00002000;
3372 mask = 0x000f3f00;
Ben Skeggs83fc0832011-07-05 13:08:40 +10003373 }
3374
Ben Skeggse84a35a2014-06-05 10:59:55 +10003375 nv50_sor_ctrl(nv_encoder, mask | owner, ctrl | owner);
Ben Skeggs83fc0832011-07-05 13:08:40 +10003376}
3377
3378static void
Ben Skeggse225f442012-11-21 14:40:21 +10003379nv50_sor_destroy(struct drm_encoder *encoder)
Ben Skeggs83fc0832011-07-05 13:08:40 +10003380{
Ben Skeggs52aa30f2016-11-04 17:20:36 +10003381 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
3382 nv50_mstm_del(&nv_encoder->dp.mstm);
Ben Skeggs83fc0832011-07-05 13:08:40 +10003383 drm_encoder_cleanup(encoder);
3384 kfree(encoder);
3385}
3386
Ben Skeggse225f442012-11-21 14:40:21 +10003387static const struct drm_encoder_helper_funcs nv50_sor_hfunc = {
3388 .dpms = nv50_sor_dpms,
Ben Skeggsa91d3222014-12-22 16:30:13 +10003389 .mode_fixup = nv50_encoder_mode_fixup,
Ben Skeggs5a885f02013-02-20 14:34:18 +10003390 .prepare = nv50_sor_disconnect,
Ben Skeggse225f442012-11-21 14:40:21 +10003391 .commit = nv50_sor_commit,
3392 .mode_set = nv50_sor_mode_set,
3393 .disable = nv50_sor_disconnect,
3394 .get_crtc = nv50_display_crtc_get,
Ben Skeggs83fc0832011-07-05 13:08:40 +10003395};
3396
Ben Skeggse225f442012-11-21 14:40:21 +10003397static const struct drm_encoder_funcs nv50_sor_func = {
3398 .destroy = nv50_sor_destroy,
Ben Skeggs83fc0832011-07-05 13:08:40 +10003399};
3400
3401static int
Ben Skeggse225f442012-11-21 14:40:21 +10003402nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
Ben Skeggs83fc0832011-07-05 13:08:40 +10003403{
Ben Skeggs52aa30f2016-11-04 17:20:36 +10003404 struct nouveau_connector *nv_connector = nouveau_connector(connector);
Ben Skeggs5ed50202013-02-11 20:15:03 +10003405 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +10003406 struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
Ben Skeggs83fc0832011-07-05 13:08:40 +10003407 struct nouveau_encoder *nv_encoder;
3408 struct drm_encoder *encoder;
Ben Skeggs52aa30f2016-11-04 17:20:36 +10003409 int type, ret;
Ben Skeggs5ed50202013-02-11 20:15:03 +10003410
3411 switch (dcbe->type) {
3412 case DCB_OUTPUT_LVDS: type = DRM_MODE_ENCODER_LVDS; break;
3413 case DCB_OUTPUT_TMDS:
3414 case DCB_OUTPUT_DP:
3415 default:
3416 type = DRM_MODE_ENCODER_TMDS;
3417 break;
3418 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10003419
3420 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
3421 if (!nv_encoder)
3422 return -ENOMEM;
3423 nv_encoder->dcb = dcbe;
3424 nv_encoder->or = ffs(dcbe->or) - 1;
3425 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
3426
Ben Skeggs52aa30f2016-11-04 17:20:36 +10003427 encoder = to_drm_encoder(nv_encoder);
3428 encoder->possible_crtcs = dcbe->heads;
3429 encoder->possible_clones = 0;
Ben Skeggs5a223da2016-11-04 17:20:36 +10003430 drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type,
3431 "sor-%04x-%04x", dcbe->hasht, dcbe->hashm);
Ben Skeggs52aa30f2016-11-04 17:20:36 +10003432 drm_encoder_helper_add(encoder, &nv50_sor_hfunc);
3433
3434 drm_mode_connector_attach_encoder(connector, encoder);
3435
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10003436 if (dcbe->type == DCB_OUTPUT_DP) {
3437 struct nvkm_i2c_aux *aux =
3438 nvkm_i2c_aux_find(i2c, dcbe->i2c_index);
3439 if (aux) {
3440 nv_encoder->i2c = &aux->i2c;
3441 nv_encoder->aux = aux;
3442 }
Ben Skeggs52aa30f2016-11-04 17:20:36 +10003443
3444 /*TODO: Use DP Info Table to check for support. */
3445 if (nv50_disp(encoder->dev)->disp->oclass >= GF110_DISP) {
3446 ret = nv50_mstm_new(nv_encoder, &nv_connector->aux, 16,
3447 nv_connector->base.base.id,
3448 &nv_encoder->dp.mstm);
3449 if (ret)
3450 return ret;
3451 }
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10003452 } else {
3453 struct nvkm_i2c_bus *bus =
3454 nvkm_i2c_bus_find(i2c, dcbe->i2c_index);
3455 if (bus)
3456 nv_encoder->i2c = &bus->i2c;
3457 }
3458
Ben Skeggs83fc0832011-07-05 13:08:40 +10003459 return 0;
3460}
Ben Skeggs26f6d882011-07-04 16:25:18 +10003461
3462/******************************************************************************
Ben Skeggseb6313a2013-02-11 09:52:58 +10003463 * PIOR
3464 *****************************************************************************/
3465
3466static void
3467nv50_pior_dpms(struct drm_encoder *encoder, int mode)
3468{
3469 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
3470 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs67cb49c2014-08-10 04:10:27 +10003471 struct {
3472 struct nv50_disp_mthd_v1 base;
3473 struct nv50_disp_pior_pwr_v0 pwr;
3474 } args = {
3475 .base.version = 1,
3476 .base.method = NV50_DISP_MTHD_V1_PIOR_PWR,
3477 .base.hasht = nv_encoder->dcb->hasht,
3478 .base.hashm = nv_encoder->dcb->hashm,
3479 .pwr.state = mode == DRM_MODE_DPMS_ON,
3480 .pwr.type = nv_encoder->dcb->type,
3481 };
3482
3483 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggseb6313a2013-02-11 09:52:58 +10003484}
3485
3486static bool
3487nv50_pior_mode_fixup(struct drm_encoder *encoder,
3488 const struct drm_display_mode *mode,
3489 struct drm_display_mode *adjusted_mode)
3490{
Ben Skeggsa91d3222014-12-22 16:30:13 +10003491 if (!nv50_encoder_mode_fixup(encoder, mode, adjusted_mode))
3492 return false;
Ben Skeggseb6313a2013-02-11 09:52:58 +10003493 adjusted_mode->clock *= 2;
3494 return true;
3495}
3496
3497static void
3498nv50_pior_commit(struct drm_encoder *encoder)
3499{
3500}
3501
3502static void
3503nv50_pior_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
3504 struct drm_display_mode *adjusted_mode)
3505{
3506 struct nv50_mast *mast = nv50_mast(encoder->dev);
3507 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
3508 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
3509 struct nouveau_connector *nv_connector;
3510 u8 owner = 1 << nv_crtc->index;
3511 u8 proto, depth;
3512 u32 *push;
3513
3514 nv_connector = nouveau_encoder_connector_get(nv_encoder);
3515 switch (nv_connector->base.display_info.bpc) {
3516 case 10: depth = 0x6; break;
3517 case 8: depth = 0x5; break;
3518 case 6: depth = 0x2; break;
3519 default: depth = 0x0; break;
3520 }
3521
3522 switch (nv_encoder->dcb->type) {
3523 case DCB_OUTPUT_TMDS:
3524 case DCB_OUTPUT_DP:
3525 proto = 0x0;
3526 break;
3527 default:
3528 BUG_ON(1);
3529 break;
3530 }
3531
3532 nv50_pior_dpms(encoder, DRM_MODE_DPMS_ON);
3533
3534 push = evo_wait(mast, 8);
3535 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10003536 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggseb6313a2013-02-11 09:52:58 +10003537 u32 ctrl = (depth << 16) | (proto << 8) | owner;
3538 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
3539 ctrl |= 0x00001000;
3540 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
3541 ctrl |= 0x00002000;
3542 evo_mthd(push, 0x0700 + (nv_encoder->or * 0x040), 1);
3543 evo_data(push, ctrl);
3544 }
3545
3546 evo_kick(push, mast);
3547 }
3548
3549 nv_encoder->crtc = encoder->crtc;
3550}
3551
3552static void
3553nv50_pior_disconnect(struct drm_encoder *encoder)
3554{
3555 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
3556 struct nv50_mast *mast = nv50_mast(encoder->dev);
3557 const int or = nv_encoder->or;
3558 u32 *push;
3559
3560 if (nv_encoder->crtc) {
3561 nv50_crtc_prepare(nv_encoder->crtc);
3562
3563 push = evo_wait(mast, 4);
3564 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10003565 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggseb6313a2013-02-11 09:52:58 +10003566 evo_mthd(push, 0x0700 + (or * 0x040), 1);
3567 evo_data(push, 0x00000000);
3568 }
Ben Skeggseb6313a2013-02-11 09:52:58 +10003569 evo_kick(push, mast);
3570 }
3571 }
3572
3573 nv_encoder->crtc = NULL;
3574}
3575
3576static void
3577nv50_pior_destroy(struct drm_encoder *encoder)
3578{
3579 drm_encoder_cleanup(encoder);
3580 kfree(encoder);
3581}
3582
3583static const struct drm_encoder_helper_funcs nv50_pior_hfunc = {
3584 .dpms = nv50_pior_dpms,
3585 .mode_fixup = nv50_pior_mode_fixup,
3586 .prepare = nv50_pior_disconnect,
3587 .commit = nv50_pior_commit,
3588 .mode_set = nv50_pior_mode_set,
3589 .disable = nv50_pior_disconnect,
3590 .get_crtc = nv50_display_crtc_get,
3591};
3592
3593static const struct drm_encoder_funcs nv50_pior_func = {
3594 .destroy = nv50_pior_destroy,
3595};
3596
3597static int
3598nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
3599{
3600 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggsbe83cd42015-01-14 15:36:34 +10003601 struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10003602 struct nvkm_i2c_bus *bus = NULL;
3603 struct nvkm_i2c_aux *aux = NULL;
3604 struct i2c_adapter *ddc;
Ben Skeggseb6313a2013-02-11 09:52:58 +10003605 struct nouveau_encoder *nv_encoder;
3606 struct drm_encoder *encoder;
3607 int type;
3608
3609 switch (dcbe->type) {
3610 case DCB_OUTPUT_TMDS:
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10003611 bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_EXT(dcbe->extdev));
3612 ddc = bus ? &bus->i2c : NULL;
Ben Skeggseb6313a2013-02-11 09:52:58 +10003613 type = DRM_MODE_ENCODER_TMDS;
3614 break;
3615 case DCB_OUTPUT_DP:
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10003616 aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbe->extdev));
3617 ddc = aux ? &aux->i2c : NULL;
Ben Skeggseb6313a2013-02-11 09:52:58 +10003618 type = DRM_MODE_ENCODER_TMDS;
3619 break;
3620 default:
3621 return -ENODEV;
3622 }
3623
3624 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
3625 if (!nv_encoder)
3626 return -ENOMEM;
3627 nv_encoder->dcb = dcbe;
3628 nv_encoder->or = ffs(dcbe->or) - 1;
3629 nv_encoder->i2c = ddc;
Ben Skeggs2aa5eac2015-08-20 14:54:15 +10003630 nv_encoder->aux = aux;
Ben Skeggseb6313a2013-02-11 09:52:58 +10003631
3632 encoder = to_drm_encoder(nv_encoder);
3633 encoder->possible_crtcs = dcbe->heads;
3634 encoder->possible_clones = 0;
Ben Skeggs5a223da2016-11-04 17:20:36 +10003635 drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type,
3636 "pior-%04x-%04x", dcbe->hasht, dcbe->hashm);
Ben Skeggseb6313a2013-02-11 09:52:58 +10003637 drm_encoder_helper_add(encoder, &nv50_pior_hfunc);
3638
3639 drm_mode_connector_attach_encoder(connector, encoder);
3640 return 0;
3641}
3642
3643/******************************************************************************
Ben Skeggsab0af552014-08-10 04:10:19 +10003644 * Framebuffer
3645 *****************************************************************************/
3646
Ben Skeggs8a423642014-08-10 04:10:19 +10003647static void
Ben Skeggs0ad72862014-08-10 04:10:22 +10003648nv50_fbdma_fini(struct nv50_fbdma *fbdma)
Ben Skeggs8a423642014-08-10 04:10:19 +10003649{
Ben Skeggs0ad72862014-08-10 04:10:22 +10003650 int i;
3651 for (i = 0; i < ARRAY_SIZE(fbdma->base); i++)
3652 nvif_object_fini(&fbdma->base[i]);
3653 nvif_object_fini(&fbdma->core);
Ben Skeggs8a423642014-08-10 04:10:19 +10003654 list_del(&fbdma->head);
3655 kfree(fbdma);
3656}
3657
3658static int
3659nv50_fbdma_init(struct drm_device *dev, u32 name, u64 offset, u64 length, u8 kind)
3660{
3661 struct nouveau_drm *drm = nouveau_drm(dev);
3662 struct nv50_disp *disp = nv50_disp(dev);
3663 struct nv50_mast *mast = nv50_mast(dev);
Ben Skeggs4acfd702014-08-10 04:10:24 +10003664 struct __attribute__ ((packed)) {
3665 struct nv_dma_v0 base;
3666 union {
3667 struct nv50_dma_v0 nv50;
3668 struct gf100_dma_v0 gf100;
Ben Skeggsbd70563f2015-08-20 14:54:21 +10003669 struct gf119_dma_v0 gf119;
Ben Skeggs4acfd702014-08-10 04:10:24 +10003670 };
3671 } args = {};
Ben Skeggs8a423642014-08-10 04:10:19 +10003672 struct nv50_fbdma *fbdma;
3673 struct drm_crtc *crtc;
Ben Skeggs4acfd702014-08-10 04:10:24 +10003674 u32 size = sizeof(args.base);
Ben Skeggs8a423642014-08-10 04:10:19 +10003675 int ret;
3676
3677 list_for_each_entry(fbdma, &disp->fbdma, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10003678 if (fbdma->core.handle == name)
Ben Skeggs8a423642014-08-10 04:10:19 +10003679 return 0;
3680 }
3681
3682 fbdma = kzalloc(sizeof(*fbdma), GFP_KERNEL);
3683 if (!fbdma)
3684 return -ENOMEM;
3685 list_add(&fbdma->head, &disp->fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10003686
Ben Skeggs4acfd702014-08-10 04:10:24 +10003687 args.base.target = NV_DMA_V0_TARGET_VRAM;
3688 args.base.access = NV_DMA_V0_ACCESS_RDWR;
3689 args.base.start = offset;
3690 args.base.limit = offset + length - 1;
Ben Skeggs8a423642014-08-10 04:10:19 +10003691
Ben Skeggs967e7bd2014-08-10 04:10:22 +10003692 if (drm->device.info.chipset < 0x80) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10003693 args.nv50.part = NV50_DMA_V0_PART_256;
3694 size += sizeof(args.nv50);
Ben Skeggs8a423642014-08-10 04:10:19 +10003695 } else
Ben Skeggs967e7bd2014-08-10 04:10:22 +10003696 if (drm->device.info.chipset < 0xc0) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10003697 args.nv50.part = NV50_DMA_V0_PART_256;
3698 args.nv50.kind = kind;
3699 size += sizeof(args.nv50);
Ben Skeggs8a423642014-08-10 04:10:19 +10003700 } else
Ben Skeggs967e7bd2014-08-10 04:10:22 +10003701 if (drm->device.info.chipset < 0xd0) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10003702 args.gf100.kind = kind;
3703 size += sizeof(args.gf100);
Ben Skeggs8a423642014-08-10 04:10:19 +10003704 } else {
Ben Skeggsbd70563f2015-08-20 14:54:21 +10003705 args.gf119.page = GF119_DMA_V0_PAGE_LP;
3706 args.gf119.kind = kind;
3707 size += sizeof(args.gf119);
Ben Skeggs8a423642014-08-10 04:10:19 +10003708 }
3709
3710 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10003711 struct nv50_head *head = nv50_head(crtc);
Ben Skeggs973f10c2016-11-04 17:20:36 +10003712 int ret = nvif_object_init(&head->_base->chan.base.base.user, name,
Ben Skeggsa01ca782015-08-20 14:54:15 +10003713 NV_DMA_IN_MEMORY, &args, size,
Ben Skeggs0ad72862014-08-10 04:10:22 +10003714 &fbdma->base[head->base.index]);
Ben Skeggs8a423642014-08-10 04:10:19 +10003715 if (ret) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10003716 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10003717 return ret;
3718 }
3719 }
3720
Ben Skeggsa01ca782015-08-20 14:54:15 +10003721 ret = nvif_object_init(&mast->base.base.user, name, NV_DMA_IN_MEMORY,
3722 &args, size, &fbdma->core);
Ben Skeggs8a423642014-08-10 04:10:19 +10003723 if (ret) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10003724 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10003725 return ret;
3726 }
3727
3728 return 0;
3729}
3730
Ben Skeggsab0af552014-08-10 04:10:19 +10003731static void
3732nv50_fb_dtor(struct drm_framebuffer *fb)
3733{
3734}
3735
3736static int
3737nv50_fb_ctor(struct drm_framebuffer *fb)
3738{
3739 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
3740 struct nouveau_drm *drm = nouveau_drm(fb->dev);
3741 struct nouveau_bo *nvbo = nv_fb->nvbo;
Ben Skeggs8a423642014-08-10 04:10:19 +10003742 struct nv50_disp *disp = nv50_disp(fb->dev);
Ben Skeggs8a423642014-08-10 04:10:19 +10003743 u8 kind = nouveau_bo_tile_layout(nvbo) >> 8;
3744 u8 tile = nvbo->tile_mode;
Ben Skeggsab0af552014-08-10 04:10:19 +10003745
Ben Skeggs967e7bd2014-08-10 04:10:22 +10003746 if (drm->device.info.chipset >= 0xc0)
Ben Skeggs8a423642014-08-10 04:10:19 +10003747 tile >>= 4; /* yep.. */
3748
Ben Skeggsab0af552014-08-10 04:10:19 +10003749 switch (fb->depth) {
3750 case 8: nv_fb->r_format = 0x1e00; break;
3751 case 15: nv_fb->r_format = 0xe900; break;
3752 case 16: nv_fb->r_format = 0xe800; break;
3753 case 24:
3754 case 32: nv_fb->r_format = 0xcf00; break;
3755 case 30: nv_fb->r_format = 0xd100; break;
3756 default:
3757 NV_ERROR(drm, "unknown depth %d\n", fb->depth);
3758 return -EINVAL;
3759 }
3760
Ben Skeggs648d4df2014-08-10 04:10:27 +10003761 if (disp->disp->oclass < G82_DISP) {
Ben Skeggs8a423642014-08-10 04:10:19 +10003762 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
3763 (fb->pitches[0] | 0x00100000);
3764 nv_fb->r_format |= kind << 16;
3765 } else
Ben Skeggs648d4df2014-08-10 04:10:27 +10003766 if (disp->disp->oclass < GF110_DISP) {
Ben Skeggs8a423642014-08-10 04:10:19 +10003767 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
3768 (fb->pitches[0] | 0x00100000);
Ben Skeggsab0af552014-08-10 04:10:19 +10003769 } else {
Ben Skeggs8a423642014-08-10 04:10:19 +10003770 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
3771 (fb->pitches[0] | 0x01000000);
Ben Skeggsab0af552014-08-10 04:10:19 +10003772 }
Ben Skeggs8a423642014-08-10 04:10:19 +10003773 nv_fb->r_handle = 0xffff0000 | kind;
Ben Skeggsab0af552014-08-10 04:10:19 +10003774
Ben Skeggsf392ec42014-08-10 04:10:28 +10003775 return nv50_fbdma_init(fb->dev, nv_fb->r_handle, 0,
3776 drm->device.info.ram_user, kind);
Ben Skeggsab0af552014-08-10 04:10:19 +10003777}
3778
3779/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10003780 * Init
3781 *****************************************************************************/
Ben Skeggsab0af552014-08-10 04:10:19 +10003782
Ben Skeggs2a44e492011-11-09 11:36:33 +10003783void
Ben Skeggse225f442012-11-21 14:40:21 +10003784nv50_display_fini(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10003785{
Ben Skeggs973f10c2016-11-04 17:20:36 +10003786 struct drm_plane *plane;
3787
3788 drm_for_each_plane(plane, dev) {
3789 struct nv50_wndw *wndw = nv50_wndw(plane);
3790 if (plane->funcs != &nv50_wndw)
3791 continue;
3792 nv50_wndw_fini(wndw);
3793 }
Ben Skeggs26f6d882011-07-04 16:25:18 +10003794}
3795
3796int
Ben Skeggse225f442012-11-21 14:40:21 +10003797nv50_display_init(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10003798{
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10003799 struct nv50_disp *disp = nv50_disp(dev);
Ben Skeggs973f10c2016-11-04 17:20:36 +10003800 struct drm_plane *plane;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10003801 struct drm_crtc *crtc;
3802 u32 *push;
3803
3804 push = evo_wait(nv50_mast(dev), 32);
3805 if (!push)
3806 return -EBUSY;
3807
3808 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
Ben Skeggs973f10c2016-11-04 17:20:36 +10003809 struct nv50_wndw *wndw = &nv50_head(crtc)->_base->wndw;
Maarten Lankhorst4dc63932015-01-13 09:18:49 +01003810
3811 nv50_crtc_lut_load(crtc);
Ben Skeggs973f10c2016-11-04 17:20:36 +10003812 nouveau_bo_wr32(disp->sync, wndw->sema / 4, wndw->data);
Ben Skeggs26f6d882011-07-04 16:25:18 +10003813 }
3814
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10003815 evo_mthd(push, 0x0088, 1);
Ben Skeggsf45f55c2014-08-10 04:10:23 +10003816 evo_data(push, nv50_mast(dev)->base.sync.handle);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10003817 evo_kick(push, nv50_mast(dev));
Ben Skeggs973f10c2016-11-04 17:20:36 +10003818
3819 drm_for_each_plane(plane, dev) {
3820 struct nv50_wndw *wndw = nv50_wndw(plane);
3821 if (plane->funcs != &nv50_wndw)
3822 continue;
3823 nv50_wndw_init(wndw);
3824 }
3825
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10003826 return 0;
Ben Skeggs26f6d882011-07-04 16:25:18 +10003827}
3828
3829void
Ben Skeggse225f442012-11-21 14:40:21 +10003830nv50_display_destroy(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10003831{
Ben Skeggse225f442012-11-21 14:40:21 +10003832 struct nv50_disp *disp = nv50_disp(dev);
Ben Skeggs8a423642014-08-10 04:10:19 +10003833 struct nv50_fbdma *fbdma, *fbtmp;
3834
3835 list_for_each_entry_safe(fbdma, fbtmp, &disp->fbdma, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10003836 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10003837 }
Ben Skeggs26f6d882011-07-04 16:25:18 +10003838
Ben Skeggs0ad72862014-08-10 04:10:22 +10003839 nv50_dmac_destroy(&disp->mast.base, disp->disp);
Ben Skeggsbdb8c212011-11-12 01:30:24 +10003840
Ben Skeggs816af2f2011-11-16 15:48:48 +10003841 nouveau_bo_unmap(disp->sync);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01003842 if (disp->sync)
3843 nouveau_bo_unpin(disp->sync);
Ben Skeggs816af2f2011-11-16 15:48:48 +10003844 nouveau_bo_ref(NULL, &disp->sync);
Ben Skeggs51beb422011-07-05 10:33:08 +10003845
Ben Skeggs77145f12012-07-31 16:16:21 +10003846 nouveau_display(dev)->priv = NULL;
Ben Skeggs26f6d882011-07-04 16:25:18 +10003847 kfree(disp);
3848}
3849
3850int
Ben Skeggse225f442012-11-21 14:40:21 +10003851nv50_display_create(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10003852{
Ben Skeggs967e7bd2014-08-10 04:10:22 +10003853 struct nvif_device *device = &nouveau_drm(dev)->device;
Ben Skeggs77145f12012-07-31 16:16:21 +10003854 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs77145f12012-07-31 16:16:21 +10003855 struct dcb_table *dcb = &drm->vbios.dcb;
Ben Skeggs83fc0832011-07-05 13:08:40 +10003856 struct drm_connector *connector, *tmp;
Ben Skeggse225f442012-11-21 14:40:21 +10003857 struct nv50_disp *disp;
Ben Skeggscb75d972012-07-11 10:44:20 +10003858 struct dcb_output *dcbe;
Ben Skeggs7c5f6a82012-03-04 16:25:59 +10003859 int crtcs, ret, i;
Ben Skeggs26f6d882011-07-04 16:25:18 +10003860
3861 disp = kzalloc(sizeof(*disp), GFP_KERNEL);
3862 if (!disp)
3863 return -ENOMEM;
Ben Skeggs8a423642014-08-10 04:10:19 +10003864 INIT_LIST_HEAD(&disp->fbdma);
Ben Skeggs77145f12012-07-31 16:16:21 +10003865
3866 nouveau_display(dev)->priv = disp;
Ben Skeggse225f442012-11-21 14:40:21 +10003867 nouveau_display(dev)->dtor = nv50_display_destroy;
3868 nouveau_display(dev)->init = nv50_display_init;
3869 nouveau_display(dev)->fini = nv50_display_fini;
Ben Skeggsab0af552014-08-10 04:10:19 +10003870 nouveau_display(dev)->fb_ctor = nv50_fb_ctor;
3871 nouveau_display(dev)->fb_dtor = nv50_fb_dtor;
Ben Skeggs0ad72862014-08-10 04:10:22 +10003872 disp->disp = &nouveau_display(dev)->disp;
Ben Skeggs26f6d882011-07-04 16:25:18 +10003873
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003874 /* small shared memory area we use for notifiers and semaphores */
3875 ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
Maarten Lankhorstbb6178b2014-01-09 11:03:15 +01003876 0, 0x0000, NULL, NULL, &disp->sync);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003877 if (!ret) {
Ben Skeggs547ad072014-11-10 12:35:06 +10003878 ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM, true);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01003879 if (!ret) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003880 ret = nouveau_bo_map(disp->sync);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01003881 if (ret)
3882 nouveau_bo_unpin(disp->sync);
3883 }
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003884 if (ret)
3885 nouveau_bo_ref(NULL, &disp->sync);
3886 }
3887
3888 if (ret)
3889 goto out;
3890
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003891 /* allocate master evo channel */
Ben Skeggsa01ca782015-08-20 14:54:15 +10003892 ret = nv50_core_create(device, disp->disp, disp->sync->bo.offset,
Ben Skeggs410f3ec2014-08-10 04:10:25 +10003893 &disp->mast);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10003894 if (ret)
3895 goto out;
3896
Ben Skeggs438d99e2011-07-05 16:48:06 +10003897 /* create crtc objects to represent the hw heads */
Ben Skeggs648d4df2014-08-10 04:10:27 +10003898 if (disp->disp->oclass >= GF110_DISP)
Ben Skeggsa01ca782015-08-20 14:54:15 +10003899 crtcs = nvif_rd32(&device->object, 0x022448);
Ben Skeggs63718a02012-11-16 11:44:14 +10003900 else
3901 crtcs = 2;
3902
Ben Skeggs7c5f6a82012-03-04 16:25:59 +10003903 for (i = 0; i < crtcs; i++) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10003904 ret = nv50_crtc_create(dev, i);
Ben Skeggs438d99e2011-07-05 16:48:06 +10003905 if (ret)
3906 goto out;
3907 }
3908
Ben Skeggs83fc0832011-07-05 13:08:40 +10003909 /* create encoder/connector objects based on VBIOS DCB table */
3910 for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
3911 connector = nouveau_connector_create(dev, dcbe->connector);
3912 if (IS_ERR(connector))
3913 continue;
3914
Ben Skeggseb6313a2013-02-11 09:52:58 +10003915 if (dcbe->location == DCB_LOC_ON_CHIP) {
3916 switch (dcbe->type) {
3917 case DCB_OUTPUT_TMDS:
3918 case DCB_OUTPUT_LVDS:
3919 case DCB_OUTPUT_DP:
3920 ret = nv50_sor_create(connector, dcbe);
3921 break;
3922 case DCB_OUTPUT_ANALOG:
3923 ret = nv50_dac_create(connector, dcbe);
3924 break;
3925 default:
3926 ret = -ENODEV;
3927 break;
3928 }
3929 } else {
3930 ret = nv50_pior_create(connector, dcbe);
Ben Skeggs83fc0832011-07-05 13:08:40 +10003931 }
3932
Ben Skeggseb6313a2013-02-11 09:52:58 +10003933 if (ret) {
3934 NV_WARN(drm, "failed to create encoder %d/%d/%d: %d\n",
3935 dcbe->location, dcbe->type,
3936 ffs(dcbe->or) - 1, ret);
Ben Skeggs94f54f52013-03-05 22:26:06 +10003937 ret = 0;
Ben Skeggs83fc0832011-07-05 13:08:40 +10003938 }
3939 }
3940
3941 /* cull any connectors we created that don't have an encoder */
3942 list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) {
3943 if (connector->encoder_ids[0])
3944 continue;
3945
Ben Skeggs77145f12012-07-31 16:16:21 +10003946 NV_WARN(drm, "%s has no encoders, removing\n",
Jani Nikula8c6c3612014-06-03 14:56:18 +03003947 connector->name);
Ben Skeggs83fc0832011-07-05 13:08:40 +10003948 connector->funcs->destroy(connector);
3949 }
3950
Ben Skeggs26f6d882011-07-04 16:25:18 +10003951out:
3952 if (ret)
Ben Skeggse225f442012-11-21 14:40:21 +10003953 nv50_display_destroy(dev);
Ben Skeggs26f6d882011-07-04 16:25:18 +10003954 return ret;
3955}