blob: 4f50add8e6dd8f1c0dc7a1971c26e0562f771a19 [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>
Ben Skeggs48743222014-05-31 01:48:06 +100029#include <drm/drm_dp_helper.h>
Ben Skeggs26f6d882011-07-04 16:25:18 +100030
Ben Skeggsfdb751e2014-08-10 04:10:23 +100031#include <nvif/class.h>
32
Ben Skeggs77145f12012-07-31 16:16:21 +100033#include "nouveau_drm.h"
34#include "nouveau_dma.h"
35#include "nouveau_gem.h"
Ben Skeggs26f6d882011-07-04 16:25:18 +100036#include "nouveau_connector.h"
37#include "nouveau_encoder.h"
38#include "nouveau_crtc.h"
Ben Skeggsf589be82012-07-22 11:55:54 +100039#include "nouveau_fence.h"
Ben Skeggs3a89cd02011-07-07 10:47:10 +100040#include "nv50_display.h"
Ben Skeggs26f6d882011-07-04 16:25:18 +100041
Ben Skeggs8a464382011-11-12 23:52:07 +100042#define EVO_DMA_NR 9
43
Ben Skeggsbdb8c212011-11-12 01:30:24 +100044#define EVO_MASTER (0x00)
Ben Skeggsa63a97e2011-11-16 15:22:34 +100045#define EVO_FLIP(c) (0x01 + (c))
Ben Skeggs8a464382011-11-12 23:52:07 +100046#define EVO_OVLY(c) (0x05 + (c))
47#define EVO_OIMM(c) (0x09 + (c))
Ben Skeggsbdb8c212011-11-12 01:30:24 +100048#define EVO_CURS(c) (0x0d + (c))
49
Ben Skeggs816af2f2011-11-16 15:48:48 +100050/* offsets in shared sync bo of various structures */
51#define EVO_SYNC(c, o) ((c) * 0x0100 + (o))
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +100052#define EVO_MAST_NTFY EVO_SYNC( 0, 0x00)
53#define EVO_FLIP_SEM0(c) EVO_SYNC((c) + 1, 0x00)
54#define EVO_FLIP_SEM1(c) EVO_SYNC((c) + 1, 0x10)
Ben Skeggs816af2f2011-11-16 15:48:48 +100055
Ben Skeggsb5a794b2012-10-16 14:18:32 +100056#define EVO_CORE_HANDLE (0xd1500000)
57#define EVO_CHAN_HANDLE(t,i) (0xd15c0000 | (((t) & 0x00ff) << 8) | (i))
Ben Skeggs0ad72862014-08-10 04:10:22 +100058#define EVO_CHAN_OCLASS(t,c) (((c)->oclass & 0xff00) | ((t) & 0x00ff))
Ben Skeggsb5a794b2012-10-16 14:18:32 +100059#define EVO_PUSH_HANDLE(t,i) (0xd15b0000 | (i) | \
60 (((NV50_DISP_##t##_CLASS) & 0x00ff) << 8))
61
62/******************************************************************************
63 * EVO channel
64 *****************************************************************************/
65
Ben Skeggse225f442012-11-21 14:40:21 +100066struct nv50_chan {
Ben Skeggs0ad72862014-08-10 04:10:22 +100067 struct nvif_object user;
Ben Skeggsb5a794b2012-10-16 14:18:32 +100068};
69
70static int
Ben Skeggs0ad72862014-08-10 04:10:22 +100071nv50_chan_create(struct nvif_object *disp, u32 bclass, u8 head,
Ben Skeggse225f442012-11-21 14:40:21 +100072 void *data, u32 size, struct nv50_chan *chan)
Ben Skeggsb5a794b2012-10-16 14:18:32 +100073{
Ben Skeggs0ad72862014-08-10 04:10:22 +100074 const u32 oclass = EVO_CHAN_OCLASS(bclass, disp);
Ben Skeggsb5a794b2012-10-16 14:18:32 +100075 const u32 handle = EVO_CHAN_HANDLE(bclass, head);
76 int ret;
77
Ben Skeggs0ad72862014-08-10 04:10:22 +100078 ret = nvif_object_init(disp, NULL, handle, oclass, data, size,
79 &chan->user);
Ben Skeggsb5a794b2012-10-16 14:18:32 +100080 if (ret)
81 return ret;
82
Ben Skeggsb5a794b2012-10-16 14:18:32 +100083 return 0;
84}
85
86static void
Ben Skeggs0ad72862014-08-10 04:10:22 +100087nv50_chan_destroy(struct nv50_chan *chan)
Ben Skeggsb5a794b2012-10-16 14:18:32 +100088{
Ben Skeggs0ad72862014-08-10 04:10:22 +100089 nvif_object_fini(&chan->user);
Ben Skeggsb5a794b2012-10-16 14:18:32 +100090}
91
92/******************************************************************************
93 * PIO EVO channel
94 *****************************************************************************/
95
Ben Skeggse225f442012-11-21 14:40:21 +100096struct nv50_pioc {
97 struct nv50_chan base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +100098};
99
100static void
Ben Skeggs0ad72862014-08-10 04:10:22 +1000101nv50_pioc_destroy(struct nv50_pioc *pioc)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000102{
Ben Skeggs0ad72862014-08-10 04:10:22 +1000103 nv50_chan_destroy(&pioc->base);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000104}
105
106static int
Ben Skeggs0ad72862014-08-10 04:10:22 +1000107nv50_pioc_create(struct nvif_object *disp, u32 bclass, u8 head,
Ben Skeggse225f442012-11-21 14:40:21 +1000108 void *data, u32 size, struct nv50_pioc *pioc)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000109{
Ben Skeggs0ad72862014-08-10 04:10:22 +1000110 return nv50_chan_create(disp, bclass, head, data, size, &pioc->base);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000111}
112
113/******************************************************************************
114 * DMA EVO channel
115 *****************************************************************************/
116
Ben Skeggse225f442012-11-21 14:40:21 +1000117struct nv50_dmac {
118 struct nv50_chan base;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000119 dma_addr_t handle;
120 u32 *ptr;
Daniel Vetter59ad1462012-12-02 14:49:44 +0100121
Ben Skeggs0ad72862014-08-10 04:10:22 +1000122 struct nvif_object sync;
123 struct nvif_object vram;
124
Daniel Vetter59ad1462012-12-02 14:49:44 +0100125 /* Protects against concurrent pushbuf access to this channel, lock is
126 * grabbed by evo_wait (if the pushbuf reservation is successful) and
127 * dropped again by evo_kick. */
128 struct mutex lock;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000129};
130
131static void
Ben Skeggs0ad72862014-08-10 04:10:22 +1000132nv50_dmac_destroy(struct nv50_dmac *dmac, struct nvif_object *disp)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000133{
Ben Skeggs0ad72862014-08-10 04:10:22 +1000134 nvif_object_fini(&dmac->vram);
135 nvif_object_fini(&dmac->sync);
136
137 nv50_chan_destroy(&dmac->base);
138
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000139 if (dmac->ptr) {
Ben Skeggs0ad72862014-08-10 04:10:22 +1000140 struct pci_dev *pdev = nvkm_device(nvif_device(disp))->pdev;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000141 pci_free_consistent(pdev, PAGE_SIZE, dmac->ptr, dmac->handle);
142 }
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000143}
144
145static int
Ben Skeggs0ad72862014-08-10 04:10:22 +1000146nv50_dmac_create(struct nvif_object *disp, u32 bclass, u8 head,
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000147 void *data, u32 size, u64 syncbuf,
Ben Skeggse225f442012-11-21 14:40:21 +1000148 struct nv50_dmac *dmac)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000149{
Ben Skeggs0ad72862014-08-10 04:10:22 +1000150 struct nouveau_fb *pfb = nvkm_fb(nvif_device(disp));
151 struct nvif_object pushbuf;
152 u32 handle = *(u32 *)data;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000153 int ret;
154
Daniel Vetter59ad1462012-12-02 14:49:44 +0100155 mutex_init(&dmac->lock);
156
Ben Skeggs0ad72862014-08-10 04:10:22 +1000157 dmac->ptr = pci_alloc_consistent(nvkm_device(nvif_device(disp))->pdev,
158 PAGE_SIZE, &dmac->handle);
Ben Skeggs47057302012-11-16 13:58:48 +1000159 if (!dmac->ptr)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000160 return -ENOMEM;
161
Ben Skeggs0ad72862014-08-10 04:10:22 +1000162 ret = nvif_object_init(nvif_object(nvif_device(disp)), NULL, handle,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000163 NV_DMA_FROM_MEMORY,
164 &(struct nv_dma_v0) {
165 .target = NV_DMA_V0_TARGET_PCI_US,
166 .access = NV_DMA_V0_ACCESS_RD,
Ben Skeggs47057302012-11-16 13:58:48 +1000167 .start = dmac->handle + 0x0000,
168 .limit = dmac->handle + 0x0fff,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000169 }, sizeof(struct nv_dma_v0), &pushbuf);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000170 if (ret)
171 return ret;
172
Ben Skeggs0ad72862014-08-10 04:10:22 +1000173 ret = nv50_chan_create(disp, bclass, head, data, size, &dmac->base);
174 nvif_object_fini(&pushbuf);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000175 if (ret)
176 return ret;
177
Ben Skeggsf45f55c2014-08-10 04:10:23 +1000178 ret = nvif_object_init(&dmac->base.user, NULL, 0xf0000000,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000179 NV_DMA_IN_MEMORY,
180 &(struct nv_dma_v0) {
181 .target = NV_DMA_V0_TARGET_VRAM,
182 .access = NV_DMA_V0_ACCESS_RDWR,
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000183 .start = syncbuf + 0x0000,
184 .limit = syncbuf + 0x0fff,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000185 }, sizeof(struct nv_dma_v0),
Ben Skeggs0ad72862014-08-10 04:10:22 +1000186 &dmac->sync);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000187 if (ret)
Ben Skeggs47057302012-11-16 13:58:48 +1000188 return ret;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000189
Ben Skeggsf45f55c2014-08-10 04:10:23 +1000190 ret = nvif_object_init(&dmac->base.user, NULL, 0xf0000001,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000191 NV_DMA_IN_MEMORY,
192 &(struct nv_dma_v0) {
193 .target = NV_DMA_V0_TARGET_VRAM,
194 .access = NV_DMA_V0_ACCESS_RDWR,
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000195 .start = 0,
Ben Skeggsdceef5d2013-03-04 13:01:21 +1000196 .limit = pfb->ram->size - 1,
Ben Skeggs4acfd702014-08-10 04:10:24 +1000197 }, sizeof(struct nv_dma_v0),
Ben Skeggs0ad72862014-08-10 04:10:22 +1000198 &dmac->vram);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000199 if (ret)
Ben Skeggs47057302012-11-16 13:58:48 +1000200 return ret;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000201
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000202 return ret;
203}
204
Ben Skeggse225f442012-11-21 14:40:21 +1000205struct nv50_mast {
206 struct nv50_dmac base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000207};
208
Ben Skeggse225f442012-11-21 14:40:21 +1000209struct nv50_curs {
210 struct nv50_pioc base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000211};
212
Ben Skeggse225f442012-11-21 14:40:21 +1000213struct nv50_sync {
214 struct nv50_dmac base;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000215 u32 addr;
216 u32 data;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000217};
218
Ben Skeggse225f442012-11-21 14:40:21 +1000219struct nv50_ovly {
220 struct nv50_dmac base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000221};
Ben Skeggsf20ce962011-07-08 13:17:01 +1000222
Ben Skeggse225f442012-11-21 14:40:21 +1000223struct nv50_oimm {
224 struct nv50_pioc base;
Ben Skeggs26f6d882011-07-04 16:25:18 +1000225};
226
Ben Skeggse225f442012-11-21 14:40:21 +1000227struct nv50_head {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +1000228 struct nouveau_crtc base;
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000229 struct nouveau_bo *image;
Ben Skeggse225f442012-11-21 14:40:21 +1000230 struct nv50_curs curs;
231 struct nv50_sync sync;
232 struct nv50_ovly ovly;
233 struct nv50_oimm oimm;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000234};
235
Ben Skeggse225f442012-11-21 14:40:21 +1000236#define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c))
237#define nv50_curs(c) (&nv50_head(c)->curs)
238#define nv50_sync(c) (&nv50_head(c)->sync)
239#define nv50_ovly(c) (&nv50_head(c)->ovly)
240#define nv50_oimm(c) (&nv50_head(c)->oimm)
241#define nv50_chan(c) (&(c)->base.base)
Ben Skeggs0ad72862014-08-10 04:10:22 +1000242#define nv50_vers(c) nv50_chan(c)->user.oclass
243
244struct nv50_fbdma {
245 struct list_head head;
246 struct nvif_object core;
247 struct nvif_object base[4];
248};
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000249
Ben Skeggse225f442012-11-21 14:40:21 +1000250struct nv50_disp {
Ben Skeggs0ad72862014-08-10 04:10:22 +1000251 struct nvif_object *disp;
Ben Skeggse225f442012-11-21 14:40:21 +1000252 struct nv50_mast mast;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000253
Ben Skeggs8a423642014-08-10 04:10:19 +1000254 struct list_head fbdma;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000255
256 struct nouveau_bo *sync;
Ben Skeggsdd0e3d52012-10-16 14:00:31 +1000257};
258
Ben Skeggse225f442012-11-21 14:40:21 +1000259static struct nv50_disp *
260nv50_disp(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +1000261{
Ben Skeggs77145f12012-07-31 16:16:21 +1000262 return nouveau_display(dev)->priv;
Ben Skeggs26f6d882011-07-04 16:25:18 +1000263}
264
Ben Skeggse225f442012-11-21 14:40:21 +1000265#define nv50_mast(d) (&nv50_disp(d)->mast)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000266
Ben Skeggsbdb8c212011-11-12 01:30:24 +1000267static struct drm_crtc *
Ben Skeggse225f442012-11-21 14:40:21 +1000268nv50_display_crtc_get(struct drm_encoder *encoder)
Ben Skeggsbdb8c212011-11-12 01:30:24 +1000269{
270 return nouveau_encoder(encoder)->crtc;
271}
272
273/******************************************************************************
274 * EVO channel helpers
275 *****************************************************************************/
Ben Skeggs51beb422011-07-05 10:33:08 +1000276static u32 *
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000277evo_wait(void *evoc, int nr)
Ben Skeggs51beb422011-07-05 10:33:08 +1000278{
Ben Skeggse225f442012-11-21 14:40:21 +1000279 struct nv50_dmac *dmac = evoc;
Ben Skeggs0ad72862014-08-10 04:10:22 +1000280 u32 put = nvif_rd32(&dmac->base.user, 0x0000) / 4;
Ben Skeggs51beb422011-07-05 10:33:08 +1000281
Daniel Vetter59ad1462012-12-02 14:49:44 +0100282 mutex_lock(&dmac->lock);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000283 if (put + nr >= (PAGE_SIZE / 4) - 8) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000284 dmac->ptr[put] = 0x20000000;
Ben Skeggs51beb422011-07-05 10:33:08 +1000285
Ben Skeggs0ad72862014-08-10 04:10:22 +1000286 nvif_wr32(&dmac->base.user, 0x0000, 0x00000000);
287 if (!nvkm_wait(&dmac->base.user, 0x0004, ~0, 0x00000000)) {
Daniel Vetter59ad1462012-12-02 14:49:44 +0100288 mutex_unlock(&dmac->lock);
Ben Skeggs0ad72862014-08-10 04:10:22 +1000289 nv_error(nvkm_object(&dmac->base.user), "channel stalled\n");
Ben Skeggs51beb422011-07-05 10:33:08 +1000290 return NULL;
291 }
292
293 put = 0;
294 }
295
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000296 return dmac->ptr + put;
Ben Skeggs51beb422011-07-05 10:33:08 +1000297}
298
299static void
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000300evo_kick(u32 *push, void *evoc)
Ben Skeggs51beb422011-07-05 10:33:08 +1000301{
Ben Skeggse225f442012-11-21 14:40:21 +1000302 struct nv50_dmac *dmac = evoc;
Ben Skeggs0ad72862014-08-10 04:10:22 +1000303 nvif_wr32(&dmac->base.user, 0x0000, (push - dmac->ptr) << 2);
Daniel Vetter59ad1462012-12-02 14:49:44 +0100304 mutex_unlock(&dmac->lock);
Ben Skeggs51beb422011-07-05 10:33:08 +1000305}
306
307#define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m))
308#define evo_data(p,d) *((p)++) = (d)
309
Ben Skeggs3376ee32011-11-12 14:28:12 +1000310static bool
311evo_sync_wait(void *data)
312{
Ben Skeggs5cc027f2013-02-18 17:50:51 -0500313 if (nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000)
314 return true;
315 usleep_range(1, 2);
316 return false;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000317}
318
319static int
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000320evo_sync(struct drm_device *dev)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000321{
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000322 struct nvif_device *device = &nouveau_drm(dev)->device;
Ben Skeggse225f442012-11-21 14:40:21 +1000323 struct nv50_disp *disp = nv50_disp(dev);
324 struct nv50_mast *mast = nv50_mast(dev);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000325 u32 *push = evo_wait(mast, 8);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000326 if (push) {
Ben Skeggs816af2f2011-11-16 15:48:48 +1000327 nouveau_bo_wr32(disp->sync, EVO_MAST_NTFY, 0x00000000);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000328 evo_mthd(push, 0x0084, 1);
Ben Skeggs816af2f2011-11-16 15:48:48 +1000329 evo_data(push, 0x80000000 | EVO_MAST_NTFY);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000330 evo_mthd(push, 0x0080, 2);
331 evo_data(push, 0x00000000);
332 evo_data(push, 0x00000000);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000333 evo_kick(push, mast);
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000334 if (nv_wait_cb(nvkm_device(device), evo_sync_wait, disp->sync))
Ben Skeggs3376ee32011-11-12 14:28:12 +1000335 return 0;
336 }
337
338 return -EBUSY;
339}
340
341/******************************************************************************
Ben Skeggsa63a97e2011-11-16 15:22:34 +1000342 * Page flipping channel
Ben Skeggs3376ee32011-11-12 14:28:12 +1000343 *****************************************************************************/
344struct nouveau_bo *
Ben Skeggse225f442012-11-21 14:40:21 +1000345nv50_display_crtc_sema(struct drm_device *dev, int crtc)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000346{
Ben Skeggse225f442012-11-21 14:40:21 +1000347 return nv50_disp(dev)->sync;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000348}
349
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000350struct nv50_display_flip {
351 struct nv50_disp *disp;
352 struct nv50_sync *chan;
353};
354
355static bool
356nv50_display_flip_wait(void *data)
357{
358 struct nv50_display_flip *flip = data;
359 if (nouveau_bo_rd32(flip->disp->sync, flip->chan->addr / 4) ==
Calvin Owensb1ea3e62013-04-07 21:01:19 -0500360 flip->chan->data)
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000361 return true;
362 usleep_range(1, 2);
363 return false;
364}
365
Ben Skeggs3376ee32011-11-12 14:28:12 +1000366void
Ben Skeggse225f442012-11-21 14:40:21 +1000367nv50_display_flip_stop(struct drm_crtc *crtc)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000368{
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000369 struct nvif_device *device = &nouveau_drm(crtc->dev)->device;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000370 struct nv50_display_flip flip = {
371 .disp = nv50_disp(crtc->dev),
372 .chan = nv50_sync(crtc),
373 };
Ben Skeggs3376ee32011-11-12 14:28:12 +1000374 u32 *push;
375
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000376 push = evo_wait(flip.chan, 8);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000377 if (push) {
378 evo_mthd(push, 0x0084, 1);
379 evo_data(push, 0x00000000);
380 evo_mthd(push, 0x0094, 1);
381 evo_data(push, 0x00000000);
382 evo_mthd(push, 0x00c0, 1);
383 evo_data(push, 0x00000000);
384 evo_mthd(push, 0x0080, 1);
385 evo_data(push, 0x00000000);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000386 evo_kick(push, flip.chan);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000387 }
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000388
Ben Skeggs967e7bd2014-08-10 04:10:22 +1000389 nv_wait_cb(nvkm_device(device), nv50_display_flip_wait, &flip);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000390}
391
392int
Ben Skeggse225f442012-11-21 14:40:21 +1000393nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
Ben Skeggs3376ee32011-11-12 14:28:12 +1000394 struct nouveau_channel *chan, u32 swap_interval)
395{
396 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000397 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000398 struct nv50_head *head = nv50_head(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +1000399 struct nv50_sync *sync = nv50_sync(crtc);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000400 u32 *push;
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000401 int ret;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000402
403 swap_interval <<= 4;
404 if (swap_interval == 0)
405 swap_interval |= 0x100;
Ben Skeggsf60b6e72013-03-19 15:20:00 +1000406 if (chan == NULL)
407 evo_sync(crtc->dev);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000408
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000409 push = evo_wait(sync, 128);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000410 if (unlikely(push == NULL))
411 return -EBUSY;
412
Ben Skeggsbbf89062014-08-10 04:10:25 +1000413 if (chan && chan->object->oclass < G82_CHANNEL_GPFIFO) {
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000414 ret = RING_SPACE(chan, 8);
415 if (ret)
416 return ret;
Ben Skeggs67f97182013-02-26 12:02:54 +1000417
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000418 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000419 OUT_RING (chan, NvEvoSema0 + nv_crtc->index);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000420 OUT_RING (chan, sync->addr ^ 0x10);
421 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
422 OUT_RING (chan, sync->data + 1);
423 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_OFFSET, 2);
424 OUT_RING (chan, sync->addr);
425 OUT_RING (chan, sync->data);
426 } else
Ben Skeggsbbf89062014-08-10 04:10:25 +1000427 if (chan && chan->object->oclass < FERMI_CHANNEL_GPFIFO) {
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000428 u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000429 ret = RING_SPACE(chan, 12);
430 if (ret)
431 return ret;
Ben Skeggsa34caf72013-02-14 09:28:37 +1000432
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000433 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
Ben Skeggs0ad72862014-08-10 04:10:22 +1000434 OUT_RING (chan, chan->vram.handle);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000435 BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
436 OUT_RING (chan, upper_32_bits(addr ^ 0x10));
437 OUT_RING (chan, lower_32_bits(addr ^ 0x10));
438 OUT_RING (chan, sync->data + 1);
439 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG);
440 BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
441 OUT_RING (chan, upper_32_bits(addr));
442 OUT_RING (chan, lower_32_bits(addr));
443 OUT_RING (chan, sync->data);
444 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL);
445 } else
446 if (chan) {
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000447 u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000448 ret = RING_SPACE(chan, 10);
449 if (ret)
450 return ret;
Ben Skeggs67f97182013-02-26 12:02:54 +1000451
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000452 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
453 OUT_RING (chan, upper_32_bits(addr ^ 0x10));
454 OUT_RING (chan, lower_32_bits(addr ^ 0x10));
455 OUT_RING (chan, sync->data + 1);
456 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG |
457 NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD);
458 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
459 OUT_RING (chan, upper_32_bits(addr));
460 OUT_RING (chan, lower_32_bits(addr));
461 OUT_RING (chan, sync->data);
462 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL |
463 NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD);
464 }
Ben Skeggs35bcf5d2012-04-30 11:34:10 -0500465
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000466 if (chan) {
467 sync->addr ^= 0x10;
468 sync->data++;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000469 FIRE_RING (chan);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000470 }
471
472 /* queue the flip */
473 evo_mthd(push, 0x0100, 1);
474 evo_data(push, 0xfffe0000);
475 evo_mthd(push, 0x0084, 1);
476 evo_data(push, swap_interval);
477 if (!(swap_interval & 0x00000100)) {
478 evo_mthd(push, 0x00e0, 1);
479 evo_data(push, 0x40000000);
480 }
481 evo_mthd(push, 0x0088, 4);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +1000482 evo_data(push, sync->addr);
483 evo_data(push, sync->data++);
484 evo_data(push, sync->data);
Ben Skeggsf45f55c2014-08-10 04:10:23 +1000485 evo_data(push, sync->base.sync.handle);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000486 evo_mthd(push, 0x00a0, 2);
487 evo_data(push, 0x00000000);
488 evo_data(push, 0x00000000);
489 evo_mthd(push, 0x00c0, 1);
Ben Skeggs8a423642014-08-10 04:10:19 +1000490 evo_data(push, nv_fb->r_handle);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000491 evo_mthd(push, 0x0110, 2);
492 evo_data(push, 0x00000000);
493 evo_data(push, 0x00000000);
Ben Skeggse225f442012-11-21 14:40:21 +1000494 if (nv50_vers(sync) < NVD0_DISP_SYNC_CLASS) {
Ben Skeggsed5085a52012-11-16 13:16:51 +1000495 evo_mthd(push, 0x0800, 5);
496 evo_data(push, nv_fb->nvbo->bo.offset >> 8);
497 evo_data(push, 0);
498 evo_data(push, (fb->height << 16) | fb->width);
499 evo_data(push, nv_fb->r_pitch);
500 evo_data(push, nv_fb->r_format);
501 } else {
502 evo_mthd(push, 0x0400, 5);
503 evo_data(push, nv_fb->nvbo->bo.offset >> 8);
504 evo_data(push, 0);
505 evo_data(push, (fb->height << 16) | fb->width);
506 evo_data(push, nv_fb->r_pitch);
507 evo_data(push, nv_fb->r_format);
508 }
Ben Skeggs3376ee32011-11-12 14:28:12 +1000509 evo_mthd(push, 0x0080, 1);
510 evo_data(push, 0x00000000);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000511 evo_kick(push, sync);
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000512
513 nouveau_bo_ref(nv_fb->nvbo, &head->image);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000514 return 0;
515}
516
Ben Skeggs26f6d882011-07-04 16:25:18 +1000517/******************************************************************************
Ben Skeggs438d99e2011-07-05 16:48:06 +1000518 * CRTC
519 *****************************************************************************/
520static int
Ben Skeggse225f442012-11-21 14:40:21 +1000521nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000522{
Ben Skeggse225f442012-11-21 14:40:21 +1000523 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde691852011-10-17 12:23:41 +1000524 struct nouveau_connector *nv_connector;
525 struct drm_connector *connector;
526 u32 *push, mode = 0x00;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000527
Ben Skeggs488ff202011-10-17 10:38:10 +1000528 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggsde691852011-10-17 12:23:41 +1000529 connector = &nv_connector->base;
530 if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) {
Matt Roperf4510a22014-04-01 15:22:40 -0700531 if (nv_crtc->base.primary->fb->depth > connector->display_info.bpc * 3)
Ben Skeggsde691852011-10-17 12:23:41 +1000532 mode = DITHERING_MODE_DYNAMIC2X2;
533 } else {
534 mode = nv_connector->dithering_mode;
535 }
536
537 if (nv_connector->dithering_depth == DITHERING_DEPTH_AUTO) {
538 if (connector->display_info.bpc >= 8)
539 mode |= DITHERING_DEPTH_8BPC;
540 } else {
541 mode |= nv_connector->dithering_depth;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000542 }
543
Ben Skeggsde8268c2012-11-16 10:24:31 +1000544 push = evo_wait(mast, 4);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000545 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000546 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000547 evo_mthd(push, 0x08a0 + (nv_crtc->index * 0x0400), 1);
548 evo_data(push, mode);
549 } else
Ben Skeggse225f442012-11-21 14:40:21 +1000550 if (nv50_vers(mast) < NVE0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000551 evo_mthd(push, 0x0490 + (nv_crtc->index * 0x0300), 1);
552 evo_data(push, mode);
553 } else {
554 evo_mthd(push, 0x04a0 + (nv_crtc->index * 0x0300), 1);
555 evo_data(push, mode);
556 }
557
Ben Skeggs438d99e2011-07-05 16:48:06 +1000558 if (update) {
559 evo_mthd(push, 0x0080, 1);
560 evo_data(push, 0x00000000);
561 }
Ben Skeggsde8268c2012-11-16 10:24:31 +1000562 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000563 }
564
565 return 0;
566}
567
568static int
Ben Skeggse225f442012-11-21 14:40:21 +1000569nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000570{
Ben Skeggse225f442012-11-21 14:40:21 +1000571 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggs92854622011-11-11 23:49:06 +1000572 struct drm_display_mode *omode, *umode = &nv_crtc->base.mode;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000573 struct drm_crtc *crtc = &nv_crtc->base;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000574 struct nouveau_connector *nv_connector;
Ben Skeggs92854622011-11-11 23:49:06 +1000575 int mode = DRM_MODE_SCALE_NONE;
576 u32 oX, oY, *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000577
Ben Skeggs92854622011-11-11 23:49:06 +1000578 /* start off at the resolution we programmed the crtc for, this
579 * effectively handles NONE/FULL scaling
580 */
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000581 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggs92854622011-11-11 23:49:06 +1000582 if (nv_connector && nv_connector->native_mode)
583 mode = nv_connector->scaling_mode;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000584
Ben Skeggs92854622011-11-11 23:49:06 +1000585 if (mode != DRM_MODE_SCALE_NONE)
586 omode = nv_connector->native_mode;
587 else
588 omode = umode;
589
590 oX = omode->hdisplay;
591 oY = omode->vdisplay;
592 if (omode->flags & DRM_MODE_FLAG_DBLSCAN)
593 oY *= 2;
594
595 /* add overscan compensation if necessary, will keep the aspect
596 * ratio the same as the backend mode unless overridden by the
597 * user setting both hborder and vborder properties.
598 */
599 if (nv_connector && ( nv_connector->underscan == UNDERSCAN_ON ||
600 (nv_connector->underscan == UNDERSCAN_AUTO &&
601 nv_connector->edid &&
602 drm_detect_hdmi_monitor(nv_connector->edid)))) {
603 u32 bX = nv_connector->underscan_hborder;
604 u32 bY = nv_connector->underscan_vborder;
605 u32 aspect = (oY << 19) / oX;
606
607 if (bX) {
608 oX -= (bX * 2);
609 if (bY) oY -= (bY * 2);
610 else oY = ((oX * aspect) + (aspect / 2)) >> 19;
611 } else {
612 oX -= (oX >> 4) + 32;
613 if (bY) oY -= (bY * 2);
614 else oY = ((oX * aspect) + (aspect / 2)) >> 19;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000615 }
616 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000617
Ben Skeggs92854622011-11-11 23:49:06 +1000618 /* handle CENTER/ASPECT scaling, taking into account the areas
619 * removed already for overscan compensation
620 */
621 switch (mode) {
622 case DRM_MODE_SCALE_CENTER:
623 oX = min((u32)umode->hdisplay, oX);
624 oY = min((u32)umode->vdisplay, oY);
625 /* fall-through */
626 case DRM_MODE_SCALE_ASPECT:
627 if (oY < oX) {
628 u32 aspect = (umode->hdisplay << 19) / umode->vdisplay;
629 oX = ((oY * aspect) + (aspect / 2)) >> 19;
630 } else {
631 u32 aspect = (umode->vdisplay << 19) / umode->hdisplay;
632 oY = ((oX * aspect) + (aspect / 2)) >> 19;
633 }
634 break;
635 default:
636 break;
637 }
638
Ben Skeggsde8268c2012-11-16 10:24:31 +1000639 push = evo_wait(mast, 8);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000640 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000641 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000642 /*XXX: SCALE_CTRL_ACTIVE??? */
643 evo_mthd(push, 0x08d8 + (nv_crtc->index * 0x400), 2);
644 evo_data(push, (oY << 16) | oX);
645 evo_data(push, (oY << 16) | oX);
646 evo_mthd(push, 0x08a4 + (nv_crtc->index * 0x400), 1);
647 evo_data(push, 0x00000000);
648 evo_mthd(push, 0x08c8 + (nv_crtc->index * 0x400), 1);
649 evo_data(push, umode->vdisplay << 16 | umode->hdisplay);
650 } else {
651 evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3);
652 evo_data(push, (oY << 16) | oX);
653 evo_data(push, (oY << 16) | oX);
654 evo_data(push, (oY << 16) | oX);
655 evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1);
656 evo_data(push, 0x00000000);
657 evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1);
658 evo_data(push, umode->vdisplay << 16 | umode->hdisplay);
659 }
660
661 evo_kick(push, mast);
662
Ben Skeggs3376ee32011-11-12 14:28:12 +1000663 if (update) {
Ben Skeggse225f442012-11-21 14:40:21 +1000664 nv50_display_flip_stop(crtc);
Matt Roperf4510a22014-04-01 15:22:40 -0700665 nv50_display_flip_next(crtc, crtc->primary->fb,
666 NULL, 1);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000667 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000668 }
669
670 return 0;
671}
672
673static int
Ben Skeggse225f442012-11-21 14:40:21 +1000674nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggsf9887d02012-11-21 13:03:42 +1000675{
Ben Skeggse225f442012-11-21 14:40:21 +1000676 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsf9887d02012-11-21 13:03:42 +1000677 u32 *push, hue, vib;
678 int adj;
679
680 adj = (nv_crtc->color_vibrance > 0) ? 50 : 0;
681 vib = ((nv_crtc->color_vibrance * 2047 + adj) / 100) & 0xfff;
682 hue = ((nv_crtc->vibrant_hue * 2047) / 100) & 0xfff;
683
684 push = evo_wait(mast, 16);
685 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000686 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsf9887d02012-11-21 13:03:42 +1000687 evo_mthd(push, 0x08a8 + (nv_crtc->index * 0x400), 1);
688 evo_data(push, (hue << 20) | (vib << 8));
689 } else {
690 evo_mthd(push, 0x0498 + (nv_crtc->index * 0x300), 1);
691 evo_data(push, (hue << 20) | (vib << 8));
692 }
693
694 if (update) {
695 evo_mthd(push, 0x0080, 1);
696 evo_data(push, 0x00000000);
697 }
698 evo_kick(push, mast);
699 }
700
701 return 0;
702}
703
704static int
Ben Skeggse225f442012-11-21 14:40:21 +1000705nv50_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb,
Ben Skeggs438d99e2011-07-05 16:48:06 +1000706 int x, int y, bool update)
707{
708 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb);
Ben Skeggse225f442012-11-21 14:40:21 +1000709 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000710 u32 *push;
711
Ben Skeggsde8268c2012-11-16 10:24:31 +1000712 push = evo_wait(mast, 16);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000713 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000714 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000715 evo_mthd(push, 0x0860 + (nv_crtc->index * 0x400), 1);
716 evo_data(push, nvfb->nvbo->bo.offset >> 8);
717 evo_mthd(push, 0x0868 + (nv_crtc->index * 0x400), 3);
718 evo_data(push, (fb->height << 16) | fb->width);
719 evo_data(push, nvfb->r_pitch);
720 evo_data(push, nvfb->r_format);
721 evo_mthd(push, 0x08c0 + (nv_crtc->index * 0x400), 1);
722 evo_data(push, (y << 16) | x);
Ben Skeggse225f442012-11-21 14:40:21 +1000723 if (nv50_vers(mast) > NV50_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000724 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
Ben Skeggs8a423642014-08-10 04:10:19 +1000725 evo_data(push, nvfb->r_handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000726 }
727 } else {
728 evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1);
729 evo_data(push, nvfb->nvbo->bo.offset >> 8);
730 evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4);
731 evo_data(push, (fb->height << 16) | fb->width);
732 evo_data(push, nvfb->r_pitch);
733 evo_data(push, nvfb->r_format);
Ben Skeggs8a423642014-08-10 04:10:19 +1000734 evo_data(push, nvfb->r_handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000735 evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1);
736 evo_data(push, (y << 16) | x);
737 }
738
Ben Skeggsa46232e2011-07-07 15:23:48 +1000739 if (update) {
740 evo_mthd(push, 0x0080, 1);
741 evo_data(push, 0x00000000);
742 }
Ben Skeggsde8268c2012-11-16 10:24:31 +1000743 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000744 }
745
Ben Skeggs8a423642014-08-10 04:10:19 +1000746 nv_crtc->fb.handle = nvfb->r_handle;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000747 return 0;
748}
749
750static void
Ben Skeggse225f442012-11-21 14:40:21 +1000751nv50_crtc_cursor_show(struct nouveau_crtc *nv_crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000752{
Ben Skeggse225f442012-11-21 14:40:21 +1000753 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000754 u32 *push = evo_wait(mast, 16);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000755 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000756 if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000757 evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2);
758 evo_data(push, 0x85000000);
759 evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
760 } else
Ben Skeggse225f442012-11-21 14:40:21 +1000761 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000762 evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2);
763 evo_data(push, 0x85000000);
764 evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
765 evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1);
Ben Skeggsf45f55c2014-08-10 04:10:23 +1000766 evo_data(push, mast->base.vram.handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000767 } else {
Ben Skeggs438d99e2011-07-05 16:48:06 +1000768 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2);
769 evo_data(push, 0x85000000);
770 evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
771 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
Ben Skeggsf45f55c2014-08-10 04:10:23 +1000772 evo_data(push, mast->base.vram.handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000773 }
774 evo_kick(push, mast);
775 }
776}
777
778static void
Ben Skeggse225f442012-11-21 14:40:21 +1000779nv50_crtc_cursor_hide(struct nouveau_crtc *nv_crtc)
Ben Skeggsde8268c2012-11-16 10:24:31 +1000780{
Ben Skeggse225f442012-11-21 14:40:21 +1000781 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000782 u32 *push = evo_wait(mast, 16);
783 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000784 if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000785 evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 1);
786 evo_data(push, 0x05000000);
787 } else
Ben Skeggse225f442012-11-21 14:40:21 +1000788 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000789 evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 1);
790 evo_data(push, 0x05000000);
791 evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1);
792 evo_data(push, 0x00000000);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000793 } else {
794 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1);
795 evo_data(push, 0x05000000);
796 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
797 evo_data(push, 0x00000000);
798 }
Ben Skeggsde8268c2012-11-16 10:24:31 +1000799 evo_kick(push, mast);
800 }
801}
Ben Skeggs438d99e2011-07-05 16:48:06 +1000802
Ben Skeggsde8268c2012-11-16 10:24:31 +1000803static void
Ben Skeggse225f442012-11-21 14:40:21 +1000804nv50_crtc_cursor_show_hide(struct nouveau_crtc *nv_crtc, bool show, bool update)
Ben Skeggsde8268c2012-11-16 10:24:31 +1000805{
Ben Skeggse225f442012-11-21 14:40:21 +1000806 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000807
808 if (show)
Ben Skeggse225f442012-11-21 14:40:21 +1000809 nv50_crtc_cursor_show(nv_crtc);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000810 else
Ben Skeggse225f442012-11-21 14:40:21 +1000811 nv50_crtc_cursor_hide(nv_crtc);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000812
813 if (update) {
814 u32 *push = evo_wait(mast, 2);
815 if (push) {
Ben Skeggs438d99e2011-07-05 16:48:06 +1000816 evo_mthd(push, 0x0080, 1);
817 evo_data(push, 0x00000000);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000818 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000819 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000820 }
821}
822
823static void
Ben Skeggse225f442012-11-21 14:40:21 +1000824nv50_crtc_dpms(struct drm_crtc *crtc, int mode)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000825{
826}
827
828static void
Ben Skeggse225f442012-11-21 14:40:21 +1000829nv50_crtc_prepare(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000830{
831 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +1000832 struct nv50_mast *mast = nv50_mast(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000833 u32 *push;
834
Ben Skeggse225f442012-11-21 14:40:21 +1000835 nv50_display_flip_stop(crtc);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000836
Ben Skeggs56d237d2014-05-19 14:54:33 +1000837 push = evo_wait(mast, 6);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000838 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000839 if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000840 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
841 evo_data(push, 0x00000000);
842 evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 1);
843 evo_data(push, 0x40000000);
844 } else
Ben Skeggse225f442012-11-21 14:40:21 +1000845 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000846 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
847 evo_data(push, 0x00000000);
848 evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 1);
849 evo_data(push, 0x40000000);
850 evo_mthd(push, 0x085c + (nv_crtc->index * 0x400), 1);
851 evo_data(push, 0x00000000);
852 } else {
853 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
854 evo_data(push, 0x00000000);
855 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1);
856 evo_data(push, 0x03000000);
857 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
858 evo_data(push, 0x00000000);
859 }
860
861 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000862 }
863
Ben Skeggse225f442012-11-21 14:40:21 +1000864 nv50_crtc_cursor_show_hide(nv_crtc, false, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000865}
866
867static void
Ben Skeggse225f442012-11-21 14:40:21 +1000868nv50_crtc_commit(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000869{
870 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +1000871 struct nv50_mast *mast = nv50_mast(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000872 u32 *push;
873
Ben Skeggsde8268c2012-11-16 10:24:31 +1000874 push = evo_wait(mast, 32);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000875 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000876 if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000877 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
Ben Skeggs8a423642014-08-10 04:10:19 +1000878 evo_data(push, nv_crtc->fb.handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000879 evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 2);
880 evo_data(push, 0xc0000000);
881 evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
882 } else
Ben Skeggse225f442012-11-21 14:40:21 +1000883 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000884 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
Ben Skeggs8a423642014-08-10 04:10:19 +1000885 evo_data(push, nv_crtc->fb.handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000886 evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 2);
887 evo_data(push, 0xc0000000);
888 evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
889 evo_mthd(push, 0x085c + (nv_crtc->index * 0x400), 1);
Ben Skeggsf45f55c2014-08-10 04:10:23 +1000890 evo_data(push, mast->base.vram.handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000891 } else {
892 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
Ben Skeggs8a423642014-08-10 04:10:19 +1000893 evo_data(push, nv_crtc->fb.handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000894 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4);
895 evo_data(push, 0x83000000);
896 evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
897 evo_data(push, 0x00000000);
898 evo_data(push, 0x00000000);
899 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
Ben Skeggsf45f55c2014-08-10 04:10:23 +1000900 evo_data(push, mast->base.vram.handle);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000901 evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1);
902 evo_data(push, 0xffffff00);
903 }
904
905 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000906 }
907
Ben Skeggse225f442012-11-21 14:40:21 +1000908 nv50_crtc_cursor_show_hide(nv_crtc, nv_crtc->cursor.visible, true);
Matt Roperf4510a22014-04-01 15:22:40 -0700909 nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000910}
911
912static bool
Ben Skeggse225f442012-11-21 14:40:21 +1000913nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
Ben Skeggs438d99e2011-07-05 16:48:06 +1000914 struct drm_display_mode *adjusted_mode)
915{
Ben Skeggseb2e9682014-01-24 10:13:23 +1000916 drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000917 return true;
918}
919
920static int
Ben Skeggse225f442012-11-21 14:40:21 +1000921nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000922{
Matt Roperf4510a22014-04-01 15:22:40 -0700923 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb);
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000924 struct nv50_head *head = nv50_head(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000925 int ret;
926
927 ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000928 if (ret == 0) {
929 if (head->image)
930 nouveau_bo_unpin(head->image);
931 nouveau_bo_ref(nvfb->nvbo, &head->image);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000932 }
933
Ben Skeggs8dda53f2013-07-09 12:35:55 +1000934 return ret;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000935}
936
937static int
Ben Skeggse225f442012-11-21 14:40:21 +1000938nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
Ben Skeggs438d99e2011-07-05 16:48:06 +1000939 struct drm_display_mode *mode, int x, int y,
940 struct drm_framebuffer *old_fb)
941{
Ben Skeggse225f442012-11-21 14:40:21 +1000942 struct nv50_mast *mast = nv50_mast(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000943 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
944 struct nouveau_connector *nv_connector;
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000945 u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1;
946 u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
947 u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks;
948 u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks;
949 u32 vblan2e = 0, vblan2s = 1;
Ben Skeggs3488c572012-03-12 11:42:20 +1000950 u32 *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000951 int ret;
952
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000953 hactive = mode->htotal;
954 hsynce = mode->hsync_end - mode->hsync_start - 1;
955 hbackp = mode->htotal - mode->hsync_end;
956 hblanke = hsynce + hbackp;
957 hfrontp = mode->hsync_start - mode->hdisplay;
958 hblanks = mode->htotal - hfrontp - 1;
959
960 vactive = mode->vtotal * vscan / ilace;
961 vsynce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1;
962 vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace;
963 vblanke = vsynce + vbackp;
964 vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
965 vblanks = vactive - vfrontp - 1;
966 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
967 vblan2e = vactive + vsynce + vbackp;
968 vblan2s = vblan2e + (mode->vdisplay * vscan / ilace);
969 vactive = (vactive * 2) + 1;
Ben Skeggs2d1d8982011-11-11 23:39:22 +1000970 }
971
Ben Skeggse225f442012-11-21 14:40:21 +1000972 ret = nv50_crtc_swap_fbs(crtc, old_fb);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000973 if (ret)
974 return ret;
975
Ben Skeggsde8268c2012-11-16 10:24:31 +1000976 push = evo_wait(mast, 64);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000977 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000978 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000979 evo_mthd(push, 0x0804 + (nv_crtc->index * 0x400), 2);
980 evo_data(push, 0x00800000 | mode->clock);
981 evo_data(push, (ilace == 2) ? 2 : 0);
982 evo_mthd(push, 0x0810 + (nv_crtc->index * 0x400), 6);
983 evo_data(push, 0x00000000);
984 evo_data(push, (vactive << 16) | hactive);
985 evo_data(push, ( vsynce << 16) | hsynce);
986 evo_data(push, (vblanke << 16) | hblanke);
987 evo_data(push, (vblanks << 16) | hblanks);
988 evo_data(push, (vblan2e << 16) | vblan2s);
989 evo_mthd(push, 0x082c + (nv_crtc->index * 0x400), 1);
990 evo_data(push, 0x00000000);
991 evo_mthd(push, 0x0900 + (nv_crtc->index * 0x400), 2);
992 evo_data(push, 0x00000311);
993 evo_data(push, 0x00000100);
994 } else {
995 evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 6);
996 evo_data(push, 0x00000000);
997 evo_data(push, (vactive << 16) | hactive);
998 evo_data(push, ( vsynce << 16) | hsynce);
999 evo_data(push, (vblanke << 16) | hblanke);
1000 evo_data(push, (vblanks << 16) | hblanks);
1001 evo_data(push, (vblan2e << 16) | vblan2s);
1002 evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1);
1003 evo_data(push, 0x00000000); /* ??? */
1004 evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3);
1005 evo_data(push, mode->clock * 1000);
1006 evo_data(push, 0x00200000); /* ??? */
1007 evo_data(push, mode->clock * 1000);
1008 evo_mthd(push, 0x04d0 + (nv_crtc->index * 0x300), 2);
1009 evo_data(push, 0x00000311);
1010 evo_data(push, 0x00000100);
1011 }
1012
1013 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001014 }
1015
1016 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001017 nv50_crtc_set_dither(nv_crtc, false);
1018 nv50_crtc_set_scale(nv_crtc, false);
1019 nv50_crtc_set_color_vibrance(nv_crtc, false);
Matt Roperf4510a22014-04-01 15:22:40 -07001020 nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001021 return 0;
1022}
1023
1024static int
Ben Skeggse225f442012-11-21 14:40:21 +10001025nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001026 struct drm_framebuffer *old_fb)
1027{
Ben Skeggs77145f12012-07-31 16:16:21 +10001028 struct nouveau_drm *drm = nouveau_drm(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001029 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1030 int ret;
1031
Matt Roperf4510a22014-04-01 15:22:40 -07001032 if (!crtc->primary->fb) {
Ben Skeggs77145f12012-07-31 16:16:21 +10001033 NV_DEBUG(drm, "No FB bound\n");
Ben Skeggs84e2ad82011-08-26 09:40:39 +10001034 return 0;
1035 }
1036
Ben Skeggse225f442012-11-21 14:40:21 +10001037 ret = nv50_crtc_swap_fbs(crtc, old_fb);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001038 if (ret)
1039 return ret;
1040
Ben Skeggse225f442012-11-21 14:40:21 +10001041 nv50_display_flip_stop(crtc);
Matt Roperf4510a22014-04-01 15:22:40 -07001042 nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, true);
1043 nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001044 return 0;
1045}
1046
1047static int
Ben Skeggse225f442012-11-21 14:40:21 +10001048nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001049 struct drm_framebuffer *fb, int x, int y,
1050 enum mode_set_atomic state)
1051{
1052 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001053 nv50_display_flip_stop(crtc);
1054 nv50_crtc_set_image(nv_crtc, fb, x, y, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001055 return 0;
1056}
1057
1058static void
Ben Skeggse225f442012-11-21 14:40:21 +10001059nv50_crtc_lut_load(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001060{
Ben Skeggse225f442012-11-21 14:40:21 +10001061 struct nv50_disp *disp = nv50_disp(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001062 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1063 void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
1064 int i;
1065
1066 for (i = 0; i < 256; i++) {
Ben Skeggsde8268c2012-11-16 10:24:31 +10001067 u16 r = nv_crtc->lut.r[i] >> 2;
1068 u16 g = nv_crtc->lut.g[i] >> 2;
1069 u16 b = nv_crtc->lut.b[i] >> 2;
1070
Ben Skeggs0ad72862014-08-10 04:10:22 +10001071 if (disp->disp->oclass < NVD0_DISP_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +10001072 writew(r + 0x0000, lut + (i * 0x08) + 0);
1073 writew(g + 0x0000, lut + (i * 0x08) + 2);
1074 writew(b + 0x0000, lut + (i * 0x08) + 4);
1075 } else {
1076 writew(r + 0x6000, lut + (i * 0x20) + 0);
1077 writew(g + 0x6000, lut + (i * 0x20) + 2);
1078 writew(b + 0x6000, lut + (i * 0x20) + 4);
1079 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10001080 }
1081}
1082
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001083static void
1084nv50_crtc_disable(struct drm_crtc *crtc)
1085{
1086 struct nv50_head *head = nv50_head(crtc);
Ben Skeggsefa366f2014-06-05 12:56:35 +10001087 evo_sync(crtc->dev);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001088 if (head->image)
1089 nouveau_bo_unpin(head->image);
1090 nouveau_bo_ref(NULL, &head->image);
1091}
1092
Ben Skeggs438d99e2011-07-05 16:48:06 +10001093static int
Ben Skeggse225f442012-11-21 14:40:21 +10001094nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001095 uint32_t handle, uint32_t width, uint32_t height)
1096{
1097 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1098 struct drm_device *dev = crtc->dev;
1099 struct drm_gem_object *gem;
1100 struct nouveau_bo *nvbo;
1101 bool visible = (handle != 0);
1102 int i, ret = 0;
1103
1104 if (visible) {
1105 if (width != 64 || height != 64)
1106 return -EINVAL;
1107
1108 gem = drm_gem_object_lookup(dev, file_priv, handle);
1109 if (unlikely(!gem))
1110 return -ENOENT;
1111 nvbo = nouveau_gem_object(gem);
1112
1113 ret = nouveau_bo_map(nvbo);
1114 if (ret == 0) {
1115 for (i = 0; i < 64 * 64; i++) {
1116 u32 v = nouveau_bo_rd32(nvbo, i);
1117 nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v);
1118 }
1119 nouveau_bo_unmap(nvbo);
1120 }
1121
1122 drm_gem_object_unreference_unlocked(gem);
1123 }
1124
1125 if (visible != nv_crtc->cursor.visible) {
Ben Skeggse225f442012-11-21 14:40:21 +10001126 nv50_crtc_cursor_show_hide(nv_crtc, visible, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001127 nv_crtc->cursor.visible = visible;
1128 }
1129
1130 return ret;
1131}
1132
1133static int
Ben Skeggse225f442012-11-21 14:40:21 +10001134nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001135{
Ben Skeggse225f442012-11-21 14:40:21 +10001136 struct nv50_curs *curs = nv50_curs(crtc);
1137 struct nv50_chan *chan = nv50_chan(curs);
Ben Skeggs0ad72862014-08-10 04:10:22 +10001138 nvif_wr32(&chan->user, 0x0084, (y << 16) | (x & 0xffff));
1139 nvif_wr32(&chan->user, 0x0080, 0x00000000);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001140 return 0;
1141}
1142
1143static void
Ben Skeggse225f442012-11-21 14:40:21 +10001144nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001145 uint32_t start, uint32_t size)
1146{
1147 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Dan Carpenterbdefc8c2013-11-28 01:18:47 +03001148 u32 end = min_t(u32, start + size, 256);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001149 u32 i;
1150
1151 for (i = start; i < end; i++) {
1152 nv_crtc->lut.r[i] = r[i];
1153 nv_crtc->lut.g[i] = g[i];
1154 nv_crtc->lut.b[i] = b[i];
1155 }
1156
Ben Skeggse225f442012-11-21 14:40:21 +10001157 nv50_crtc_lut_load(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001158}
1159
1160static void
Ben Skeggse225f442012-11-21 14:40:21 +10001161nv50_crtc_destroy(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001162{
1163 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001164 struct nv50_disp *disp = nv50_disp(crtc->dev);
1165 struct nv50_head *head = nv50_head(crtc);
Ben Skeggs0ad72862014-08-10 04:10:22 +10001166 struct nv50_fbdma *fbdma;
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001167
Ben Skeggs0ad72862014-08-10 04:10:22 +10001168 list_for_each_entry(fbdma, &disp->fbdma, head) {
1169 nvif_object_fini(&fbdma->base[nv_crtc->index]);
1170 }
1171
1172 nv50_dmac_destroy(&head->ovly.base, disp->disp);
1173 nv50_pioc_destroy(&head->oimm.base);
1174 nv50_dmac_destroy(&head->sync.base, disp->disp);
1175 nv50_pioc_destroy(&head->curs.base);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001176
1177 /*XXX: this shouldn't be necessary, but the core doesn't call
1178 * disconnect() during the cleanup paths
1179 */
1180 if (head->image)
1181 nouveau_bo_unpin(head->image);
1182 nouveau_bo_ref(NULL, &head->image);
1183
Ben Skeggs438d99e2011-07-05 16:48:06 +10001184 nouveau_bo_unmap(nv_crtc->cursor.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001185 if (nv_crtc->cursor.nvbo)
1186 nouveau_bo_unpin(nv_crtc->cursor.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001187 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001188
Ben Skeggs438d99e2011-07-05 16:48:06 +10001189 nouveau_bo_unmap(nv_crtc->lut.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001190 if (nv_crtc->lut.nvbo)
1191 nouveau_bo_unpin(nv_crtc->lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001192 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001193
Ben Skeggs438d99e2011-07-05 16:48:06 +10001194 drm_crtc_cleanup(crtc);
1195 kfree(crtc);
1196}
1197
Ben Skeggse225f442012-11-21 14:40:21 +10001198static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = {
1199 .dpms = nv50_crtc_dpms,
1200 .prepare = nv50_crtc_prepare,
1201 .commit = nv50_crtc_commit,
1202 .mode_fixup = nv50_crtc_mode_fixup,
1203 .mode_set = nv50_crtc_mode_set,
1204 .mode_set_base = nv50_crtc_mode_set_base,
1205 .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
1206 .load_lut = nv50_crtc_lut_load,
Ben Skeggs8dda53f2013-07-09 12:35:55 +10001207 .disable = nv50_crtc_disable,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001208};
1209
Ben Skeggse225f442012-11-21 14:40:21 +10001210static const struct drm_crtc_funcs nv50_crtc_func = {
1211 .cursor_set = nv50_crtc_cursor_set,
1212 .cursor_move = nv50_crtc_cursor_move,
1213 .gamma_set = nv50_crtc_gamma_set,
Dave Airlie5addcf02012-09-10 14:20:51 +10001214 .set_config = nouveau_crtc_set_config,
Ben Skeggse225f442012-11-21 14:40:21 +10001215 .destroy = nv50_crtc_destroy,
Ben Skeggs3376ee32011-11-12 14:28:12 +10001216 .page_flip = nouveau_crtc_page_flip,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001217};
1218
Ben Skeggsc20ab3e2011-08-25 14:09:43 +10001219static void
Ben Skeggse225f442012-11-21 14:40:21 +10001220nv50_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
Ben Skeggsc20ab3e2011-08-25 14:09:43 +10001221{
1222}
1223
1224static void
Ben Skeggse225f442012-11-21 14:40:21 +10001225nv50_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
Ben Skeggsc20ab3e2011-08-25 14:09:43 +10001226{
1227}
1228
Ben Skeggs438d99e2011-07-05 16:48:06 +10001229static int
Ben Skeggs0ad72862014-08-10 04:10:22 +10001230nv50_crtc_create(struct drm_device *dev, int index)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001231{
Ben Skeggse225f442012-11-21 14:40:21 +10001232 struct nv50_disp *disp = nv50_disp(dev);
1233 struct nv50_head *head;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001234 struct drm_crtc *crtc;
1235 int ret, i;
1236
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001237 head = kzalloc(sizeof(*head), GFP_KERNEL);
1238 if (!head)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001239 return -ENOMEM;
1240
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001241 head->base.index = index;
Ben Skeggse225f442012-11-21 14:40:21 +10001242 head->base.set_dither = nv50_crtc_set_dither;
1243 head->base.set_scale = nv50_crtc_set_scale;
1244 head->base.set_color_vibrance = nv50_crtc_set_color_vibrance;
Ben Skeggsf9887d02012-11-21 13:03:42 +10001245 head->base.color_vibrance = 50;
1246 head->base.vibrant_hue = 0;
Ben Skeggse225f442012-11-21 14:40:21 +10001247 head->base.cursor.set_offset = nv50_cursor_set_offset;
1248 head->base.cursor.set_pos = nv50_cursor_set_pos;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001249 for (i = 0; i < 256; i++) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001250 head->base.lut.r[i] = i << 8;
1251 head->base.lut.g[i] = i << 8;
1252 head->base.lut.b[i] = i << 8;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001253 }
1254
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001255 crtc = &head->base.base;
Ben Skeggse225f442012-11-21 14:40:21 +10001256 drm_crtc_init(dev, crtc, &nv50_crtc_func);
1257 drm_crtc_helper_add(crtc, &nv50_crtc_hfunc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001258 drm_mode_crtc_set_gamma_size(crtc, 256);
1259
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +10001260 ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001261 0, 0x0000, NULL, &head->base.lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001262 if (!ret) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001263 ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001264 if (!ret) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001265 ret = nouveau_bo_map(head->base.lut.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001266 if (ret)
1267 nouveau_bo_unpin(head->base.lut.nvbo);
1268 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10001269 if (ret)
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001270 nouveau_bo_ref(NULL, &head->base.lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001271 }
1272
1273 if (ret)
1274 goto out;
1275
Ben Skeggse225f442012-11-21 14:40:21 +10001276 nv50_crtc_lut_load(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001277
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001278 /* allocate cursor resources */
Ben Skeggs0ad72862014-08-10 04:10:22 +10001279 ret = nv50_pioc_create(disp->disp, NV50_DISP_CURS_CLASS, index,
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001280 &(struct nv50_display_curs_class) {
1281 .head = index,
1282 }, sizeof(struct nv50_display_curs_class),
1283 &head->curs.base);
1284 if (ret)
1285 goto out;
1286
1287 ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM,
1288 0, 0x0000, NULL, &head->base.cursor.nvbo);
1289 if (!ret) {
1290 ret = nouveau_bo_pin(head->base.cursor.nvbo, TTM_PL_FLAG_VRAM);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001291 if (!ret) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001292 ret = nouveau_bo_map(head->base.cursor.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001293 if (ret)
1294 nouveau_bo_unpin(head->base.lut.nvbo);
1295 }
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001296 if (ret)
1297 nouveau_bo_ref(NULL, &head->base.cursor.nvbo);
1298 }
1299
1300 if (ret)
1301 goto out;
1302
1303 /* allocate page flip / sync resources */
Ben Skeggs0ad72862014-08-10 04:10:22 +10001304 ret = nv50_dmac_create(disp->disp, NV50_DISP_SYNC_CLASS, index,
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001305 &(struct nv50_display_sync_class) {
1306 .pushbuf = EVO_PUSH_HANDLE(SYNC, index),
1307 .head = index,
1308 }, sizeof(struct nv50_display_sync_class),
1309 disp->sync->bo.offset, &head->sync.base);
1310 if (ret)
1311 goto out;
1312
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10001313 head->sync.addr = EVO_FLIP_SEM0(index);
1314 head->sync.data = 0x00000000;
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001315
1316 /* allocate overlay resources */
Ben Skeggs0ad72862014-08-10 04:10:22 +10001317 ret = nv50_pioc_create(disp->disp, NV50_DISP_OIMM_CLASS, index,
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001318 &(struct nv50_display_oimm_class) {
1319 .head = index,
1320 }, sizeof(struct nv50_display_oimm_class),
1321 &head->oimm.base);
1322 if (ret)
1323 goto out;
1324
Ben Skeggs0ad72862014-08-10 04:10:22 +10001325 ret = nv50_dmac_create(disp->disp, NV50_DISP_OVLY_CLASS, index,
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001326 &(struct nv50_display_ovly_class) {
1327 .pushbuf = EVO_PUSH_HANDLE(OVLY, index),
1328 .head = index,
1329 }, sizeof(struct nv50_display_ovly_class),
1330 disp->sync->bo.offset, &head->ovly.base);
1331 if (ret)
1332 goto out;
1333
Ben Skeggs438d99e2011-07-05 16:48:06 +10001334out:
1335 if (ret)
Ben Skeggse225f442012-11-21 14:40:21 +10001336 nv50_crtc_destroy(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001337 return ret;
1338}
1339
1340/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10001341 * DAC
1342 *****************************************************************************/
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001343static void
Ben Skeggse225f442012-11-21 14:40:21 +10001344nv50_dac_dpms(struct drm_encoder *encoder, int mode)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001345{
1346 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10001347 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001348 int or = nv_encoder->or;
1349 u32 dpms_ctrl;
1350
Ben Skeggs35b21d32012-11-08 12:08:55 +10001351 dpms_ctrl = 0x00000000;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001352 if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF)
1353 dpms_ctrl |= 0x00000001;
1354 if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF)
1355 dpms_ctrl |= 0x00000004;
1356
Ben Skeggs0ad72862014-08-10 04:10:22 +10001357 nvif_exec(disp->disp, NV50_DISP_DAC_PWR + or, &dpms_ctrl, sizeof(dpms_ctrl));
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001358}
1359
1360static bool
Ben Skeggse225f442012-11-21 14:40:21 +10001361nv50_dac_mode_fixup(struct drm_encoder *encoder,
Laurent Pincharte811f5a2012-07-17 17:56:50 +02001362 const struct drm_display_mode *mode,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001363 struct drm_display_mode *adjusted_mode)
1364{
1365 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1366 struct nouveau_connector *nv_connector;
1367
1368 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1369 if (nv_connector && nv_connector->native_mode) {
1370 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
1371 int id = adjusted_mode->base.id;
1372 *adjusted_mode = *nv_connector->native_mode;
1373 adjusted_mode->base.id = id;
1374 }
1375 }
1376
1377 return true;
1378}
1379
1380static void
Ben Skeggse225f442012-11-21 14:40:21 +10001381nv50_dac_commit(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001382{
1383}
1384
1385static void
Ben Skeggse225f442012-11-21 14:40:21 +10001386nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001387 struct drm_display_mode *adjusted_mode)
1388{
Ben Skeggse225f442012-11-21 14:40:21 +10001389 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001390 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1391 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs97b19b52012-11-16 11:21:37 +10001392 u32 *push;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001393
Ben Skeggse225f442012-11-21 14:40:21 +10001394 nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001395
Ben Skeggs97b19b52012-11-16 11:21:37 +10001396 push = evo_wait(mast, 8);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001397 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +10001398 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggs97b19b52012-11-16 11:21:37 +10001399 u32 syncs = 0x00000000;
1400
1401 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1402 syncs |= 0x00000001;
1403 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1404 syncs |= 0x00000002;
1405
1406 evo_mthd(push, 0x0400 + (nv_encoder->or * 0x080), 2);
1407 evo_data(push, 1 << nv_crtc->index);
1408 evo_data(push, syncs);
1409 } else {
1410 u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
1411 u32 syncs = 0x00000001;
1412
1413 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1414 syncs |= 0x00000008;
1415 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1416 syncs |= 0x00000010;
1417
1418 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1419 magic |= 0x00000001;
1420
1421 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
1422 evo_data(push, syncs);
1423 evo_data(push, magic);
1424 evo_mthd(push, 0x0180 + (nv_encoder->or * 0x020), 1);
1425 evo_data(push, 1 << nv_crtc->index);
1426 }
1427
1428 evo_kick(push, mast);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001429 }
1430
1431 nv_encoder->crtc = encoder->crtc;
1432}
1433
1434static void
Ben Skeggse225f442012-11-21 14:40:21 +10001435nv50_dac_disconnect(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001436{
1437 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10001438 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs97b19b52012-11-16 11:21:37 +10001439 const int or = nv_encoder->or;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001440 u32 *push;
1441
1442 if (nv_encoder->crtc) {
Ben Skeggse225f442012-11-21 14:40:21 +10001443 nv50_crtc_prepare(nv_encoder->crtc);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001444
Ben Skeggs97b19b52012-11-16 11:21:37 +10001445 push = evo_wait(mast, 4);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001446 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +10001447 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggs97b19b52012-11-16 11:21:37 +10001448 evo_mthd(push, 0x0400 + (or * 0x080), 1);
1449 evo_data(push, 0x00000000);
1450 } else {
1451 evo_mthd(push, 0x0180 + (or * 0x020), 1);
1452 evo_data(push, 0x00000000);
1453 }
Ben Skeggs97b19b52012-11-16 11:21:37 +10001454 evo_kick(push, mast);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001455 }
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001456 }
Ben Skeggs97b19b52012-11-16 11:21:37 +10001457
1458 nv_encoder->crtc = NULL;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001459}
1460
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10001461static enum drm_connector_status
Ben Skeggse225f442012-11-21 14:40:21 +10001462nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10001463{
Ben Skeggse225f442012-11-21 14:40:21 +10001464 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs35b21d32012-11-08 12:08:55 +10001465 int ret, or = nouveau_encoder(encoder)->or;
Ben Skeggsd40ee482013-06-03 16:40:14 +10001466 u32 load = nouveau_drm(encoder->dev)->vbios.dactestval;
1467 if (load == 0)
1468 load = 340;
Ben Skeggsb6819932011-07-08 11:14:50 +10001469
Ben Skeggs0ad72862014-08-10 04:10:22 +10001470 ret = nvif_exec(disp->disp, NV50_DISP_DAC_LOAD + or, &load, sizeof(load));
Ben Skeggs4b31ebc2013-09-04 11:01:42 +10001471 if (ret || !load)
Ben Skeggs35b21d32012-11-08 12:08:55 +10001472 return connector_status_disconnected;
Ben Skeggsb6819932011-07-08 11:14:50 +10001473
Ben Skeggs35b21d32012-11-08 12:08:55 +10001474 return connector_status_connected;
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10001475}
1476
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001477static void
Ben Skeggse225f442012-11-21 14:40:21 +10001478nv50_dac_destroy(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001479{
1480 drm_encoder_cleanup(encoder);
1481 kfree(encoder);
1482}
1483
Ben Skeggse225f442012-11-21 14:40:21 +10001484static const struct drm_encoder_helper_funcs nv50_dac_hfunc = {
1485 .dpms = nv50_dac_dpms,
1486 .mode_fixup = nv50_dac_mode_fixup,
1487 .prepare = nv50_dac_disconnect,
1488 .commit = nv50_dac_commit,
1489 .mode_set = nv50_dac_mode_set,
1490 .disable = nv50_dac_disconnect,
1491 .get_crtc = nv50_display_crtc_get,
1492 .detect = nv50_dac_detect
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001493};
1494
Ben Skeggse225f442012-11-21 14:40:21 +10001495static const struct drm_encoder_funcs nv50_dac_func = {
1496 .destroy = nv50_dac_destroy,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001497};
1498
1499static int
Ben Skeggse225f442012-11-21 14:40:21 +10001500nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001501{
Ben Skeggs5ed50202013-02-11 20:15:03 +10001502 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggs967e7bd2014-08-10 04:10:22 +10001503 struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001504 struct nouveau_encoder *nv_encoder;
1505 struct drm_encoder *encoder;
Ben Skeggs5ed50202013-02-11 20:15:03 +10001506 int type = DRM_MODE_ENCODER_DAC;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001507
1508 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
1509 if (!nv_encoder)
1510 return -ENOMEM;
1511 nv_encoder->dcb = dcbe;
1512 nv_encoder->or = ffs(dcbe->or) - 1;
Ben Skeggs5ed50202013-02-11 20:15:03 +10001513 nv_encoder->i2c = i2c->find(i2c, dcbe->i2c_index);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001514
1515 encoder = to_drm_encoder(nv_encoder);
1516 encoder->possible_crtcs = dcbe->heads;
1517 encoder->possible_clones = 0;
Ben Skeggs5ed50202013-02-11 20:15:03 +10001518 drm_encoder_init(connector->dev, encoder, &nv50_dac_func, type);
Ben Skeggse225f442012-11-21 14:40:21 +10001519 drm_encoder_helper_add(encoder, &nv50_dac_hfunc);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001520
1521 drm_mode_connector_attach_encoder(connector, encoder);
1522 return 0;
1523}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001524
1525/******************************************************************************
Ben Skeggs78951d22011-11-11 18:13:13 +10001526 * Audio
1527 *****************************************************************************/
1528static void
Ben Skeggse225f442012-11-21 14:40:21 +10001529nv50_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
Ben Skeggs78951d22011-11-11 18:13:13 +10001530{
1531 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1532 struct nouveau_connector *nv_connector;
Ben Skeggse225f442012-11-21 14:40:21 +10001533 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs78951d22011-11-11 18:13:13 +10001534
1535 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1536 if (!drm_detect_monitor_audio(nv_connector->edid))
1537 return;
1538
Ben Skeggs78951d22011-11-11 18:13:13 +10001539 drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
Ben Skeggs78951d22011-11-11 18:13:13 +10001540
Ben Skeggs0ad72862014-08-10 04:10:22 +10001541 nvif_exec(disp->disp, NVA3_DISP_SOR_HDA_ELD + nv_encoder->or,
1542 nv_connector->base.eld,
1543 nv_connector->base.eld[2] * 4);
Ben Skeggs78951d22011-11-11 18:13:13 +10001544}
1545
1546static void
Ben Skeggse225f442012-11-21 14:40:21 +10001547nv50_audio_disconnect(struct drm_encoder *encoder)
Ben Skeggs78951d22011-11-11 18:13:13 +10001548{
1549 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10001550 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs78951d22011-11-11 18:13:13 +10001551
Ben Skeggs0ad72862014-08-10 04:10:22 +10001552 nvif_exec(disp->disp, NVA3_DISP_SOR_HDA_ELD + nv_encoder->or, NULL, 0);
Ben Skeggs78951d22011-11-11 18:13:13 +10001553}
1554
1555/******************************************************************************
1556 * HDMI
1557 *****************************************************************************/
1558static void
Ben Skeggse225f442012-11-21 14:40:21 +10001559nv50_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
Ben Skeggs78951d22011-11-11 18:13:13 +10001560{
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001561 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1562 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
1563 struct nouveau_connector *nv_connector;
Ben Skeggse225f442012-11-21 14:40:21 +10001564 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs1c30cd02012-11-08 14:22:28 +10001565 const u32 moff = (nv_crtc->index << 3) | nv_encoder->or;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001566 u32 rekey = 56; /* binary driver, and tegra constant */
1567 u32 max_ac_packet;
Ben Skeggs0ad72862014-08-10 04:10:22 +10001568 u32 data;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001569
1570 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1571 if (!drm_detect_hdmi_monitor(nv_connector->edid))
1572 return;
1573
1574 max_ac_packet = mode->htotal - mode->hdisplay;
1575 max_ac_packet -= rekey;
1576 max_ac_packet -= 18; /* constant from tegra */
1577 max_ac_packet /= 32;
1578
Ben Skeggs0ad72862014-08-10 04:10:22 +10001579 data = NV84_DISP_SOR_HDMI_PWR_STATE_ON | (max_ac_packet << 16) | rekey;
1580 nvif_exec(disp->disp, NV84_DISP_SOR_HDMI_PWR + moff, &data, sizeof(data));
Ben Skeggs091e40c2011-11-11 20:46:00 +10001581
Ben Skeggse225f442012-11-21 14:40:21 +10001582 nv50_audio_mode_set(encoder, mode);
Ben Skeggs78951d22011-11-11 18:13:13 +10001583}
1584
1585static void
Ben Skeggse84a35a2014-06-05 10:59:55 +10001586nv50_hdmi_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
Ben Skeggs78951d22011-11-11 18:13:13 +10001587{
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001588 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10001589 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs1c30cd02012-11-08 14:22:28 +10001590 const u32 moff = (nv_crtc->index << 3) | nv_encoder->or;
Ben Skeggs0ad72862014-08-10 04:10:22 +10001591 u32 data = 0;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001592
Ben Skeggse225f442012-11-21 14:40:21 +10001593 nv50_audio_disconnect(encoder);
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001594
Ben Skeggs0ad72862014-08-10 04:10:22 +10001595 nvif_exec(disp->disp, NV84_DISP_SOR_HDMI_PWR + moff, &data, sizeof(data));
Ben Skeggs78951d22011-11-11 18:13:13 +10001596}
1597
1598/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10001599 * SOR
1600 *****************************************************************************/
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001601static void
Ben Skeggse225f442012-11-21 14:40:21 +10001602nv50_sor_dpms(struct drm_encoder *encoder, int mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001603{
1604 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1605 struct drm_device *dev = encoder->dev;
Ben Skeggse225f442012-11-21 14:40:21 +10001606 struct nv50_disp *disp = nv50_disp(dev);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001607 struct drm_encoder *partner;
Ben Skeggs0ad72862014-08-10 04:10:22 +10001608 u32 mthd, data;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001609
1610 nv_encoder->last_dpms = mode;
1611
1612 list_for_each_entry(partner, &dev->mode_config.encoder_list, head) {
1613 struct nouveau_encoder *nv_partner = nouveau_encoder(partner);
1614
1615 if (partner->encoder_type != DRM_MODE_ENCODER_TMDS)
1616 continue;
1617
1618 if (nv_partner != nv_encoder &&
Ben Skeggs26cfa812011-11-17 09:10:02 +10001619 nv_partner->dcb->or == nv_encoder->dcb->or) {
Ben Skeggs83fc0832011-07-05 13:08:40 +10001620 if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
1621 return;
1622 break;
1623 }
1624 }
1625
Ben Skeggs276e5262014-06-30 11:10:02 +10001626 mthd = (ffs(nv_encoder->dcb->heads) - 1) << 3;
1627 mthd |= (ffs(nv_encoder->dcb->sorconf.link) - 1) << 2;
Ben Skeggs48743222014-05-31 01:48:06 +10001628 mthd |= nv_encoder->or;
1629
1630 if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10001631 data = 1;
1632 nvif_exec(disp->disp, NV50_DISP_SOR_PWR | mthd, &data, sizeof(data));
Ben Skeggs48743222014-05-31 01:48:06 +10001633 mthd |= NV94_DISP_SOR_DP_PWR;
1634 } else {
1635 mthd |= NV50_DISP_SOR_PWR;
1636 }
1637
Ben Skeggs0ad72862014-08-10 04:10:22 +10001638 data = (mode == DRM_MODE_DPMS_ON);
1639 nvif_exec(disp->disp, mthd, &data, sizeof(data));
Ben Skeggs83fc0832011-07-05 13:08:40 +10001640}
1641
1642static bool
Ben Skeggse225f442012-11-21 14:40:21 +10001643nv50_sor_mode_fixup(struct drm_encoder *encoder,
Laurent Pincharte811f5a2012-07-17 17:56:50 +02001644 const struct drm_display_mode *mode,
Ben Skeggs83fc0832011-07-05 13:08:40 +10001645 struct drm_display_mode *adjusted_mode)
1646{
1647 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1648 struct nouveau_connector *nv_connector;
1649
1650 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1651 if (nv_connector && nv_connector->native_mode) {
1652 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
1653 int id = adjusted_mode->base.id;
1654 *adjusted_mode = *nv_connector->native_mode;
1655 adjusted_mode->base.id = id;
1656 }
1657 }
1658
1659 return true;
1660}
1661
1662static void
Ben Skeggse84a35a2014-06-05 10:59:55 +10001663nv50_sor_ctrl(struct nouveau_encoder *nv_encoder, u32 mask, u32 data)
1664{
1665 struct nv50_mast *mast = nv50_mast(nv_encoder->base.base.dev);
1666 u32 temp = (nv_encoder->ctrl & ~mask) | (data & mask), *push;
1667 if (temp != nv_encoder->ctrl && (push = evo_wait(mast, 2))) {
1668 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
1669 evo_mthd(push, 0x0600 + (nv_encoder->or * 0x40), 1);
1670 evo_data(push, (nv_encoder->ctrl = temp));
1671 } else {
1672 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1);
1673 evo_data(push, (nv_encoder->ctrl = temp));
1674 }
1675 evo_kick(push, mast);
1676 }
1677}
1678
1679static void
Ben Skeggse225f442012-11-21 14:40:21 +10001680nv50_sor_disconnect(struct drm_encoder *encoder)
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10001681{
1682 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse84a35a2014-06-05 10:59:55 +10001683 struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001684
1685 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1686 nv_encoder->crtc = NULL;
Ben Skeggse84a35a2014-06-05 10:59:55 +10001687
1688 if (nv_crtc) {
1689 nv50_crtc_prepare(&nv_crtc->base);
1690 nv50_sor_ctrl(nv_encoder, 1 << nv_crtc->index, 0);
1691 nv50_hdmi_disconnect(&nv_encoder->base.base, nv_crtc);
1692 }
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10001693}
1694
1695static void
Ben Skeggse225f442012-11-21 14:40:21 +10001696nv50_sor_commit(struct drm_encoder *encoder)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001697{
1698}
1699
1700static void
Ben Skeggse225f442012-11-21 14:40:21 +10001701nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001702 struct drm_display_mode *mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001703{
Ben Skeggse225f442012-11-21 14:40:21 +10001704 struct nv50_disp *disp = nv50_disp(encoder->dev);
1705 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs78951d22011-11-11 18:13:13 +10001706 struct drm_device *dev = encoder->dev;
Ben Skeggs77145f12012-07-31 16:16:21 +10001707 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001708 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1709 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001710 struct nouveau_connector *nv_connector;
Ben Skeggs77145f12012-07-31 16:16:21 +10001711 struct nvbios *bios = &drm->vbios;
Ben Skeggse84a35a2014-06-05 10:59:55 +10001712 u32 lvds = 0, mask, ctrl;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001713 u8 owner = 1 << nv_crtc->index;
1714 u8 proto = 0xf;
1715 u8 depth = 0x0;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001716
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001717 nv_connector = nouveau_encoder_connector_get(nv_encoder);
Ben Skeggse84a35a2014-06-05 10:59:55 +10001718 nv_encoder->crtc = encoder->crtc;
1719
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001720 switch (nv_encoder->dcb->type) {
Ben Skeggscb75d972012-07-11 10:44:20 +10001721 case DCB_OUTPUT_TMDS:
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001722 if (nv_encoder->dcb->sorconf.link & 1) {
1723 if (mode->clock < 165000)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001724 proto = 0x1;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001725 else
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001726 proto = 0x5;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001727 } else {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001728 proto = 0x2;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001729 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10001730
Ben Skeggse84a35a2014-06-05 10:59:55 +10001731 nv50_hdmi_mode_set(&nv_encoder->base.base, mode);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001732 break;
Ben Skeggscb75d972012-07-11 10:44:20 +10001733 case DCB_OUTPUT_LVDS:
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001734 proto = 0x0;
1735
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001736 if (bios->fp_no_ddc) {
1737 if (bios->fp.dual_link)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001738 lvds |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001739 if (bios->fp.if_is_24bit)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001740 lvds |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001741 } else {
Ben Skeggsbefb51e2011-11-18 10:23:59 +10001742 if (nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001743 if (((u8 *)nv_connector->edid)[121] == 2)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001744 lvds |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001745 } else
1746 if (mode->clock >= bios->fp.duallink_transition_clk) {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001747 lvds |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001748 }
1749
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001750 if (lvds & 0x0100) {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001751 if (bios->fp.strapless_is_24bit & 2)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001752 lvds |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001753 } else {
1754 if (bios->fp.strapless_is_24bit & 1)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001755 lvds |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001756 }
1757
1758 if (nv_connector->base.display_info.bpc == 8)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001759 lvds |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001760 }
Ben Skeggs4a230fa2012-11-09 11:25:37 +10001761
Ben Skeggs0ad72862014-08-10 04:10:22 +10001762 nvif_exec(disp->disp, NV50_DISP_SOR_LVDS_SCRIPT + nv_encoder->or, &lvds, sizeof(lvds));
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001763 break;
Ben Skeggscb75d972012-07-11 10:44:20 +10001764 case DCB_OUTPUT_DP:
Ben Skeggs3488c572012-03-12 11:42:20 +10001765 if (nv_connector->base.display_info.bpc == 6) {
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001766 nv_encoder->dp.datarate = mode->clock * 18 / 8;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001767 depth = 0x2;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001768 } else
1769 if (nv_connector->base.display_info.bpc == 8) {
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001770 nv_encoder->dp.datarate = mode->clock * 24 / 8;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001771 depth = 0x5;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001772 } else {
1773 nv_encoder->dp.datarate = mode->clock * 30 / 8;
1774 depth = 0x6;
Ben Skeggs3488c572012-03-12 11:42:20 +10001775 }
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001776
1777 if (nv_encoder->dcb->sorconf.link & 1)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001778 proto = 0x8;
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001779 else
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001780 proto = 0x9;
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001781 break;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001782 default:
1783 BUG_ON(1);
1784 break;
1785 }
Ben Skeggsff8ff502011-07-08 11:53:37 +10001786
Ben Skeggse84a35a2014-06-05 10:59:55 +10001787 nv50_sor_dpms(&nv_encoder->base.base, DRM_MODE_DPMS_ON);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001788
Ben Skeggse84a35a2014-06-05 10:59:55 +10001789 if (nv50_vers(mast) >= NVD0_DISP_CLASS) {
1790 u32 *push = evo_wait(mast, 3);
1791 if (push) {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001792 u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
1793 u32 syncs = 0x00000001;
1794
1795 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1796 syncs |= 0x00000008;
1797 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1798 syncs |= 0x00000010;
1799
1800 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1801 magic |= 0x00000001;
1802
1803 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
1804 evo_data(push, syncs | (depth << 6));
1805 evo_data(push, magic);
Ben Skeggse84a35a2014-06-05 10:59:55 +10001806 evo_kick(push, mast);
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001807 }
1808
Ben Skeggse84a35a2014-06-05 10:59:55 +10001809 ctrl = proto << 8;
1810 mask = 0x00000f00;
1811 } else {
1812 ctrl = (depth << 16) | (proto << 8);
1813 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1814 ctrl |= 0x00001000;
1815 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1816 ctrl |= 0x00002000;
1817 mask = 0x000f3f00;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001818 }
1819
Ben Skeggse84a35a2014-06-05 10:59:55 +10001820 nv50_sor_ctrl(nv_encoder, mask | owner, ctrl | owner);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001821}
1822
1823static void
Ben Skeggse225f442012-11-21 14:40:21 +10001824nv50_sor_destroy(struct drm_encoder *encoder)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001825{
1826 drm_encoder_cleanup(encoder);
1827 kfree(encoder);
1828}
1829
Ben Skeggse225f442012-11-21 14:40:21 +10001830static const struct drm_encoder_helper_funcs nv50_sor_hfunc = {
1831 .dpms = nv50_sor_dpms,
1832 .mode_fixup = nv50_sor_mode_fixup,
Ben Skeggs5a885f02013-02-20 14:34:18 +10001833 .prepare = nv50_sor_disconnect,
Ben Skeggse225f442012-11-21 14:40:21 +10001834 .commit = nv50_sor_commit,
1835 .mode_set = nv50_sor_mode_set,
1836 .disable = nv50_sor_disconnect,
1837 .get_crtc = nv50_display_crtc_get,
Ben Skeggs83fc0832011-07-05 13:08:40 +10001838};
1839
Ben Skeggse225f442012-11-21 14:40:21 +10001840static const struct drm_encoder_funcs nv50_sor_func = {
1841 .destroy = nv50_sor_destroy,
Ben Skeggs83fc0832011-07-05 13:08:40 +10001842};
1843
1844static int
Ben Skeggse225f442012-11-21 14:40:21 +10001845nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001846{
Ben Skeggs5ed50202013-02-11 20:15:03 +10001847 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggs967e7bd2014-08-10 04:10:22 +10001848 struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001849 struct nouveau_encoder *nv_encoder;
1850 struct drm_encoder *encoder;
Ben Skeggs5ed50202013-02-11 20:15:03 +10001851 int type;
1852
1853 switch (dcbe->type) {
1854 case DCB_OUTPUT_LVDS: type = DRM_MODE_ENCODER_LVDS; break;
1855 case DCB_OUTPUT_TMDS:
1856 case DCB_OUTPUT_DP:
1857 default:
1858 type = DRM_MODE_ENCODER_TMDS;
1859 break;
1860 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10001861
1862 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
1863 if (!nv_encoder)
1864 return -ENOMEM;
1865 nv_encoder->dcb = dcbe;
1866 nv_encoder->or = ffs(dcbe->or) - 1;
Ben Skeggs5ed50202013-02-11 20:15:03 +10001867 nv_encoder->i2c = i2c->find(i2c, dcbe->i2c_index);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001868 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1869
1870 encoder = to_drm_encoder(nv_encoder);
1871 encoder->possible_crtcs = dcbe->heads;
1872 encoder->possible_clones = 0;
Ben Skeggs5ed50202013-02-11 20:15:03 +10001873 drm_encoder_init(connector->dev, encoder, &nv50_sor_func, type);
Ben Skeggse225f442012-11-21 14:40:21 +10001874 drm_encoder_helper_add(encoder, &nv50_sor_hfunc);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001875
1876 drm_mode_connector_attach_encoder(connector, encoder);
1877 return 0;
1878}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001879
1880/******************************************************************************
Ben Skeggseb6313a2013-02-11 09:52:58 +10001881 * PIOR
1882 *****************************************************************************/
1883
1884static void
1885nv50_pior_dpms(struct drm_encoder *encoder, int mode)
1886{
1887 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1888 struct nv50_disp *disp = nv50_disp(encoder->dev);
1889 u32 mthd = (nv_encoder->dcb->type << 12) | nv_encoder->or;
1890 u32 ctrl = (mode == DRM_MODE_DPMS_ON);
Ben Skeggs0ad72862014-08-10 04:10:22 +10001891 nvif_exec(disp->disp, NV50_DISP_PIOR_PWR + mthd, &ctrl, sizeof(ctrl));
Ben Skeggseb6313a2013-02-11 09:52:58 +10001892}
1893
1894static bool
1895nv50_pior_mode_fixup(struct drm_encoder *encoder,
1896 const struct drm_display_mode *mode,
1897 struct drm_display_mode *adjusted_mode)
1898{
1899 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1900 struct nouveau_connector *nv_connector;
1901
1902 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1903 if (nv_connector && nv_connector->native_mode) {
1904 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
1905 int id = adjusted_mode->base.id;
1906 *adjusted_mode = *nv_connector->native_mode;
1907 adjusted_mode->base.id = id;
1908 }
1909 }
1910
1911 adjusted_mode->clock *= 2;
1912 return true;
1913}
1914
1915static void
1916nv50_pior_commit(struct drm_encoder *encoder)
1917{
1918}
1919
1920static void
1921nv50_pior_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
1922 struct drm_display_mode *adjusted_mode)
1923{
1924 struct nv50_mast *mast = nv50_mast(encoder->dev);
1925 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1926 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
1927 struct nouveau_connector *nv_connector;
1928 u8 owner = 1 << nv_crtc->index;
1929 u8 proto, depth;
1930 u32 *push;
1931
1932 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1933 switch (nv_connector->base.display_info.bpc) {
1934 case 10: depth = 0x6; break;
1935 case 8: depth = 0x5; break;
1936 case 6: depth = 0x2; break;
1937 default: depth = 0x0; break;
1938 }
1939
1940 switch (nv_encoder->dcb->type) {
1941 case DCB_OUTPUT_TMDS:
1942 case DCB_OUTPUT_DP:
1943 proto = 0x0;
1944 break;
1945 default:
1946 BUG_ON(1);
1947 break;
1948 }
1949
1950 nv50_pior_dpms(encoder, DRM_MODE_DPMS_ON);
1951
1952 push = evo_wait(mast, 8);
1953 if (push) {
1954 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
1955 u32 ctrl = (depth << 16) | (proto << 8) | owner;
1956 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1957 ctrl |= 0x00001000;
1958 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1959 ctrl |= 0x00002000;
1960 evo_mthd(push, 0x0700 + (nv_encoder->or * 0x040), 1);
1961 evo_data(push, ctrl);
1962 }
1963
1964 evo_kick(push, mast);
1965 }
1966
1967 nv_encoder->crtc = encoder->crtc;
1968}
1969
1970static void
1971nv50_pior_disconnect(struct drm_encoder *encoder)
1972{
1973 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1974 struct nv50_mast *mast = nv50_mast(encoder->dev);
1975 const int or = nv_encoder->or;
1976 u32 *push;
1977
1978 if (nv_encoder->crtc) {
1979 nv50_crtc_prepare(nv_encoder->crtc);
1980
1981 push = evo_wait(mast, 4);
1982 if (push) {
1983 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
1984 evo_mthd(push, 0x0700 + (or * 0x040), 1);
1985 evo_data(push, 0x00000000);
1986 }
Ben Skeggseb6313a2013-02-11 09:52:58 +10001987 evo_kick(push, mast);
1988 }
1989 }
1990
1991 nv_encoder->crtc = NULL;
1992}
1993
1994static void
1995nv50_pior_destroy(struct drm_encoder *encoder)
1996{
1997 drm_encoder_cleanup(encoder);
1998 kfree(encoder);
1999}
2000
2001static const struct drm_encoder_helper_funcs nv50_pior_hfunc = {
2002 .dpms = nv50_pior_dpms,
2003 .mode_fixup = nv50_pior_mode_fixup,
2004 .prepare = nv50_pior_disconnect,
2005 .commit = nv50_pior_commit,
2006 .mode_set = nv50_pior_mode_set,
2007 .disable = nv50_pior_disconnect,
2008 .get_crtc = nv50_display_crtc_get,
2009};
2010
2011static const struct drm_encoder_funcs nv50_pior_func = {
2012 .destroy = nv50_pior_destroy,
2013};
2014
2015static int
2016nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
2017{
2018 struct nouveau_drm *drm = nouveau_drm(connector->dev);
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002019 struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
Ben Skeggseb6313a2013-02-11 09:52:58 +10002020 struct nouveau_i2c_port *ddc = NULL;
2021 struct nouveau_encoder *nv_encoder;
2022 struct drm_encoder *encoder;
2023 int type;
2024
2025 switch (dcbe->type) {
2026 case DCB_OUTPUT_TMDS:
2027 ddc = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(dcbe->extdev));
2028 type = DRM_MODE_ENCODER_TMDS;
2029 break;
2030 case DCB_OUTPUT_DP:
2031 ddc = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(dcbe->extdev));
2032 type = DRM_MODE_ENCODER_TMDS;
2033 break;
2034 default:
2035 return -ENODEV;
2036 }
2037
2038 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
2039 if (!nv_encoder)
2040 return -ENOMEM;
2041 nv_encoder->dcb = dcbe;
2042 nv_encoder->or = ffs(dcbe->or) - 1;
2043 nv_encoder->i2c = ddc;
2044
2045 encoder = to_drm_encoder(nv_encoder);
2046 encoder->possible_crtcs = dcbe->heads;
2047 encoder->possible_clones = 0;
2048 drm_encoder_init(connector->dev, encoder, &nv50_pior_func, type);
2049 drm_encoder_helper_add(encoder, &nv50_pior_hfunc);
2050
2051 drm_mode_connector_attach_encoder(connector, encoder);
2052 return 0;
2053}
2054
2055/******************************************************************************
Ben Skeggsab0af552014-08-10 04:10:19 +10002056 * Framebuffer
2057 *****************************************************************************/
2058
Ben Skeggs8a423642014-08-10 04:10:19 +10002059static void
Ben Skeggs0ad72862014-08-10 04:10:22 +10002060nv50_fbdma_fini(struct nv50_fbdma *fbdma)
Ben Skeggs8a423642014-08-10 04:10:19 +10002061{
Ben Skeggs0ad72862014-08-10 04:10:22 +10002062 int i;
2063 for (i = 0; i < ARRAY_SIZE(fbdma->base); i++)
2064 nvif_object_fini(&fbdma->base[i]);
2065 nvif_object_fini(&fbdma->core);
Ben Skeggs8a423642014-08-10 04:10:19 +10002066 list_del(&fbdma->head);
2067 kfree(fbdma);
2068}
2069
2070static int
2071nv50_fbdma_init(struct drm_device *dev, u32 name, u64 offset, u64 length, u8 kind)
2072{
2073 struct nouveau_drm *drm = nouveau_drm(dev);
2074 struct nv50_disp *disp = nv50_disp(dev);
2075 struct nv50_mast *mast = nv50_mast(dev);
Ben Skeggs4acfd702014-08-10 04:10:24 +10002076 struct __attribute__ ((packed)) {
2077 struct nv_dma_v0 base;
2078 union {
2079 struct nv50_dma_v0 nv50;
2080 struct gf100_dma_v0 gf100;
2081 struct gf110_dma_v0 gf110;
2082 };
2083 } args = {};
Ben Skeggs8a423642014-08-10 04:10:19 +10002084 struct nv50_fbdma *fbdma;
2085 struct drm_crtc *crtc;
Ben Skeggs4acfd702014-08-10 04:10:24 +10002086 u32 size = sizeof(args.base);
Ben Skeggs8a423642014-08-10 04:10:19 +10002087 int ret;
2088
2089 list_for_each_entry(fbdma, &disp->fbdma, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002090 if (fbdma->core.handle == name)
Ben Skeggs8a423642014-08-10 04:10:19 +10002091 return 0;
2092 }
2093
2094 fbdma = kzalloc(sizeof(*fbdma), GFP_KERNEL);
2095 if (!fbdma)
2096 return -ENOMEM;
2097 list_add(&fbdma->head, &disp->fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10002098
Ben Skeggs4acfd702014-08-10 04:10:24 +10002099 args.base.target = NV_DMA_V0_TARGET_VRAM;
2100 args.base.access = NV_DMA_V0_ACCESS_RDWR;
2101 args.base.start = offset;
2102 args.base.limit = offset + length - 1;
Ben Skeggs8a423642014-08-10 04:10:19 +10002103
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002104 if (drm->device.info.chipset < 0x80) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10002105 args.nv50.part = NV50_DMA_V0_PART_256;
2106 size += sizeof(args.nv50);
Ben Skeggs8a423642014-08-10 04:10:19 +10002107 } else
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002108 if (drm->device.info.chipset < 0xc0) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10002109 args.nv50.part = NV50_DMA_V0_PART_256;
2110 args.nv50.kind = kind;
2111 size += sizeof(args.nv50);
Ben Skeggs8a423642014-08-10 04:10:19 +10002112 } else
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002113 if (drm->device.info.chipset < 0xd0) {
Ben Skeggs4acfd702014-08-10 04:10:24 +10002114 args.gf100.kind = kind;
2115 size += sizeof(args.gf100);
Ben Skeggs8a423642014-08-10 04:10:19 +10002116 } else {
Ben Skeggs4acfd702014-08-10 04:10:24 +10002117 args.gf110.page = GF110_DMA_V0_PAGE_LP;
2118 args.gf110.kind = kind;
2119 size += sizeof(args.gf110);
Ben Skeggs8a423642014-08-10 04:10:19 +10002120 }
2121
2122 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002123 struct nv50_head *head = nv50_head(crtc);
2124 int ret = nvif_object_init(&head->sync.base.base.user, NULL,
Ben Skeggs4acfd702014-08-10 04:10:24 +10002125 name, NV_DMA_IN_MEMORY, &args, size,
Ben Skeggs0ad72862014-08-10 04:10:22 +10002126 &fbdma->base[head->base.index]);
Ben Skeggs8a423642014-08-10 04:10:19 +10002127 if (ret) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002128 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10002129 return ret;
2130 }
2131 }
2132
Ben Skeggs0ad72862014-08-10 04:10:22 +10002133 ret = nvif_object_init(&mast->base.base.user, NULL, name,
Ben Skeggs4acfd702014-08-10 04:10:24 +10002134 NV_DMA_IN_MEMORY, &args, size,
Ben Skeggs0ad72862014-08-10 04:10:22 +10002135 &fbdma->core);
Ben Skeggs8a423642014-08-10 04:10:19 +10002136 if (ret) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002137 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10002138 return ret;
2139 }
2140
2141 return 0;
2142}
2143
Ben Skeggsab0af552014-08-10 04:10:19 +10002144static void
2145nv50_fb_dtor(struct drm_framebuffer *fb)
2146{
2147}
2148
2149static int
2150nv50_fb_ctor(struct drm_framebuffer *fb)
2151{
2152 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
2153 struct nouveau_drm *drm = nouveau_drm(fb->dev);
2154 struct nouveau_bo *nvbo = nv_fb->nvbo;
Ben Skeggs8a423642014-08-10 04:10:19 +10002155 struct nv50_disp *disp = nv50_disp(fb->dev);
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002156 struct nouveau_fb *pfb = nvkm_fb(&drm->device);
Ben Skeggs8a423642014-08-10 04:10:19 +10002157 u8 kind = nouveau_bo_tile_layout(nvbo) >> 8;
2158 u8 tile = nvbo->tile_mode;
Ben Skeggsab0af552014-08-10 04:10:19 +10002159
2160 if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) {
2161 NV_ERROR(drm, "framebuffer requires contiguous bo\n");
2162 return -EINVAL;
2163 }
2164
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002165 if (drm->device.info.chipset >= 0xc0)
Ben Skeggs8a423642014-08-10 04:10:19 +10002166 tile >>= 4; /* yep.. */
2167
Ben Skeggsab0af552014-08-10 04:10:19 +10002168 switch (fb->depth) {
2169 case 8: nv_fb->r_format = 0x1e00; break;
2170 case 15: nv_fb->r_format = 0xe900; break;
2171 case 16: nv_fb->r_format = 0xe800; break;
2172 case 24:
2173 case 32: nv_fb->r_format = 0xcf00; break;
2174 case 30: nv_fb->r_format = 0xd100; break;
2175 default:
2176 NV_ERROR(drm, "unknown depth %d\n", fb->depth);
2177 return -EINVAL;
2178 }
2179
Ben Skeggs0ad72862014-08-10 04:10:22 +10002180 if (disp->disp->oclass < NV84_DISP_CLASS) {
Ben Skeggs8a423642014-08-10 04:10:19 +10002181 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
2182 (fb->pitches[0] | 0x00100000);
2183 nv_fb->r_format |= kind << 16;
2184 } else
Ben Skeggs0ad72862014-08-10 04:10:22 +10002185 if (disp->disp->oclass < NVD0_DISP_CLASS) {
Ben Skeggs8a423642014-08-10 04:10:19 +10002186 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
2187 (fb->pitches[0] | 0x00100000);
Ben Skeggsab0af552014-08-10 04:10:19 +10002188 } else {
Ben Skeggs8a423642014-08-10 04:10:19 +10002189 nv_fb->r_pitch = kind ? (((fb->pitches[0] / 4) << 4) | tile) :
2190 (fb->pitches[0] | 0x01000000);
Ben Skeggsab0af552014-08-10 04:10:19 +10002191 }
Ben Skeggs8a423642014-08-10 04:10:19 +10002192 nv_fb->r_handle = 0xffff0000 | kind;
Ben Skeggsab0af552014-08-10 04:10:19 +10002193
Ben Skeggs8a423642014-08-10 04:10:19 +10002194 return nv50_fbdma_init(fb->dev, nv_fb->r_handle, 0, pfb->ram->size, kind);
Ben Skeggsab0af552014-08-10 04:10:19 +10002195}
2196
2197/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10002198 * Init
2199 *****************************************************************************/
Ben Skeggsab0af552014-08-10 04:10:19 +10002200
Ben Skeggs2a44e492011-11-09 11:36:33 +10002201void
Ben Skeggse225f442012-11-21 14:40:21 +10002202nv50_display_fini(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10002203{
Ben Skeggs26f6d882011-07-04 16:25:18 +10002204}
2205
2206int
Ben Skeggse225f442012-11-21 14:40:21 +10002207nv50_display_init(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10002208{
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10002209 struct nv50_disp *disp = nv50_disp(dev);
2210 struct drm_crtc *crtc;
2211 u32 *push;
2212
2213 push = evo_wait(nv50_mast(dev), 32);
2214 if (!push)
2215 return -EBUSY;
2216
2217 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
2218 struct nv50_sync *sync = nv50_sync(crtc);
2219 nouveau_bo_wr32(disp->sync, sync->addr / 4, sync->data);
Ben Skeggs26f6d882011-07-04 16:25:18 +10002220 }
2221
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10002222 evo_mthd(push, 0x0088, 1);
Ben Skeggsf45f55c2014-08-10 04:10:23 +10002223 evo_data(push, nv50_mast(dev)->base.sync.handle);
Ben Skeggs9f9bdaa2013-03-02 13:21:31 +10002224 evo_kick(push, nv50_mast(dev));
2225 return 0;
Ben Skeggs26f6d882011-07-04 16:25:18 +10002226}
2227
2228void
Ben Skeggse225f442012-11-21 14:40:21 +10002229nv50_display_destroy(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10002230{
Ben Skeggse225f442012-11-21 14:40:21 +10002231 struct nv50_disp *disp = nv50_disp(dev);
Ben Skeggs8a423642014-08-10 04:10:19 +10002232 struct nv50_fbdma *fbdma, *fbtmp;
2233
2234 list_for_each_entry_safe(fbdma, fbtmp, &disp->fbdma, head) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002235 nv50_fbdma_fini(fbdma);
Ben Skeggs8a423642014-08-10 04:10:19 +10002236 }
Ben Skeggs26f6d882011-07-04 16:25:18 +10002237
Ben Skeggs0ad72862014-08-10 04:10:22 +10002238 nv50_dmac_destroy(&disp->mast.base, disp->disp);
Ben Skeggsbdb8c212011-11-12 01:30:24 +10002239
Ben Skeggs816af2f2011-11-16 15:48:48 +10002240 nouveau_bo_unmap(disp->sync);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01002241 if (disp->sync)
2242 nouveau_bo_unpin(disp->sync);
Ben Skeggs816af2f2011-11-16 15:48:48 +10002243 nouveau_bo_ref(NULL, &disp->sync);
Ben Skeggs51beb422011-07-05 10:33:08 +10002244
Ben Skeggs77145f12012-07-31 16:16:21 +10002245 nouveau_display(dev)->priv = NULL;
Ben Skeggs26f6d882011-07-04 16:25:18 +10002246 kfree(disp);
2247}
2248
2249int
Ben Skeggse225f442012-11-21 14:40:21 +10002250nv50_display_create(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10002251{
Ben Skeggs967e7bd2014-08-10 04:10:22 +10002252 struct nvif_device *device = &nouveau_drm(dev)->device;
Ben Skeggs77145f12012-07-31 16:16:21 +10002253 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs77145f12012-07-31 16:16:21 +10002254 struct dcb_table *dcb = &drm->vbios.dcb;
Ben Skeggs83fc0832011-07-05 13:08:40 +10002255 struct drm_connector *connector, *tmp;
Ben Skeggse225f442012-11-21 14:40:21 +10002256 struct nv50_disp *disp;
Ben Skeggscb75d972012-07-11 10:44:20 +10002257 struct dcb_output *dcbe;
Ben Skeggs7c5f6a82012-03-04 16:25:59 +10002258 int crtcs, ret, i;
Ben Skeggs26f6d882011-07-04 16:25:18 +10002259
2260 disp = kzalloc(sizeof(*disp), GFP_KERNEL);
2261 if (!disp)
2262 return -ENOMEM;
Ben Skeggs8a423642014-08-10 04:10:19 +10002263 INIT_LIST_HEAD(&disp->fbdma);
Ben Skeggs77145f12012-07-31 16:16:21 +10002264
2265 nouveau_display(dev)->priv = disp;
Ben Skeggse225f442012-11-21 14:40:21 +10002266 nouveau_display(dev)->dtor = nv50_display_destroy;
2267 nouveau_display(dev)->init = nv50_display_init;
2268 nouveau_display(dev)->fini = nv50_display_fini;
Ben Skeggsab0af552014-08-10 04:10:19 +10002269 nouveau_display(dev)->fb_ctor = nv50_fb_ctor;
2270 nouveau_display(dev)->fb_dtor = nv50_fb_dtor;
Ben Skeggs0ad72862014-08-10 04:10:22 +10002271 disp->disp = &nouveau_display(dev)->disp;
Ben Skeggs26f6d882011-07-04 16:25:18 +10002272
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002273 /* small shared memory area we use for notifiers and semaphores */
2274 ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
2275 0, 0x0000, NULL, &disp->sync);
2276 if (!ret) {
2277 ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01002278 if (!ret) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002279 ret = nouveau_bo_map(disp->sync);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01002280 if (ret)
2281 nouveau_bo_unpin(disp->sync);
2282 }
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002283 if (ret)
2284 nouveau_bo_ref(NULL, &disp->sync);
2285 }
2286
2287 if (ret)
2288 goto out;
2289
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002290 /* allocate master evo channel */
Ben Skeggs0ad72862014-08-10 04:10:22 +10002291 ret = nv50_dmac_create(disp->disp, NV50_DISP_MAST_CLASS, 0,
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002292 &(struct nv50_display_mast_class) {
2293 .pushbuf = EVO_PUSH_HANDLE(MAST, 0),
2294 }, sizeof(struct nv50_display_mast_class),
2295 disp->sync->bo.offset, &disp->mast.base);
2296 if (ret)
2297 goto out;
2298
Ben Skeggs438d99e2011-07-05 16:48:06 +10002299 /* create crtc objects to represent the hw heads */
Ben Skeggs0ad72862014-08-10 04:10:22 +10002300 if (disp->disp->oclass >= NVD0_DISP_CLASS)
Ben Skeggsdb2bec12014-08-10 04:10:22 +10002301 crtcs = nvif_rd32(device, 0x022448);
Ben Skeggs63718a02012-11-16 11:44:14 +10002302 else
2303 crtcs = 2;
2304
Ben Skeggs7c5f6a82012-03-04 16:25:59 +10002305 for (i = 0; i < crtcs; i++) {
Ben Skeggs0ad72862014-08-10 04:10:22 +10002306 ret = nv50_crtc_create(dev, i);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002307 if (ret)
2308 goto out;
2309 }
2310
Ben Skeggs83fc0832011-07-05 13:08:40 +10002311 /* create encoder/connector objects based on VBIOS DCB table */
2312 for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
2313 connector = nouveau_connector_create(dev, dcbe->connector);
2314 if (IS_ERR(connector))
2315 continue;
2316
Ben Skeggseb6313a2013-02-11 09:52:58 +10002317 if (dcbe->location == DCB_LOC_ON_CHIP) {
2318 switch (dcbe->type) {
2319 case DCB_OUTPUT_TMDS:
2320 case DCB_OUTPUT_LVDS:
2321 case DCB_OUTPUT_DP:
2322 ret = nv50_sor_create(connector, dcbe);
2323 break;
2324 case DCB_OUTPUT_ANALOG:
2325 ret = nv50_dac_create(connector, dcbe);
2326 break;
2327 default:
2328 ret = -ENODEV;
2329 break;
2330 }
2331 } else {
2332 ret = nv50_pior_create(connector, dcbe);
Ben Skeggs83fc0832011-07-05 13:08:40 +10002333 }
2334
Ben Skeggseb6313a2013-02-11 09:52:58 +10002335 if (ret) {
2336 NV_WARN(drm, "failed to create encoder %d/%d/%d: %d\n",
2337 dcbe->location, dcbe->type,
2338 ffs(dcbe->or) - 1, ret);
Ben Skeggs94f54f52013-03-05 22:26:06 +10002339 ret = 0;
Ben Skeggs83fc0832011-07-05 13:08:40 +10002340 }
2341 }
2342
2343 /* cull any connectors we created that don't have an encoder */
2344 list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) {
2345 if (connector->encoder_ids[0])
2346 continue;
2347
Ben Skeggs77145f12012-07-31 16:16:21 +10002348 NV_WARN(drm, "%s has no encoders, removing\n",
Jani Nikula8c6c3612014-06-03 14:56:18 +03002349 connector->name);
Ben Skeggs83fc0832011-07-05 13:08:40 +10002350 connector->funcs->destroy(connector);
2351 }
2352
Ben Skeggs26f6d882011-07-04 16:25:18 +10002353out:
2354 if (ret)
Ben Skeggse225f442012-11-21 14:40:21 +10002355 nv50_display_destroy(dev);
Ben Skeggs26f6d882011-07-04 16:25:18 +10002356 return ret;
2357}