blob: 27d5418ea16810b920681ff30af189d14bc736ea [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>
28#include <drm/drm_crtc_helper.h>
Daniel Vetter3cb9ae42014-10-29 10:03:57 +010029#include <drm/drm_plane_helper.h>
Ben Skeggs48743222014-05-31 01:48:06 +100030#include <drm/drm_dp_helper.h>
Ben Skeggs26f6d882011-07-04 16:25:18 +100031
Ben Skeggsfdb751e2014-08-10 04:10:23 +100032#include <nvif/class.h>
33
Ben Skeggs77145f12012-07-31 16:16:21 +100034#include "nouveau_drm.h"
35#include "nouveau_dma.h"
36#include "nouveau_gem.h"
Ben Skeggs26f6d882011-07-04 16:25:18 +100037#include "nouveau_connector.h"
38#include "nouveau_encoder.h"
39#include "nouveau_crtc.h"
Ben Skeggsf589be82012-07-22 11:55:54 +100040#include "nouveau_fence.h"
Ben Skeggs3a89cd02011-07-07 10:47:10 +100041#include "nv50_display.h"
Ben Skeggs26f6d882011-07-04 16:25:18 +100042
Ben Skeggs8a464382011-11-12 23:52:07 +100043#define EVO_DMA_NR 9
44
Ben Skeggsbdb8c212011-11-12 01:30:24 +100045#define EVO_MASTER (0x00)
Ben Skeggsa63a97e2011-11-16 15:22:34 +100046#define EVO_FLIP(c) (0x01 + (c))
Ben Skeggs8a464382011-11-12 23:52:07 +100047#define EVO_OVLY(c) (0x05 + (c))
48#define EVO_OIMM(c) (0x09 + (c))
Ben Skeggsbdb8c212011-11-12 01:30:24 +100049#define EVO_CURS(c) (0x0d + (c))
50
Ben Skeggs816af2f2011-11-16 15:48:48 +100051/* offsets in shared sync bo of various structures */
52#define EVO_SYNC(c, o) ((c) * 0x0100 + (o))
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +100053#define EVO_MAST_NTFY EVO_SYNC( 0, 0x00)
54#define EVO_FLIP_SEM0(c) EVO_SYNC((c) + 1, 0x00)
55#define EVO_FLIP_SEM1(c) EVO_SYNC((c) + 1, 0x10)
Ben Skeggs816af2f2011-11-16 15:48:48 +100056
Ben Skeggsb5a794b2012-10-16 14:18:32 +100057/******************************************************************************
58 * EVO channel
59 *****************************************************************************/
60
Ben Skeggse225f442012-11-21 14:40:21 +100061struct nv50_chan {
Ben Skeggs0ad72862014-08-10 04:10:22 +100062 struct nvif_object user;
Ben Skeggsb5a794b2012-10-16 14:18:32 +100063};
64
65static int
Ben Skeggs410f3ec2014-08-10 04:10:25 +100066nv50_chan_create(struct nvif_object *disp, const u32 *oclass, u8 head,
Ben Skeggse225f442012-11-21 14:40:21 +100067 void *data, u32 size, struct nv50_chan *chan)
Ben Skeggsb5a794b2012-10-16 14:18:32 +100068{
Ben Skeggs410f3ec2014-08-10 04:10:25 +100069 while (oclass[0]) {
70 int ret = nvif_object_init(disp, NULL, (oclass[0] << 16) | head,
71 oclass[0], data, size,
72 &chan->user);
Ben Skeggsb76f1522014-08-10 04:10:28 +100073 if (oclass++, ret == 0) {
74 nvif_object_map(&chan->user);
Ben Skeggs410f3ec2014-08-10 04:10:25 +100075 return ret;
Ben Skeggsb76f1522014-08-10 04:10:28 +100076 }
Ben Skeggs410f3ec2014-08-10 04:10:25 +100077 }
78 return -ENOSYS;
Ben Skeggsb5a794b2012-10-16 14:18:32 +100079}
80
81static void
Ben Skeggs0ad72862014-08-10 04:10:22 +100082nv50_chan_destroy(struct nv50_chan *chan)
Ben Skeggsb5a794b2012-10-16 14:18:32 +100083{
Ben Skeggs0ad72862014-08-10 04:10:22 +100084 nvif_object_fini(&chan->user);
Ben Skeggsb5a794b2012-10-16 14:18:32 +100085}
86
87/******************************************************************************
88 * PIO EVO channel
89 *****************************************************************************/
90
Ben Skeggse225f442012-11-21 14:40:21 +100091struct nv50_pioc {
92 struct nv50_chan base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +100093};
94
95static void
Ben Skeggs0ad72862014-08-10 04:10:22 +100096nv50_pioc_destroy(struct nv50_pioc *pioc)
Ben Skeggsb5a794b2012-10-16 14:18:32 +100097{
Ben Skeggs0ad72862014-08-10 04:10:22 +100098 nv50_chan_destroy(&pioc->base);
Ben Skeggsb5a794b2012-10-16 14:18:32 +100099}
100
101static int
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000102nv50_pioc_create(struct nvif_object *disp, const u32 *oclass, u8 head,
Ben Skeggse225f442012-11-21 14:40:21 +1000103 void *data, u32 size, struct nv50_pioc *pioc)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000104{
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000105 return nv50_chan_create(disp, oclass, head, data, size, &pioc->base);
106}
107
108/******************************************************************************
109 * Cursor Immediate
110 *****************************************************************************/
111
112struct nv50_curs {
113 struct nv50_pioc base;
114};
115
116static int
117nv50_curs_create(struct nvif_object *disp, int head, struct nv50_curs *curs)
118{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000119 struct nv50_disp_cursor_v0 args = {
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000120 .head = head,
121 };
122 static const u32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000123 GK104_DISP_CURSOR,
124 GF110_DISP_CURSOR,
125 GT214_DISP_CURSOR,
126 G82_DISP_CURSOR,
127 NV50_DISP_CURSOR,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000128 0
129 };
130
131 return nv50_pioc_create(disp, oclass, head, &args, sizeof(args),
132 &curs->base);
133}
134
135/******************************************************************************
136 * Overlay Immediate
137 *****************************************************************************/
138
139struct nv50_oimm {
140 struct nv50_pioc base;
141};
142
143static int
144nv50_oimm_create(struct nvif_object *disp, int head, struct nv50_oimm *oimm)
145{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000146 struct nv50_disp_cursor_v0 args = {
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000147 .head = head,
148 };
149 static const u32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000150 GK104_DISP_OVERLAY,
151 GF110_DISP_OVERLAY,
152 GT214_DISP_OVERLAY,
153 G82_DISP_OVERLAY,
154 NV50_DISP_OVERLAY,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000155 0
156 };
157
158 return nv50_pioc_create(disp, oclass, head, &args, sizeof(args),
159 &oimm->base);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000160}
161
162/******************************************************************************
163 * DMA EVO channel
164 *****************************************************************************/
165
Ben Skeggse225f442012-11-21 14:40:21 +1000166struct nv50_dmac {
167 struct nv50_chan base;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000168 dma_addr_t handle;
169 u32 *ptr;
Daniel Vetter59ad1462012-12-02 14:49:44 +0100170
Ben Skeggs0ad72862014-08-10 04:10:22 +1000171 struct nvif_object sync;
172 struct nvif_object vram;
173
Daniel Vetter59ad1462012-12-02 14:49:44 +0100174 /* Protects against concurrent pushbuf access to this channel, lock is
175 * grabbed by evo_wait (if the pushbuf reservation is successful) and
176 * dropped again by evo_kick. */
177 struct mutex lock;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000178};
179
180static void
Ben Skeggs0ad72862014-08-10 04:10:22 +1000181nv50_dmac_destroy(struct nv50_dmac *dmac, struct nvif_object *disp)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000182{
Ben Skeggs0ad72862014-08-10 04:10:22 +1000183 nvif_object_fini(&dmac->vram);
184 nvif_object_fini(&dmac->sync);
185
186 nv50_chan_destroy(&dmac->base);
187
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000188 if (dmac->ptr) {
Ben Skeggs0ad72862014-08-10 04:10:22 +1000189 struct pci_dev *pdev = nvkm_device(nvif_device(disp))->pdev;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000190 pci_free_consistent(pdev, PAGE_SIZE, dmac->ptr, dmac->handle);
191 }
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000192}
193
194static int
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000195nv50_dmac_create(struct nvif_object *disp, const u32 *oclass, u8 head,
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000196 void *data, u32 size, u64 syncbuf,
Ben Skeggse225f442012-11-21 14:40:21 +1000197 struct nv50_dmac *dmac)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000198{
Ben Skeggsf392ec42014-08-10 04:10:28 +1000199 struct nvif_device *device = nvif_device(disp);
Ben Skeggs648d4df2014-08-10 04:10:27 +1000200 struct nv50_disp_core_channel_dma_v0 *args = data;
Ben Skeggs0ad72862014-08-10 04:10:22 +1000201 struct nvif_object pushbuf;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000202 int ret;
203
Daniel Vetter59ad1462012-12-02 14:49:44 +0100204 mutex_init(&dmac->lock);
205
Ben Skeggsf392ec42014-08-10 04:10:28 +1000206 dmac->ptr = pci_alloc_consistent(nvkm_device(device)->pdev,
Ben Skeggs0ad72862014-08-10 04:10:22 +1000207 PAGE_SIZE, &dmac->handle);
Ben Skeggs47057302012-11-16 13:58:48 +1000208 if (!dmac->ptr)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000209 return -ENOMEM;
210
Ben Skeggsf392ec42014-08-10 04:10:28 +1000211 ret = nvif_object_init(nvif_object(device), NULL,
Ben Skeggs648d4df2014-08-10 04:10:27 +1000212 args->pushbuf, NV_DMA_FROM_MEMORY,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000213 &(struct nv_dma_v0) {
214 .target = NV_DMA_V0_TARGET_PCI_US,
215 .access = NV_DMA_V0_ACCESS_RD,
Ben Skeggs47057302012-11-16 13:58:48 +1000216 .start = dmac->handle + 0x0000,
217 .limit = dmac->handle + 0x0fff,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000218 }, sizeof(struct nv_dma_v0), &pushbuf);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000219 if (ret)
220 return ret;
221
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000222 ret = nv50_chan_create(disp, oclass, head, data, size, &dmac->base);
Ben Skeggs0ad72862014-08-10 04:10:22 +1000223 nvif_object_fini(&pushbuf);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000224 if (ret)
225 return ret;
226
Ben Skeggsf45f55c2014-08-10 04:10:23 +1000227 ret = nvif_object_init(&dmac->base.user, NULL, 0xf0000000,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000228 NV_DMA_IN_MEMORY,
229 &(struct nv_dma_v0) {
230 .target = NV_DMA_V0_TARGET_VRAM,
231 .access = NV_DMA_V0_ACCESS_RDWR,
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000232 .start = syncbuf + 0x0000,
233 .limit = syncbuf + 0x0fff,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000234 }, sizeof(struct nv_dma_v0),
Ben Skeggs0ad72862014-08-10 04:10:22 +1000235 &dmac->sync);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000236 if (ret)
Ben Skeggs47057302012-11-16 13:58:48 +1000237 return ret;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000238
Ben Skeggsf45f55c2014-08-10 04:10:23 +1000239 ret = nvif_object_init(&dmac->base.user, NULL, 0xf0000001,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000240 NV_DMA_IN_MEMORY,
241 &(struct nv_dma_v0) {
242 .target = NV_DMA_V0_TARGET_VRAM,
243 .access = NV_DMA_V0_ACCESS_RDWR,
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000244 .start = 0,
Ben Skeggsf392ec42014-08-10 04:10:28 +1000245 .limit = device->info.ram_user - 1,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000246 }, sizeof(struct nv_dma_v0),
Ben Skeggs0ad72862014-08-10 04:10:22 +1000247 &dmac->vram);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000248 if (ret)
Ben Skeggs47057302012-11-16 13:58:48 +1000249 return ret;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000250
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000251 return ret;
252}
253
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000254/******************************************************************************
255 * Core
256 *****************************************************************************/
257
Ben Skeggse225f442012-11-21 14:40:21 +1000258struct nv50_mast {
259 struct nv50_dmac base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000260};
261
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000262static int
263nv50_core_create(struct nvif_object *disp, u64 syncbuf, struct nv50_mast *core)
264{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000265 struct nv50_disp_core_channel_dma_v0 args = {
266 .pushbuf = 0xb0007d00,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000267 };
268 static const u32 oclass[] = {
Ben Skeggsdbbd6bc2014-08-19 10:23:47 +1000269 GM204_DISP_CORE_CHANNEL_DMA,
Ben Skeggs648d4df2014-08-10 04:10:27 +1000270 GM107_DISP_CORE_CHANNEL_DMA,
271 GK110_DISP_CORE_CHANNEL_DMA,
272 GK104_DISP_CORE_CHANNEL_DMA,
273 GF110_DISP_CORE_CHANNEL_DMA,
274 GT214_DISP_CORE_CHANNEL_DMA,
275 GT206_DISP_CORE_CHANNEL_DMA,
276 GT200_DISP_CORE_CHANNEL_DMA,
277 G82_DISP_CORE_CHANNEL_DMA,
278 NV50_DISP_CORE_CHANNEL_DMA,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000279 0
280 };
281
282 return nv50_dmac_create(disp, oclass, 0, &args, sizeof(args), syncbuf,
283 &core->base);
284}
285
286/******************************************************************************
287 * Base
288 *****************************************************************************/
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000289
Ben Skeggse225f442012-11-21 14:40:21 +1000290struct nv50_sync {
291 struct nv50_dmac base;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000292 u32 addr;
293 u32 data;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000294};
295
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000296static int
297nv50_base_create(struct nvif_object *disp, int head, u64 syncbuf,
298 struct nv50_sync *base)
299{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000300 struct nv50_disp_base_channel_dma_v0 args = {
301 .pushbuf = 0xb0007c00 | head,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000302 .head = head,
303 };
304 static const u32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000305 GK110_DISP_BASE_CHANNEL_DMA,
306 GK104_DISP_BASE_CHANNEL_DMA,
307 GF110_DISP_BASE_CHANNEL_DMA,
308 GT214_DISP_BASE_CHANNEL_DMA,
309 GT200_DISP_BASE_CHANNEL_DMA,
310 G82_DISP_BASE_CHANNEL_DMA,
311 NV50_DISP_BASE_CHANNEL_DMA,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000312 0
313 };
314
315 return nv50_dmac_create(disp, oclass, head, &args, sizeof(args),
316 syncbuf, &base->base);
317}
318
319/******************************************************************************
320 * Overlay
321 *****************************************************************************/
322
Ben Skeggse225f442012-11-21 14:40:21 +1000323struct nv50_ovly {
324 struct nv50_dmac base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000325};
Ben Skeggsf20ce962011-07-08 13:17:01 +1000326
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000327static int
328nv50_ovly_create(struct nvif_object *disp, int head, u64 syncbuf,
329 struct nv50_ovly *ovly)
330{
Ben Skeggs648d4df2014-08-10 04:10:27 +1000331 struct nv50_disp_overlay_channel_dma_v0 args = {
332 .pushbuf = 0xb0007e00 | head,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000333 .head = head,
334 };
335 static const u32 oclass[] = {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000336 GK104_DISP_OVERLAY_CONTROL_DMA,
337 GF110_DISP_OVERLAY_CONTROL_DMA,
338 GT214_DISP_OVERLAY_CHANNEL_DMA,
339 GT200_DISP_OVERLAY_CHANNEL_DMA,
340 G82_DISP_OVERLAY_CHANNEL_DMA,
341 NV50_DISP_OVERLAY_CHANNEL_DMA,
Ben Skeggs410f3ec2014-08-10 04:10:25 +1000342 0
343 };
344
345 return nv50_dmac_create(disp, oclass, head, &args, sizeof(args),
346 syncbuf, &ovly->base);
347}
Ben Skeggs26f6d882011-07-04 16:25:18 +1000348
Ben Skeggse225f442012-11-21 14:40:21 +1000349struct nv50_head {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +1000350 struct nouveau_crtc base;
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000351 struct nouveau_bo *image;
Ben Skeggse225f442012-11-21 14:40:21 +1000352 struct nv50_curs curs;
353 struct nv50_sync sync;
354 struct nv50_ovly ovly;
355 struct nv50_oimm oimm;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000356};
357
Ben Skeggse225f442012-11-21 14:40:21 +1000358#define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c))
359#define nv50_curs(c) (&nv50_head(c)->curs)
360#define nv50_sync(c) (&nv50_head(c)->sync)
361#define nv50_ovly(c) (&nv50_head(c)->ovly)
362#define nv50_oimm(c) (&nv50_head(c)->oimm)
363#define nv50_chan(c) (&(c)->base.base)
Ben Skeggs0ad72862014-08-10 04:10:22 +1000364#define nv50_vers(c) nv50_chan(c)->user.oclass
365
366struct nv50_fbdma {
367 struct list_head head;
368 struct nvif_object core;
369 struct nvif_object base[4];
370};
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000371
Ben Skeggse225f442012-11-21 14:40:21 +1000372struct nv50_disp {
Ben Skeggs0ad72862014-08-10 04:10:22 +1000373 struct nvif_object *disp;
Ben Skeggse225f442012-11-21 14:40:21 +1000374 struct nv50_mast mast;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000375
Ben Skeggs8a423642014-08-10 04:10:19 +1000376 struct list_head fbdma;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000377
378 struct nouveau_bo *sync;
Ben Skeggsdd0e3d52012-10-16 14:00:31 +1000379};
380
Ben Skeggse225f442012-11-21 14:40:21 +1000381static struct nv50_disp *
382nv50_disp(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +1000383{
Ben Skeggs77145f12012-07-31 16:16:21 +1000384 return nouveau_display(dev)->priv;
Ben Skeggs26f6d882011-07-04 16:25:18 +1000385}
386
Ben Skeggse225f442012-11-21 14:40:21 +1000387#define nv50_mast(d) (&nv50_disp(d)->mast)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000388
Ben Skeggsbdb8c212011-11-12 01:30:24 +1000389static struct drm_crtc *
Ben Skeggse225f442012-11-21 14:40:21 +1000390nv50_display_crtc_get(struct drm_encoder *encoder)
Ben Skeggsbdb8c212011-11-12 01:30:24 +1000391{
392 return nouveau_encoder(encoder)->crtc;
393}
394
395/******************************************************************************
396 * EVO channel helpers
397 *****************************************************************************/
Ben Skeggs51beb422011-07-05 10:33:08 +1000398static u32 *
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000399evo_wait(void *evoc, int nr)
Ben Skeggs51beb422011-07-05 10:33:08 +1000400{
Ben Skeggse225f442012-11-21 14:40:21 +1000401 struct nv50_dmac *dmac = evoc;
Ben Skeggs0ad72862014-08-10 04:10:22 +1000402 u32 put = nvif_rd32(&dmac->base.user, 0x0000) / 4;
Ben Skeggs51beb422011-07-05 10:33:08 +1000403
Daniel Vetter59ad1462012-12-02 14:49:44 +0100404 mutex_lock(&dmac->lock);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000405 if (put + nr >= (PAGE_SIZE / 4) - 8) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000406 dmac->ptr[put] = 0x20000000;
Ben Skeggs51beb422011-07-05 10:33:08 +1000407
Ben Skeggs0ad72862014-08-10 04:10:22 +1000408 nvif_wr32(&dmac->base.user, 0x0000, 0x00000000);
409 if (!nvkm_wait(&dmac->base.user, 0x0004, ~0, 0x00000000)) {
Daniel Vetter59ad1462012-12-02 14:49:44 +0100410 mutex_unlock(&dmac->lock);
Ben Skeggs0ad72862014-08-10 04:10:22 +1000411 nv_error(nvkm_object(&dmac->base.user), "channel stalled\n");
Ben Skeggs51beb422011-07-05 10:33:08 +1000412 return NULL;
413 }
414
415 put = 0;
416 }
417
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000418 return dmac->ptr + put;
Ben Skeggs51beb422011-07-05 10:33:08 +1000419}
420
421static void
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000422evo_kick(u32 *push, void *evoc)
Ben Skeggs51beb422011-07-05 10:33:08 +1000423{
Ben Skeggse225f442012-11-21 14:40:21 +1000424 struct nv50_dmac *dmac = evoc;
Ben Skeggs0ad72862014-08-10 04:10:22 +1000425 nvif_wr32(&dmac->base.user, 0x0000, (push - dmac->ptr) << 2);
Daniel Vetter59ad1462012-12-02 14:49:44 +0100426 mutex_unlock(&dmac->lock);
Ben Skeggs51beb422011-07-05 10:33:08 +1000427}
428
429#define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m))
430#define evo_data(p,d) *((p)++) = (d)
431
Ben Skeggs3376ee32011-11-12 14:28:12 +1000432static bool
433evo_sync_wait(void *data)
434{
Ben Skeggs5cc027f2013-02-18 17:50:51 -0500435 if (nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000)
436 return true;
437 usleep_range(1, 2);
438 return false;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000439}
440
441static int
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000442evo_sync(struct drm_device *dev)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000443{
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000444 struct nvif_device *device = &nouveau_drm(dev)->device;
Ben Skeggse225f442012-11-21 14:40:21 +1000445 struct nv50_disp *disp = nv50_disp(dev);
446 struct nv50_mast *mast = nv50_mast(dev);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000447 u32 *push = evo_wait(mast, 8);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000448 if (push) {
Ben Skeggs816af2f2011-11-16 15:48:48 +1000449 nouveau_bo_wr32(disp->sync, EVO_MAST_NTFY, 0x00000000);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000450 evo_mthd(push, 0x0084, 1);
Ben Skeggs816af2f2011-11-16 15:48:48 +1000451 evo_data(push, 0x80000000 | EVO_MAST_NTFY);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000452 evo_mthd(push, 0x0080, 2);
453 evo_data(push, 0x00000000);
454 evo_data(push, 0x00000000);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000455 evo_kick(push, mast);
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000456 if (nv_wait_cb(nvkm_device(device), evo_sync_wait, disp->sync))
Ben Skeggs3376ee32011-11-12 14:28:12 +1000457 return 0;
458 }
459
460 return -EBUSY;
461}
462
463/******************************************************************************
Ben Skeggsa63a97e2011-11-16 15:22:34 +1000464 * Page flipping channel
Ben Skeggs3376ee32011-11-12 14:28:12 +1000465 *****************************************************************************/
466struct nouveau_bo *
Ben Skeggse225f442012-11-21 14:40:21 +1000467nv50_display_crtc_sema(struct drm_device *dev, int crtc)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000468{
Ben Skeggse225f442012-11-21 14:40:21 +1000469 return nv50_disp(dev)->sync;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000470}
471
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000472struct nv50_display_flip {
473 struct nv50_disp *disp;
474 struct nv50_sync *chan;
475};
476
477static bool
478nv50_display_flip_wait(void *data)
479{
480 struct nv50_display_flip *flip = data;
481 if (nouveau_bo_rd32(flip->disp->sync, flip->chan->addr / 4) ==
Calvin Owensb1ea3e62013-04-07 21:01:19 -0500482 flip->chan->data)
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000483 return true;
484 usleep_range(1, 2);
485 return false;
486}
487
Ben Skeggs3376ee32011-11-12 14:28:12 +1000488void
Ben Skeggse225f442012-11-21 14:40:21 +1000489nv50_display_flip_stop(struct drm_crtc *crtc)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000490{
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000491 struct nvif_device *device = &nouveau_drm(crtc->dev)->device;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000492 struct nv50_display_flip flip = {
493 .disp = nv50_disp(crtc->dev),
494 .chan = nv50_sync(crtc),
495 };
Ben Skeggs3376ee32011-11-12 14:28:12 +1000496 u32 *push;
497
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000498 push = evo_wait(flip.chan, 8);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000499 if (push) {
500 evo_mthd(push, 0x0084, 1);
501 evo_data(push, 0x00000000);
502 evo_mthd(push, 0x0094, 1);
503 evo_data(push, 0x00000000);
504 evo_mthd(push, 0x00c0, 1);
505 evo_data(push, 0x00000000);
506 evo_mthd(push, 0x0080, 1);
507 evo_data(push, 0x00000000);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000508 evo_kick(push, flip.chan);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000509 }
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000510
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000511 nv_wait_cb(nvkm_device(device), nv50_display_flip_wait, &flip);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000512}
513
514int
Ben Skeggse225f442012-11-21 14:40:21 +1000515nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
Ben Skeggs3376ee32011-11-12 14:28:12 +1000516 struct nouveau_channel *chan, u32 swap_interval)
517{
518 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000519 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000520 struct nv50_head *head = nv50_head(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +1000521 struct nv50_sync *sync = nv50_sync(crtc);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000522 u32 *push;
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000523 int ret;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000524
525 swap_interval <<= 4;
526 if (swap_interval == 0)
527 swap_interval |= 0x100;
Ben Skeggsf60b6e72013-03-19 15:20:00 +1000528 if (chan == NULL)
529 evo_sync(crtc->dev);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000530
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000531 push = evo_wait(sync, 128);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000532 if (unlikely(push == NULL))
533 return -EBUSY;
534
Ben Skeggsbbf89062014-08-10 04:10:25 +1000535 if (chan && chan->object->oclass < G82_CHANNEL_GPFIFO) {
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000536 ret = RING_SPACE(chan, 8);
537 if (ret)
538 return ret;
Ben Skeggs67f97182013-02-26 12:02:54 +1000539
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000540 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000541 OUT_RING (chan, NvEvoSema0 + nv_crtc->index);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000542 OUT_RING (chan, sync->addr ^ 0x10);
543 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
544 OUT_RING (chan, sync->data + 1);
545 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_OFFSET, 2);
546 OUT_RING (chan, sync->addr);
547 OUT_RING (chan, sync->data);
548 } else
Ben Skeggsbbf89062014-08-10 04:10:25 +1000549 if (chan && chan->object->oclass < FERMI_CHANNEL_GPFIFO) {
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000550 u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000551 ret = RING_SPACE(chan, 12);
552 if (ret)
553 return ret;
Ben Skeggsa34caf72013-02-14 09:28:37 +1000554
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000555 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
Ben Skeggs0ad72862014-08-10 04:10:22 +1000556 OUT_RING (chan, chan->vram.handle);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000557 BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
558 OUT_RING (chan, upper_32_bits(addr ^ 0x10));
559 OUT_RING (chan, lower_32_bits(addr ^ 0x10));
560 OUT_RING (chan, sync->data + 1);
561 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG);
562 BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
563 OUT_RING (chan, upper_32_bits(addr));
564 OUT_RING (chan, lower_32_bits(addr));
565 OUT_RING (chan, sync->data);
566 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL);
567 } else
568 if (chan) {
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000569 u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000570 ret = RING_SPACE(chan, 10);
571 if (ret)
572 return ret;
Ben Skeggs67f97182013-02-26 12:02:54 +1000573
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000574 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
575 OUT_RING (chan, upper_32_bits(addr ^ 0x10));
576 OUT_RING (chan, lower_32_bits(addr ^ 0x10));
577 OUT_RING (chan, sync->data + 1);
578 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG |
579 NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD);
580 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
581 OUT_RING (chan, upper_32_bits(addr));
582 OUT_RING (chan, lower_32_bits(addr));
583 OUT_RING (chan, sync->data);
584 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL |
585 NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD);
586 }
Ben Skeggs35bcf5d2012-04-30 11:34:10 -0500587
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000588 if (chan) {
589 sync->addr ^= 0x10;
590 sync->data++;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000591 FIRE_RING (chan);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000592 }
593
594 /* queue the flip */
595 evo_mthd(push, 0x0100, 1);
596 evo_data(push, 0xfffe0000);
597 evo_mthd(push, 0x0084, 1);
598 evo_data(push, swap_interval);
599 if (!(swap_interval & 0x00000100)) {
600 evo_mthd(push, 0x00e0, 1);
601 evo_data(push, 0x40000000);
602 }
603 evo_mthd(push, 0x0088, 4);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000604 evo_data(push, sync->addr);
605 evo_data(push, sync->data++);
606 evo_data(push, sync->data);
Ben Skeggsf45f55c2014-08-10 04:10:23 +1000607 evo_data(push, sync->base.sync.handle);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000608 evo_mthd(push, 0x00a0, 2);
609 evo_data(push, 0x00000000);
610 evo_data(push, 0x00000000);
611 evo_mthd(push, 0x00c0, 1);
Ben Skeggs8a423642014-08-10 04:10:19 +1000612 evo_data(push, nv_fb->r_handle);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000613 evo_mthd(push, 0x0110, 2);
614 evo_data(push, 0x00000000);
615 evo_data(push, 0x00000000);
Ben Skeggs648d4df2014-08-10 04:10:27 +1000616 if (nv50_vers(sync) < GF110_DISP_BASE_CHANNEL_DMA) {
Ben Skeggsed5085a52012-11-16 13:16:51 +1000617 evo_mthd(push, 0x0800, 5);
618 evo_data(push, nv_fb->nvbo->bo.offset >> 8);
619 evo_data(push, 0);
620 evo_data(push, (fb->height << 16) | fb->width);
621 evo_data(push, nv_fb->r_pitch);
622 evo_data(push, nv_fb->r_format);
623 } else {
624 evo_mthd(push, 0x0400, 5);
625 evo_data(push, nv_fb->nvbo->bo.offset >> 8);
626 evo_data(push, 0);
627 evo_data(push, (fb->height << 16) | fb->width);
628 evo_data(push, nv_fb->r_pitch);
629 evo_data(push, nv_fb->r_format);
630 }
Ben Skeggs3376ee32011-11-12 14:28:12 +1000631 evo_mthd(push, 0x0080, 1);
632 evo_data(push, 0x00000000);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000633 evo_kick(push, sync);
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000634
635 nouveau_bo_ref(nv_fb->nvbo, &head->image);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000636 return 0;
637}
638
Ben Skeggs26f6d882011-07-04 16:25:18 +1000639/******************************************************************************
Ben Skeggs438d99e2011-07-05 16:48:06 +1000640 * CRTC
641 *****************************************************************************/
642static int
Ben Skeggse225f442012-11-21 14:40:21 +1000643nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000644{
Ben Skeggse225f442012-11-21 14:40:21 +1000645 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde691852011-10-17 12:23:41 +1000646 struct nouveau_connector *nv_connector;
647 struct drm_connector *connector;
648 u32 *push, mode = 0x00;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000649
Ben Skeggs488ff202011-10-17 10:38:10 +1000650 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggsde691852011-10-17 12:23:41 +1000651 connector = &nv_connector->base;
652 if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) {
Matt Roperf4510a22014-04-01 15:22:40 -0700653 if (nv_crtc->base.primary->fb->depth > connector->display_info.bpc * 3)
Ben Skeggsde691852011-10-17 12:23:41 +1000654 mode = DITHERING_MODE_DYNAMIC2X2;
655 } else {
656 mode = nv_connector->dithering_mode;
657 }
658
659 if (nv_connector->dithering_depth == DITHERING_DEPTH_AUTO) {
660 if (connector->display_info.bpc >= 8)
661 mode |= DITHERING_DEPTH_8BPC;
662 } else {
663 mode |= nv_connector->dithering_depth;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000664 }
665
Ben Skeggsde8268c2012-11-16 10:24:31 +1000666 push = evo_wait(mast, 4);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000667 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000668 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000669 evo_mthd(push, 0x08a0 + (nv_crtc->index * 0x0400), 1);
670 evo_data(push, mode);
671 } else
Ben Skeggs648d4df2014-08-10 04:10:27 +1000672 if (nv50_vers(mast) < GK104_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000673 evo_mthd(push, 0x0490 + (nv_crtc->index * 0x0300), 1);
674 evo_data(push, mode);
675 } else {
676 evo_mthd(push, 0x04a0 + (nv_crtc->index * 0x0300), 1);
677 evo_data(push, mode);
678 }
679
Ben Skeggs438d99e2011-07-05 16:48:06 +1000680 if (update) {
681 evo_mthd(push, 0x0080, 1);
682 evo_data(push, 0x00000000);
683 }
Ben Skeggsde8268c2012-11-16 10:24:31 +1000684 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000685 }
686
687 return 0;
688}
689
690static int
Ben Skeggse225f442012-11-21 14:40:21 +1000691nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000692{
Ben Skeggse225f442012-11-21 14:40:21 +1000693 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggs92854622011-11-11 23:49:06 +1000694 struct drm_display_mode *omode, *umode = &nv_crtc->base.mode;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000695 struct drm_crtc *crtc = &nv_crtc->base;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000696 struct nouveau_connector *nv_connector;
Ben Skeggs92854622011-11-11 23:49:06 +1000697 int mode = DRM_MODE_SCALE_NONE;
698 u32 oX, oY, *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000699
Ben Skeggs92854622011-11-11 23:49:06 +1000700 /* start off at the resolution we programmed the crtc for, this
701 * effectively handles NONE/FULL scaling
702 */
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000703 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggs92854622011-11-11 23:49:06 +1000704 if (nv_connector && nv_connector->native_mode)
705 mode = nv_connector->scaling_mode;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000706
Ben Skeggs92854622011-11-11 23:49:06 +1000707 if (mode != DRM_MODE_SCALE_NONE)
708 omode = nv_connector->native_mode;
709 else
710 omode = umode;
711
712 oX = omode->hdisplay;
713 oY = omode->vdisplay;
714 if (omode->flags & DRM_MODE_FLAG_DBLSCAN)
715 oY *= 2;
716
717 /* add overscan compensation if necessary, will keep the aspect
718 * ratio the same as the backend mode unless overridden by the
719 * user setting both hborder and vborder properties.
720 */
721 if (nv_connector && ( nv_connector->underscan == UNDERSCAN_ON ||
722 (nv_connector->underscan == UNDERSCAN_AUTO &&
723 nv_connector->edid &&
724 drm_detect_hdmi_monitor(nv_connector->edid)))) {
725 u32 bX = nv_connector->underscan_hborder;
726 u32 bY = nv_connector->underscan_vborder;
727 u32 aspect = (oY << 19) / oX;
728
729 if (bX) {
730 oX -= (bX * 2);
731 if (bY) oY -= (bY * 2);
732 else oY = ((oX * aspect) + (aspect / 2)) >> 19;
733 } else {
734 oX -= (oX >> 4) + 32;
735 if (bY) oY -= (bY * 2);
736 else oY = ((oX * aspect) + (aspect / 2)) >> 19;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000737 }
738 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000739
Ben Skeggs92854622011-11-11 23:49:06 +1000740 /* handle CENTER/ASPECT scaling, taking into account the areas
741 * removed already for overscan compensation
742 */
743 switch (mode) {
744 case DRM_MODE_SCALE_CENTER:
745 oX = min((u32)umode->hdisplay, oX);
746 oY = min((u32)umode->vdisplay, oY);
747 /* fall-through */
748 case DRM_MODE_SCALE_ASPECT:
749 if (oY < oX) {
750 u32 aspect = (umode->hdisplay << 19) / umode->vdisplay;
751 oX = ((oY * aspect) + (aspect / 2)) >> 19;
752 } else {
753 u32 aspect = (umode->vdisplay << 19) / umode->hdisplay;
754 oY = ((oX * aspect) + (aspect / 2)) >> 19;
755 }
756 break;
757 default:
758 break;
759 }
760
Ben Skeggsde8268c2012-11-16 10:24:31 +1000761 push = evo_wait(mast, 8);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000762 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000763 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000764 /*XXX: SCALE_CTRL_ACTIVE??? */
765 evo_mthd(push, 0x08d8 + (nv_crtc->index * 0x400), 2);
766 evo_data(push, (oY << 16) | oX);
767 evo_data(push, (oY << 16) | oX);
768 evo_mthd(push, 0x08a4 + (nv_crtc->index * 0x400), 1);
769 evo_data(push, 0x00000000);
770 evo_mthd(push, 0x08c8 + (nv_crtc->index * 0x400), 1);
771 evo_data(push, umode->vdisplay << 16 | umode->hdisplay);
772 } else {
773 evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3);
774 evo_data(push, (oY << 16) | oX);
775 evo_data(push, (oY << 16) | oX);
776 evo_data(push, (oY << 16) | oX);
777 evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1);
778 evo_data(push, 0x00000000);
779 evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1);
780 evo_data(push, umode->vdisplay << 16 | umode->hdisplay);
781 }
782
783 evo_kick(push, mast);
784
Ben Skeggs3376ee32011-11-12 14:28:12 +1000785 if (update) {
Ben Skeggse225f442012-11-21 14:40:21 +1000786 nv50_display_flip_stop(crtc);
Matt Roperf4510a22014-04-01 15:22:40 -0700787 nv50_display_flip_next(crtc, crtc->primary->fb,
788 NULL, 1);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000789 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000790 }
791
792 return 0;
793}
794
795static int
Ben Skeggse225f442012-11-21 14:40:21 +1000796nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggsf9887d02012-11-21 13:03:42 +1000797{
Ben Skeggse225f442012-11-21 14:40:21 +1000798 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsf9887d02012-11-21 13:03:42 +1000799 u32 *push, hue, vib;
800 int adj;
801
802 adj = (nv_crtc->color_vibrance > 0) ? 50 : 0;
803 vib = ((nv_crtc->color_vibrance * 2047 + adj) / 100) & 0xfff;
804 hue = ((nv_crtc->vibrant_hue * 2047) / 100) & 0xfff;
805
806 push = evo_wait(mast, 16);
807 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000808 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsf9887d02012-11-21 13:03:42 +1000809 evo_mthd(push, 0x08a8 + (nv_crtc->index * 0x400), 1);
810 evo_data(push, (hue << 20) | (vib << 8));
811 } else {
812 evo_mthd(push, 0x0498 + (nv_crtc->index * 0x300), 1);
813 evo_data(push, (hue << 20) | (vib << 8));
814 }
815
816 if (update) {
817 evo_mthd(push, 0x0080, 1);
818 evo_data(push, 0x00000000);
819 }
820 evo_kick(push, mast);
821 }
822
823 return 0;
824}
825
826static int
Ben Skeggse225f442012-11-21 14:40:21 +1000827nv50_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb,
Ben Skeggs438d99e2011-07-05 16:48:06 +1000828 int x, int y, bool update)
829{
830 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb);
Ben Skeggse225f442012-11-21 14:40:21 +1000831 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000832 u32 *push;
833
Ben Skeggsde8268c2012-11-16 10:24:31 +1000834 push = evo_wait(mast, 16);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000835 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000836 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000837 evo_mthd(push, 0x0860 + (nv_crtc->index * 0x400), 1);
838 evo_data(push, nvfb->nvbo->bo.offset >> 8);
839 evo_mthd(push, 0x0868 + (nv_crtc->index * 0x400), 3);
840 evo_data(push, (fb->height << 16) | fb->width);
841 evo_data(push, nvfb->r_pitch);
842 evo_data(push, nvfb->r_format);
843 evo_mthd(push, 0x08c0 + (nv_crtc->index * 0x400), 1);
844 evo_data(push, (y << 16) | x);
Ben Skeggs648d4df2014-08-10 04:10:27 +1000845 if (nv50_vers(mast) > NV50_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000846 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
Ben Skeggs8a423642014-08-10 04:10:19 +1000847 evo_data(push, nvfb->r_handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000848 }
849 } else {
850 evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1);
851 evo_data(push, nvfb->nvbo->bo.offset >> 8);
852 evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4);
853 evo_data(push, (fb->height << 16) | fb->width);
854 evo_data(push, nvfb->r_pitch);
855 evo_data(push, nvfb->r_format);
Ben Skeggs8a423642014-08-10 04:10:19 +1000856 evo_data(push, nvfb->r_handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000857 evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1);
858 evo_data(push, (y << 16) | x);
859 }
860
Ben Skeggsa46232e2011-07-07 15:23:48 +1000861 if (update) {
862 evo_mthd(push, 0x0080, 1);
863 evo_data(push, 0x00000000);
864 }
Ben Skeggsde8268c2012-11-16 10:24:31 +1000865 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000866 }
867
Ben Skeggs8a423642014-08-10 04:10:19 +1000868 nv_crtc->fb.handle = nvfb->r_handle;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000869 return 0;
870}
871
872static void
Ben Skeggse225f442012-11-21 14:40:21 +1000873nv50_crtc_cursor_show(struct nouveau_crtc *nv_crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000874{
Ben Skeggse225f442012-11-21 14:40:21 +1000875 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000876 u32 *push = evo_wait(mast, 16);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000877 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000878 if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000879 evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2);
880 evo_data(push, 0x85000000);
881 evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
882 } else
Ben Skeggs648d4df2014-08-10 04:10:27 +1000883 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000884 evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2);
885 evo_data(push, 0x85000000);
886 evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
887 evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1);
Ben Skeggsf45f55c2014-08-10 04:10:23 +1000888 evo_data(push, mast->base.vram.handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000889 } else {
Ben Skeggs438d99e2011-07-05 16:48:06 +1000890 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2);
891 evo_data(push, 0x85000000);
892 evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
893 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
Ben Skeggsf45f55c2014-08-10 04:10:23 +1000894 evo_data(push, mast->base.vram.handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000895 }
896 evo_kick(push, mast);
897 }
898}
899
900static void
Ben Skeggse225f442012-11-21 14:40:21 +1000901nv50_crtc_cursor_hide(struct nouveau_crtc *nv_crtc)
Ben Skeggsde8268c2012-11-16 10:24:31 +1000902{
Ben Skeggse225f442012-11-21 14:40:21 +1000903 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000904 u32 *push = evo_wait(mast, 16);
905 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000906 if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000907 evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 1);
908 evo_data(push, 0x05000000);
909 } else
Ben Skeggs648d4df2014-08-10 04:10:27 +1000910 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000911 evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 1);
912 evo_data(push, 0x05000000);
913 evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1);
914 evo_data(push, 0x00000000);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000915 } else {
916 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1);
917 evo_data(push, 0x05000000);
918 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
919 evo_data(push, 0x00000000);
920 }
Ben Skeggsde8268c2012-11-16 10:24:31 +1000921 evo_kick(push, mast);
922 }
923}
Ben Skeggs438d99e2011-07-05 16:48:06 +1000924
Ben Skeggsde8268c2012-11-16 10:24:31 +1000925static void
Ben Skeggse225f442012-11-21 14:40:21 +1000926nv50_crtc_cursor_show_hide(struct nouveau_crtc *nv_crtc, bool show, bool update)
Ben Skeggsde8268c2012-11-16 10:24:31 +1000927{
Ben Skeggse225f442012-11-21 14:40:21 +1000928 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000929
930 if (show)
Ben Skeggse225f442012-11-21 14:40:21 +1000931 nv50_crtc_cursor_show(nv_crtc);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000932 else
Ben Skeggse225f442012-11-21 14:40:21 +1000933 nv50_crtc_cursor_hide(nv_crtc);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000934
935 if (update) {
936 u32 *push = evo_wait(mast, 2);
937 if (push) {
Ben Skeggs438d99e2011-07-05 16:48:06 +1000938 evo_mthd(push, 0x0080, 1);
939 evo_data(push, 0x00000000);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000940 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000941 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000942 }
943}
944
945static void
Ben Skeggse225f442012-11-21 14:40:21 +1000946nv50_crtc_dpms(struct drm_crtc *crtc, int mode)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000947{
948}
949
950static void
Ben Skeggse225f442012-11-21 14:40:21 +1000951nv50_crtc_prepare(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000952{
953 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +1000954 struct nv50_mast *mast = nv50_mast(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000955 u32 *push;
956
Ben Skeggse225f442012-11-21 14:40:21 +1000957 nv50_display_flip_stop(crtc);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000958
Ben Skeggs56d237d2014-05-19 14:54:33 +1000959 push = evo_wait(mast, 6);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000960 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000961 if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000962 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
963 evo_data(push, 0x00000000);
964 evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 1);
965 evo_data(push, 0x40000000);
966 } else
Ben Skeggs648d4df2014-08-10 04:10:27 +1000967 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000968 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
969 evo_data(push, 0x00000000);
970 evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 1);
971 evo_data(push, 0x40000000);
972 evo_mthd(push, 0x085c + (nv_crtc->index * 0x400), 1);
973 evo_data(push, 0x00000000);
974 } else {
975 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
976 evo_data(push, 0x00000000);
977 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1);
978 evo_data(push, 0x03000000);
979 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
980 evo_data(push, 0x00000000);
981 }
982
983 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000984 }
985
Ben Skeggse225f442012-11-21 14:40:21 +1000986 nv50_crtc_cursor_show_hide(nv_crtc, false, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000987}
988
989static void
Ben Skeggse225f442012-11-21 14:40:21 +1000990nv50_crtc_commit(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000991{
992 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +1000993 struct nv50_mast *mast = nv50_mast(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000994 u32 *push;
995
Ben Skeggsde8268c2012-11-16 10:24:31 +1000996 push = evo_wait(mast, 32);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000997 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +1000998 if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000999 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
Ben Skeggs8a423642014-08-10 04:10:19 +10001000 evo_data(push, nv_crtc->fb.handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +10001001 evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 2);
1002 evo_data(push, 0xc0000000);
1003 evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
1004 } else
Ben Skeggs648d4df2014-08-10 04:10:27 +10001005 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsde8268c2012-11-16 10:24:31 +10001006 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
Ben Skeggs8a423642014-08-10 04:10:19 +10001007 evo_data(push, nv_crtc->fb.handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +10001008 evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 2);
1009 evo_data(push, 0xc0000000);
1010 evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
1011 evo_mthd(push, 0x085c + (nv_crtc->index * 0x400), 1);
Ben Skeggsf45f55c2014-08-10 04:10:23 +10001012 evo_data(push, mast->base.vram.handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +10001013 } else {
1014 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
Ben Skeggs8a423642014-08-10 04:10:19 +10001015 evo_data(push, nv_crtc->fb.handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +10001016 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4);
1017 evo_data(push, 0x83000000);
1018 evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
1019 evo_data(push, 0x00000000);
1020 evo_data(push, 0x00000000);
1021 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
Ben Skeggsf45f55c2014-08-10 04:10:23 +10001022 evo_data(push, mast->base.vram.handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +10001023 evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1);
1024 evo_data(push, 0xffffff00);
1025 }
1026
1027 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001028 }
1029
Ben Skeggse225f442012-11-21 14:40:21 +10001030 nv50_crtc_cursor_show_hide(nv_crtc, nv_crtc->cursor.visible, true);
Matt Roperf4510a22014-04-01 15:22:40 -07001031 nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001032}
1033
1034static bool
Ben Skeggse225f442012-11-21 14:40:21 +10001035nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001036 struct drm_display_mode *adjusted_mode)
1037{
Ben Skeggseb2e9682014-01-24 10:13:23 +10001038 drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001039 return true;
1040}
1041
1042static int
Ben Skeggse225f442012-11-21 14:40:21 +10001043nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001044{
Matt Roperf4510a22014-04-01 15:22:40 -07001045 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001046 struct nv50_head *head = nv50_head(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001047 int ret;
1048
1049 ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001050 if (ret == 0) {
1051 if (head->image)
1052 nouveau_bo_unpin(head->image);
1053 nouveau_bo_ref(nvfb->nvbo, &head->image);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001054 }
1055
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001056 return ret;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001057}
1058
1059static int
Ben Skeggse225f442012-11-21 14:40:21 +10001060nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001061 struct drm_display_mode *mode, int x, int y,
1062 struct drm_framebuffer *old_fb)
1063{
Ben Skeggse225f442012-11-21 14:40:21 +10001064 struct nv50_mast *mast = nv50_mast(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001065 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1066 struct nouveau_connector *nv_connector;
Ben Skeggs2d1d8982011-11-11 23:39:22 +10001067 u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1;
1068 u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
1069 u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks;
1070 u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks;
Roy Spliet1dce6262014-09-12 18:00:13 +02001071 u32 vblan2e = 0, vblan2s = 1, vblankus = 0;
Ben Skeggs3488c572012-03-12 11:42:20 +10001072 u32 *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001073 int ret;
1074
Ben Skeggs2d1d8982011-11-11 23:39:22 +10001075 hactive = mode->htotal;
1076 hsynce = mode->hsync_end - mode->hsync_start - 1;
1077 hbackp = mode->htotal - mode->hsync_end;
1078 hblanke = hsynce + hbackp;
1079 hfrontp = mode->hsync_start - mode->hdisplay;
1080 hblanks = mode->htotal - hfrontp - 1;
1081
1082 vactive = mode->vtotal * vscan / ilace;
1083 vsynce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1;
1084 vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace;
1085 vblanke = vsynce + vbackp;
1086 vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
1087 vblanks = vactive - vfrontp - 1;
Roy Spliet1dce6262014-09-12 18:00:13 +02001088 /* XXX: Safe underestimate, even "0" works */
1089 vblankus = (vactive - mode->vdisplay - 2) * hactive;
1090 vblankus *= 1000;
1091 vblankus /= mode->clock;
1092
Ben Skeggs2d1d8982011-11-11 23:39:22 +10001093 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
1094 vblan2e = vactive + vsynce + vbackp;
1095 vblan2s = vblan2e + (mode->vdisplay * vscan / ilace);
1096 vactive = (vactive * 2) + 1;
Ben Skeggs2d1d8982011-11-11 23:39:22 +10001097 }
1098
Ben Skeggse225f442012-11-21 14:40:21 +10001099 ret = nv50_crtc_swap_fbs(crtc, old_fb);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001100 if (ret)
1101 return ret;
1102
Ben Skeggsde8268c2012-11-16 10:24:31 +10001103 push = evo_wait(mast, 64);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001104 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10001105 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggsde8268c2012-11-16 10:24:31 +10001106 evo_mthd(push, 0x0804 + (nv_crtc->index * 0x400), 2);
1107 evo_data(push, 0x00800000 | mode->clock);
1108 evo_data(push, (ilace == 2) ? 2 : 0);
Roy Spliet1dce6262014-09-12 18:00:13 +02001109 evo_mthd(push, 0x0810 + (nv_crtc->index * 0x400), 8);
Ben Skeggsde8268c2012-11-16 10:24:31 +10001110 evo_data(push, 0x00000000);
1111 evo_data(push, (vactive << 16) | hactive);
1112 evo_data(push, ( vsynce << 16) | hsynce);
1113 evo_data(push, (vblanke << 16) | hblanke);
1114 evo_data(push, (vblanks << 16) | hblanks);
1115 evo_data(push, (vblan2e << 16) | vblan2s);
Roy Spliet1dce6262014-09-12 18:00:13 +02001116 evo_data(push, vblankus);
Ben Skeggsde8268c2012-11-16 10:24:31 +10001117 evo_data(push, 0x00000000);
1118 evo_mthd(push, 0x0900 + (nv_crtc->index * 0x400), 2);
1119 evo_data(push, 0x00000311);
1120 evo_data(push, 0x00000100);
1121 } else {
1122 evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 6);
1123 evo_data(push, 0x00000000);
1124 evo_data(push, (vactive << 16) | hactive);
1125 evo_data(push, ( vsynce << 16) | hsynce);
1126 evo_data(push, (vblanke << 16) | hblanke);
1127 evo_data(push, (vblanks << 16) | hblanks);
1128 evo_data(push, (vblan2e << 16) | vblan2s);
1129 evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1);
1130 evo_data(push, 0x00000000); /* ??? */
1131 evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3);
1132 evo_data(push, mode->clock * 1000);
1133 evo_data(push, 0x00200000); /* ??? */
1134 evo_data(push, mode->clock * 1000);
1135 evo_mthd(push, 0x04d0 + (nv_crtc->index * 0x300), 2);
1136 evo_data(push, 0x00000311);
1137 evo_data(push, 0x00000100);
1138 }
1139
1140 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001141 }
1142
1143 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001144 nv50_crtc_set_dither(nv_crtc, false);
1145 nv50_crtc_set_scale(nv_crtc, false);
1146 nv50_crtc_set_color_vibrance(nv_crtc, false);
Matt Roperf4510a22014-04-01 15:22:40 -07001147 nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001148 return 0;
1149}
1150
1151static int
Ben Skeggse225f442012-11-21 14:40:21 +10001152nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001153 struct drm_framebuffer *old_fb)
1154{
Ben Skeggs77145f12012-07-31 16:16:21 +10001155 struct nouveau_drm *drm = nouveau_drm(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001156 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1157 int ret;
1158
Matt Roperf4510a22014-04-01 15:22:40 -07001159 if (!crtc->primary->fb) {
Ben Skeggs77145f12012-07-31 16:16:21 +10001160 NV_DEBUG(drm, "No FB bound\n");
Ben Skeggs84e2ad82011-08-26 09:40:39 +10001161 return 0;
1162 }
1163
Ben Skeggse225f442012-11-21 14:40:21 +10001164 ret = nv50_crtc_swap_fbs(crtc, old_fb);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001165 if (ret)
1166 return ret;
1167
Ben Skeggse225f442012-11-21 14:40:21 +10001168 nv50_display_flip_stop(crtc);
Matt Roperf4510a22014-04-01 15:22:40 -07001169 nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, true);
1170 nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001171 return 0;
1172}
1173
1174static int
Ben Skeggse225f442012-11-21 14:40:21 +10001175nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001176 struct drm_framebuffer *fb, int x, int y,
1177 enum mode_set_atomic state)
1178{
1179 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001180 nv50_display_flip_stop(crtc);
1181 nv50_crtc_set_image(nv_crtc, fb, x, y, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001182 return 0;
1183}
1184
1185static void
Ben Skeggse225f442012-11-21 14:40:21 +10001186nv50_crtc_lut_load(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001187{
Ben Skeggse225f442012-11-21 14:40:21 +10001188 struct nv50_disp *disp = nv50_disp(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001189 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1190 void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
1191 int i;
1192
1193 for (i = 0; i < 256; i++) {
Ben Skeggsde8268c2012-11-16 10:24:31 +10001194 u16 r = nv_crtc->lut.r[i] >> 2;
1195 u16 g = nv_crtc->lut.g[i] >> 2;
1196 u16 b = nv_crtc->lut.b[i] >> 2;
1197
Ben Skeggs648d4df2014-08-10 04:10:27 +10001198 if (disp->disp->oclass < GF110_DISP) {
Ben Skeggsde8268c2012-11-16 10:24:31 +10001199 writew(r + 0x0000, lut + (i * 0x08) + 0);
1200 writew(g + 0x0000, lut + (i * 0x08) + 2);
1201 writew(b + 0x0000, lut + (i * 0x08) + 4);
1202 } else {
1203 writew(r + 0x6000, lut + (i * 0x20) + 0);
1204 writew(g + 0x6000, lut + (i * 0x20) + 2);
1205 writew(b + 0x6000, lut + (i * 0x20) + 4);
1206 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10001207 }
1208}
1209
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001210static void
1211nv50_crtc_disable(struct drm_crtc *crtc)
1212{
1213 struct nv50_head *head = nv50_head(crtc);
Ben Skeggsefa366f2014-06-05 12:56:35 +10001214 evo_sync(crtc->dev);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001215 if (head->image)
1216 nouveau_bo_unpin(head->image);
1217 nouveau_bo_ref(NULL, &head->image);
1218}
1219
Ben Skeggs438d99e2011-07-05 16:48:06 +10001220static int
Ben Skeggse225f442012-11-21 14:40:21 +10001221nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001222 uint32_t handle, uint32_t width, uint32_t height)
1223{
1224 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1225 struct drm_device *dev = crtc->dev;
1226 struct drm_gem_object *gem;
1227 struct nouveau_bo *nvbo;
1228 bool visible = (handle != 0);
1229 int i, ret = 0;
1230
1231 if (visible) {
1232 if (width != 64 || height != 64)
1233 return -EINVAL;
1234
1235 gem = drm_gem_object_lookup(dev, file_priv, handle);
1236 if (unlikely(!gem))
1237 return -ENOENT;
1238 nvbo = nouveau_gem_object(gem);
1239
1240 ret = nouveau_bo_map(nvbo);
1241 if (ret == 0) {
1242 for (i = 0; i < 64 * 64; i++) {
1243 u32 v = nouveau_bo_rd32(nvbo, i);
1244 nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v);
1245 }
1246 nouveau_bo_unmap(nvbo);
1247 }
1248
1249 drm_gem_object_unreference_unlocked(gem);
1250 }
1251
1252 if (visible != nv_crtc->cursor.visible) {
Ben Skeggse225f442012-11-21 14:40:21 +10001253 nv50_crtc_cursor_show_hide(nv_crtc, visible, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001254 nv_crtc->cursor.visible = visible;
1255 }
1256
1257 return ret;
1258}
1259
1260static int
Ben Skeggse225f442012-11-21 14:40:21 +10001261nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001262{
Ben Skeggse225f442012-11-21 14:40:21 +10001263 struct nv50_curs *curs = nv50_curs(crtc);
1264 struct nv50_chan *chan = nv50_chan(curs);
Ben Skeggs0ad72862014-08-10 04:10:22 +10001265 nvif_wr32(&chan->user, 0x0084, (y << 16) | (x & 0xffff));
1266 nvif_wr32(&chan->user, 0x0080, 0x00000000);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001267 return 0;
1268}
1269
1270static void
Ben Skeggse225f442012-11-21 14:40:21 +10001271nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001272 uint32_t start, uint32_t size)
1273{
1274 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Dan Carpenterbdefc8c2013-11-28 01:18:47 +03001275 u32 end = min_t(u32, start + size, 256);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001276 u32 i;
1277
1278 for (i = start; i < end; i++) {
1279 nv_crtc->lut.r[i] = r[i];
1280 nv_crtc->lut.g[i] = g[i];
1281 nv_crtc->lut.b[i] = b[i];
1282 }
1283
Ben Skeggse225f442012-11-21 14:40:21 +10001284 nv50_crtc_lut_load(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001285}
1286
1287static void
Ben Skeggse225f442012-11-21 14:40:21 +10001288nv50_crtc_destroy(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001289{
1290 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001291 struct nv50_disp *disp = nv50_disp(crtc->dev);
1292 struct nv50_head *head = nv50_head(crtc);
Ben Skeggs0ad72862014-08-10 04:10:22 +10001293 struct nv50_fbdma *fbdma;
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001294
Ben Skeggs0ad72862014-08-10 04:10:22 +10001295 list_for_each_entry(fbdma, &disp->fbdma, head) {
1296 nvif_object_fini(&fbdma->base[nv_crtc->index]);
1297 }
1298
1299 nv50_dmac_destroy(&head->ovly.base, disp->disp);
1300 nv50_pioc_destroy(&head->oimm.base);
1301 nv50_dmac_destroy(&head->sync.base, disp->disp);
1302 nv50_pioc_destroy(&head->curs.base);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001303
1304 /*XXX: this shouldn't be necessary, but the core doesn't call
1305 * disconnect() during the cleanup paths
1306 */
1307 if (head->image)
1308 nouveau_bo_unpin(head->image);
1309 nouveau_bo_ref(NULL, &head->image);
1310
Ben Skeggs438d99e2011-07-05 16:48:06 +10001311 nouveau_bo_unmap(nv_crtc->cursor.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001312 if (nv_crtc->cursor.nvbo)
1313 nouveau_bo_unpin(nv_crtc->cursor.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001314 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001315
Ben Skeggs438d99e2011-07-05 16:48:06 +10001316 nouveau_bo_unmap(nv_crtc->lut.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001317 if (nv_crtc->lut.nvbo)
1318 nouveau_bo_unpin(nv_crtc->lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001319 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001320
Ben Skeggs438d99e2011-07-05 16:48:06 +10001321 drm_crtc_cleanup(crtc);
1322 kfree(crtc);
1323}
1324
Ben Skeggse225f442012-11-21 14:40:21 +10001325static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = {
1326 .dpms = nv50_crtc_dpms,
1327 .prepare = nv50_crtc_prepare,
1328 .commit = nv50_crtc_commit,
1329 .mode_fixup = nv50_crtc_mode_fixup,
1330 .mode_set = nv50_crtc_mode_set,
1331 .mode_set_base = nv50_crtc_mode_set_base,
1332 .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
1333 .load_lut = nv50_crtc_lut_load,
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001334 .disable = nv50_crtc_disable,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001335};
1336
Ben Skeggse225f442012-11-21 14:40:21 +10001337static const struct drm_crtc_funcs nv50_crtc_func = {
1338 .cursor_set = nv50_crtc_cursor_set,
1339 .cursor_move = nv50_crtc_cursor_move,
1340 .gamma_set = nv50_crtc_gamma_set,
Dave Airlie5addcf02012-09-10 14:20:51 +10001341 .set_config = nouveau_crtc_set_config,
Ben Skeggse225f442012-11-21 14:40:21 +10001342 .destroy = nv50_crtc_destroy,
Ben Skeggs3376ee32011-11-12 14:28:12 +10001343 .page_flip = nouveau_crtc_page_flip,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001344};
1345
Ben Skeggsc20ab3e2011-08-25 14:09:43 +10001346static void
Ben Skeggse225f442012-11-21 14:40:21 +10001347nv50_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
Ben Skeggsc20ab3e2011-08-25 14:09:43 +10001348{
1349}
1350
1351static void
Ben Skeggse225f442012-11-21 14:40:21 +10001352nv50_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
Ben Skeggsc20ab3e2011-08-25 14:09:43 +10001353{
1354}
1355
Ben Skeggs438d99e2011-07-05 16:48:06 +10001356static int
Ben Skeggs0ad72862014-08-10 04:10:22 +10001357nv50_crtc_create(struct drm_device *dev, int index)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001358{
Ben Skeggse225f442012-11-21 14:40:21 +10001359 struct nv50_disp *disp = nv50_disp(dev);
1360 struct nv50_head *head;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001361 struct drm_crtc *crtc;
1362 int ret, i;
1363
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001364 head = kzalloc(sizeof(*head), GFP_KERNEL);
1365 if (!head)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001366 return -ENOMEM;
1367
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001368 head->base.index = index;
Ben Skeggse225f442012-11-21 14:40:21 +10001369 head->base.set_dither = nv50_crtc_set_dither;
1370 head->base.set_scale = nv50_crtc_set_scale;
1371 head->base.set_color_vibrance = nv50_crtc_set_color_vibrance;
Ben Skeggsf9887d02012-11-21 13:03:42 +10001372 head->base.color_vibrance = 50;
1373 head->base.vibrant_hue = 0;
Ben Skeggse225f442012-11-21 14:40:21 +10001374 head->base.cursor.set_offset = nv50_cursor_set_offset;
1375 head->base.cursor.set_pos = nv50_cursor_set_pos;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001376 for (i = 0; i < 256; i++) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001377 head->base.lut.r[i] = i << 8;
1378 head->base.lut.g[i] = i << 8;
1379 head->base.lut.b[i] = i << 8;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001380 }
1381
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001382 crtc = &head->base.base;
Ben Skeggse225f442012-11-21 14:40:21 +10001383 drm_crtc_init(dev, crtc, &nv50_crtc_func);
1384 drm_crtc_helper_add(crtc, &nv50_crtc_hfunc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001385 drm_mode_crtc_set_gamma_size(crtc, 256);
1386
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +10001387 ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
Maarten Lankhorstbb6178b2014-01-09 11:03:15 +01001388 0, 0x0000, NULL, NULL, &head->base.lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001389 if (!ret) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001390 ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001391 if (!ret) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001392 ret = nouveau_bo_map(head->base.lut.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001393 if (ret)
1394 nouveau_bo_unpin(head->base.lut.nvbo);
1395 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10001396 if (ret)
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001397 nouveau_bo_ref(NULL, &head->base.lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001398 }
1399
1400 if (ret)
1401 goto out;
1402
Ben Skeggse225f442012-11-21 14:40:21 +10001403 nv50_crtc_lut_load(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001404
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001405 /* allocate cursor resources */
Ben Skeggs410f3ec2014-08-10 04:10:25 +10001406 ret = nv50_curs_create(disp->disp, index, &head->curs);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001407 if (ret)
1408 goto out;
1409
1410 ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM,
Maarten Lankhorstbb6178b2014-01-09 11:03:15 +01001411 0, 0x0000, NULL, NULL, &head->base.cursor.nvbo);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001412 if (!ret) {
1413 ret = nouveau_bo_pin(head->base.cursor.nvbo, TTM_PL_FLAG_VRAM);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001414 if (!ret) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001415 ret = nouveau_bo_map(head->base.cursor.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001416 if (ret)
1417 nouveau_bo_unpin(head->base.lut.nvbo);
1418 }
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001419 if (ret)
1420 nouveau_bo_ref(NULL, &head->base.cursor.nvbo);
1421 }
1422
1423 if (ret)
1424 goto out;
1425
1426 /* allocate page flip / sync resources */
Ben Skeggs410f3ec2014-08-10 04:10:25 +10001427 ret = nv50_base_create(disp->disp, index, disp->sync->bo.offset,
1428 &head->sync);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001429 if (ret)
1430 goto out;
1431
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001432 head->sync.addr = EVO_FLIP_SEM0(index);
1433 head->sync.data = 0x00000000;
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001434
1435 /* allocate overlay resources */
Ben Skeggs410f3ec2014-08-10 04:10:25 +10001436 ret = nv50_oimm_create(disp->disp, index, &head->oimm);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001437 if (ret)
1438 goto out;
1439
Ben Skeggs410f3ec2014-08-10 04:10:25 +10001440 ret = nv50_ovly_create(disp->disp, index, disp->sync->bo.offset,
1441 &head->ovly);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001442 if (ret)
1443 goto out;
1444
Ben Skeggs438d99e2011-07-05 16:48:06 +10001445out:
1446 if (ret)
Ben Skeggse225f442012-11-21 14:40:21 +10001447 nv50_crtc_destroy(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001448 return ret;
1449}
1450
1451/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10001452 * DAC
1453 *****************************************************************************/
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001454static void
Ben Skeggse225f442012-11-21 14:40:21 +10001455nv50_dac_dpms(struct drm_encoder *encoder, int mode)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001456{
1457 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10001458 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggsbf0eb892014-08-10 04:10:26 +10001459 struct {
1460 struct nv50_disp_mthd_v1 base;
1461 struct nv50_disp_dac_pwr_v0 pwr;
1462 } args = {
1463 .base.version = 1,
1464 .base.method = NV50_DISP_MTHD_V1_DAC_PWR,
1465 .base.hasht = nv_encoder->dcb->hasht,
1466 .base.hashm = nv_encoder->dcb->hashm,
1467 .pwr.state = 1,
1468 .pwr.data = 1,
1469 .pwr.vsync = (mode != DRM_MODE_DPMS_SUSPEND &&
1470 mode != DRM_MODE_DPMS_OFF),
1471 .pwr.hsync = (mode != DRM_MODE_DPMS_STANDBY &&
1472 mode != DRM_MODE_DPMS_OFF),
1473 };
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001474
Ben Skeggsbf0eb892014-08-10 04:10:26 +10001475 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001476}
1477
1478static bool
Ben Skeggse225f442012-11-21 14:40:21 +10001479nv50_dac_mode_fixup(struct drm_encoder *encoder,
Laurent Pincharte811f5a2012-07-17 17:56:50 +02001480 const struct drm_display_mode *mode,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001481 struct drm_display_mode *adjusted_mode)
1482{
1483 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1484 struct nouveau_connector *nv_connector;
1485
1486 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1487 if (nv_connector && nv_connector->native_mode) {
1488 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
1489 int id = adjusted_mode->base.id;
1490 *adjusted_mode = *nv_connector->native_mode;
1491 adjusted_mode->base.id = id;
1492 }
1493 }
1494
1495 return true;
1496}
1497
1498static void
Ben Skeggse225f442012-11-21 14:40:21 +10001499nv50_dac_commit(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001500{
1501}
1502
1503static void
Ben Skeggse225f442012-11-21 14:40:21 +10001504nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001505 struct drm_display_mode *adjusted_mode)
1506{
Ben Skeggse225f442012-11-21 14:40:21 +10001507 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001508 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1509 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs97b19b52012-11-16 11:21:37 +10001510 u32 *push;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001511
Ben Skeggse225f442012-11-21 14:40:21 +10001512 nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001513
Ben Skeggs97b19b52012-11-16 11:21:37 +10001514 push = evo_wait(mast, 8);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001515 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10001516 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggs97b19b52012-11-16 11:21:37 +10001517 u32 syncs = 0x00000000;
1518
1519 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1520 syncs |= 0x00000001;
1521 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1522 syncs |= 0x00000002;
1523
1524 evo_mthd(push, 0x0400 + (nv_encoder->or * 0x080), 2);
1525 evo_data(push, 1 << nv_crtc->index);
1526 evo_data(push, syncs);
1527 } else {
1528 u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
1529 u32 syncs = 0x00000001;
1530
1531 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1532 syncs |= 0x00000008;
1533 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1534 syncs |= 0x00000010;
1535
1536 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1537 magic |= 0x00000001;
1538
1539 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
1540 evo_data(push, syncs);
1541 evo_data(push, magic);
1542 evo_mthd(push, 0x0180 + (nv_encoder->or * 0x020), 1);
1543 evo_data(push, 1 << nv_crtc->index);
1544 }
1545
1546 evo_kick(push, mast);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001547 }
1548
1549 nv_encoder->crtc = encoder->crtc;
1550}
1551
1552static void
Ben Skeggse225f442012-11-21 14:40:21 +10001553nv50_dac_disconnect(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001554{
1555 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10001556 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs97b19b52012-11-16 11:21:37 +10001557 const int or = nv_encoder->or;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001558 u32 *push;
1559
1560 if (nv_encoder->crtc) {
Ben Skeggse225f442012-11-21 14:40:21 +10001561 nv50_crtc_prepare(nv_encoder->crtc);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001562
Ben Skeggs97b19b52012-11-16 11:21:37 +10001563 push = evo_wait(mast, 4);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001564 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10001565 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggs97b19b52012-11-16 11:21:37 +10001566 evo_mthd(push, 0x0400 + (or * 0x080), 1);
1567 evo_data(push, 0x00000000);
1568 } else {
1569 evo_mthd(push, 0x0180 + (or * 0x020), 1);
1570 evo_data(push, 0x00000000);
1571 }
Ben Skeggs97b19b52012-11-16 11:21:37 +10001572 evo_kick(push, mast);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001573 }
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001574 }
Ben Skeggs97b19b52012-11-16 11:21:37 +10001575
1576 nv_encoder->crtc = NULL;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001577}
1578
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10001579static enum drm_connector_status
Ben Skeggse225f442012-11-21 14:40:21 +10001580nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10001581{
Ben Skeggsc4abd312014-08-10 04:10:26 +10001582 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10001583 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggsc4abd312014-08-10 04:10:26 +10001584 struct {
1585 struct nv50_disp_mthd_v1 base;
1586 struct nv50_disp_dac_load_v0 load;
1587 } args = {
1588 .base.version = 1,
1589 .base.method = NV50_DISP_MTHD_V1_DAC_LOAD,
1590 .base.hasht = nv_encoder->dcb->hasht,
1591 .base.hashm = nv_encoder->dcb->hashm,
1592 };
1593 int ret;
Ben Skeggsb6819932011-07-08 11:14:50 +10001594
Ben Skeggsc4abd312014-08-10 04:10:26 +10001595 args.load.data = nouveau_drm(encoder->dev)->vbios.dactestval;
1596 if (args.load.data == 0)
1597 args.load.data = 340;
1598
1599 ret = nvif_mthd(disp->disp, 0, &args, sizeof(args));
1600 if (ret || !args.load.load)
Ben Skeggs35b21d32012-11-08 12:08:55 +10001601 return connector_status_disconnected;
Ben Skeggsb6819932011-07-08 11:14:50 +10001602
Ben Skeggs35b21d32012-11-08 12:08:55 +10001603 return connector_status_connected;
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10001604}
1605
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001606static void
Ben Skeggse225f442012-11-21 14:40:21 +10001607nv50_dac_destroy(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001608{
1609 drm_encoder_cleanup(encoder);
1610 kfree(encoder);
1611}
1612
Ben Skeggse225f442012-11-21 14:40:21 +10001613static const struct drm_encoder_helper_funcs nv50_dac_hfunc = {
1614 .dpms = nv50_dac_dpms,
1615 .mode_fixup = nv50_dac_mode_fixup,
1616 .prepare = nv50_dac_disconnect,
1617 .commit = nv50_dac_commit,
1618 .mode_set = nv50_dac_mode_set,
1619 .disable = nv50_dac_disconnect,
1620 .get_crtc = nv50_display_crtc_get,
1621 .detect = nv50_dac_detect
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001622};
1623
Ben Skeggse225f442012-11-21 14:40:21 +10001624static const struct drm_encoder_funcs nv50_dac_func = {
1625 .destroy = nv50_dac_destroy,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001626};
1627
1628static int
Ben Skeggse225f442012-11-21 14:40:21 +10001629nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001630{
Ben Skeggs5ed50202013-02-11 20:15:03 +10001631 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggs967e7bd2014-08-10 04:10:22 +10001632 struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001633 struct nouveau_encoder *nv_encoder;
1634 struct drm_encoder *encoder;
Ben Skeggs5ed50202013-02-11 20:15:03 +10001635 int type = DRM_MODE_ENCODER_DAC;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001636
1637 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
1638 if (!nv_encoder)
1639 return -ENOMEM;
1640 nv_encoder->dcb = dcbe;
1641 nv_encoder->or = ffs(dcbe->or) - 1;
Ben Skeggs5ed50202013-02-11 20:15:03 +10001642 nv_encoder->i2c = i2c->find(i2c, dcbe->i2c_index);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001643
1644 encoder = to_drm_encoder(nv_encoder);
1645 encoder->possible_crtcs = dcbe->heads;
1646 encoder->possible_clones = 0;
Ben Skeggs5ed50202013-02-11 20:15:03 +10001647 drm_encoder_init(connector->dev, encoder, &nv50_dac_func, type);
Ben Skeggse225f442012-11-21 14:40:21 +10001648 drm_encoder_helper_add(encoder, &nv50_dac_hfunc);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001649
1650 drm_mode_connector_attach_encoder(connector, encoder);
1651 return 0;
1652}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001653
1654/******************************************************************************
Ben Skeggs78951d22011-11-11 18:13:13 +10001655 * Audio
1656 *****************************************************************************/
1657static void
Ben Skeggse225f442012-11-21 14:40:21 +10001658nv50_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
Ben Skeggs78951d22011-11-11 18:13:13 +10001659{
1660 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggscc2a9072014-09-15 21:29:05 +10001661 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs78951d22011-11-11 18:13:13 +10001662 struct nouveau_connector *nv_connector;
Ben Skeggse225f442012-11-21 14:40:21 +10001663 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggsd889c522014-09-15 21:11:51 +10001664 struct __packed {
1665 struct {
1666 struct nv50_disp_mthd_v1 mthd;
1667 struct nv50_disp_sor_hda_eld_v0 eld;
1668 } base;
Ben Skeggs120b0c32014-08-10 04:10:26 +10001669 u8 data[sizeof(nv_connector->base.eld)];
1670 } args = {
Ben Skeggsd889c522014-09-15 21:11:51 +10001671 .base.mthd.version = 1,
1672 .base.mthd.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
1673 .base.mthd.hasht = nv_encoder->dcb->hasht,
Ben Skeggscc2a9072014-09-15 21:29:05 +10001674 .base.mthd.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
1675 (0x0100 << nv_crtc->index),
Ben Skeggs120b0c32014-08-10 04:10:26 +10001676 };
Ben Skeggs78951d22011-11-11 18:13:13 +10001677
1678 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1679 if (!drm_detect_monitor_audio(nv_connector->edid))
1680 return;
1681
Ben Skeggs78951d22011-11-11 18:13:13 +10001682 drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
Ben Skeggs120b0c32014-08-10 04:10:26 +10001683 memcpy(args.data, nv_connector->base.eld, sizeof(args.data));
Ben Skeggs78951d22011-11-11 18:13:13 +10001684
Ben Skeggsd889c522014-09-15 21:11:51 +10001685 nvif_mthd(disp->disp, 0, &args, sizeof(args.base) + args.data[2] * 4);
Ben Skeggs78951d22011-11-11 18:13:13 +10001686}
1687
1688static void
Ben Skeggscc2a9072014-09-15 21:29:05 +10001689nv50_audio_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
Ben Skeggs78951d22011-11-11 18:13:13 +10001690{
1691 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10001692 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs120b0c32014-08-10 04:10:26 +10001693 struct {
1694 struct nv50_disp_mthd_v1 base;
1695 struct nv50_disp_sor_hda_eld_v0 eld;
1696 } args = {
1697 .base.version = 1,
1698 .base.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
1699 .base.hasht = nv_encoder->dcb->hasht,
Ben Skeggscc2a9072014-09-15 21:29:05 +10001700 .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
1701 (0x0100 << nv_crtc->index),
Ben Skeggs120b0c32014-08-10 04:10:26 +10001702 };
Ben Skeggs78951d22011-11-11 18:13:13 +10001703
Ben Skeggs120b0c32014-08-10 04:10:26 +10001704 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs78951d22011-11-11 18:13:13 +10001705}
1706
1707/******************************************************************************
1708 * HDMI
1709 *****************************************************************************/
1710static void
Ben Skeggse225f442012-11-21 14:40:21 +10001711nv50_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
Ben Skeggs78951d22011-11-11 18:13:13 +10001712{
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001713 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1714 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001715 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggse00f2232014-08-10 04:10:26 +10001716 struct {
1717 struct nv50_disp_mthd_v1 base;
1718 struct nv50_disp_sor_hdmi_pwr_v0 pwr;
1719 } args = {
1720 .base.version = 1,
1721 .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR,
1722 .base.hasht = nv_encoder->dcb->hasht,
1723 .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
1724 (0x0100 << nv_crtc->index),
1725 .pwr.state = 1,
1726 .pwr.rekey = 56, /* binary driver, and tegra, constant */
1727 };
1728 struct nouveau_connector *nv_connector;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001729 u32 max_ac_packet;
1730
1731 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1732 if (!drm_detect_hdmi_monitor(nv_connector->edid))
1733 return;
1734
1735 max_ac_packet = mode->htotal - mode->hdisplay;
Ben Skeggse00f2232014-08-10 04:10:26 +10001736 max_ac_packet -= args.pwr.rekey;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001737 max_ac_packet -= 18; /* constant from tegra */
Ben Skeggse00f2232014-08-10 04:10:26 +10001738 args.pwr.max_ac_packet = max_ac_packet / 32;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001739
Ben Skeggse00f2232014-08-10 04:10:26 +10001740 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggse225f442012-11-21 14:40:21 +10001741 nv50_audio_mode_set(encoder, mode);
Ben Skeggs78951d22011-11-11 18:13:13 +10001742}
1743
1744static void
Ben Skeggse84a35a2014-06-05 10:59:55 +10001745nv50_hdmi_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
Ben Skeggs78951d22011-11-11 18:13:13 +10001746{
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001747 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10001748 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggse00f2232014-08-10 04:10:26 +10001749 struct {
1750 struct nv50_disp_mthd_v1 base;
1751 struct nv50_disp_sor_hdmi_pwr_v0 pwr;
1752 } args = {
1753 .base.version = 1,
1754 .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR,
1755 .base.hasht = nv_encoder->dcb->hasht,
1756 .base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
1757 (0x0100 << nv_crtc->index),
1758 };
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001759
Ben Skeggse00f2232014-08-10 04:10:26 +10001760 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs78951d22011-11-11 18:13:13 +10001761}
1762
1763/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10001764 * SOR
1765 *****************************************************************************/
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001766static void
Ben Skeggse225f442012-11-21 14:40:21 +10001767nv50_sor_dpms(struct drm_encoder *encoder, int mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001768{
1769 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggsd55b4af2014-08-10 04:10:26 +10001770 struct nv50_disp *disp = nv50_disp(encoder->dev);
1771 struct {
1772 struct nv50_disp_mthd_v1 base;
1773 struct nv50_disp_sor_pwr_v0 pwr;
1774 } args = {
1775 .base.version = 1,
1776 .base.method = NV50_DISP_MTHD_V1_SOR_PWR,
1777 .base.hasht = nv_encoder->dcb->hasht,
1778 .base.hashm = nv_encoder->dcb->hashm,
1779 .pwr.state = mode == DRM_MODE_DPMS_ON,
1780 };
Ben Skeggsc02ed2b2014-08-10 04:10:27 +10001781 struct {
1782 struct nv50_disp_mthd_v1 base;
1783 struct nv50_disp_sor_dp_pwr_v0 pwr;
1784 } link = {
1785 .base.version = 1,
1786 .base.method = NV50_DISP_MTHD_V1_SOR_DP_PWR,
1787 .base.hasht = nv_encoder->dcb->hasht,
1788 .base.hashm = nv_encoder->dcb->hashm,
1789 .pwr.state = mode == DRM_MODE_DPMS_ON,
1790 };
Ben Skeggs83fc0832011-07-05 13:08:40 +10001791 struct drm_device *dev = encoder->dev;
1792 struct drm_encoder *partner;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001793
1794 nv_encoder->last_dpms = mode;
1795
1796 list_for_each_entry(partner, &dev->mode_config.encoder_list, head) {
1797 struct nouveau_encoder *nv_partner = nouveau_encoder(partner);
1798
1799 if (partner->encoder_type != DRM_MODE_ENCODER_TMDS)
1800 continue;
1801
1802 if (nv_partner != nv_encoder &&
Ben Skeggs26cfa812011-11-17 09:10:02 +10001803 nv_partner->dcb->or == nv_encoder->dcb->or) {
Ben Skeggs83fc0832011-07-05 13:08:40 +10001804 if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
1805 return;
1806 break;
1807 }
1808 }
1809
Ben Skeggs48743222014-05-31 01:48:06 +10001810 if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
Ben Skeggsd55b4af2014-08-10 04:10:26 +10001811 args.pwr.state = 1;
1812 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggsc02ed2b2014-08-10 04:10:27 +10001813 nvif_mthd(disp->disp, 0, &link, sizeof(link));
Ben Skeggs48743222014-05-31 01:48:06 +10001814 } else {
Ben Skeggsd55b4af2014-08-10 04:10:26 +10001815 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggs48743222014-05-31 01:48:06 +10001816 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10001817}
1818
1819static bool
Ben Skeggse225f442012-11-21 14:40:21 +10001820nv50_sor_mode_fixup(struct drm_encoder *encoder,
Laurent Pincharte811f5a2012-07-17 17:56:50 +02001821 const struct drm_display_mode *mode,
Ben Skeggs83fc0832011-07-05 13:08:40 +10001822 struct drm_display_mode *adjusted_mode)
1823{
1824 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1825 struct nouveau_connector *nv_connector;
1826
1827 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1828 if (nv_connector && nv_connector->native_mode) {
1829 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
1830 int id = adjusted_mode->base.id;
1831 *adjusted_mode = *nv_connector->native_mode;
1832 adjusted_mode->base.id = id;
1833 }
1834 }
1835
1836 return true;
1837}
1838
1839static void
Ben Skeggse84a35a2014-06-05 10:59:55 +10001840nv50_sor_ctrl(struct nouveau_encoder *nv_encoder, u32 mask, u32 data)
1841{
1842 struct nv50_mast *mast = nv50_mast(nv_encoder->base.base.dev);
1843 u32 temp = (nv_encoder->ctrl & ~mask) | (data & mask), *push;
1844 if (temp != nv_encoder->ctrl && (push = evo_wait(mast, 2))) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10001845 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggse84a35a2014-06-05 10:59:55 +10001846 evo_mthd(push, 0x0600 + (nv_encoder->or * 0x40), 1);
1847 evo_data(push, (nv_encoder->ctrl = temp));
1848 } else {
1849 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
1850 evo_data(push, (nv_encoder->ctrl = temp));
1851 }
1852 evo_kick(push, mast);
1853 }
1854}
1855
1856static void
Ben Skeggse225f442012-11-21 14:40:21 +10001857nv50_sor_disconnect(struct drm_encoder *encoder)
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10001858{
1859 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse84a35a2014-06-05 10:59:55 +10001860 struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001861
1862 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1863 nv_encoder->crtc = NULL;
Ben Skeggse84a35a2014-06-05 10:59:55 +10001864
1865 if (nv_crtc) {
1866 nv50_crtc_prepare(&nv_crtc->base);
1867 nv50_sor_ctrl(nv_encoder, 1 << nv_crtc->index, 0);
Ben Skeggscc2a9072014-09-15 21:29:05 +10001868 nv50_audio_disconnect(encoder, nv_crtc);
Ben Skeggse84a35a2014-06-05 10:59:55 +10001869 nv50_hdmi_disconnect(&nv_encoder->base.base, nv_crtc);
1870 }
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10001871}
1872
1873static void
Ben Skeggse225f442012-11-21 14:40:21 +10001874nv50_sor_commit(struct drm_encoder *encoder)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001875{
1876}
1877
1878static void
Ben Skeggse225f442012-11-21 14:40:21 +10001879nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001880 struct drm_display_mode *mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001881{
Ben Skeggsa3761fa2014-08-10 04:10:27 +10001882 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1883 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
1884 struct {
1885 struct nv50_disp_mthd_v1 base;
1886 struct nv50_disp_sor_lvds_script_v0 lvds;
1887 } lvds = {
1888 .base.version = 1,
1889 .base.method = NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT,
1890 .base.hasht = nv_encoder->dcb->hasht,
1891 .base.hashm = nv_encoder->dcb->hashm,
1892 };
Ben Skeggse225f442012-11-21 14:40:21 +10001893 struct nv50_disp *disp = nv50_disp(encoder->dev);
1894 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs78951d22011-11-11 18:13:13 +10001895 struct drm_device *dev = encoder->dev;
Ben Skeggs77145f12012-07-31 16:16:21 +10001896 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001897 struct nouveau_connector *nv_connector;
Ben Skeggs77145f12012-07-31 16:16:21 +10001898 struct nvbios *bios = &drm->vbios;
Ben Skeggsa3761fa2014-08-10 04:10:27 +10001899 u32 mask, ctrl;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001900 u8 owner = 1 << nv_crtc->index;
1901 u8 proto = 0xf;
1902 u8 depth = 0x0;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001903
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001904 nv_connector = nouveau_encoder_connector_get(nv_encoder);
Ben Skeggse84a35a2014-06-05 10:59:55 +10001905 nv_encoder->crtc = encoder->crtc;
1906
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001907 switch (nv_encoder->dcb->type) {
Ben Skeggscb75d972012-07-11 10:44:20 +10001908 case DCB_OUTPUT_TMDS:
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001909 if (nv_encoder->dcb->sorconf.link & 1) {
1910 if (mode->clock < 165000)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001911 proto = 0x1;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001912 else
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001913 proto = 0x5;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001914 } else {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001915 proto = 0x2;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001916 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10001917
Ben Skeggse84a35a2014-06-05 10:59:55 +10001918 nv50_hdmi_mode_set(&nv_encoder->base.base, mode);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001919 break;
Ben Skeggscb75d972012-07-11 10:44:20 +10001920 case DCB_OUTPUT_LVDS:
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001921 proto = 0x0;
1922
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001923 if (bios->fp_no_ddc) {
1924 if (bios->fp.dual_link)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10001925 lvds.lvds.script |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001926 if (bios->fp.if_is_24bit)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10001927 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001928 } else {
Ben Skeggsbefb51e2011-11-18 10:23:59 +10001929 if (nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001930 if (((u8 *)nv_connector->edid)[121] == 2)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10001931 lvds.lvds.script |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001932 } else
1933 if (mode->clock >= bios->fp.duallink_transition_clk) {
Ben Skeggsa3761fa2014-08-10 04:10:27 +10001934 lvds.lvds.script |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001935 }
1936
Ben Skeggsa3761fa2014-08-10 04:10:27 +10001937 if (lvds.lvds.script & 0x0100) {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001938 if (bios->fp.strapless_is_24bit & 2)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10001939 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001940 } else {
1941 if (bios->fp.strapless_is_24bit & 1)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10001942 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001943 }
1944
1945 if (nv_connector->base.display_info.bpc == 8)
Ben Skeggsa3761fa2014-08-10 04:10:27 +10001946 lvds.lvds.script |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001947 }
Ben Skeggs4a230fa2012-11-09 11:25:37 +10001948
Ben Skeggsa3761fa2014-08-10 04:10:27 +10001949 nvif_mthd(disp->disp, 0, &lvds, sizeof(lvds));
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001950 break;
Ben Skeggscb75d972012-07-11 10:44:20 +10001951 case DCB_OUTPUT_DP:
Ben Skeggs3488c572012-03-12 11:42:20 +10001952 if (nv_connector->base.display_info.bpc == 6) {
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001953 nv_encoder->dp.datarate = mode->clock * 18 / 8;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001954 depth = 0x2;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001955 } else
1956 if (nv_connector->base.display_info.bpc == 8) {
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001957 nv_encoder->dp.datarate = mode->clock * 24 / 8;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001958 depth = 0x5;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001959 } else {
1960 nv_encoder->dp.datarate = mode->clock * 30 / 8;
1961 depth = 0x6;
Ben Skeggs3488c572012-03-12 11:42:20 +10001962 }
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001963
1964 if (nv_encoder->dcb->sorconf.link & 1)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001965 proto = 0x8;
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001966 else
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001967 proto = 0x9;
Ben Skeggs3eee8642014-09-15 15:20:47 +10001968 nv50_audio_mode_set(encoder, mode);
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001969 break;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001970 default:
1971 BUG_ON(1);
1972 break;
1973 }
Ben Skeggsff8ff502011-07-08 11:53:37 +10001974
Ben Skeggse84a35a2014-06-05 10:59:55 +10001975 nv50_sor_dpms(&nv_encoder->base.base, DRM_MODE_DPMS_ON);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001976
Ben Skeggs648d4df2014-08-10 04:10:27 +10001977 if (nv50_vers(mast) >= GF110_DISP) {
Ben Skeggse84a35a2014-06-05 10:59:55 +10001978 u32 *push = evo_wait(mast, 3);
1979 if (push) {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001980 u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
1981 u32 syncs = 0x00000001;
1982
1983 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1984 syncs |= 0x00000008;
1985 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1986 syncs |= 0x00000010;
1987
1988 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1989 magic |= 0x00000001;
1990
1991 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
1992 evo_data(push, syncs | (depth << 6));
1993 evo_data(push, magic);
Ben Skeggse84a35a2014-06-05 10:59:55 +10001994 evo_kick(push, mast);
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001995 }
1996
Ben Skeggse84a35a2014-06-05 10:59:55 +10001997 ctrl = proto << 8;
1998 mask = 0x00000f00;
1999 } else {
2000 ctrl = (depth << 16) | (proto << 8);
2001 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
2002 ctrl |= 0x00001000;
2003 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
2004 ctrl |= 0x00002000;
2005 mask = 0x000f3f00;
Ben Skeggs83fc0832011-07-05 13:08:40 +10002006 }
2007
Ben Skeggse84a35a2014-06-05 10:59:55 +10002008 nv50_sor_ctrl(nv_encoder, mask | owner, ctrl | owner);
Ben Skeggs83fc0832011-07-05 13:08:40 +10002009}
2010
2011static void
Ben Skeggse225f442012-11-21 14:40:21 +10002012nv50_sor_destroy(struct drm_encoder *encoder)
Ben Skeggs83fc0832011-07-05 13:08:40 +10002013{
2014 drm_encoder_cleanup(encoder);
2015 kfree(encoder);
2016}
2017
Ben Skeggse225f442012-11-21 14:40:21 +10002018static const struct drm_encoder_helper_funcs nv50_sor_hfunc = {
2019 .dpms = nv50_sor_dpms,
2020 .mode_fixup = nv50_sor_mode_fixup,
Ben Skeggs5a885f02013-02-20 14:34:18 +10002021 .prepare = nv50_sor_disconnect,
Ben Skeggse225f442012-11-21 14:40:21 +10002022 .commit = nv50_sor_commit,
2023 .mode_set = nv50_sor_mode_set,
2024 .disable = nv50_sor_disconnect,
2025 .get_crtc = nv50_display_crtc_get,
Ben Skeggs83fc0832011-07-05 13:08:40 +10002026};
2027
Ben Skeggse225f442012-11-21 14:40:21 +10002028static const struct drm_encoder_funcs nv50_sor_func = {
2029 .destroy = nv50_sor_destroy,
Ben Skeggs83fc0832011-07-05 13:08:40 +10002030};
2031
2032static int
Ben Skeggse225f442012-11-21 14:40:21 +10002033nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
Ben Skeggs83fc0832011-07-05 13:08:40 +10002034{
Ben Skeggs5ed50202013-02-11 20:15:03 +10002035 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002036 struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
Ben Skeggs83fc0832011-07-05 13:08:40 +10002037 struct nouveau_encoder *nv_encoder;
2038 struct drm_encoder *encoder;
Ben Skeggs5ed50202013-02-11 20:15:03 +10002039 int type;
2040
2041 switch (dcbe->type) {
2042 case DCB_OUTPUT_LVDS: type = DRM_MODE_ENCODER_LVDS; break;
2043 case DCB_OUTPUT_TMDS:
2044 case DCB_OUTPUT_DP:
2045 default:
2046 type = DRM_MODE_ENCODER_TMDS;
2047 break;
2048 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10002049
2050 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
2051 if (!nv_encoder)
2052 return -ENOMEM;
2053 nv_encoder->dcb = dcbe;
2054 nv_encoder->or = ffs(dcbe->or) - 1;
Ben Skeggs5ed50202013-02-11 20:15:03 +10002055 nv_encoder->i2c = i2c->find(i2c, dcbe->i2c_index);
Ben Skeggs83fc0832011-07-05 13:08:40 +10002056 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
2057
2058 encoder = to_drm_encoder(nv_encoder);
2059 encoder->possible_crtcs = dcbe->heads;
2060 encoder->possible_clones = 0;
Ben Skeggs5ed50202013-02-11 20:15:03 +10002061 drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type);
Ben Skeggse225f442012-11-21 14:40:21 +10002062 drm_encoder_helper_add(encoder, &nv50_sor_hfunc);
Ben Skeggs83fc0832011-07-05 13:08:40 +10002063
2064 drm_mode_connector_attach_encoder(connector, encoder);
2065 return 0;
2066}
Ben Skeggs26f6d882011-07-04 16:25:18 +10002067
2068/******************************************************************************
Ben Skeggseb6313a2013-02-11 09:52:58 +10002069 * PIOR
2070 *****************************************************************************/
2071
2072static void
2073nv50_pior_dpms(struct drm_encoder *encoder, int mode)
2074{
2075 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2076 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs67cb49c2014-08-10 04:10:27 +10002077 struct {
2078 struct nv50_disp_mthd_v1 base;
2079 struct nv50_disp_pior_pwr_v0 pwr;
2080 } args = {
2081 .base.version = 1,
2082 .base.method = NV50_DISP_MTHD_V1_PIOR_PWR,
2083 .base.hasht = nv_encoder->dcb->hasht,
2084 .base.hashm = nv_encoder->dcb->hashm,
2085 .pwr.state = mode == DRM_MODE_DPMS_ON,
2086 .pwr.type = nv_encoder->dcb->type,
2087 };
2088
2089 nvif_mthd(disp->disp, 0, &args, sizeof(args));
Ben Skeggseb6313a2013-02-11 09:52:58 +10002090}
2091
2092static bool
2093nv50_pior_mode_fixup(struct drm_encoder *encoder,
2094 const struct drm_display_mode *mode,
2095 struct drm_display_mode *adjusted_mode)
2096{
2097 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2098 struct nouveau_connector *nv_connector;
2099
2100 nv_connector = nouveau_encoder_connector_get(nv_encoder);
2101 if (nv_connector && nv_connector->native_mode) {
2102 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
2103 int id = adjusted_mode->base.id;
2104 *adjusted_mode = *nv_connector->native_mode;
2105 adjusted_mode->base.id = id;
2106 }
2107 }
2108
2109 adjusted_mode->clock *= 2;
2110 return true;
2111}
2112
2113static void
2114nv50_pior_commit(struct drm_encoder *encoder)
2115{
2116}
2117
2118static void
2119nv50_pior_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
2120 struct drm_display_mode *adjusted_mode)
2121{
2122 struct nv50_mast *mast = nv50_mast(encoder->dev);
2123 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2124 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
2125 struct nouveau_connector *nv_connector;
2126 u8 owner = 1 << nv_crtc->index;
2127 u8 proto, depth;
2128 u32 *push;
2129
2130 nv_connector = nouveau_encoder_connector_get(nv_encoder);
2131 switch (nv_connector->base.display_info.bpc) {
2132 case 10: depth = 0x6; break;
2133 case 8: depth = 0x5; break;
2134 case 6: depth = 0x2; break;
2135 default: depth = 0x0; break;
2136 }
2137
2138 switch (nv_encoder->dcb->type) {
2139 case DCB_OUTPUT_TMDS:
2140 case DCB_OUTPUT_DP:
2141 proto = 0x0;
2142 break;
2143 default:
2144 BUG_ON(1);
2145 break;
2146 }
2147
2148 nv50_pior_dpms(encoder, DRM_MODE_DPMS_ON);
2149
2150 push = evo_wait(mast, 8);
2151 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10002152 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggseb6313a2013-02-11 09:52:58 +10002153 u32 ctrl = (depth << 16) | (proto << 8) | owner;
2154 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
2155 ctrl |= 0x00001000;
2156 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
2157 ctrl |= 0x00002000;
2158 evo_mthd(push, 0x0700 + (nv_encoder->or * 0x040), 1);
2159 evo_data(push, ctrl);
2160 }
2161
2162 evo_kick(push, mast);
2163 }
2164
2165 nv_encoder->crtc = encoder->crtc;
2166}
2167
2168static void
2169nv50_pior_disconnect(struct drm_encoder *encoder)
2170{
2171 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
2172 struct nv50_mast *mast = nv50_mast(encoder->dev);
2173 const int or = nv_encoder->or;
2174 u32 *push;
2175
2176 if (nv_encoder->crtc) {
2177 nv50_crtc_prepare(nv_encoder->crtc);
2178
2179 push = evo_wait(mast, 4);
2180 if (push) {
Ben Skeggs648d4df2014-08-10 04:10:27 +10002181 if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
Ben Skeggseb6313a2013-02-11 09:52:58 +10002182 evo_mthd(push, 0x0700 + (or * 0x040), 1);
2183 evo_data(push, 0x00000000);
2184 }
Ben Skeggseb6313a2013-02-11 09:52:58 +10002185 evo_kick(push, mast);
2186 }
2187 }
2188
2189 nv_encoder->crtc = NULL;
2190}
2191
2192static void
2193nv50_pior_destroy(struct drm_encoder *encoder)
2194{
2195 drm_encoder_cleanup(encoder);
2196 kfree(encoder);
2197}
2198
2199static const struct drm_encoder_helper_funcs nv50_pior_hfunc = {
2200 .dpms = nv50_pior_dpms,
2201 .mode_fixup = nv50_pior_mode_fixup,
2202 .prepare = nv50_pior_disconnect,
2203 .commit = nv50_pior_commit,
2204 .mode_set = nv50_pior_mode_set,
2205 .disable = nv50_pior_disconnect,
2206 .get_crtc = nv50_display_crtc_get,
2207};
2208
2209static const struct drm_encoder_funcs nv50_pior_func = {
2210 .destroy = nv50_pior_destroy,
2211};
2212
2213static int
2214nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
2215{
2216 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002217 struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
Ben Skeggseb6313a2013-02-11 09:52:58 +10002218 struct nouveau_i2c_port *ddc = NULL;
2219 struct nouveau_encoder *nv_encoder;
2220 struct drm_encoder *encoder;
2221 int type;
2222
2223 switch (dcbe->type) {
2224 case DCB_OUTPUT_TMDS:
2225 ddc = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(dcbe->extdev));
2226 type = DRM_MODE_ENCODER_TMDS;
2227 break;
2228 case DCB_OUTPUT_DP:
2229 ddc = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(dcbe->extdev));
2230 type = DRM_MODE_ENCODER_TMDS;
2231 break;
2232 default:
2233 return -ENODEV;
2234 }
2235
2236 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
2237 if (!nv_encoder)
2238 return -ENOMEM;
2239 nv_encoder->dcb = dcbe;
2240 nv_encoder->or = ffs(dcbe->or) - 1;
2241 nv_encoder->i2c = ddc;
2242
2243 encoder = to_drm_encoder(nv_encoder);
2244 encoder->possible_crtcs = dcbe->heads;
2245 encoder->possible_clones = 0;
2246 drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type);
2247 drm_encoder_helper_add(encoder, &nv50_pior_hfunc);
2248
2249 drm_mode_connector_attach_encoder(connector, encoder);
2250 return 0;
2251}
2252
2253/******************************************************************************
Ben Skeggsab0af552014-08-10 04:10:19 +10002254 * Framebuffer
2255 *****************************************************************************/
2256
Ben Skeggs8a423642014-08-10 04:10:19 +10002257static void
Ben Skeggs0ad72862014-08-10 04:10:22 +10002258nv50_fbdma_fini(struct nv50_fbdma *fbdma)
Ben Skeggs8a423642014-08-10 04:10:19 +10002259{
Ben Skeggs0ad72862014-08-10 04:10:22 +10002260 int i;
2261 for (i = 0; i < ARRAY_SIZE(fbdma->base); i++)
2262 nvif_object_fini(&fbdma->base[i]);
2263 nvif_object_fini(&fbdma->core);
Ben Skeggs8a423642014-08-10 04:10:19 +10002264 list_del(&fbdma->head);
2265 kfree(fbdma);
2266}
2267
2268static int
2269nv50_fbdma_init(struct drm_device *dev, u32 name, u64 offset, u64 length, u8 kind)
2270{
2271 struct nouveau_drm *drm = nouveau_drm(dev);
2272 struct nv50_disp *disp = nv50_disp(dev);
2273 struct nv50_mast *mast = nv50_mast(dev);
Ben Skeggs4acfd702014-08-10 04:10:24 +10002274 struct __attribute__ ((packed)) {
2275 struct nv_dma_v0 base;
2276 union {
2277 struct nv50_dma_v0 nv50;
2278 struct gf100_dma_v0 gf100;
2279 struct gf110_dma_v0 gf110;
2280 };
2281 } args = {};
Ben Skeggs8a423642014-08-10 04:10:19 +10002282 struct nv50_fbdma *fbdma;
2283 struct drm_crtc *crtc;
Ben Skeggs4acfd702014-08-10 04:10:24 +10002284 u32 size = sizeof(args.base);
Ben Skeggs8a423642014-08-10 04:10:19 +10002285 int ret;
2286
2287 list_for_each_entry(fbdma, &disp->fbdma, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002288 if (fbdma->core.handle == name)
Ben Skeggs8a423642014-08-10 04:10:19 +10002289 return 0;
2290 }
2291
2292 fbdma = kzalloc(sizeof(*fbdma), GFP_KERNEL);
2293 if (!fbdma)
2294 return -ENOMEM;
2295 list_add(&fbdma->head, &disp->fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10002296
Ben Skeggs4acfd702014-08-10 04:10:24 +10002297 args.base.target = NV_DMA_V0_TARGET_VRAM;
2298 args.base.access = NV_DMA_V0_ACCESS_RDWR;
2299 args.base.start = offset;
2300 args.base.limit = offset + length - 1;
Ben Skeggs8a423642014-08-10 04:10:19 +10002301
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002302 if (drm->device.info.chipset < 0x80) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10002303 args.nv50.part = NV50_DMA_V0_PART_256;
2304 size += sizeof(args.nv50);
Ben Skeggs8a423642014-08-10 04:10:19 +10002305 } else
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002306 if (drm->device.info.chipset < 0xc0) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10002307 args.nv50.part = NV50_DMA_V0_PART_256;
2308 args.nv50.kind = kind;
2309 size += sizeof(args.nv50);
Ben Skeggs8a423642014-08-10 04:10:19 +10002310 } else
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002311 if (drm->device.info.chipset < 0xd0) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10002312 args.gf100.kind = kind;
2313 size += sizeof(args.gf100);
Ben Skeggs8a423642014-08-10 04:10:19 +10002314 } else {
Ben Skeggs4acfd702014-08-10 04:10:24 +10002315 args.gf110.page = GF110_DMA_V0_PAGE_LP;
2316 args.gf110.kind = kind;
2317 size += sizeof(args.gf110);
Ben Skeggs8a423642014-08-10 04:10:19 +10002318 }
2319
2320 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002321 struct nv50_head *head = nv50_head(crtc);
2322 int ret = nvif_object_init(&head->sync.base.base.user, NULL,
Ben Skeggs4acfd702014-08-10 04:10:24 +10002323 name, NV_DMA_IN_MEMORY, &args, size,
Ben Skeggs0ad72862014-08-10 04:10:22 +10002324 &fbdma->base[head->base.index]);
Ben Skeggs8a423642014-08-10 04:10:19 +10002325 if (ret) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002326 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10002327 return ret;
2328 }
2329 }
2330
Ben Skeggs0ad72862014-08-10 04:10:22 +10002331 ret = nvif_object_init(&mast->base.base.user, NULL, name,
Ben Skeggs4acfd702014-08-10 04:10:24 +10002332 NV_DMA_IN_MEMORY, &args, size,
Ben Skeggs0ad72862014-08-10 04:10:22 +10002333 &fbdma->core);
Ben Skeggs8a423642014-08-10 04:10:19 +10002334 if (ret) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002335 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10002336 return ret;
2337 }
2338
2339 return 0;
2340}
2341
Ben Skeggsab0af552014-08-10 04:10:19 +10002342static void
2343nv50_fb_dtor(struct drm_framebuffer *fb)
2344{
2345}
2346
2347static int
2348nv50_fb_ctor(struct drm_framebuffer *fb)
2349{
2350 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
2351 struct nouveau_drm *drm = nouveau_drm(fb->dev);
2352 struct nouveau_bo *nvbo = nv_fb->nvbo;
Ben Skeggs8a423642014-08-10 04:10:19 +10002353 struct nv50_disp *disp = nv50_disp(fb->dev);
Ben Skeggs8a423642014-08-10 04:10:19 +10002354 u8 kind = nouveau_bo_tile_layout(nvbo) >> 8;
2355 u8 tile = nvbo->tile_mode;
Ben Skeggsab0af552014-08-10 04:10:19 +10002356
2357 if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) {
2358 NV_ERROR(drm, "framebuffer requires contiguous bo\n");
2359 return -EINVAL;
2360 }
2361
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002362 if (drm->device.info.chipset >= 0xc0)
Ben Skeggs8a423642014-08-10 04:10:19 +10002363 tile >>= 4; /* yep.. */
2364
Ben Skeggsab0af552014-08-10 04:10:19 +10002365 switch (fb->depth) {
2366 case 8: nv_fb->r_format = 0x1e00; break;
2367 case 15: nv_fb->r_format = 0xe900; break;
2368 case 16: nv_fb->r_format = 0xe800; break;
2369 case 24:
2370 case 32: nv_fb->r_format = 0xcf00; break;
2371 case 30: nv_fb->r_format = 0xd100; break;
2372 default:
2373 NV_ERROR(drm, "unknown depth %d\n", fb->depth);
2374 return -EINVAL;
2375 }
2376
Ben Skeggs648d4df2014-08-10 04:10:27 +10002377 if (disp->disp->oclass < G82_DISP) {
Ben Skeggs8a423642014-08-10 04:10:19 +10002378 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
2379 (fb->pitches[0] | 0x00100000);
2380 nv_fb->r_format |= kind << 16;
2381 } else
Ben Skeggs648d4df2014-08-10 04:10:27 +10002382 if (disp->disp->oclass < GF110_DISP) {
Ben Skeggs8a423642014-08-10 04:10:19 +10002383 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
2384 (fb->pitches[0] | 0x00100000);
Ben Skeggsab0af552014-08-10 04:10:19 +10002385 } else {
Ben Skeggs8a423642014-08-10 04:10:19 +10002386 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
2387 (fb->pitches[0] | 0x01000000);
Ben Skeggsab0af552014-08-10 04:10:19 +10002388 }
Ben Skeggs8a423642014-08-10 04:10:19 +10002389 nv_fb->r_handle = 0xffff0000 | kind;
Ben Skeggsab0af552014-08-10 04:10:19 +10002390
Ben Skeggsf392ec42014-08-10 04:10:28 +10002391 return nv50_fbdma_init(fb->dev, nv_fb->r_handle, 0,
2392 drm->device.info.ram_user, kind);
Ben Skeggsab0af552014-08-10 04:10:19 +10002393}
2394
2395/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10002396 * Init
2397 *****************************************************************************/
Ben Skeggsab0af552014-08-10 04:10:19 +10002398
Ben Skeggs2a44e492011-11-09 11:36:33 +10002399void
Ben Skeggse225f442012-11-21 14:40:21 +10002400nv50_display_fini(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10002401{
Ben Skeggs26f6d882011-07-04 16:25:18 +10002402}
2403
2404int
Ben Skeggse225f442012-11-21 14:40:21 +10002405nv50_display_init(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10002406{
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10002407 struct nv50_disp *disp = nv50_disp(dev);
2408 struct drm_crtc *crtc;
2409 u32 *push;
2410
2411 push = evo_wait(nv50_mast(dev), 32);
2412 if (!push)
2413 return -EBUSY;
2414
2415 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
2416 struct nv50_sync *sync = nv50_sync(crtc);
2417 nouveau_bo_wr32(disp->sync, sync->addr / 4, sync->data);
Ben Skeggs26f6d882011-07-04 16:25:18 +10002418 }
2419
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10002420 evo_mthd(push, 0x0088, 1);
Ben Skeggsf45f55c2014-08-10 04:10:23 +10002421 evo_data(push, nv50_mast(dev)->base.sync.handle);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10002422 evo_kick(push, nv50_mast(dev));
2423 return 0;
Ben Skeggs26f6d882011-07-04 16:25:18 +10002424}
2425
2426void
Ben Skeggse225f442012-11-21 14:40:21 +10002427nv50_display_destroy(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10002428{
Ben Skeggse225f442012-11-21 14:40:21 +10002429 struct nv50_disp *disp = nv50_disp(dev);
Ben Skeggs8a423642014-08-10 04:10:19 +10002430 struct nv50_fbdma *fbdma, *fbtmp;
2431
2432 list_for_each_entry_safe(fbdma, fbtmp, &disp->fbdma, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002433 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10002434 }
Ben Skeggs26f6d882011-07-04 16:25:18 +10002435
Ben Skeggs0ad72862014-08-10 04:10:22 +10002436 nv50_dmac_destroy(&disp->mast.base, disp->disp);
Ben Skeggsbdb8c212011-11-12 01:30:24 +10002437
Ben Skeggs816af2f2011-11-16 15:48:48 +10002438 nouveau_bo_unmap(disp->sync);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01002439 if (disp->sync)
2440 nouveau_bo_unpin(disp->sync);
Ben Skeggs816af2f2011-11-16 15:48:48 +10002441 nouveau_bo_ref(NULL, &disp->sync);
Ben Skeggs51beb422011-07-05 10:33:08 +10002442
Ben Skeggs77145f12012-07-31 16:16:21 +10002443 nouveau_display(dev)->priv = NULL;
Ben Skeggs26f6d882011-07-04 16:25:18 +10002444 kfree(disp);
2445}
2446
2447int
Ben Skeggse225f442012-11-21 14:40:21 +10002448nv50_display_create(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10002449{
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002450 struct nvif_device *device = &nouveau_drm(dev)->device;
Ben Skeggs77145f12012-07-31 16:16:21 +10002451 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs77145f12012-07-31 16:16:21 +10002452 struct dcb_table *dcb = &drm->vbios.dcb;
Ben Skeggs83fc0832011-07-05 13:08:40 +10002453 struct drm_connector *connector, *tmp;
Ben Skeggse225f442012-11-21 14:40:21 +10002454 struct nv50_disp *disp;
Ben Skeggscb75d972012-07-11 10:44:20 +10002455 struct dcb_output *dcbe;
Ben Skeggs7c5f6a82012-03-04 16:25:59 +10002456 int crtcs, ret, i;
Ben Skeggs26f6d882011-07-04 16:25:18 +10002457
2458 disp = kzalloc(sizeof(*disp), GFP_KERNEL);
2459 if (!disp)
2460 return -ENOMEM;
Ben Skeggs8a423642014-08-10 04:10:19 +10002461 INIT_LIST_HEAD(&disp->fbdma);
Ben Skeggs77145f12012-07-31 16:16:21 +10002462
2463 nouveau_display(dev)->priv = disp;
Ben Skeggse225f442012-11-21 14:40:21 +10002464 nouveau_display(dev)->dtor = nv50_display_destroy;
2465 nouveau_display(dev)->init = nv50_display_init;
2466 nouveau_display(dev)->fini = nv50_display_fini;
Ben Skeggsab0af552014-08-10 04:10:19 +10002467 nouveau_display(dev)->fb_ctor = nv50_fb_ctor;
2468 nouveau_display(dev)->fb_dtor = nv50_fb_dtor;
Ben Skeggs0ad72862014-08-10 04:10:22 +10002469 disp->disp = &nouveau_display(dev)->disp;
Ben Skeggs26f6d882011-07-04 16:25:18 +10002470
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002471 /* small shared memory area we use for notifiers and semaphores */
2472 ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
Maarten Lankhorstbb6178b2014-01-09 11:03:15 +01002473 0, 0x0000, NULL, NULL, &disp->sync);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002474 if (!ret) {
2475 ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01002476 if (!ret) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002477 ret = nouveau_bo_map(disp->sync);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01002478 if (ret)
2479 nouveau_bo_unpin(disp->sync);
2480 }
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002481 if (ret)
2482 nouveau_bo_ref(NULL, &disp->sync);
2483 }
2484
2485 if (ret)
2486 goto out;
2487
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002488 /* allocate master evo channel */
Ben Skeggs410f3ec2014-08-10 04:10:25 +10002489 ret = nv50_core_create(disp->disp, disp->sync->bo.offset,
2490 &disp->mast);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002491 if (ret)
2492 goto out;
2493
Ben Skeggs438d99e2011-07-05 16:48:06 +10002494 /* create crtc objects to represent the hw heads */
Ben Skeggs648d4df2014-08-10 04:10:27 +10002495 if (disp->disp->oclass >= GF110_DISP)
Ben Skeggsdb2bec12014-08-10 04:10:22 +10002496 crtcs = nvif_rd32(device, 0x022448);
Ben Skeggs63718a02012-11-16 11:44:14 +10002497 else
2498 crtcs = 2;
2499
Ben Skeggs7c5f6a82012-03-04 16:25:59 +10002500 for (i = 0; i < crtcs; i++) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002501 ret = nv50_crtc_create(dev, i);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002502 if (ret)
2503 goto out;
2504 }
2505
Ben Skeggs83fc0832011-07-05 13:08:40 +10002506 /* create encoder/connector objects based on VBIOS DCB table */
2507 for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
2508 connector = nouveau_connector_create(dev, dcbe->connector);
2509 if (IS_ERR(connector))
2510 continue;
2511
Ben Skeggseb6313a2013-02-11 09:52:58 +10002512 if (dcbe->location == DCB_LOC_ON_CHIP) {
2513 switch (dcbe->type) {
2514 case DCB_OUTPUT_TMDS:
2515 case DCB_OUTPUT_LVDS:
2516 case DCB_OUTPUT_DP:
2517 ret = nv50_sor_create(connector, dcbe);
2518 break;
2519 case DCB_OUTPUT_ANALOG:
2520 ret = nv50_dac_create(connector, dcbe);
2521 break;
2522 default:
2523 ret = -ENODEV;
2524 break;
2525 }
2526 } else {
2527 ret = nv50_pior_create(connector, dcbe);
Ben Skeggs83fc0832011-07-05 13:08:40 +10002528 }
2529
Ben Skeggseb6313a2013-02-11 09:52:58 +10002530 if (ret) {
2531 NV_WARN(drm, "failed to create encoder %d/%d/%d: %d\n",
2532 dcbe->location, dcbe->type,
2533 ffs(dcbe->or) - 1, ret);
Ben Skeggs94f54f52013-03-05 22:26:06 +10002534 ret = 0;
Ben Skeggs83fc0832011-07-05 13:08:40 +10002535 }
2536 }
2537
2538 /* cull any connectors we created that don't have an encoder */
2539 list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) {
2540 if (connector->encoder_ids[0])
2541 continue;
2542
Ben Skeggs77145f12012-07-31 16:16:21 +10002543 NV_WARN(drm, "%s has no encoders, removing\n",
Jani Nikula8c6c3612014-06-03 14:56:18 +03002544 connector->name);
Ben Skeggs83fc0832011-07-05 13:08:40 +10002545 connector->funcs->destroy(connector);
2546 }
2547
Ben Skeggs26f6d882011-07-04 16:25:18 +10002548out:
2549 if (ret)
Ben Skeggse225f442012-11-21 14:40:21 +10002550 nv50_display_destroy(dev);
Ben Skeggs26f6d882011-07-04 16:25:18 +10002551 return ret;
2552}