nv50.c 22.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Copyright 2012 Red Hat Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors: Ben Skeggs
 */
24
#include "nv50.h"
25
#include "head.h"
26
#include "rootnv50.h"
27

28
#include <core/client.h>
29
#include <core/enum.h>
30
#include <core/gpuobj.h>
31 32 33 34
#include <subdev/bios.h>
#include <subdev/bios/disp.h>
#include <subdev/bios/init.h>
#include <subdev/bios/pll.h>
35
#include <subdev/devinit.h>
36
#include <subdev/timer.h>
37

38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
static const struct nvkm_disp_oclass *
nv50_disp_root_(struct nvkm_disp *base)
{
	return nv50_disp(base)->func->root;
}

static int
nv50_disp_outp_internal_crt_(struct nvkm_disp *base, int index,
			     struct dcb_output *dcb, struct nvkm_output **poutp)
{
	struct nv50_disp *disp = nv50_disp(base);
	return disp->func->outp.internal.crt(base, index, dcb, poutp);
}

static int
nv50_disp_outp_internal_tmds_(struct nvkm_disp *base, int index,
			      struct dcb_output *dcb,
			      struct nvkm_output **poutp)
{
	struct nv50_disp *disp = nv50_disp(base);
	return disp->func->outp.internal.tmds(base, index, dcb, poutp);
}

static int
nv50_disp_outp_internal_lvds_(struct nvkm_disp *base, int index,
			      struct dcb_output *dcb,
			      struct nvkm_output **poutp)
{
	struct nv50_disp *disp = nv50_disp(base);
	return disp->func->outp.internal.lvds(base, index, dcb, poutp);
}

static int
nv50_disp_outp_internal_dp_(struct nvkm_disp *base, int index,
			    struct dcb_output *dcb, struct nvkm_output **poutp)
{
	struct nv50_disp *disp = nv50_disp(base);
	if (disp->func->outp.internal.dp)
		return disp->func->outp.internal.dp(base, index, dcb, poutp);
	return -ENODEV;
}

static int
nv50_disp_outp_external_tmds_(struct nvkm_disp *base, int index,
			      struct dcb_output *dcb,
			      struct nvkm_output **poutp)
{
	struct nv50_disp *disp = nv50_disp(base);
	if (disp->func->outp.external.tmds)
		return disp->func->outp.external.tmds(base, index, dcb, poutp);
	return -ENODEV;
}

static int
nv50_disp_outp_external_dp_(struct nvkm_disp *base, int index,
			    struct dcb_output *dcb, struct nvkm_output **poutp)
{
	struct nv50_disp *disp = nv50_disp(base);
	if (disp->func->outp.external.dp)
		return disp->func->outp.external.dp(base, index, dcb, poutp);
	return -ENODEV;
}

static void
nv50_disp_intr_(struct nvkm_disp *base)
{
	struct nv50_disp *disp = nv50_disp(base);
	disp->func->intr(disp);
}

static void *
nv50_disp_dtor_(struct nvkm_disp *base)
{
	struct nv50_disp *disp = nv50_disp(base);
	nvkm_event_fini(&disp->uevent);
	return disp;
114 115
}

116 117 118 119 120 121 122 123 124 125 126
static const struct nvkm_disp_func
nv50_disp_ = {
	.dtor = nv50_disp_dtor_,
	.intr = nv50_disp_intr_,
	.root = nv50_disp_root_,
	.outp.internal.crt = nv50_disp_outp_internal_crt_,
	.outp.internal.tmds = nv50_disp_outp_internal_tmds_,
	.outp.internal.lvds = nv50_disp_outp_internal_lvds_,
	.outp.internal.dp = nv50_disp_outp_internal_dp_,
	.outp.external.tmds = nv50_disp_outp_external_tmds_,
	.outp.external.dp = nv50_disp_outp_external_dp_,
127 128
};

129 130 131 132 133
int
nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device,
	       int index, int heads, struct nvkm_disp **pdisp)
{
	struct nv50_disp *disp;
134
	int ret, i;
135 136 137 138 139 140 141

	if (!(disp = kzalloc(sizeof(*disp), GFP_KERNEL)))
		return -ENOMEM;
	INIT_WORK(&disp->supervisor, func->super);
	disp->func = func;
	*pdisp = &disp->base;

142
	ret = nvkm_disp_ctor(&nv50_disp_, device, index, &disp->base);
143 144 145
	if (ret)
		return ret;

146 147 148 149 150 151
	for (i = 0; func->head.new && i < heads; i++) {
		ret = func->head.new(&disp->base, i);
		if (ret)
			return ret;
	}

152 153 154
	return nvkm_event_init(func->uevent, 1, 1 + (heads * 4), &disp->uevent);
}

155
static struct nvkm_output *
B
Ben Skeggs 已提交
156
exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl,
157
	    u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
158 159
	    struct nvbios_outp *info)
{
160 161
	struct nvkm_subdev *subdev = &disp->base.engine.subdev;
	struct nvkm_bios *bios = subdev->device->bios;
162 163
	struct nvkm_output *outp;
	u16 mask, type;
164

165
	if (or < 4) {
166 167
		type = DCB_OUTPUT_ANALOG;
		mask = 0;
168
	} else
169
	if (or < 8) {
170 171 172 173 174 175 176 177
		switch (ctrl & 0x00000f00) {
		case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
		case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
		case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
		case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
		case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
		case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
		default:
178
			nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl);
179
			return NULL;
180
		}
181
		or  -= 4;
182
	} else {
183
		or   = or - 8;
184 185 186
		type = 0x0010;
		mask = 0;
		switch (ctrl & 0x00000f00) {
B
Ben Skeggs 已提交
187
		case 0x00000000: type |= disp->pior.type[or]; break;
188
		default:
189
			nvkm_error(subdev, "unknown PIOR mc %08x\n", ctrl);
190
			return NULL;
191
		}
192 193 194
	}

	mask  = 0x00c0 & (mask << 6);
195
	mask |= 0x0001 << or;
196 197
	mask |= 0x0100 << head;

B
Ben Skeggs 已提交
198
	list_for_each_entry(outp, &disp->base.outp, head) {
199 200
		if ((outp->info.hasht & 0xff) == type &&
		    (outp->info.hashm & mask) == mask) {
201
			*data = nvbios_outp_match(bios, outp->info.hasht, mask,
202 203 204 205 206 207
						  ver, hdr, cnt, len, info);
			if (!*data)
				return NULL;
			return outp;
		}
	}
208

209
	return NULL;
210 211
}

212
static struct nvkm_output *
B
Ben Skeggs 已提交
213
exec_script(struct nv50_disp *disp, int head, int id)
214
{
215 216
	struct nvkm_subdev *subdev = &disp->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
217
	struct nvkm_bios *bios = device->bios;
218
	struct nvkm_output *outp;
219 220
	struct nvbios_outp info;
	u8  ver, hdr, cnt, len;
221
	u32 data, ctrl = 0;
222
	u32 reg;
223 224
	int i;

225
	/* DAC */
226
	for (i = 0; !(ctrl & (1 << head)) && i < disp->func->dac.nr; i++)
227
		ctrl = nvkm_rd32(device, 0x610b5c + (i * 8));
228

229
	/* SOR */
230
	if (!(ctrl & (1 << head))) {
231 232 233
		if (device->chipset  < 0x90 ||
		    device->chipset == 0x92 ||
		    device->chipset == 0xa0) {
234
			reg = 0x610b74;
235
		} else {
236
			reg = 0x610798;
237
		}
238
		for (i = 0; !(ctrl & (1 << head)) && i < disp->func->sor.nr; i++)
239
			ctrl = nvkm_rd32(device, reg + (i * 8));
240
		i += 4;
241 242
	}

243 244
	/* PIOR */
	if (!(ctrl & (1 << head))) {
245
		for (i = 0; !(ctrl & (1 << head)) && i < disp->func->pior.nr; i++)
246
			ctrl = nvkm_rd32(device, 0x610b84 + (i * 8));
247 248 249
		i += 8;
	}

250
	if (!(ctrl & (1 << head)))
251
		return NULL;
252
	i--;
253

B
Ben Skeggs 已提交
254
	outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
255
	if (outp) {
256
		struct nvbios_init init = {
257
			.subdev = subdev,
258 259
			.bios = bios,
			.offset = info.script[id],
260
			.outp = &outp->info,
261 262 263 264
			.crtc = head,
			.execute = 1,
		};

265
		nvbios_exec(&init);
266 267
	}

268
	return outp;
269 270
}

271
static struct nvkm_output *
B
Ben Skeggs 已提交
272
exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf)
273
{
274 275
	struct nvkm_subdev *subdev = &disp->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
276
	struct nvkm_bios *bios = device->bios;
277
	struct nvkm_output *outp;
278 279 280
	struct nvbios_outp info1;
	struct nvbios_ocfg info2;
	u8  ver, hdr, cnt, len;
281
	u32 data, ctrl = 0;
282
	u32 reg;
283 284
	int i;

285
	/* DAC */
286
	for (i = 0; !(ctrl & (1 << head)) && i < disp->func->dac.nr; i++)
287
		ctrl = nvkm_rd32(device, 0x610b58 + (i * 8));
288

289
	/* SOR */
290
	if (!(ctrl & (1 << head))) {
291 292 293
		if (device->chipset  < 0x90 ||
		    device->chipset == 0x92 ||
		    device->chipset == 0xa0) {
294
			reg = 0x610b70;
295
		} else {
296
			reg = 0x610794;
297
		}
298
		for (i = 0; !(ctrl & (1 << head)) && i < disp->func->sor.nr; i++)
299
			ctrl = nvkm_rd32(device, reg + (i * 8));
300
		i += 4;
301 302
	}

303 304
	/* PIOR */
	if (!(ctrl & (1 << head))) {
305
		for (i = 0; !(ctrl & (1 << head)) && i < disp->func->pior.nr; i++)
306
			ctrl = nvkm_rd32(device, 0x610b80 + (i * 8));
307 308 309
		i += 8;
	}

310
	if (!(ctrl & (1 << head)))
311
		return NULL;
312
	i--;
313

B
Ben Skeggs 已提交
314
	outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
315
	if (!outp)
316
		return NULL;
317

318
	*conf = (ctrl & 0x00000f00) >> 8;
319 320
	if (outp->info.location == 0) {
		switch (outp->info.type) {
321
		case DCB_OUTPUT_TMDS:
322
			if (*conf == 5)
323
				*conf |= 0x0100;
324 325
			break;
		case DCB_OUTPUT_LVDS:
326
			*conf |= disp->sor.lvdsconf;
327 328 329 330 331
			break;
		default:
			break;
		}
	} else {
332
		*conf = (ctrl & 0x00000f00) >> 8;
333
		pclk = pclk / 2;
334 335
	}

336 337
	data = nvbios_ocfg_match(bios, data, *conf & 0xff, *conf >> 8,
				 &ver, &hdr, &cnt, &len, &info2);
338
	if (data && id < 0xff) {
339 340 341
		data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
		if (data) {
			struct nvbios_init init = {
342
				.subdev = subdev,
343 344
				.bios = bios,
				.offset = data,
345
				.outp = &outp->info,
346 347 348 349
				.crtc = head,
				.execute = 1,
			};

350
			nvbios_exec(&init);
351 352 353
		}
	}

354
	return outp;
355 356
}

357 358 359 360 361 362 363 364
/* If programming a TMDS output on a SOR that can also be configured for
 * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
 *
 * It looks like the VBIOS TMDS scripts make an attempt at this, however,
 * the VBIOS scripts on at least one board I have only switch it off on
 * link 0, causing a blank display if the output has previously been
 * programmed for DisplayPort.
 */
365
static void
366 367
nv50_disp_intr_unk40_0_tmds(struct nv50_disp *disp,
			    struct dcb_output *outp)
368 369
{
	struct nvkm_device *device = disp->base.engine.subdev.device;
370 371 372 373 374 375 376
	struct nvkm_bios *bios = device->bios;
	const int link = !(outp->sorconf.link & 1);
	const int   or = ffs(outp->or) - 1;
	const u32 loff = (or * 0x800) + (link * 0x80);
	const u16 mask = (outp->sorconf.link << 6) | outp->or;
	struct dcb_output match;
	u8  ver, hdr;
377

378 379
	if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match))
		nvkm_mask(device, 0x61c10c + loff, 0x00000001, 0x00000000);
380 381 382
}

static void
383
nv50_disp_intr_unk40_0(struct nv50_disp *disp, int head)
384 385
{
	struct nvkm_device *device = disp->base.engine.subdev.device;
386 387 388
	struct nvkm_output *outp;
	u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff;
	u32 conf;
389

390 391
	outp = exec_clkcmp(disp, head, 1, pclk, &conf);
	if (!outp)
392 393
		return;

394 395 396
	if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS)
		nv50_disp_intr_unk40_0_tmds(disp, &outp->info);
	nv50_disp_dptmds_war_3(disp, &outp->info);
397 398 399
}

static void
B
Ben Skeggs 已提交
400
nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head,
401
			  struct dcb_output *outp, u32 pclk)
402
{
403 404
	struct nvkm_subdev *subdev = &disp->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
405 406 407 408
	const int link = !(outp->sorconf.link & 1);
	const int   or = ffs(outp->or) - 1;
	const u32 soff = (  or * 0x800);
	const u32 loff = (link * 0x080) + soff;
409
	const u32 ctrl = nvkm_rd32(device, 0x610794 + (or * 8));
410
	const u32 symbol = 100000;
411 412 413 414 415
	const s32 vactive = nvkm_rd32(device, 0x610af8 + (head * 0x540)) & 0xffff;
	const s32 vblanke = nvkm_rd32(device, 0x610ae8 + (head * 0x540)) & 0xffff;
	const s32 vblanks = nvkm_rd32(device, 0x610af0 + (head * 0x540)) & 0xffff;
	u32 dpctrl = nvkm_rd32(device, 0x61c10c + loff);
	u32 clksor = nvkm_rd32(device, 0x614300 + soff);
416 417 418 419
	int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
	int TU, VTUi, VTUf, VTUa;
	u64 link_data_rate, link_ratio, unk;
	u32 best_diff = 64 * symbol;
B
Ben Skeggs 已提交
420
	u32 link_nr, link_bw, bits;
421 422 423 424 425 426 427 428 429 430
	u64 value;

	link_bw = (clksor & 0x000c0000) ? 270000 : 162000;
	link_nr = hweight32(dpctrl & 0x000f0000);

	/* symbols/hblank - algorithm taken from comments in tegra driver */
	value = vblanke + vactive - vblanks - 7;
	value = value * link_bw;
	do_div(value, pclk);
	value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
431
	nvkm_mask(device, 0x61c1e8 + soff, 0x0000ffff, value);
432 433 434 435 436 437

	/* symbols/vblank - algorithm taken from comments in tegra driver */
	value = vblanks - vblanke - 25;
	value = value * link_bw;
	do_div(value, pclk);
	value = value - ((36 / link_nr) + 3) - 1;
438
	nvkm_mask(device, 0x61c1ec + soff, 0x00ffffff, value);
439 440

	/* watermark / activesym */
441 442 443 444
	if      ((ctrl & 0xf0000) == 0x60000) bits = 30;
	else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
	else                                  bits = 18;

445 446 447 448
	link_data_rate = (pclk * bits / 8) / link_nr;

	/* calculate ratio of packed data rate to link symbol rate */
	link_ratio = link_data_rate * symbol;
B
Ben Skeggs 已提交
449
	do_div(link_ratio, link_bw);
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502

	for (TU = 64; TU >= 32; TU--) {
		/* calculate average number of valid symbols in each TU */
		u32 tu_valid = link_ratio * TU;
		u32 calc, diff;

		/* find a hw representation for the fraction.. */
		VTUi = tu_valid / symbol;
		calc = VTUi * symbol;
		diff = tu_valid - calc;
		if (diff) {
			if (diff >= (symbol / 2)) {
				VTUf = symbol / (symbol - diff);
				if (symbol - (VTUf * diff))
					VTUf++;

				if (VTUf <= 15) {
					VTUa  = 1;
					calc += symbol - (symbol / VTUf);
				} else {
					VTUa  = 0;
					VTUf  = 1;
					calc += symbol;
				}
			} else {
				VTUa  = 0;
				VTUf  = min((int)(symbol / diff), 15);
				calc += symbol / VTUf;
			}

			diff = calc - tu_valid;
		} else {
			/* no remainder, but the hw doesn't like the fractional
			 * part to be zero.  decrement the integer part and
			 * have the fraction add a whole symbol back
			 */
			VTUa = 0;
			VTUf = 1;
			VTUi--;
		}

		if (diff < best_diff) {
			best_diff = diff;
			bestTU = TU;
			bestVTUa = VTUa;
			bestVTUf = VTUf;
			bestVTUi = VTUi;
			if (diff == 0)
				break;
		}
	}

	if (!bestTU) {
503
		nvkm_error(subdev, "unable to find suitable dp config\n");
504 505 506 507 508 509
		return;
	}

	/* XXX close to vbios numbers, but not right */
	unk  = (symbol - link_ratio) * bestTU;
	unk *= link_ratio;
B
Ben Skeggs 已提交
510 511
	do_div(unk, symbol);
	do_div(unk, symbol);
512 513
	unk += 6;

514 515
	nvkm_mask(device, 0x61c10c + loff, 0x000001fc, bestTU << 2);
	nvkm_mask(device, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 |
516 517 518 519 520
						   bestVTUf << 16 |
						   bestVTUi << 8 | unk);
}

static void
B
Ben Skeggs 已提交
521
nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head)
522
{
523
	struct nvkm_device *device = disp->base.engine.subdev.device;
524
	struct nvkm_output *outp;
525
	u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff;
526 527
	u32 hval, hreg = 0x614200 + (head * 0x800);
	u32 oval, oreg;
528
	u32 mask, conf;
529

B
Ben Skeggs 已提交
530
	outp = exec_clkcmp(disp, head, 0xff, pclk, &conf);
531 532
	if (!outp)
		return;
533

534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
	/* we allow both encoder attach and detach operations to occur
	 * within a single supervisor (ie. modeset) sequence.  the
	 * encoder detach scripts quite often switch off power to the
	 * lanes, which requires the link to be re-trained.
	 *
	 * this is not generally an issue as the sink "must" (heh)
	 * signal an irq when it's lost sync so the driver can
	 * re-train.
	 *
	 * however, on some boards, if one does not configure at least
	 * the gpu side of the link *before* attaching, then various
	 * things can go horribly wrong (PDISP disappearing from mmio,
	 * third supervisor never happens, etc).
	 *
	 * the solution is simply to retrain here, if necessary.  last
	 * i checked, the binary driver userspace does not appear to
	 * trigger this situation (it forces an UPDATE between steps).
	 */
552
	if (outp->info.type == DCB_OUTPUT_DP) {
553
		u32 soff = (ffs(outp->info.or) - 1) * 0x08;
554 555 556
		u32 ctrl, datarate;

		if (outp->info.location == 0) {
557
			ctrl = nvkm_rd32(device, 0x610794 + soff);
558 559
			soff = 1;
		} else {
560
			ctrl = nvkm_rd32(device, 0x610b80 + soff);
561 562
			soff = 2;
		}
563 564

		switch ((ctrl & 0x000f0000) >> 16) {
565 566
		case 6: datarate = pclk * 30; break;
		case 5: datarate = pclk * 24; break;
567 568
		case 2:
		default:
569
			datarate = pclk * 18;
570
			break;
571 572
		}

573
		if (nvkm_output_dp_train(outp, datarate / soff))
574
			OUTP_ERR(outp, "link not trained before attach");
575 576
	}

B
Ben Skeggs 已提交
577
	exec_clkcmp(disp, head, 0, pclk, &conf);
578 579 580 581 582 583 584 585 586

	if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) {
		oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800;
		oval = 0x00000000;
		hval = 0x00000000;
		mask = 0xffffffff;
	} else
	if (!outp->info.location) {
		if (outp->info.type == DCB_OUTPUT_DP)
B
Ben Skeggs 已提交
587
			nv50_disp_intr_unk20_2_dp(disp, head, &outp->info, pclk);
588 589 590 591 592 593 594 595 596
		oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
		oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
		hval = 0x00000000;
		mask = 0x00000707;
	} else {
		oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800;
		oval = 0x00000001;
		hval = 0x00000001;
		mask = 0x00000707;
597
	}
598

599 600
	nvkm_mask(device, hreg, 0x0000000f, hval);
	nvkm_mask(device, oreg, mask, oval);
601 602

	nv50_disp_dptmds_war_2(disp, &outp->info);
603 604 605
}

static void
606
nv50_disp_intr_unk20_1(struct nv50_disp *disp, int head)
607
{
608
	struct nvkm_device *device = disp->base.engine.subdev.device;
609 610 611 612
	struct nvkm_devinit *devinit = device->devinit;
	u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff;
	if (pclk)
		nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk);
613 614 615
}

static void
616
nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head)
617
{
618 619
	struct nvkm_subdev *subdev = &disp->base.engine.subdev;
	struct nvkm_output *outp = exec_script(disp, head, 2);
620

621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
	/* the binary driver does this outside of the supervisor handling
	 * (after the third supervisor from a detach).  we (currently?)
	 * allow both detach/attach to happen in the same set of
	 * supervisor interrupts, so it would make sense to execute this
	 * (full power down?) script after all the detach phases of the
	 * supervisor handling.  like with training if needed from the
	 * second supervisor, nvidia doesn't do this, so who knows if it's
	 * entirely safe, but it does appear to work..
	 *
	 * without this script being run, on some configurations i've
	 * seen, switching from DP to TMDS on a DP connector may result
	 * in a blank screen (SOR_PWR off/on can restore it)
	 */
	if (outp && outp->info.type == DCB_OUTPUT_DP) {
		struct nvkm_output_dp *outpdp = nvkm_output_dp(outp);
		struct nvbios_init init = {
			.subdev = subdev,
			.bios = subdev->device->bios,
			.outp = &outp->info,
			.crtc = head,
			.offset = outpdp->info.script[4],
			.execute = 1,
		};
644

645 646 647 648 649 650 651 652 653 654
		nvkm_notify_put(&outpdp->irq);
		nvbios_exec(&init);
		atomic_set(&outpdp->lt.done, 0);
	}
}

static void
nv50_disp_intr_unk10_0(struct nv50_disp *disp, int head)
{
	exec_script(disp, head, 1);
655 656
}

657
void
658
nv50_disp_super(struct work_struct *work)
659
{
B
Ben Skeggs 已提交
660 661
	struct nv50_disp *disp =
		container_of(work, struct nv50_disp, supervisor);
662 663
	struct nvkm_subdev *subdev = &disp->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
664
	struct nvkm_head *head;
665
	u32 super = nvkm_rd32(device, 0x610030);
666

667
	nvkm_debug(subdev, "supervisor %08x %08x\n", disp->super, super);
668

B
Ben Skeggs 已提交
669
	if (disp->super & 0x00000010) {
670
		nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG);
671 672
		list_for_each_entry(head, &disp->base.head, head) {
			if (!(super & (0x00000020 << head->id)))
673
				continue;
674
			if (!(super & (0x00000080 << head->id)))
675
				continue;
676
			nv50_disp_intr_unk10_0(disp, head->id);
677 678
		}
	} else
B
Ben Skeggs 已提交
679
	if (disp->super & 0x00000020) {
680 681
		list_for_each_entry(head, &disp->base.head, head) {
			if (!(super & (0x00000080 << head->id)))
682
				continue;
683
			nv50_disp_intr_unk20_0(disp, head->id);
684
		}
685 686
		list_for_each_entry(head, &disp->base.head, head) {
			if (!(super & (0x00000200 << head->id)))
687
				continue;
688
			nv50_disp_intr_unk20_1(disp, head->id);
689
		}
690 691
		list_for_each_entry(head, &disp->base.head, head) {
			if (!(super & (0x00000080 << head->id)))
692
				continue;
693
			nv50_disp_intr_unk20_2(disp, head->id);
694 695
		}
	} else
B
Ben Skeggs 已提交
696
	if (disp->super & 0x00000040) {
697 698
		list_for_each_entry(head, &disp->base.head, head) {
			if (!(super & (0x00000080 << head->id)))
699
				continue;
700
			nv50_disp_intr_unk40_0(disp, head->id);
701
		}
702
		nv50_disp_update_sppll1(disp);
703 704
	}

705
	nvkm_wr32(device, 0x610030, 0x80000000);
706 707
}

708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
static const struct nvkm_enum
nv50_disp_intr_error_type[] = {
	{ 3, "ILLEGAL_MTHD" },
	{ 4, "INVALID_VALUE" },
	{ 5, "INVALID_STATE" },
	{ 7, "INVALID_HANDLE" },
	{}
};

static const struct nvkm_enum
nv50_disp_intr_error_code[] = {
	{ 0x00, "" },
	{}
};

static void
nv50_disp_intr_error(struct nv50_disp *disp, int chid)
{
	struct nvkm_subdev *subdev = &disp->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
	u32 data = nvkm_rd32(device, 0x610084 + (chid * 0x08));
	u32 addr = nvkm_rd32(device, 0x610080 + (chid * 0x08));
	u32 code = (addr & 0x00ff0000) >> 16;
	u32 type = (addr & 0x00007000) >> 12;
	u32 mthd = (addr & 0x00000ffc);
	const struct nvkm_enum *ec, *et;

	et = nvkm_enum_find(nv50_disp_intr_error_type, type);
	ec = nvkm_enum_find(nv50_disp_intr_error_code, code);

	nvkm_error(subdev,
		   "ERROR %d [%s] %02x [%s] chid %d mthd %04x data %08x\n",
		   type, et ? et->name : "", code, ec ? ec->name : "",
		   chid, mthd, data);

	if (chid < ARRAY_SIZE(disp->chan)) {
		switch (mthd) {
		case 0x0080:
			nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR);
			break;
		default:
			break;
		}
	}

	nvkm_wr32(device, 0x610020, 0x00010000 << chid);
	nvkm_wr32(device, 0x610080 + (chid * 0x08), 0x90000000);
}

757
void
758
nv50_disp_intr(struct nv50_disp *disp)
759
{
760 761 762
	struct nvkm_device *device = disp->base.engine.subdev.device;
	u32 intr0 = nvkm_rd32(device, 0x610020);
	u32 intr1 = nvkm_rd32(device, 0x610024);
763

764 765
	while (intr0 & 0x001f0000) {
		u32 chid = __ffs(intr0 & 0x001f0000) - 16;
B
Ben Skeggs 已提交
766
		nv50_disp_intr_error(disp, chid);
767
		intr0 &= ~(0x00010000 << chid);
768 769
	}

770 771
	while (intr0 & 0x0000001f) {
		u32 chid = __ffs(intr0 & 0x0000001f);
B
Ben Skeggs 已提交
772
		nv50_disp_chan_uevent_send(disp, chid);
773 774 775
		intr0 &= ~(0x00000001 << chid);
	}

776
	if (intr1 & 0x00000004) {
B
Ben Skeggs 已提交
777
		nvkm_disp_vblank(&disp->base, 0);
778
		nvkm_wr32(device, 0x610024, 0x00000004);
779 780
	}

781
	if (intr1 & 0x00000008) {
B
Ben Skeggs 已提交
782
		nvkm_disp_vblank(&disp->base, 1);
783
		nvkm_wr32(device, 0x610024, 0x00000008);
784 785
	}

786
	if (intr1 & 0x00000070) {
B
Ben Skeggs 已提交
787 788
		disp->super = (intr1 & 0x00000070);
		schedule_work(&disp->supervisor);
789
		nvkm_wr32(device, 0x610024, disp->super);
790
	}
791 792
}

793
static const struct nv50_disp_func
794
nv50_disp = {
795 796
	.intr = nv50_disp_intr,
	.uevent = &nv50_disp_chan_uevent,
797
	.super = nv50_disp_super,
798
	.root = &nv50_disp_root_oclass,
799
	.head.new = nv50_head_new,
800 801 802 803 804 805 806 807 808 809 810 811
	.outp.internal.crt = nv50_dac_output_new,
	.outp.internal.tmds = nv50_sor_output_new,
	.outp.internal.lvds = nv50_sor_output_new,
	.outp.external.tmds = nv50_pior_output_new,
	.outp.external.dp = nv50_pior_dp_new,
	.dac.nr = 3,
	.dac.power = nv50_dac_power,
	.dac.sense = nv50_dac_sense,
	.sor.nr = 2,
	.sor.power = nv50_sor_power,
	.pior.nr = 3,
	.pior.power = nv50_pior_power,
812 813
};

814 815
int
nv50_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp)
816
{
817
	return nv50_disp_new_(&nv50_disp, device, index, 2, pdisp);
818
}