blob: d4cbea19b8908628da62093d24a7936221a6edfa [file] [log] [blame]
Ben Skeggse225f442012-11-21 14:40:21 +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 Skeggs26f6d882011-07-04 16:25:18 +100029
Ben Skeggs77145f12012-07-31 16:16:21 +100030#include "nouveau_drm.h"
31#include "nouveau_dma.h"
32#include "nouveau_gem.h"
Ben Skeggs26f6d882011-07-04 16:25:18 +100033#include "nouveau_connector.h"
34#include "nouveau_encoder.h"
35#include "nouveau_crtc.h"
Ben Skeggsf589be82012-07-22 11:55:54 +100036#include "nouveau_fence.h"
Ben Skeggs3a89cd02011-07-07 10:47:10 +100037#include "nv50_display.h"
Ben Skeggs26f6d882011-07-04 16:25:18 +100038
Ben Skeggsb5a794b2012-10-16 14:18:32 +100039#include <core/client.h>
Ben Skeggs77145f12012-07-31 16:16:21 +100040#include <core/gpuobj.h>
Ben Skeggsb5a794b2012-10-16 14:18:32 +100041#include <core/class.h>
Ben Skeggs77145f12012-07-31 16:16:21 +100042
43#include <subdev/timer.h>
44#include <subdev/bar.h>
45#include <subdev/fb.h>
46
Ben Skeggs8a464382011-11-12 23:52:07 +100047#define EVO_DMA_NR 9
48
Ben Skeggsbdb8c212011-11-12 01:30:24 +100049#define EVO_MASTER (0x00)
Ben Skeggsa63a97e2011-11-16 15:22:34 +100050#define EVO_FLIP(c) (0x01 + (c))
Ben Skeggs8a464382011-11-12 23:52:07 +100051#define EVO_OVLY(c) (0x05 + (c))
52#define EVO_OIMM(c) (0x09 + (c))
Ben Skeggsbdb8c212011-11-12 01:30:24 +100053#define EVO_CURS(c) (0x0d + (c))
54
Ben Skeggs816af2f2011-11-16 15:48:48 +100055/* offsets in shared sync bo of various structures */
56#define EVO_SYNC(c, o) ((c) * 0x0100 + (o))
57#define EVO_MAST_NTFY EVO_SYNC( 0, 0x00)
58#define EVO_FLIP_SEM0(c) EVO_SYNC((c), 0x00)
59#define EVO_FLIP_SEM1(c) EVO_SYNC((c), 0x10)
60
Ben Skeggsb5a794b2012-10-16 14:18:32 +100061#define EVO_CORE_HANDLE (0xd1500000)
62#define EVO_CHAN_HANDLE(t,i) (0xd15c0000 | (((t) & 0x00ff) << 8) | (i))
63#define EVO_CHAN_OCLASS(t,c) ((nv_hclass(c) & 0xff00) | ((t) & 0x00ff))
64#define EVO_PUSH_HANDLE(t,i) (0xd15b0000 | (i) | \
65 (((NV50_DISP_##t##_CLASS) & 0x00ff) << 8))
66
67/******************************************************************************
68 * EVO channel
69 *****************************************************************************/
70
Ben Skeggse225f442012-11-21 14:40:21 +100071struct nv50_chan {
Ben Skeggsb5a794b2012-10-16 14:18:32 +100072 struct nouveau_object *user;
73 u32 handle;
74};
75
76static int
Ben Skeggse225f442012-11-21 14:40:21 +100077nv50_chan_create(struct nouveau_object *core, u32 bclass, u8 head,
78 void *data, u32 size, struct nv50_chan *chan)
Ben Skeggsb5a794b2012-10-16 14:18:32 +100079{
80 struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS);
81 const u32 oclass = EVO_CHAN_OCLASS(bclass, core);
82 const u32 handle = EVO_CHAN_HANDLE(bclass, head);
83 int ret;
84
85 ret = nouveau_object_new(client, EVO_CORE_HANDLE, handle,
86 oclass, data, size, &chan->user);
87 if (ret)
88 return ret;
89
90 chan->handle = handle;
91 return 0;
92}
93
94static void
Ben Skeggse225f442012-11-21 14:40:21 +100095nv50_chan_destroy(struct nouveau_object *core, struct nv50_chan *chan)
Ben Skeggsb5a794b2012-10-16 14:18:32 +100096{
97 struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS);
98 if (chan->handle)
99 nouveau_object_del(client, EVO_CORE_HANDLE, chan->handle);
100}
101
102/******************************************************************************
103 * PIO EVO channel
104 *****************************************************************************/
105
Ben Skeggse225f442012-11-21 14:40:21 +1000106struct nv50_pioc {
107 struct nv50_chan base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000108};
109
110static void
Ben Skeggse225f442012-11-21 14:40:21 +1000111nv50_pioc_destroy(struct nouveau_object *core, struct nv50_pioc *pioc)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000112{
Ben Skeggse225f442012-11-21 14:40:21 +1000113 nv50_chan_destroy(core, &pioc->base);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000114}
115
116static int
Ben Skeggse225f442012-11-21 14:40:21 +1000117nv50_pioc_create(struct nouveau_object *core, u32 bclass, u8 head,
118 void *data, u32 size, struct nv50_pioc *pioc)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000119{
Ben Skeggse225f442012-11-21 14:40:21 +1000120 return nv50_chan_create(core, bclass, head, data, size, &pioc->base);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000121}
122
123/******************************************************************************
124 * DMA EVO channel
125 *****************************************************************************/
126
Ben Skeggse225f442012-11-21 14:40:21 +1000127struct nv50_dmac {
128 struct nv50_chan base;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000129 dma_addr_t handle;
130 u32 *ptr;
Daniel Vetter59ad1462012-12-02 14:49:44 +0100131
132 /* Protects against concurrent pushbuf access to this channel, lock is
133 * grabbed by evo_wait (if the pushbuf reservation is successful) and
134 * dropped again by evo_kick. */
135 struct mutex lock;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000136};
137
138static void
Ben Skeggse225f442012-11-21 14:40:21 +1000139nv50_dmac_destroy(struct nouveau_object *core, struct nv50_dmac *dmac)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000140{
141 if (dmac->ptr) {
142 struct pci_dev *pdev = nv_device(core)->pdev;
143 pci_free_consistent(pdev, PAGE_SIZE, dmac->ptr, dmac->handle);
144 }
145
Ben Skeggse225f442012-11-21 14:40:21 +1000146 nv50_chan_destroy(core, &dmac->base);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000147}
148
149static int
Ben Skeggs47057302012-11-16 13:58:48 +1000150nv50_dmac_create_fbdma(struct nouveau_object *core, u32 parent)
151{
152 struct nouveau_fb *pfb = nouveau_fb(core);
153 struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS);
154 struct nouveau_object *object;
155 int ret = nouveau_object_new(client, parent, NvEvoVRAM_LP,
156 NV_DMA_IN_MEMORY_CLASS,
157 &(struct nv_dma_class) {
158 .flags = NV_DMA_TARGET_VRAM |
159 NV_DMA_ACCESS_RDWR,
160 .start = 0,
161 .limit = pfb->ram.size - 1,
162 .conf0 = NV50_DMA_CONF0_ENABLE |
163 NV50_DMA_CONF0_PART_256,
164 }, sizeof(struct nv_dma_class), &object);
165 if (ret)
166 return ret;
167
168 ret = nouveau_object_new(client, parent, NvEvoFB16,
169 NV_DMA_IN_MEMORY_CLASS,
170 &(struct nv_dma_class) {
171 .flags = NV_DMA_TARGET_VRAM |
172 NV_DMA_ACCESS_RDWR,
173 .start = 0,
174 .limit = pfb->ram.size - 1,
175 .conf0 = NV50_DMA_CONF0_ENABLE | 0x70 |
176 NV50_DMA_CONF0_PART_256,
177 }, sizeof(struct nv_dma_class), &object);
178 if (ret)
179 return ret;
180
181 ret = nouveau_object_new(client, parent, NvEvoFB32,
182 NV_DMA_IN_MEMORY_CLASS,
183 &(struct nv_dma_class) {
184 .flags = NV_DMA_TARGET_VRAM |
185 NV_DMA_ACCESS_RDWR,
186 .start = 0,
187 .limit = pfb->ram.size - 1,
188 .conf0 = NV50_DMA_CONF0_ENABLE | 0x7a |
189 NV50_DMA_CONF0_PART_256,
190 }, sizeof(struct nv_dma_class), &object);
191 return ret;
192}
193
194static int
195nvc0_dmac_create_fbdma(struct nouveau_object *core, u32 parent)
196{
197 struct nouveau_fb *pfb = nouveau_fb(core);
198 struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS);
199 struct nouveau_object *object;
200 int ret = nouveau_object_new(client, parent, NvEvoVRAM_LP,
201 NV_DMA_IN_MEMORY_CLASS,
202 &(struct nv_dma_class) {
203 .flags = NV_DMA_TARGET_VRAM |
204 NV_DMA_ACCESS_RDWR,
205 .start = 0,
206 .limit = pfb->ram.size - 1,
207 .conf0 = NVC0_DMA_CONF0_ENABLE,
208 }, sizeof(struct nv_dma_class), &object);
209 if (ret)
210 return ret;
211
212 ret = nouveau_object_new(client, parent, NvEvoFB16,
213 NV_DMA_IN_MEMORY_CLASS,
214 &(struct nv_dma_class) {
215 .flags = NV_DMA_TARGET_VRAM |
216 NV_DMA_ACCESS_RDWR,
217 .start = 0,
218 .limit = pfb->ram.size - 1,
219 .conf0 = NVC0_DMA_CONF0_ENABLE | 0xfe,
220 }, sizeof(struct nv_dma_class), &object);
221 if (ret)
222 return ret;
223
224 ret = nouveau_object_new(client, parent, NvEvoFB32,
225 NV_DMA_IN_MEMORY_CLASS,
226 &(struct nv_dma_class) {
227 .flags = NV_DMA_TARGET_VRAM |
228 NV_DMA_ACCESS_RDWR,
229 .start = 0,
230 .limit = pfb->ram.size - 1,
231 .conf0 = NVC0_DMA_CONF0_ENABLE | 0xfe,
232 }, sizeof(struct nv_dma_class), &object);
233 return ret;
234}
235
236static int
237nvd0_dmac_create_fbdma(struct nouveau_object *core, u32 parent)
238{
239 struct nouveau_fb *pfb = nouveau_fb(core);
240 struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS);
241 struct nouveau_object *object;
242 int ret = nouveau_object_new(client, parent, NvEvoVRAM_LP,
243 NV_DMA_IN_MEMORY_CLASS,
244 &(struct nv_dma_class) {
245 .flags = NV_DMA_TARGET_VRAM |
246 NV_DMA_ACCESS_RDWR,
247 .start = 0,
248 .limit = pfb->ram.size - 1,
249 .conf0 = NVD0_DMA_CONF0_ENABLE |
250 NVD0_DMA_CONF0_PAGE_LP,
251 }, sizeof(struct nv_dma_class), &object);
252 if (ret)
253 return ret;
254
255 ret = nouveau_object_new(client, parent, NvEvoFB32,
256 NV_DMA_IN_MEMORY_CLASS,
257 &(struct nv_dma_class) {
258 .flags = NV_DMA_TARGET_VRAM |
259 NV_DMA_ACCESS_RDWR,
260 .start = 0,
261 .limit = pfb->ram.size - 1,
262 .conf0 = NVD0_DMA_CONF0_ENABLE | 0xfe |
263 NVD0_DMA_CONF0_PAGE_LP,
264 }, sizeof(struct nv_dma_class), &object);
265 return ret;
266}
267
268static int
Ben Skeggse225f442012-11-21 14:40:21 +1000269nv50_dmac_create(struct nouveau_object *core, u32 bclass, u8 head,
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000270 void *data, u32 size, u64 syncbuf,
Ben Skeggse225f442012-11-21 14:40:21 +1000271 struct nv50_dmac *dmac)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000272{
273 struct nouveau_fb *pfb = nouveau_fb(core);
274 struct nouveau_object *client = nv_pclass(core, NV_CLIENT_CLASS);
275 struct nouveau_object *object;
276 u32 pushbuf = *(u32 *)data;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000277 int ret;
278
Daniel Vetter59ad1462012-12-02 14:49:44 +0100279 mutex_init(&dmac->lock);
280
Ben Skeggs47057302012-11-16 13:58:48 +1000281 dmac->ptr = pci_alloc_consistent(nv_device(core)->pdev, PAGE_SIZE,
282 &dmac->handle);
283 if (!dmac->ptr)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000284 return -ENOMEM;
285
286 ret = nouveau_object_new(client, NVDRM_DEVICE, pushbuf,
287 NV_DMA_FROM_MEMORY_CLASS,
288 &(struct nv_dma_class) {
289 .flags = NV_DMA_TARGET_PCI_US |
290 NV_DMA_ACCESS_RD,
Ben Skeggs47057302012-11-16 13:58:48 +1000291 .start = dmac->handle + 0x0000,
292 .limit = dmac->handle + 0x0fff,
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000293 }, sizeof(struct nv_dma_class), &object);
294 if (ret)
295 return ret;
296
Ben Skeggse225f442012-11-21 14:40:21 +1000297 ret = nv50_chan_create(core, bclass, head, data, size, &dmac->base);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000298 if (ret)
299 return ret;
300
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000301 ret = nouveau_object_new(client, dmac->base.handle, NvEvoSync,
302 NV_DMA_IN_MEMORY_CLASS,
303 &(struct nv_dma_class) {
304 .flags = NV_DMA_TARGET_VRAM |
305 NV_DMA_ACCESS_RDWR,
306 .start = syncbuf + 0x0000,
307 .limit = syncbuf + 0x0fff,
308 }, sizeof(struct nv_dma_class), &object);
309 if (ret)
Ben Skeggs47057302012-11-16 13:58:48 +1000310 return ret;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000311
312 ret = nouveau_object_new(client, dmac->base.handle, NvEvoVRAM,
313 NV_DMA_IN_MEMORY_CLASS,
314 &(struct nv_dma_class) {
315 .flags = NV_DMA_TARGET_VRAM |
316 NV_DMA_ACCESS_RDWR,
317 .start = 0,
318 .limit = pfb->ram.size - 1,
319 }, sizeof(struct nv_dma_class), &object);
320 if (ret)
Ben Skeggs47057302012-11-16 13:58:48 +1000321 return ret;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000322
Ben Skeggs47057302012-11-16 13:58:48 +1000323 if (nv_device(core)->card_type < NV_C0)
324 ret = nv50_dmac_create_fbdma(core, dmac->base.handle);
325 else
326 if (nv_device(core)->card_type < NV_D0)
327 ret = nvc0_dmac_create_fbdma(core, dmac->base.handle);
328 else
329 ret = nvd0_dmac_create_fbdma(core, dmac->base.handle);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000330 return ret;
331}
332
Ben Skeggse225f442012-11-21 14:40:21 +1000333struct nv50_mast {
334 struct nv50_dmac base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000335};
336
Ben Skeggse225f442012-11-21 14:40:21 +1000337struct nv50_curs {
338 struct nv50_pioc base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000339};
340
Ben Skeggse225f442012-11-21 14:40:21 +1000341struct nv50_sync {
342 struct nv50_dmac base;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000343 struct {
Ben Skeggs3376ee32011-11-12 14:28:12 +1000344 u32 offset;
345 u16 value;
346 } sem;
347};
348
Ben Skeggse225f442012-11-21 14:40:21 +1000349struct nv50_ovly {
350 struct nv50_dmac base;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000351};
Ben Skeggsf20ce962011-07-08 13:17:01 +1000352
Ben Skeggse225f442012-11-21 14:40:21 +1000353struct nv50_oimm {
354 struct nv50_pioc base;
Ben Skeggs26f6d882011-07-04 16:25:18 +1000355};
356
Ben Skeggse225f442012-11-21 14:40:21 +1000357struct nv50_head {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +1000358 struct nouveau_crtc base;
Ben Skeggse225f442012-11-21 14:40:21 +1000359 struct nv50_curs curs;
360 struct nv50_sync sync;
361 struct nv50_ovly ovly;
362 struct nv50_oimm oimm;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000363};
364
Ben Skeggse225f442012-11-21 14:40:21 +1000365#define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c))
366#define nv50_curs(c) (&nv50_head(c)->curs)
367#define nv50_sync(c) (&nv50_head(c)->sync)
368#define nv50_ovly(c) (&nv50_head(c)->ovly)
369#define nv50_oimm(c) (&nv50_head(c)->oimm)
370#define nv50_chan(c) (&(c)->base.base)
371#define nv50_vers(c) nv_mclass(nv50_chan(c)->user)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000372
Ben Skeggse225f442012-11-21 14:40:21 +1000373struct nv50_disp {
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000374 struct nouveau_object *core;
Ben Skeggse225f442012-11-21 14:40:21 +1000375 struct nv50_mast mast;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000376
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000377 u32 modeset;
378
379 struct nouveau_bo *sync;
Ben Skeggsdd0e3d52012-10-16 14:00:31 +1000380};
381
Ben Skeggse225f442012-11-21 14:40:21 +1000382static struct nv50_disp *
383nv50_disp(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +1000384{
Ben Skeggs77145f12012-07-31 16:16:21 +1000385 return nouveau_display(dev)->priv;
Ben Skeggs26f6d882011-07-04 16:25:18 +1000386}
387
Ben Skeggse225f442012-11-21 14:40:21 +1000388#define nv50_mast(d) (&nv50_disp(d)->mast)
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000389
Ben Skeggsbdb8c212011-11-12 01:30:24 +1000390static struct drm_crtc *
Ben Skeggse225f442012-11-21 14:40:21 +1000391nv50_display_crtc_get(struct drm_encoder *encoder)
Ben Skeggsbdb8c212011-11-12 01:30:24 +1000392{
393 return nouveau_encoder(encoder)->crtc;
394}
395
396/******************************************************************************
397 * EVO channel helpers
398 *****************************************************************************/
Ben Skeggs51beb422011-07-05 10:33:08 +1000399static u32 *
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000400evo_wait(void *evoc, int nr)
Ben Skeggs51beb422011-07-05 10:33:08 +1000401{
Ben Skeggse225f442012-11-21 14:40:21 +1000402 struct nv50_dmac *dmac = evoc;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000403 u32 put = nv_ro32(dmac->base.user, 0x0000) / 4;
Ben Skeggs51beb422011-07-05 10:33:08 +1000404
Daniel Vetter59ad1462012-12-02 14:49:44 +0100405 mutex_lock(&dmac->lock);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000406 if (put + nr >= (PAGE_SIZE / 4) - 8) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000407 dmac->ptr[put] = 0x20000000;
Ben Skeggs51beb422011-07-05 10:33:08 +1000408
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000409 nv_wo32(dmac->base.user, 0x0000, 0x00000000);
410 if (!nv_wait(dmac->base.user, 0x0004, ~0, 0x00000000)) {
Daniel Vetter59ad1462012-12-02 14:49:44 +0100411 mutex_unlock(&dmac->lock);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000412 NV_ERROR(dmac->base.user, "channel stalled\n");
Ben Skeggs51beb422011-07-05 10:33:08 +1000413 return NULL;
414 }
415
416 put = 0;
417 }
418
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000419 return dmac->ptr + put;
Ben Skeggs51beb422011-07-05 10:33:08 +1000420}
421
422static void
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000423evo_kick(u32 *push, void *evoc)
Ben Skeggs51beb422011-07-05 10:33:08 +1000424{
Ben Skeggse225f442012-11-21 14:40:21 +1000425 struct nv50_dmac *dmac = evoc;
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000426 nv_wo32(dmac->base.user, 0x0000, (push - dmac->ptr) << 2);
Daniel Vetter59ad1462012-12-02 14:49:44 +0100427 mutex_unlock(&dmac->lock);
Ben Skeggs51beb422011-07-05 10:33:08 +1000428}
429
430#define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m))
431#define evo_data(p,d) *((p)++) = (d)
432
Ben Skeggs3376ee32011-11-12 14:28:12 +1000433static bool
434evo_sync_wait(void *data)
435{
Ben Skeggs816af2f2011-11-16 15:48:48 +1000436 return nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000437}
438
439static int
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000440evo_sync(struct drm_device *dev)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000441{
Ben Skeggs77145f12012-07-31 16:16:21 +1000442 struct nouveau_device *device = nouveau_dev(dev);
Ben Skeggse225f442012-11-21 14:40:21 +1000443 struct nv50_disp *disp = nv50_disp(dev);
444 struct nv50_mast *mast = nv50_mast(dev);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000445 u32 *push = evo_wait(mast, 8);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000446 if (push) {
Ben Skeggs816af2f2011-11-16 15:48:48 +1000447 nouveau_bo_wr32(disp->sync, EVO_MAST_NTFY, 0x00000000);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000448 evo_mthd(push, 0x0084, 1);
Ben Skeggs816af2f2011-11-16 15:48:48 +1000449 evo_data(push, 0x80000000 | EVO_MAST_NTFY);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000450 evo_mthd(push, 0x0080, 2);
451 evo_data(push, 0x00000000);
452 evo_data(push, 0x00000000);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000453 evo_kick(push, mast);
Ben Skeggs77145f12012-07-31 16:16:21 +1000454 if (nv_wait_cb(device, evo_sync_wait, disp->sync))
Ben Skeggs3376ee32011-11-12 14:28:12 +1000455 return 0;
456 }
457
458 return -EBUSY;
459}
460
461/******************************************************************************
Ben Skeggsa63a97e2011-11-16 15:22:34 +1000462 * Page flipping channel
Ben Skeggs3376ee32011-11-12 14:28:12 +1000463 *****************************************************************************/
464struct nouveau_bo *
Ben Skeggse225f442012-11-21 14:40:21 +1000465nv50_display_crtc_sema(struct drm_device *dev, int crtc)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000466{
Ben Skeggse225f442012-11-21 14:40:21 +1000467 return nv50_disp(dev)->sync;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000468}
469
470void
Ben Skeggse225f442012-11-21 14:40:21 +1000471nv50_display_flip_stop(struct drm_crtc *crtc)
Ben Skeggs3376ee32011-11-12 14:28:12 +1000472{
Ben Skeggse225f442012-11-21 14:40:21 +1000473 struct nv50_sync *sync = nv50_sync(crtc);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000474 u32 *push;
475
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000476 push = evo_wait(sync, 8);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000477 if (push) {
478 evo_mthd(push, 0x0084, 1);
479 evo_data(push, 0x00000000);
480 evo_mthd(push, 0x0094, 1);
481 evo_data(push, 0x00000000);
482 evo_mthd(push, 0x00c0, 1);
483 evo_data(push, 0x00000000);
484 evo_mthd(push, 0x0080, 1);
485 evo_data(push, 0x00000000);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000486 evo_kick(push, sync);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000487 }
488}
489
490int
Ben Skeggse225f442012-11-21 14:40:21 +1000491nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
Ben Skeggs3376ee32011-11-12 14:28:12 +1000492 struct nouveau_channel *chan, u32 swap_interval)
493{
494 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
Ben Skeggse225f442012-11-21 14:40:21 +1000495 struct nv50_disp *disp = nv50_disp(crtc->dev);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000496 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +1000497 struct nv50_sync *sync = nv50_sync(crtc);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000498 u32 *push;
499 int ret;
500
501 swap_interval <<= 4;
502 if (swap_interval == 0)
503 swap_interval |= 0x100;
504
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000505 push = evo_wait(sync, 128);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000506 if (unlikely(push == NULL))
507 return -EBUSY;
508
509 /* synchronise with the rendering channel, if necessary */
510 if (likely(chan)) {
511 ret = RING_SPACE(chan, 10);
512 if (ret)
513 return ret;
514
Ben Skeggsed5085a52012-11-16 13:16:51 +1000515 if (nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) {
516 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
517 OUT_RING (chan, NvEvoSema0 + nv_crtc->index);
518 OUT_RING (chan, sync->sem.offset);
519 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
520 OUT_RING (chan, 0xf00d0000 | sync->sem.value);
521 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_OFFSET, 2);
522 OUT_RING (chan, sync->sem.offset ^ 0x10);
523 OUT_RING (chan, 0x74b1e000);
524 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
525 if (nv_mclass(chan->object) < NV84_CHANNEL_DMA_CLASS)
526 OUT_RING (chan, NvSema);
527 else
528 OUT_RING (chan, chan->vram);
529 } else {
530 u64 offset = nvc0_fence_crtc(chan, nv_crtc->index);
531 offset += sync->sem.offset;
Ben Skeggs35bcf5d2012-04-30 11:34:10 -0500532
Ben Skeggsed5085a52012-11-16 13:16:51 +1000533 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
534 OUT_RING (chan, upper_32_bits(offset));
535 OUT_RING (chan, lower_32_bits(offset));
536 OUT_RING (chan, 0xf00d0000 | sync->sem.value);
537 OUT_RING (chan, 0x1002);
538 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
539 OUT_RING (chan, upper_32_bits(offset));
540 OUT_RING (chan, lower_32_bits(offset ^ 0x10));
541 OUT_RING (chan, 0x74b1e000);
542 OUT_RING (chan, 0x1001);
543 }
Ben Skeggs3376ee32011-11-12 14:28:12 +1000544
Ben Skeggs3376ee32011-11-12 14:28:12 +1000545 FIRE_RING (chan);
546 } else {
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000547 nouveau_bo_wr32(disp->sync, sync->sem.offset / 4,
548 0xf00d0000 | sync->sem.value);
549 evo_sync(crtc->dev);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000550 }
551
552 /* queue the flip */
553 evo_mthd(push, 0x0100, 1);
554 evo_data(push, 0xfffe0000);
555 evo_mthd(push, 0x0084, 1);
556 evo_data(push, swap_interval);
557 if (!(swap_interval & 0x00000100)) {
558 evo_mthd(push, 0x00e0, 1);
559 evo_data(push, 0x40000000);
560 }
561 evo_mthd(push, 0x0088, 4);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000562 evo_data(push, sync->sem.offset);
563 evo_data(push, 0xf00d0000 | sync->sem.value);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000564 evo_data(push, 0x74b1e000);
565 evo_data(push, NvEvoSync);
566 evo_mthd(push, 0x00a0, 2);
567 evo_data(push, 0x00000000);
568 evo_data(push, 0x00000000);
569 evo_mthd(push, 0x00c0, 1);
570 evo_data(push, nv_fb->r_dma);
571 evo_mthd(push, 0x0110, 2);
572 evo_data(push, 0x00000000);
573 evo_data(push, 0x00000000);
Ben Skeggse225f442012-11-21 14:40:21 +1000574 if (nv50_vers(sync) < NVD0_DISP_SYNC_CLASS) {
Ben Skeggsed5085a52012-11-16 13:16:51 +1000575 evo_mthd(push, 0x0800, 5);
576 evo_data(push, nv_fb->nvbo->bo.offset >> 8);
577 evo_data(push, 0);
578 evo_data(push, (fb->height << 16) | fb->width);
579 evo_data(push, nv_fb->r_pitch);
580 evo_data(push, nv_fb->r_format);
581 } else {
582 evo_mthd(push, 0x0400, 5);
583 evo_data(push, nv_fb->nvbo->bo.offset >> 8);
584 evo_data(push, 0);
585 evo_data(push, (fb->height << 16) | fb->width);
586 evo_data(push, nv_fb->r_pitch);
587 evo_data(push, nv_fb->r_format);
588 }
Ben Skeggs3376ee32011-11-12 14:28:12 +1000589 evo_mthd(push, 0x0080, 1);
590 evo_data(push, 0x00000000);
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000591 evo_kick(push, sync);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000592
Ben Skeggsb5a794b2012-10-16 14:18:32 +1000593 sync->sem.offset ^= 0x10;
594 sync->sem.value++;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000595 return 0;
596}
597
Ben Skeggs26f6d882011-07-04 16:25:18 +1000598/******************************************************************************
Ben Skeggs438d99e2011-07-05 16:48:06 +1000599 * CRTC
600 *****************************************************************************/
601static int
Ben Skeggse225f442012-11-21 14:40:21 +1000602nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000603{
Ben Skeggse225f442012-11-21 14:40:21 +1000604 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde691852011-10-17 12:23:41 +1000605 struct nouveau_connector *nv_connector;
606 struct drm_connector *connector;
607 u32 *push, mode = 0x00;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000608
Ben Skeggs488ff202011-10-17 10:38:10 +1000609 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggsde691852011-10-17 12:23:41 +1000610 connector = &nv_connector->base;
611 if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) {
612 if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3)
613 mode = DITHERING_MODE_DYNAMIC2X2;
614 } else {
615 mode = nv_connector->dithering_mode;
616 }
617
618 if (nv_connector->dithering_depth == DITHERING_DEPTH_AUTO) {
619 if (connector->display_info.bpc >= 8)
620 mode |= DITHERING_DEPTH_8BPC;
621 } else {
622 mode |= nv_connector->dithering_depth;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000623 }
624
Ben Skeggsde8268c2012-11-16 10:24:31 +1000625 push = evo_wait(mast, 4);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000626 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000627 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000628 evo_mthd(push, 0x08a0 + (nv_crtc->index * 0x0400), 1);
629 evo_data(push, mode);
630 } else
Ben Skeggse225f442012-11-21 14:40:21 +1000631 if (nv50_vers(mast) < NVE0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000632 evo_mthd(push, 0x0490 + (nv_crtc->index * 0x0300), 1);
633 evo_data(push, mode);
634 } else {
635 evo_mthd(push, 0x04a0 + (nv_crtc->index * 0x0300), 1);
636 evo_data(push, mode);
637 }
638
Ben Skeggs438d99e2011-07-05 16:48:06 +1000639 if (update) {
640 evo_mthd(push, 0x0080, 1);
641 evo_data(push, 0x00000000);
642 }
Ben Skeggsde8268c2012-11-16 10:24:31 +1000643 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000644 }
645
646 return 0;
647}
648
649static int
Ben Skeggse225f442012-11-21 14:40:21 +1000650nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000651{
Ben Skeggse225f442012-11-21 14:40:21 +1000652 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggs92854622011-11-11 23:49:06 +1000653 struct drm_display_mode *omode, *umode = &nv_crtc->base.mode;
Ben Skeggs3376ee32011-11-12 14:28:12 +1000654 struct drm_crtc *crtc = &nv_crtc->base;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000655 struct nouveau_connector *nv_connector;
Ben Skeggs92854622011-11-11 23:49:06 +1000656 int mode = DRM_MODE_SCALE_NONE;
657 u32 oX, oY, *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000658
Ben Skeggs92854622011-11-11 23:49:06 +1000659 /* start off at the resolution we programmed the crtc for, this
660 * effectively handles NONE/FULL scaling
661 */
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000662 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggs92854622011-11-11 23:49:06 +1000663 if (nv_connector && nv_connector->native_mode)
664 mode = nv_connector->scaling_mode;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000665
Ben Skeggs92854622011-11-11 23:49:06 +1000666 if (mode != DRM_MODE_SCALE_NONE)
667 omode = nv_connector->native_mode;
668 else
669 omode = umode;
670
671 oX = omode->hdisplay;
672 oY = omode->vdisplay;
673 if (omode->flags & DRM_MODE_FLAG_DBLSCAN)
674 oY *= 2;
675
676 /* add overscan compensation if necessary, will keep the aspect
677 * ratio the same as the backend mode unless overridden by the
678 * user setting both hborder and vborder properties.
679 */
680 if (nv_connector && ( nv_connector->underscan == UNDERSCAN_ON ||
681 (nv_connector->underscan == UNDERSCAN_AUTO &&
682 nv_connector->edid &&
683 drm_detect_hdmi_monitor(nv_connector->edid)))) {
684 u32 bX = nv_connector->underscan_hborder;
685 u32 bY = nv_connector->underscan_vborder;
686 u32 aspect = (oY << 19) / oX;
687
688 if (bX) {
689 oX -= (bX * 2);
690 if (bY) oY -= (bY * 2);
691 else oY = ((oX * aspect) + (aspect / 2)) >> 19;
692 } else {
693 oX -= (oX >> 4) + 32;
694 if (bY) oY -= (bY * 2);
695 else oY = ((oX * aspect) + (aspect / 2)) >> 19;
Ben Skeggsf3fdc522011-07-07 16:01:57 +1000696 }
697 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000698
Ben Skeggs92854622011-11-11 23:49:06 +1000699 /* handle CENTER/ASPECT scaling, taking into account the areas
700 * removed already for overscan compensation
701 */
702 switch (mode) {
703 case DRM_MODE_SCALE_CENTER:
704 oX = min((u32)umode->hdisplay, oX);
705 oY = min((u32)umode->vdisplay, oY);
706 /* fall-through */
707 case DRM_MODE_SCALE_ASPECT:
708 if (oY < oX) {
709 u32 aspect = (umode->hdisplay << 19) / umode->vdisplay;
710 oX = ((oY * aspect) + (aspect / 2)) >> 19;
711 } else {
712 u32 aspect = (umode->vdisplay << 19) / umode->hdisplay;
713 oY = ((oX * aspect) + (aspect / 2)) >> 19;
714 }
715 break;
716 default:
717 break;
718 }
719
Ben Skeggsde8268c2012-11-16 10:24:31 +1000720 push = evo_wait(mast, 8);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000721 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000722 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000723 /*XXX: SCALE_CTRL_ACTIVE??? */
724 evo_mthd(push, 0x08d8 + (nv_crtc->index * 0x400), 2);
725 evo_data(push, (oY << 16) | oX);
726 evo_data(push, (oY << 16) | oX);
727 evo_mthd(push, 0x08a4 + (nv_crtc->index * 0x400), 1);
728 evo_data(push, 0x00000000);
729 evo_mthd(push, 0x08c8 + (nv_crtc->index * 0x400), 1);
730 evo_data(push, umode->vdisplay << 16 | umode->hdisplay);
731 } else {
732 evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3);
733 evo_data(push, (oY << 16) | oX);
734 evo_data(push, (oY << 16) | oX);
735 evo_data(push, (oY << 16) | oX);
736 evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1);
737 evo_data(push, 0x00000000);
738 evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1);
739 evo_data(push, umode->vdisplay << 16 | umode->hdisplay);
740 }
741
742 evo_kick(push, mast);
743
Ben Skeggs3376ee32011-11-12 14:28:12 +1000744 if (update) {
Ben Skeggse225f442012-11-21 14:40:21 +1000745 nv50_display_flip_stop(crtc);
746 nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000747 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000748 }
749
750 return 0;
751}
752
753static int
Ben Skeggse225f442012-11-21 14:40:21 +1000754nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update)
Ben Skeggsf9887d02012-11-21 13:03:42 +1000755{
Ben Skeggse225f442012-11-21 14:40:21 +1000756 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsf9887d02012-11-21 13:03:42 +1000757 u32 *push, hue, vib;
758 int adj;
759
760 adj = (nv_crtc->color_vibrance > 0) ? 50 : 0;
761 vib = ((nv_crtc->color_vibrance * 2047 + adj) / 100) & 0xfff;
762 hue = ((nv_crtc->vibrant_hue * 2047) / 100) & 0xfff;
763
764 push = evo_wait(mast, 16);
765 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000766 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsf9887d02012-11-21 13:03:42 +1000767 evo_mthd(push, 0x08a8 + (nv_crtc->index * 0x400), 1);
768 evo_data(push, (hue << 20) | (vib << 8));
769 } else {
770 evo_mthd(push, 0x0498 + (nv_crtc->index * 0x300), 1);
771 evo_data(push, (hue << 20) | (vib << 8));
772 }
773
774 if (update) {
775 evo_mthd(push, 0x0080, 1);
776 evo_data(push, 0x00000000);
777 }
778 evo_kick(push, mast);
779 }
780
781 return 0;
782}
783
784static int
Ben Skeggse225f442012-11-21 14:40:21 +1000785nv50_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb,
Ben Skeggs438d99e2011-07-05 16:48:06 +1000786 int x, int y, bool update)
787{
788 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb);
Ben Skeggse225f442012-11-21 14:40:21 +1000789 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000790 u32 *push;
791
Ben Skeggsde8268c2012-11-16 10:24:31 +1000792 push = evo_wait(mast, 16);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000793 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000794 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000795 evo_mthd(push, 0x0860 + (nv_crtc->index * 0x400), 1);
796 evo_data(push, nvfb->nvbo->bo.offset >> 8);
797 evo_mthd(push, 0x0868 + (nv_crtc->index * 0x400), 3);
798 evo_data(push, (fb->height << 16) | fb->width);
799 evo_data(push, nvfb->r_pitch);
800 evo_data(push, nvfb->r_format);
801 evo_mthd(push, 0x08c0 + (nv_crtc->index * 0x400), 1);
802 evo_data(push, (y << 16) | x);
Ben Skeggse225f442012-11-21 14:40:21 +1000803 if (nv50_vers(mast) > NV50_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000804 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
805 evo_data(push, nvfb->r_dma);
806 }
807 } else {
808 evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1);
809 evo_data(push, nvfb->nvbo->bo.offset >> 8);
810 evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4);
811 evo_data(push, (fb->height << 16) | fb->width);
812 evo_data(push, nvfb->r_pitch);
813 evo_data(push, nvfb->r_format);
814 evo_data(push, nvfb->r_dma);
815 evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1);
816 evo_data(push, (y << 16) | x);
817 }
818
Ben Skeggsa46232e2011-07-07 15:23:48 +1000819 if (update) {
820 evo_mthd(push, 0x0080, 1);
821 evo_data(push, 0x00000000);
822 }
Ben Skeggsde8268c2012-11-16 10:24:31 +1000823 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000824 }
825
Ben Skeggsc0cc92a2011-07-06 11:40:45 +1000826 nv_crtc->fb.tile_flags = nvfb->r_dma;
Ben Skeggs438d99e2011-07-05 16:48:06 +1000827 return 0;
828}
829
830static void
Ben Skeggse225f442012-11-21 14:40:21 +1000831nv50_crtc_cursor_show(struct nouveau_crtc *nv_crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000832{
Ben Skeggse225f442012-11-21 14:40:21 +1000833 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000834 u32 *push = evo_wait(mast, 16);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000835 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000836 if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000837 evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2);
838 evo_data(push, 0x85000000);
839 evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
840 } else
Ben Skeggse225f442012-11-21 14:40:21 +1000841 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000842 evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2);
843 evo_data(push, 0x85000000);
844 evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
845 evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1);
846 evo_data(push, NvEvoVRAM);
847 } else {
Ben Skeggs438d99e2011-07-05 16:48:06 +1000848 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2);
849 evo_data(push, 0x85000000);
850 evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
851 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
Ben Skeggs37b034a2011-07-08 14:43:19 +1000852 evo_data(push, NvEvoVRAM);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000853 }
854 evo_kick(push, mast);
855 }
856}
857
858static void
Ben Skeggse225f442012-11-21 14:40:21 +1000859nv50_crtc_cursor_hide(struct nouveau_crtc *nv_crtc)
Ben Skeggsde8268c2012-11-16 10:24:31 +1000860{
Ben Skeggse225f442012-11-21 14:40:21 +1000861 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000862 u32 *push = evo_wait(mast, 16);
863 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000864 if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000865 evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 1);
866 evo_data(push, 0x05000000);
867 } else
Ben Skeggse225f442012-11-21 14:40:21 +1000868 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000869 evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 1);
870 evo_data(push, 0x05000000);
871 evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1);
872 evo_data(push, 0x00000000);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000873 } else {
874 evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1);
875 evo_data(push, 0x05000000);
876 evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
877 evo_data(push, 0x00000000);
878 }
Ben Skeggsde8268c2012-11-16 10:24:31 +1000879 evo_kick(push, mast);
880 }
881}
Ben Skeggs438d99e2011-07-05 16:48:06 +1000882
Ben Skeggsde8268c2012-11-16 10:24:31 +1000883static void
Ben Skeggse225f442012-11-21 14:40:21 +1000884nv50_crtc_cursor_show_hide(struct nouveau_crtc *nv_crtc, bool show, bool update)
Ben Skeggsde8268c2012-11-16 10:24:31 +1000885{
Ben Skeggse225f442012-11-21 14:40:21 +1000886 struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000887
888 if (show)
Ben Skeggse225f442012-11-21 14:40:21 +1000889 nv50_crtc_cursor_show(nv_crtc);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000890 else
Ben Skeggse225f442012-11-21 14:40:21 +1000891 nv50_crtc_cursor_hide(nv_crtc);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000892
893 if (update) {
894 u32 *push = evo_wait(mast, 2);
895 if (push) {
Ben Skeggs438d99e2011-07-05 16:48:06 +1000896 evo_mthd(push, 0x0080, 1);
897 evo_data(push, 0x00000000);
Ben Skeggsde8268c2012-11-16 10:24:31 +1000898 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000899 }
Ben Skeggs438d99e2011-07-05 16:48:06 +1000900 }
901}
902
903static void
Ben Skeggse225f442012-11-21 14:40:21 +1000904nv50_crtc_dpms(struct drm_crtc *crtc, int mode)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000905{
906}
907
908static void
Ben Skeggse225f442012-11-21 14:40:21 +1000909nv50_crtc_prepare(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000910{
911 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +1000912 struct nv50_mast *mast = nv50_mast(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000913 u32 *push;
914
Ben Skeggse225f442012-11-21 14:40:21 +1000915 nv50_display_flip_stop(crtc);
Ben Skeggs3376ee32011-11-12 14:28:12 +1000916
Ben Skeggsde8268c2012-11-16 10:24:31 +1000917 push = evo_wait(mast, 2);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000918 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000919 if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000920 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
921 evo_data(push, 0x00000000);
922 evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 1);
923 evo_data(push, 0x40000000);
924 } else
Ben Skeggse225f442012-11-21 14:40:21 +1000925 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000926 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
927 evo_data(push, 0x00000000);
928 evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 1);
929 evo_data(push, 0x40000000);
930 evo_mthd(push, 0x085c + (nv_crtc->index * 0x400), 1);
931 evo_data(push, 0x00000000);
932 } else {
933 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
934 evo_data(push, 0x00000000);
935 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1);
936 evo_data(push, 0x03000000);
937 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
938 evo_data(push, 0x00000000);
939 }
940
941 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000942 }
943
Ben Skeggse225f442012-11-21 14:40:21 +1000944 nv50_crtc_cursor_show_hide(nv_crtc, false, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000945}
946
947static void
Ben Skeggse225f442012-11-21 14:40:21 +1000948nv50_crtc_commit(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +1000949{
950 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +1000951 struct nv50_mast *mast = nv50_mast(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000952 u32 *push;
953
Ben Skeggsde8268c2012-11-16 10:24:31 +1000954 push = evo_wait(mast, 32);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000955 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +1000956 if (nv50_vers(mast) < NV84_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000957 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
958 evo_data(push, NvEvoVRAM_LP);
959 evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 2);
960 evo_data(push, 0xc0000000);
961 evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
962 } else
Ben Skeggse225f442012-11-21 14:40:21 +1000963 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +1000964 evo_mthd(push, 0x0874 + (nv_crtc->index * 0x400), 1);
965 evo_data(push, nv_crtc->fb.tile_flags);
966 evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 2);
967 evo_data(push, 0xc0000000);
968 evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
969 evo_mthd(push, 0x085c + (nv_crtc->index * 0x400), 1);
970 evo_data(push, NvEvoVRAM);
971 } else {
972 evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1);
973 evo_data(push, nv_crtc->fb.tile_flags);
974 evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4);
975 evo_data(push, 0x83000000);
976 evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8);
977 evo_data(push, 0x00000000);
978 evo_data(push, 0x00000000);
979 evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1);
980 evo_data(push, NvEvoVRAM);
981 evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1);
982 evo_data(push, 0xffffff00);
983 }
984
985 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000986 }
987
Ben Skeggse225f442012-11-21 14:40:21 +1000988 nv50_crtc_cursor_show_hide(nv_crtc, nv_crtc->cursor.visible, true);
989 nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +1000990}
991
992static bool
Ben Skeggse225f442012-11-21 14:40:21 +1000993nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
Ben Skeggs438d99e2011-07-05 16:48:06 +1000994 struct drm_display_mode *adjusted_mode)
995{
996 return true;
997}
998
999static int
Ben Skeggse225f442012-11-21 14:40:21 +10001000nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001001{
1002 struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
1003 int ret;
1004
1005 ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
1006 if (ret)
1007 return ret;
1008
1009 if (old_fb) {
1010 nvfb = nouveau_framebuffer(old_fb);
1011 nouveau_bo_unpin(nvfb->nvbo);
1012 }
1013
1014 return 0;
1015}
1016
1017static int
Ben Skeggse225f442012-11-21 14:40:21 +10001018nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001019 struct drm_display_mode *mode, int x, int y,
1020 struct drm_framebuffer *old_fb)
1021{
Ben Skeggse225f442012-11-21 14:40:21 +10001022 struct nv50_mast *mast = nv50_mast(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001023 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1024 struct nouveau_connector *nv_connector;
Ben Skeggs2d1d8982011-11-11 23:39:22 +10001025 u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1;
1026 u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1;
1027 u32 hactive, hsynce, hbackp, hfrontp, hblanke, hblanks;
1028 u32 vactive, vsynce, vbackp, vfrontp, vblanke, vblanks;
1029 u32 vblan2e = 0, vblan2s = 1;
Ben Skeggs3488c572012-03-12 11:42:20 +10001030 u32 *push;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001031 int ret;
1032
Ben Skeggs2d1d8982011-11-11 23:39:22 +10001033 hactive = mode->htotal;
1034 hsynce = mode->hsync_end - mode->hsync_start - 1;
1035 hbackp = mode->htotal - mode->hsync_end;
1036 hblanke = hsynce + hbackp;
1037 hfrontp = mode->hsync_start - mode->hdisplay;
1038 hblanks = mode->htotal - hfrontp - 1;
1039
1040 vactive = mode->vtotal * vscan / ilace;
1041 vsynce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1;
1042 vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace;
1043 vblanke = vsynce + vbackp;
1044 vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace;
1045 vblanks = vactive - vfrontp - 1;
1046 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
1047 vblan2e = vactive + vsynce + vbackp;
1048 vblan2s = vblan2e + (mode->vdisplay * vscan / ilace);
1049 vactive = (vactive * 2) + 1;
Ben Skeggs2d1d8982011-11-11 23:39:22 +10001050 }
1051
Ben Skeggse225f442012-11-21 14:40:21 +10001052 ret = nv50_crtc_swap_fbs(crtc, old_fb);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001053 if (ret)
1054 return ret;
1055
Ben Skeggsde8268c2012-11-16 10:24:31 +10001056 push = evo_wait(mast, 64);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001057 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +10001058 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggsde8268c2012-11-16 10:24:31 +10001059 evo_mthd(push, 0x0804 + (nv_crtc->index * 0x400), 2);
1060 evo_data(push, 0x00800000 | mode->clock);
1061 evo_data(push, (ilace == 2) ? 2 : 0);
1062 evo_mthd(push, 0x0810 + (nv_crtc->index * 0x400), 6);
1063 evo_data(push, 0x00000000);
1064 evo_data(push, (vactive << 16) | hactive);
1065 evo_data(push, ( vsynce << 16) | hsynce);
1066 evo_data(push, (vblanke << 16) | hblanke);
1067 evo_data(push, (vblanks << 16) | hblanks);
1068 evo_data(push, (vblan2e << 16) | vblan2s);
1069 evo_mthd(push, 0x082c + (nv_crtc->index * 0x400), 1);
1070 evo_data(push, 0x00000000);
1071 evo_mthd(push, 0x0900 + (nv_crtc->index * 0x400), 2);
1072 evo_data(push, 0x00000311);
1073 evo_data(push, 0x00000100);
1074 } else {
1075 evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 6);
1076 evo_data(push, 0x00000000);
1077 evo_data(push, (vactive << 16) | hactive);
1078 evo_data(push, ( vsynce << 16) | hsynce);
1079 evo_data(push, (vblanke << 16) | hblanke);
1080 evo_data(push, (vblanks << 16) | hblanks);
1081 evo_data(push, (vblan2e << 16) | vblan2s);
1082 evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1);
1083 evo_data(push, 0x00000000); /* ??? */
1084 evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3);
1085 evo_data(push, mode->clock * 1000);
1086 evo_data(push, 0x00200000); /* ??? */
1087 evo_data(push, mode->clock * 1000);
1088 evo_mthd(push, 0x04d0 + (nv_crtc->index * 0x300), 2);
1089 evo_data(push, 0x00000311);
1090 evo_data(push, 0x00000100);
1091 }
1092
1093 evo_kick(push, mast);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001094 }
1095
1096 nv_connector = nouveau_crtc_connector_get(nv_crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001097 nv50_crtc_set_dither(nv_crtc, false);
1098 nv50_crtc_set_scale(nv_crtc, false);
1099 nv50_crtc_set_color_vibrance(nv_crtc, false);
1100 nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, false);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001101 return 0;
1102}
1103
1104static int
Ben Skeggse225f442012-11-21 14:40:21 +10001105nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001106 struct drm_framebuffer *old_fb)
1107{
Ben Skeggs77145f12012-07-31 16:16:21 +10001108 struct nouveau_drm *drm = nouveau_drm(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001109 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1110 int ret;
1111
Ben Skeggs84e2ad82011-08-26 09:40:39 +10001112 if (!crtc->fb) {
Ben Skeggs77145f12012-07-31 16:16:21 +10001113 NV_DEBUG(drm, "No FB bound\n");
Ben Skeggs84e2ad82011-08-26 09:40:39 +10001114 return 0;
1115 }
1116
Ben Skeggse225f442012-11-21 14:40:21 +10001117 ret = nv50_crtc_swap_fbs(crtc, old_fb);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001118 if (ret)
1119 return ret;
1120
Ben Skeggse225f442012-11-21 14:40:21 +10001121 nv50_display_flip_stop(crtc);
1122 nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, true);
1123 nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001124 return 0;
1125}
1126
1127static int
Ben Skeggse225f442012-11-21 14:40:21 +10001128nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001129 struct drm_framebuffer *fb, int x, int y,
1130 enum mode_set_atomic state)
1131{
1132 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001133 nv50_display_flip_stop(crtc);
1134 nv50_crtc_set_image(nv_crtc, fb, x, y, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001135 return 0;
1136}
1137
1138static void
Ben Skeggse225f442012-11-21 14:40:21 +10001139nv50_crtc_lut_load(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001140{
Ben Skeggse225f442012-11-21 14:40:21 +10001141 struct nv50_disp *disp = nv50_disp(crtc->dev);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001142 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1143 void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
1144 int i;
1145
1146 for (i = 0; i < 256; i++) {
Ben Skeggsde8268c2012-11-16 10:24:31 +10001147 u16 r = nv_crtc->lut.r[i] >> 2;
1148 u16 g = nv_crtc->lut.g[i] >> 2;
1149 u16 b = nv_crtc->lut.b[i] >> 2;
1150
1151 if (nv_mclass(disp->core) < NVD0_DISP_CLASS) {
1152 writew(r + 0x0000, lut + (i * 0x08) + 0);
1153 writew(g + 0x0000, lut + (i * 0x08) + 2);
1154 writew(b + 0x0000, lut + (i * 0x08) + 4);
1155 } else {
1156 writew(r + 0x6000, lut + (i * 0x20) + 0);
1157 writew(g + 0x6000, lut + (i * 0x20) + 2);
1158 writew(b + 0x6000, lut + (i * 0x20) + 4);
1159 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10001160 }
1161}
1162
1163static int
Ben Skeggse225f442012-11-21 14:40:21 +10001164nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001165 uint32_t handle, uint32_t width, uint32_t height)
1166{
1167 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1168 struct drm_device *dev = crtc->dev;
1169 struct drm_gem_object *gem;
1170 struct nouveau_bo *nvbo;
1171 bool visible = (handle != 0);
1172 int i, ret = 0;
1173
1174 if (visible) {
1175 if (width != 64 || height != 64)
1176 return -EINVAL;
1177
1178 gem = drm_gem_object_lookup(dev, file_priv, handle);
1179 if (unlikely(!gem))
1180 return -ENOENT;
1181 nvbo = nouveau_gem_object(gem);
1182
1183 ret = nouveau_bo_map(nvbo);
1184 if (ret == 0) {
1185 for (i = 0; i < 64 * 64; i++) {
1186 u32 v = nouveau_bo_rd32(nvbo, i);
1187 nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v);
1188 }
1189 nouveau_bo_unmap(nvbo);
1190 }
1191
1192 drm_gem_object_unreference_unlocked(gem);
1193 }
1194
1195 if (visible != nv_crtc->cursor.visible) {
Ben Skeggse225f442012-11-21 14:40:21 +10001196 nv50_crtc_cursor_show_hide(nv_crtc, visible, true);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001197 nv_crtc->cursor.visible = visible;
1198 }
1199
1200 return ret;
1201}
1202
1203static int
Ben Skeggse225f442012-11-21 14:40:21 +10001204nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001205{
Ben Skeggse225f442012-11-21 14:40:21 +10001206 struct nv50_curs *curs = nv50_curs(crtc);
1207 struct nv50_chan *chan = nv50_chan(curs);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001208 nv_wo32(chan->user, 0x0084, (y << 16) | (x & 0xffff));
1209 nv_wo32(chan->user, 0x0080, 0x00000000);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001210 return 0;
1211}
1212
1213static void
Ben Skeggse225f442012-11-21 14:40:21 +10001214nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001215 uint32_t start, uint32_t size)
1216{
1217 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
1218 u32 end = max(start + size, (u32)256);
1219 u32 i;
1220
1221 for (i = start; i < end; i++) {
1222 nv_crtc->lut.r[i] = r[i];
1223 nv_crtc->lut.g[i] = g[i];
1224 nv_crtc->lut.b[i] = b[i];
1225 }
1226
Ben Skeggse225f442012-11-21 14:40:21 +10001227 nv50_crtc_lut_load(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001228}
1229
1230static void
Ben Skeggse225f442012-11-21 14:40:21 +10001231nv50_crtc_destroy(struct drm_crtc *crtc)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001232{
1233 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001234 struct nv50_disp *disp = nv50_disp(crtc->dev);
1235 struct nv50_head *head = nv50_head(crtc);
1236 nv50_dmac_destroy(disp->core, &head->ovly.base);
1237 nv50_pioc_destroy(disp->core, &head->oimm.base);
1238 nv50_dmac_destroy(disp->core, &head->sync.base);
1239 nv50_pioc_destroy(disp->core, &head->curs.base);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001240 nouveau_bo_unmap(nv_crtc->cursor.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001241 if (nv_crtc->cursor.nvbo)
1242 nouveau_bo_unpin(nv_crtc->cursor.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001243 nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
1244 nouveau_bo_unmap(nv_crtc->lut.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001245 if (nv_crtc->lut.nvbo)
1246 nouveau_bo_unpin(nv_crtc->lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001247 nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
1248 drm_crtc_cleanup(crtc);
1249 kfree(crtc);
1250}
1251
Ben Skeggse225f442012-11-21 14:40:21 +10001252static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = {
1253 .dpms = nv50_crtc_dpms,
1254 .prepare = nv50_crtc_prepare,
1255 .commit = nv50_crtc_commit,
1256 .mode_fixup = nv50_crtc_mode_fixup,
1257 .mode_set = nv50_crtc_mode_set,
1258 .mode_set_base = nv50_crtc_mode_set_base,
1259 .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
1260 .load_lut = nv50_crtc_lut_load,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001261};
1262
Ben Skeggse225f442012-11-21 14:40:21 +10001263static const struct drm_crtc_funcs nv50_crtc_func = {
1264 .cursor_set = nv50_crtc_cursor_set,
1265 .cursor_move = nv50_crtc_cursor_move,
1266 .gamma_set = nv50_crtc_gamma_set,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001267 .set_config = drm_crtc_helper_set_config,
Ben Skeggse225f442012-11-21 14:40:21 +10001268 .destroy = nv50_crtc_destroy,
Ben Skeggs3376ee32011-11-12 14:28:12 +10001269 .page_flip = nouveau_crtc_page_flip,
Ben Skeggs438d99e2011-07-05 16:48:06 +10001270};
1271
Ben Skeggsc20ab3e2011-08-25 14:09:43 +10001272static void
Ben Skeggse225f442012-11-21 14:40:21 +10001273nv50_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
Ben Skeggsc20ab3e2011-08-25 14:09:43 +10001274{
1275}
1276
1277static void
Ben Skeggse225f442012-11-21 14:40:21 +10001278nv50_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
Ben Skeggsc20ab3e2011-08-25 14:09:43 +10001279{
1280}
1281
Ben Skeggs438d99e2011-07-05 16:48:06 +10001282static int
Ben Skeggse225f442012-11-21 14:40:21 +10001283nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001284{
Ben Skeggse225f442012-11-21 14:40:21 +10001285 struct nv50_disp *disp = nv50_disp(dev);
1286 struct nv50_head *head;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001287 struct drm_crtc *crtc;
1288 int ret, i;
1289
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001290 head = kzalloc(sizeof(*head), GFP_KERNEL);
1291 if (!head)
Ben Skeggs438d99e2011-07-05 16:48:06 +10001292 return -ENOMEM;
1293
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001294 head->base.index = index;
Ben Skeggse225f442012-11-21 14:40:21 +10001295 head->base.set_dither = nv50_crtc_set_dither;
1296 head->base.set_scale = nv50_crtc_set_scale;
1297 head->base.set_color_vibrance = nv50_crtc_set_color_vibrance;
Ben Skeggsf9887d02012-11-21 13:03:42 +10001298 head->base.color_vibrance = 50;
1299 head->base.vibrant_hue = 0;
Ben Skeggse225f442012-11-21 14:40:21 +10001300 head->base.cursor.set_offset = nv50_cursor_set_offset;
1301 head->base.cursor.set_pos = nv50_cursor_set_pos;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001302 for (i = 0; i < 256; i++) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001303 head->base.lut.r[i] = i << 8;
1304 head->base.lut.g[i] = i << 8;
1305 head->base.lut.b[i] = i << 8;
Ben Skeggs438d99e2011-07-05 16:48:06 +10001306 }
1307
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001308 crtc = &head->base.base;
Ben Skeggse225f442012-11-21 14:40:21 +10001309 drm_crtc_init(dev, crtc, &nv50_crtc_func);
1310 drm_crtc_helper_add(crtc, &nv50_crtc_hfunc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001311 drm_mode_crtc_set_gamma_size(crtc, 256);
1312
Ben Skeggs8ea0d4a2011-07-07 14:49:24 +10001313 ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001314 0, 0x0000, NULL, &head->base.lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001315 if (!ret) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001316 ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001317 if (!ret) {
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001318 ret = nouveau_bo_map(head->base.lut.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001319 if (ret)
1320 nouveau_bo_unpin(head->base.lut.nvbo);
1321 }
Ben Skeggs438d99e2011-07-05 16:48:06 +10001322 if (ret)
Ben Skeggsdd0e3d52012-10-16 14:00:31 +10001323 nouveau_bo_ref(NULL, &head->base.lut.nvbo);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001324 }
1325
1326 if (ret)
1327 goto out;
1328
Ben Skeggse225f442012-11-21 14:40:21 +10001329 nv50_crtc_lut_load(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001330
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001331 /* allocate cursor resources */
Ben Skeggse225f442012-11-21 14:40:21 +10001332 ret = nv50_pioc_create(disp->core, NV50_DISP_CURS_CLASS, index,
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001333 &(struct nv50_display_curs_class) {
1334 .head = index,
1335 }, sizeof(struct nv50_display_curs_class),
1336 &head->curs.base);
1337 if (ret)
1338 goto out;
1339
1340 ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM,
1341 0, 0x0000, NULL, &head->base.cursor.nvbo);
1342 if (!ret) {
1343 ret = nouveau_bo_pin(head->base.cursor.nvbo, TTM_PL_FLAG_VRAM);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001344 if (!ret) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001345 ret = nouveau_bo_map(head->base.cursor.nvbo);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001346 if (ret)
1347 nouveau_bo_unpin(head->base.lut.nvbo);
1348 }
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001349 if (ret)
1350 nouveau_bo_ref(NULL, &head->base.cursor.nvbo);
1351 }
1352
1353 if (ret)
1354 goto out;
1355
1356 /* allocate page flip / sync resources */
Ben Skeggse225f442012-11-21 14:40:21 +10001357 ret = nv50_dmac_create(disp->core, NV50_DISP_SYNC_CLASS, index,
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001358 &(struct nv50_display_sync_class) {
1359 .pushbuf = EVO_PUSH_HANDLE(SYNC, index),
1360 .head = index,
1361 }, sizeof(struct nv50_display_sync_class),
1362 disp->sync->bo.offset, &head->sync.base);
1363 if (ret)
1364 goto out;
1365
1366 head->sync.sem.offset = EVO_SYNC(1 + index, 0x00);
1367
1368 /* allocate overlay resources */
Ben Skeggse225f442012-11-21 14:40:21 +10001369 ret = nv50_pioc_create(disp->core, NV50_DISP_OIMM_CLASS, index,
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001370 &(struct nv50_display_oimm_class) {
1371 .head = index,
1372 }, sizeof(struct nv50_display_oimm_class),
1373 &head->oimm.base);
1374 if (ret)
1375 goto out;
1376
Ben Skeggse225f442012-11-21 14:40:21 +10001377 ret = nv50_dmac_create(disp->core, NV50_DISP_OVLY_CLASS, index,
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001378 &(struct nv50_display_ovly_class) {
1379 .pushbuf = EVO_PUSH_HANDLE(OVLY, index),
1380 .head = index,
1381 }, sizeof(struct nv50_display_ovly_class),
1382 disp->sync->bo.offset, &head->ovly.base);
1383 if (ret)
1384 goto out;
1385
Ben Skeggs438d99e2011-07-05 16:48:06 +10001386out:
1387 if (ret)
Ben Skeggse225f442012-11-21 14:40:21 +10001388 nv50_crtc_destroy(crtc);
Ben Skeggs438d99e2011-07-05 16:48:06 +10001389 return ret;
1390}
1391
1392/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10001393 * DAC
1394 *****************************************************************************/
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001395static void
Ben Skeggse225f442012-11-21 14:40:21 +10001396nv50_dac_dpms(struct drm_encoder *encoder, int mode)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001397{
1398 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10001399 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001400 int or = nv_encoder->or;
1401 u32 dpms_ctrl;
1402
Ben Skeggs35b21d32012-11-08 12:08:55 +10001403 dpms_ctrl = 0x00000000;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001404 if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF)
1405 dpms_ctrl |= 0x00000001;
1406 if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF)
1407 dpms_ctrl |= 0x00000004;
1408
Ben Skeggs35b21d32012-11-08 12:08:55 +10001409 nv_call(disp->core, NV50_DISP_DAC_PWR + or, dpms_ctrl);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001410}
1411
1412static bool
Ben Skeggse225f442012-11-21 14:40:21 +10001413nv50_dac_mode_fixup(struct drm_encoder *encoder,
Laurent Pincharte811f5a2012-07-17 17:56:50 +02001414 const struct drm_display_mode *mode,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001415 struct drm_display_mode *adjusted_mode)
1416{
1417 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1418 struct nouveau_connector *nv_connector;
1419
1420 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1421 if (nv_connector && nv_connector->native_mode) {
1422 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
1423 int id = adjusted_mode->base.id;
1424 *adjusted_mode = *nv_connector->native_mode;
1425 adjusted_mode->base.id = id;
1426 }
1427 }
1428
1429 return true;
1430}
1431
1432static void
Ben Skeggse225f442012-11-21 14:40:21 +10001433nv50_dac_commit(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001434{
1435}
1436
1437static void
Ben Skeggse225f442012-11-21 14:40:21 +10001438nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001439 struct drm_display_mode *adjusted_mode)
1440{
Ben Skeggse225f442012-11-21 14:40:21 +10001441 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001442 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1443 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs97b19b52012-11-16 11:21:37 +10001444 u32 *push;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001445
Ben Skeggse225f442012-11-21 14:40:21 +10001446 nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001447
Ben Skeggs97b19b52012-11-16 11:21:37 +10001448 push = evo_wait(mast, 8);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001449 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +10001450 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggs97b19b52012-11-16 11:21:37 +10001451 u32 syncs = 0x00000000;
1452
1453 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1454 syncs |= 0x00000001;
1455 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1456 syncs |= 0x00000002;
1457
1458 evo_mthd(push, 0x0400 + (nv_encoder->or * 0x080), 2);
1459 evo_data(push, 1 << nv_crtc->index);
1460 evo_data(push, syncs);
1461 } else {
1462 u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
1463 u32 syncs = 0x00000001;
1464
1465 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1466 syncs |= 0x00000008;
1467 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1468 syncs |= 0x00000010;
1469
1470 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1471 magic |= 0x00000001;
1472
1473 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
1474 evo_data(push, syncs);
1475 evo_data(push, magic);
1476 evo_mthd(push, 0x0180 + (nv_encoder->or * 0x020), 1);
1477 evo_data(push, 1 << nv_crtc->index);
1478 }
1479
1480 evo_kick(push, mast);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001481 }
1482
1483 nv_encoder->crtc = encoder->crtc;
1484}
1485
1486static void
Ben Skeggse225f442012-11-21 14:40:21 +10001487nv50_dac_disconnect(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001488{
1489 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10001490 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs97b19b52012-11-16 11:21:37 +10001491 const int or = nv_encoder->or;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001492 u32 *push;
1493
1494 if (nv_encoder->crtc) {
Ben Skeggse225f442012-11-21 14:40:21 +10001495 nv50_crtc_prepare(nv_encoder->crtc);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001496
Ben Skeggs97b19b52012-11-16 11:21:37 +10001497 push = evo_wait(mast, 4);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001498 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +10001499 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggs97b19b52012-11-16 11:21:37 +10001500 evo_mthd(push, 0x0400 + (or * 0x080), 1);
1501 evo_data(push, 0x00000000);
1502 } else {
1503 evo_mthd(push, 0x0180 + (or * 0x020), 1);
1504 evo_data(push, 0x00000000);
1505 }
1506
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001507 evo_mthd(push, 0x0080, 1);
1508 evo_data(push, 0x00000000);
Ben Skeggs97b19b52012-11-16 11:21:37 +10001509 evo_kick(push, mast);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001510 }
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001511 }
Ben Skeggs97b19b52012-11-16 11:21:37 +10001512
1513 nv_encoder->crtc = NULL;
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001514}
1515
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10001516static enum drm_connector_status
Ben Skeggse225f442012-11-21 14:40:21 +10001517nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10001518{
Ben Skeggse225f442012-11-21 14:40:21 +10001519 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs35b21d32012-11-08 12:08:55 +10001520 int ret, or = nouveau_encoder(encoder)->or;
Ben Skeggs7ebb38b2012-11-09 09:38:06 +10001521 u32 load = 0;
Ben Skeggsb6819932011-07-08 11:14:50 +10001522
Ben Skeggs35b21d32012-11-08 12:08:55 +10001523 ret = nv_exec(disp->core, NV50_DISP_DAC_LOAD + or, &load, sizeof(load));
1524 if (ret || load != 7)
1525 return connector_status_disconnected;
Ben Skeggsb6819932011-07-08 11:14:50 +10001526
Ben Skeggs35b21d32012-11-08 12:08:55 +10001527 return connector_status_connected;
Ben Skeggsb6d8e7e2011-07-07 09:51:29 +10001528}
1529
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001530static void
Ben Skeggse225f442012-11-21 14:40:21 +10001531nv50_dac_destroy(struct drm_encoder *encoder)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001532{
1533 drm_encoder_cleanup(encoder);
1534 kfree(encoder);
1535}
1536
Ben Skeggse225f442012-11-21 14:40:21 +10001537static const struct drm_encoder_helper_funcs nv50_dac_hfunc = {
1538 .dpms = nv50_dac_dpms,
1539 .mode_fixup = nv50_dac_mode_fixup,
1540 .prepare = nv50_dac_disconnect,
1541 .commit = nv50_dac_commit,
1542 .mode_set = nv50_dac_mode_set,
1543 .disable = nv50_dac_disconnect,
1544 .get_crtc = nv50_display_crtc_get,
1545 .detect = nv50_dac_detect
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001546};
1547
Ben Skeggse225f442012-11-21 14:40:21 +10001548static const struct drm_encoder_funcs nv50_dac_func = {
1549 .destroy = nv50_dac_destroy,
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001550};
1551
1552static int
Ben Skeggse225f442012-11-21 14:40:21 +10001553nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001554{
1555 struct drm_device *dev = connector->dev;
1556 struct nouveau_encoder *nv_encoder;
1557 struct drm_encoder *encoder;
1558
1559 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
1560 if (!nv_encoder)
1561 return -ENOMEM;
1562 nv_encoder->dcb = dcbe;
1563 nv_encoder->or = ffs(dcbe->or) - 1;
1564
1565 encoder = to_drm_encoder(nv_encoder);
1566 encoder->possible_crtcs = dcbe->heads;
1567 encoder->possible_clones = 0;
Ben Skeggse225f442012-11-21 14:40:21 +10001568 drm_encoder_init(dev, encoder, &nv50_dac_func, DRM_MODE_ENCODER_DAC);
1569 drm_encoder_helper_add(encoder, &nv50_dac_hfunc);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10001570
1571 drm_mode_connector_attach_encoder(connector, encoder);
1572 return 0;
1573}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001574
1575/******************************************************************************
Ben Skeggs78951d22011-11-11 18:13:13 +10001576 * Audio
1577 *****************************************************************************/
1578static void
Ben Skeggse225f442012-11-21 14:40:21 +10001579nv50_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
Ben Skeggs78951d22011-11-11 18:13:13 +10001580{
1581 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1582 struct nouveau_connector *nv_connector;
Ben Skeggse225f442012-11-21 14:40:21 +10001583 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs78951d22011-11-11 18:13:13 +10001584
1585 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1586 if (!drm_detect_monitor_audio(nv_connector->edid))
1587 return;
1588
Ben Skeggs78951d22011-11-11 18:13:13 +10001589 drm_edid_to_eld(&nv_connector->base, nv_connector->edid);
Ben Skeggs78951d22011-11-11 18:13:13 +10001590
Ben Skeggs0a9e2b952012-11-08 14:03:56 +10001591 nv_exec(disp->core, NVA3_DISP_SOR_HDA_ELD + nv_encoder->or,
1592 nv_connector->base.eld,
1593 nv_connector->base.eld[2] * 4);
Ben Skeggs78951d22011-11-11 18:13:13 +10001594}
1595
1596static void
Ben Skeggse225f442012-11-21 14:40:21 +10001597nv50_audio_disconnect(struct drm_encoder *encoder)
Ben Skeggs78951d22011-11-11 18:13:13 +10001598{
1599 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10001600 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs78951d22011-11-11 18:13:13 +10001601
Ben Skeggs0a9e2b952012-11-08 14:03:56 +10001602 nv_exec(disp->core, NVA3_DISP_SOR_HDA_ELD + nv_encoder->or, NULL, 0);
Ben Skeggs78951d22011-11-11 18:13:13 +10001603}
1604
1605/******************************************************************************
1606 * HDMI
1607 *****************************************************************************/
1608static void
Ben Skeggse225f442012-11-21 14:40:21 +10001609nv50_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode)
Ben Skeggs78951d22011-11-11 18:13:13 +10001610{
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001611 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1612 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
1613 struct nouveau_connector *nv_connector;
Ben Skeggse225f442012-11-21 14:40:21 +10001614 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs1c30cd02012-11-08 14:22:28 +10001615 const u32 moff = (nv_crtc->index << 3) | nv_encoder->or;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001616 u32 rekey = 56; /* binary driver, and tegra constant */
1617 u32 max_ac_packet;
1618
1619 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1620 if (!drm_detect_hdmi_monitor(nv_connector->edid))
1621 return;
1622
1623 max_ac_packet = mode->htotal - mode->hdisplay;
1624 max_ac_packet -= rekey;
1625 max_ac_packet -= 18; /* constant from tegra */
1626 max_ac_packet /= 32;
1627
Ben Skeggs1c30cd02012-11-08 14:22:28 +10001628 nv_call(disp->core, NV84_DISP_SOR_HDMI_PWR + moff,
1629 NV84_DISP_SOR_HDMI_PWR_STATE_ON |
1630 (max_ac_packet << 16) | rekey);
Ben Skeggs091e40c2011-11-11 20:46:00 +10001631
Ben Skeggse225f442012-11-21 14:40:21 +10001632 nv50_audio_mode_set(encoder, mode);
Ben Skeggs78951d22011-11-11 18:13:13 +10001633}
1634
1635static void
Ben Skeggse225f442012-11-21 14:40:21 +10001636nv50_hdmi_disconnect(struct drm_encoder *encoder)
Ben Skeggs78951d22011-11-11 18:13:13 +10001637{
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001638 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1639 struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
Ben Skeggse225f442012-11-21 14:40:21 +10001640 struct nv50_disp *disp = nv50_disp(encoder->dev);
Ben Skeggs1c30cd02012-11-08 14:22:28 +10001641 const u32 moff = (nv_crtc->index << 3) | nv_encoder->or;
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001642
Ben Skeggse225f442012-11-21 14:40:21 +10001643 nv50_audio_disconnect(encoder);
Ben Skeggs64d9cc02011-11-11 19:51:20 +10001644
Ben Skeggs1c30cd02012-11-08 14:22:28 +10001645 nv_call(disp->core, NV84_DISP_SOR_HDMI_PWR + moff, 0x00000000);
Ben Skeggs78951d22011-11-11 18:13:13 +10001646}
1647
1648/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10001649 * SOR
1650 *****************************************************************************/
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001651static void
Ben Skeggse225f442012-11-21 14:40:21 +10001652nv50_sor_dpms(struct drm_encoder *encoder, int mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001653{
1654 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1655 struct drm_device *dev = encoder->dev;
Ben Skeggse225f442012-11-21 14:40:21 +10001656 struct nv50_disp *disp = nv50_disp(dev);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001657 struct drm_encoder *partner;
1658 int or = nv_encoder->or;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001659
1660 nv_encoder->last_dpms = mode;
1661
1662 list_for_each_entry(partner, &dev->mode_config.encoder_list, head) {
1663 struct nouveau_encoder *nv_partner = nouveau_encoder(partner);
1664
1665 if (partner->encoder_type != DRM_MODE_ENCODER_TMDS)
1666 continue;
1667
1668 if (nv_partner != nv_encoder &&
Ben Skeggs26cfa812011-11-17 09:10:02 +10001669 nv_partner->dcb->or == nv_encoder->dcb->or) {
Ben Skeggs83fc0832011-07-05 13:08:40 +10001670 if (nv_partner->last_dpms == DRM_MODE_DPMS_ON)
1671 return;
1672 break;
1673 }
1674 }
1675
Ben Skeggs74b66852012-11-08 12:01:39 +10001676 nv_call(disp->core, NV50_DISP_SOR_PWR + or, (mode == DRM_MODE_DPMS_ON));
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001677
Ben Skeggs6c8e4632012-11-15 18:56:02 +10001678 if (nv_encoder->dcb->type == DCB_OUTPUT_DP)
1679 nouveau_dp_dpms(encoder, mode, nv_encoder->dp.datarate, disp->core);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001680}
1681
1682static bool
Ben Skeggse225f442012-11-21 14:40:21 +10001683nv50_sor_mode_fixup(struct drm_encoder *encoder,
Laurent Pincharte811f5a2012-07-17 17:56:50 +02001684 const struct drm_display_mode *mode,
Ben Skeggs83fc0832011-07-05 13:08:40 +10001685 struct drm_display_mode *adjusted_mode)
1686{
1687 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1688 struct nouveau_connector *nv_connector;
1689
1690 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1691 if (nv_connector && nv_connector->native_mode) {
1692 if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
1693 int id = adjusted_mode->base.id;
1694 *adjusted_mode = *nv_connector->native_mode;
1695 adjusted_mode->base.id = id;
1696 }
1697 }
1698
1699 return true;
1700}
1701
1702static void
Ben Skeggse225f442012-11-21 14:40:21 +10001703nv50_sor_disconnect(struct drm_encoder *encoder)
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10001704{
1705 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
Ben Skeggse225f442012-11-21 14:40:21 +10001706 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001707 const int or = nv_encoder->or;
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10001708 u32 *push;
1709
1710 if (nv_encoder->crtc) {
Ben Skeggse225f442012-11-21 14:40:21 +10001711 nv50_crtc_prepare(nv_encoder->crtc);
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10001712
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001713 push = evo_wait(mast, 4);
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10001714 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +10001715 if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001716 evo_mthd(push, 0x0600 + (or * 0x40), 1);
1717 evo_data(push, 0x00000000);
1718 } else {
1719 evo_mthd(push, 0x0200 + (or * 0x20), 1);
1720 evo_data(push, 0x00000000);
1721 }
1722
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10001723 evo_mthd(push, 0x0080, 1);
1724 evo_data(push, 0x00000000);
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001725 evo_kick(push, mast);
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10001726 }
1727
Ben Skeggse225f442012-11-21 14:40:21 +10001728 nv50_hdmi_disconnect(encoder);
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10001729 }
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001730
1731 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1732 nv_encoder->crtc = NULL;
Ben Skeggs4cbb0f82012-03-12 15:23:44 +10001733}
1734
1735static void
Ben Skeggse225f442012-11-21 14:40:21 +10001736nv50_sor_prepare(struct drm_encoder *encoder)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001737{
Ben Skeggse225f442012-11-21 14:40:21 +10001738 nv50_sor_disconnect(encoder);
Ben Skeggscb75d972012-07-11 10:44:20 +10001739 if (nouveau_encoder(encoder)->dcb->type == DCB_OUTPUT_DP)
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001740 evo_sync(encoder->dev);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001741}
1742
1743static void
Ben Skeggse225f442012-11-21 14:40:21 +10001744nv50_sor_commit(struct drm_encoder *encoder)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001745{
1746}
1747
1748static void
Ben Skeggse225f442012-11-21 14:40:21 +10001749nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001750 struct drm_display_mode *mode)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001751{
Ben Skeggse225f442012-11-21 14:40:21 +10001752 struct nv50_disp *disp = nv50_disp(encoder->dev);
1753 struct nv50_mast *mast = nv50_mast(encoder->dev);
Ben Skeggs78951d22011-11-11 18:13:13 +10001754 struct drm_device *dev = encoder->dev;
Ben Skeggs77145f12012-07-31 16:16:21 +10001755 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001756 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
1757 struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001758 struct nouveau_connector *nv_connector;
Ben Skeggs77145f12012-07-31 16:16:21 +10001759 struct nvbios *bios = &drm->vbios;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001760 u32 *push, lvds = 0;
1761 u8 owner = 1 << nv_crtc->index;
1762 u8 proto = 0xf;
1763 u8 depth = 0x0;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001764
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001765 nv_connector = nouveau_encoder_connector_get(nv_encoder);
1766 switch (nv_encoder->dcb->type) {
Ben Skeggscb75d972012-07-11 10:44:20 +10001767 case DCB_OUTPUT_TMDS:
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001768 if (nv_encoder->dcb->sorconf.link & 1) {
1769 if (mode->clock < 165000)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001770 proto = 0x1;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001771 else
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001772 proto = 0x5;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001773 } else {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001774 proto = 0x2;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001775 }
Ben Skeggs83fc0832011-07-05 13:08:40 +10001776
Ben Skeggse225f442012-11-21 14:40:21 +10001777 nv50_hdmi_mode_set(encoder, mode);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001778 break;
Ben Skeggscb75d972012-07-11 10:44:20 +10001779 case DCB_OUTPUT_LVDS:
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001780 proto = 0x0;
1781
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001782 if (bios->fp_no_ddc) {
1783 if (bios->fp.dual_link)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001784 lvds |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001785 if (bios->fp.if_is_24bit)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001786 lvds |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001787 } else {
Ben Skeggsbefb51e2011-11-18 10:23:59 +10001788 if (nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001789 if (((u8 *)nv_connector->edid)[121] == 2)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001790 lvds |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001791 } else
1792 if (mode->clock >= bios->fp.duallink_transition_clk) {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001793 lvds |= 0x0100;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001794 }
1795
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001796 if (lvds & 0x0100) {
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001797 if (bios->fp.strapless_is_24bit & 2)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001798 lvds |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001799 } else {
1800 if (bios->fp.strapless_is_24bit & 1)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001801 lvds |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001802 }
1803
1804 if (nv_connector->base.display_info.bpc == 8)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001805 lvds |= 0x0200;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001806 }
Ben Skeggs4a230fa2012-11-09 11:25:37 +10001807
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001808 nv_call(disp->core, NV50_DISP_SOR_LVDS_SCRIPT + nv_encoder->or, lvds);
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001809 break;
Ben Skeggscb75d972012-07-11 10:44:20 +10001810 case DCB_OUTPUT_DP:
Ben Skeggs3488c572012-03-12 11:42:20 +10001811 if (nv_connector->base.display_info.bpc == 6) {
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001812 nv_encoder->dp.datarate = mode->clock * 18 / 8;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001813 depth = 0x2;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001814 } else
1815 if (nv_connector->base.display_info.bpc == 8) {
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001816 nv_encoder->dp.datarate = mode->clock * 24 / 8;
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001817 depth = 0x5;
Ben Skeggsbf2c8862012-11-21 14:49:54 +10001818 } else {
1819 nv_encoder->dp.datarate = mode->clock * 30 / 8;
1820 depth = 0x6;
Ben Skeggs3488c572012-03-12 11:42:20 +10001821 }
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001822
1823 if (nv_encoder->dcb->sorconf.link & 1)
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001824 proto = 0x8;
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001825 else
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001826 proto = 0x9;
Ben Skeggs6e83fda2012-03-11 01:28:48 +10001827 break;
Ben Skeggs3b6d83d12011-07-08 12:52:14 +10001828 default:
1829 BUG_ON(1);
1830 break;
1831 }
Ben Skeggsff8ff502011-07-08 11:53:37 +10001832
Ben Skeggse225f442012-11-21 14:40:21 +10001833 nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001834
Ben Skeggse225f442012-11-21 14:40:21 +10001835 push = evo_wait(nv50_mast(dev), 8);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001836 if (push) {
Ben Skeggse225f442012-11-21 14:40:21 +10001837 if (nv50_vers(mast) < NVD0_DISP_CLASS) {
Ben Skeggs419e8dc2012-11-16 11:40:34 +10001838 evo_mthd(push, 0x0600 + (nv_encoder->or * 0x040), 1);
1839 evo_data(push, (depth << 16) | (proto << 8) | owner);
1840 } else {
1841 u32 magic = 0x31ec6000 | (nv_crtc->index << 25);
1842 u32 syncs = 0x00000001;
1843
1844 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1845 syncs |= 0x00000008;
1846 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1847 syncs |= 0x00000010;
1848
1849 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1850 magic |= 0x00000001;
1851
1852 evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2);
1853 evo_data(push, syncs | (depth << 6));
1854 evo_data(push, magic);
1855 evo_mthd(push, 0x0200 + (nv_encoder->or * 0x020), 1);
1856 evo_data(push, owner | (proto << 8));
1857 }
1858
1859 evo_kick(push, mast);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001860 }
1861
1862 nv_encoder->crtc = encoder->crtc;
1863}
1864
1865static void
Ben Skeggse225f442012-11-21 14:40:21 +10001866nv50_sor_destroy(struct drm_encoder *encoder)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001867{
1868 drm_encoder_cleanup(encoder);
1869 kfree(encoder);
1870}
1871
Ben Skeggse225f442012-11-21 14:40:21 +10001872static const struct drm_encoder_helper_funcs nv50_sor_hfunc = {
1873 .dpms = nv50_sor_dpms,
1874 .mode_fixup = nv50_sor_mode_fixup,
1875 .prepare = nv50_sor_prepare,
1876 .commit = nv50_sor_commit,
1877 .mode_set = nv50_sor_mode_set,
1878 .disable = nv50_sor_disconnect,
1879 .get_crtc = nv50_display_crtc_get,
Ben Skeggs83fc0832011-07-05 13:08:40 +10001880};
1881
Ben Skeggse225f442012-11-21 14:40:21 +10001882static const struct drm_encoder_funcs nv50_sor_func = {
1883 .destroy = nv50_sor_destroy,
Ben Skeggs83fc0832011-07-05 13:08:40 +10001884};
1885
1886static int
Ben Skeggse225f442012-11-21 14:40:21 +10001887nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
Ben Skeggs83fc0832011-07-05 13:08:40 +10001888{
1889 struct drm_device *dev = connector->dev;
1890 struct nouveau_encoder *nv_encoder;
1891 struct drm_encoder *encoder;
1892
1893 nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
1894 if (!nv_encoder)
1895 return -ENOMEM;
1896 nv_encoder->dcb = dcbe;
1897 nv_encoder->or = ffs(dcbe->or) - 1;
1898 nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
1899
1900 encoder = to_drm_encoder(nv_encoder);
1901 encoder->possible_crtcs = dcbe->heads;
1902 encoder->possible_clones = 0;
Ben Skeggse225f442012-11-21 14:40:21 +10001903 drm_encoder_init(dev, encoder, &nv50_sor_func, DRM_MODE_ENCODER_TMDS);
1904 drm_encoder_helper_add(encoder, &nv50_sor_hfunc);
Ben Skeggs83fc0832011-07-05 13:08:40 +10001905
1906 drm_mode_connector_attach_encoder(connector, encoder);
1907 return 0;
1908}
Ben Skeggs26f6d882011-07-04 16:25:18 +10001909
1910/******************************************************************************
Ben Skeggs26f6d882011-07-04 16:25:18 +10001911 * Init
1912 *****************************************************************************/
Ben Skeggs2a44e492011-11-09 11:36:33 +10001913void
Ben Skeggse225f442012-11-21 14:40:21 +10001914nv50_display_fini(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10001915{
Ben Skeggs26f6d882011-07-04 16:25:18 +10001916}
1917
1918int
Ben Skeggse225f442012-11-21 14:40:21 +10001919nv50_display_init(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10001920{
Ben Skeggse225f442012-11-21 14:40:21 +10001921 u32 *push = evo_wait(nv50_mast(dev), 32);
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001922 if (push) {
1923 evo_mthd(push, 0x0088, 1);
1924 evo_data(push, NvEvoSync);
Ben Skeggse225f442012-11-21 14:40:21 +10001925 evo_kick(push, nv50_mast(dev));
Ben Skeggs647bf612012-11-19 10:18:25 +10001926 return evo_sync(dev);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001927 }
1928
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001929 return -EBUSY;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001930}
1931
1932void
Ben Skeggse225f442012-11-21 14:40:21 +10001933nv50_display_destroy(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10001934{
Ben Skeggse225f442012-11-21 14:40:21 +10001935 struct nv50_disp *disp = nv50_disp(dev);
Ben Skeggs26f6d882011-07-04 16:25:18 +10001936
Ben Skeggse225f442012-11-21 14:40:21 +10001937 nv50_dmac_destroy(disp->core, &disp->mast.base);
Ben Skeggsbdb8c212011-11-12 01:30:24 +10001938
Ben Skeggs816af2f2011-11-16 15:48:48 +10001939 nouveau_bo_unmap(disp->sync);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001940 if (disp->sync)
1941 nouveau_bo_unpin(disp->sync);
Ben Skeggs816af2f2011-11-16 15:48:48 +10001942 nouveau_bo_ref(NULL, &disp->sync);
Ben Skeggs51beb422011-07-05 10:33:08 +10001943
Ben Skeggs77145f12012-07-31 16:16:21 +10001944 nouveau_display(dev)->priv = NULL;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001945 kfree(disp);
1946}
1947
1948int
Ben Skeggse225f442012-11-21 14:40:21 +10001949nv50_display_create(struct drm_device *dev)
Ben Skeggs26f6d882011-07-04 16:25:18 +10001950{
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001951 static const u16 oclass[] = {
1952 NVE0_DISP_CLASS,
1953 NVD0_DISP_CLASS,
Ben Skeggs63718a02012-11-16 11:44:14 +10001954 NVA3_DISP_CLASS,
1955 NV94_DISP_CLASS,
1956 NVA0_DISP_CLASS,
1957 NV84_DISP_CLASS,
1958 NV50_DISP_CLASS,
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001959 };
Ben Skeggs77145f12012-07-31 16:16:21 +10001960 struct nouveau_device *device = nouveau_dev(dev);
1961 struct nouveau_drm *drm = nouveau_drm(dev);
Ben Skeggs77145f12012-07-31 16:16:21 +10001962 struct dcb_table *dcb = &drm->vbios.dcb;
Ben Skeggs83fc0832011-07-05 13:08:40 +10001963 struct drm_connector *connector, *tmp;
Ben Skeggse225f442012-11-21 14:40:21 +10001964 struct nv50_disp *disp;
Ben Skeggscb75d972012-07-11 10:44:20 +10001965 struct dcb_output *dcbe;
Ben Skeggs7c5f6a82012-03-04 16:25:59 +10001966 int crtcs, ret, i;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001967
1968 disp = kzalloc(sizeof(*disp), GFP_KERNEL);
1969 if (!disp)
1970 return -ENOMEM;
Ben Skeggs77145f12012-07-31 16:16:21 +10001971
1972 nouveau_display(dev)->priv = disp;
Ben Skeggse225f442012-11-21 14:40:21 +10001973 nouveau_display(dev)->dtor = nv50_display_destroy;
1974 nouveau_display(dev)->init = nv50_display_init;
1975 nouveau_display(dev)->fini = nv50_display_fini;
Ben Skeggs26f6d882011-07-04 16:25:18 +10001976
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001977 /* small shared memory area we use for notifiers and semaphores */
1978 ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
1979 0, 0x0000, NULL, &disp->sync);
1980 if (!ret) {
1981 ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001982 if (!ret) {
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001983 ret = nouveau_bo_map(disp->sync);
Marcin Slusarz04c8c212012-11-25 23:04:23 +01001984 if (ret)
1985 nouveau_bo_unpin(disp->sync);
1986 }
Ben Skeggsb5a794b2012-10-16 14:18:32 +10001987 if (ret)
1988 nouveau_bo_ref(NULL, &disp->sync);
1989 }
1990
1991 if (ret)
1992 goto out;
1993
1994 /* attempt to allocate a supported evo display class */
1995 ret = -ENODEV;
1996 for (i = 0; ret && i < ARRAY_SIZE(oclass); i++) {
1997 ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE,
1998 0xd1500000, oclass[i], NULL, 0,
1999 &disp->core);
2000 }
2001
2002 if (ret)
2003 goto out;
2004
2005 /* allocate master evo channel */
Ben Skeggse225f442012-11-21 14:40:21 +10002006 ret = nv50_dmac_create(disp->core, NV50_DISP_MAST_CLASS, 0,
Ben Skeggsb5a794b2012-10-16 14:18:32 +10002007 &(struct nv50_display_mast_class) {
2008 .pushbuf = EVO_PUSH_HANDLE(MAST, 0),
2009 }, sizeof(struct nv50_display_mast_class),
2010 disp->sync->bo.offset, &disp->mast.base);
2011 if (ret)
2012 goto out;
2013
Ben Skeggs438d99e2011-07-05 16:48:06 +10002014 /* create crtc objects to represent the hw heads */
Ben Skeggs63718a02012-11-16 11:44:14 +10002015 if (nv_mclass(disp->core) >= NVD0_DISP_CLASS)
2016 crtcs = nv_rd32(device, 0x022448);
2017 else
2018 crtcs = 2;
2019
Ben Skeggs7c5f6a82012-03-04 16:25:59 +10002020 for (i = 0; i < crtcs; i++) {
Ben Skeggse225f442012-11-21 14:40:21 +10002021 ret = nv50_crtc_create(dev, disp->core, i);
Ben Skeggs438d99e2011-07-05 16:48:06 +10002022 if (ret)
2023 goto out;
2024 }
2025
Ben Skeggs83fc0832011-07-05 13:08:40 +10002026 /* create encoder/connector objects based on VBIOS DCB table */
2027 for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) {
2028 connector = nouveau_connector_create(dev, dcbe->connector);
2029 if (IS_ERR(connector))
2030 continue;
2031
2032 if (dcbe->location != DCB_LOC_ON_CHIP) {
Ben Skeggs77145f12012-07-31 16:16:21 +10002033 NV_WARN(drm, "skipping off-chip encoder %d/%d\n",
Ben Skeggs83fc0832011-07-05 13:08:40 +10002034 dcbe->type, ffs(dcbe->or) - 1);
2035 continue;
2036 }
2037
2038 switch (dcbe->type) {
Ben Skeggscb75d972012-07-11 10:44:20 +10002039 case DCB_OUTPUT_TMDS:
2040 case DCB_OUTPUT_LVDS:
2041 case DCB_OUTPUT_DP:
Ben Skeggse225f442012-11-21 14:40:21 +10002042 nv50_sor_create(connector, dcbe);
Ben Skeggs83fc0832011-07-05 13:08:40 +10002043 break;
Ben Skeggscb75d972012-07-11 10:44:20 +10002044 case DCB_OUTPUT_ANALOG:
Ben Skeggse225f442012-11-21 14:40:21 +10002045 nv50_dac_create(connector, dcbe);
Ben Skeggs8eaa9662011-07-06 15:25:47 +10002046 break;
Ben Skeggs83fc0832011-07-05 13:08:40 +10002047 default:
Ben Skeggs77145f12012-07-31 16:16:21 +10002048 NV_WARN(drm, "skipping unsupported encoder %d/%d\n",
Ben Skeggs83fc0832011-07-05 13:08:40 +10002049 dcbe->type, ffs(dcbe->or) - 1);
2050 continue;
2051 }
2052 }
2053
2054 /* cull any connectors we created that don't have an encoder */
2055 list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) {
2056 if (connector->encoder_ids[0])
2057 continue;
2058
Ben Skeggs77145f12012-07-31 16:16:21 +10002059 NV_WARN(drm, "%s has no encoders, removing\n",
Ben Skeggs83fc0832011-07-05 13:08:40 +10002060 drm_get_connector_name(connector));
2061 connector->funcs->destroy(connector);
2062 }
2063
Ben Skeggs26f6d882011-07-04 16:25:18 +10002064out:
2065 if (ret)
Ben Skeggse225f442012-11-21 14:40:21 +10002066 nv50_display_destroy(dev);
Ben Skeggs26f6d882011-07-04 16:25:18 +10002067 return ret;
2068}