cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nv50.c (20479B)


      1/*
      2 * Copyright 2012 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#include "nv50.h"
     25#include "head.h"
     26#include "ior.h"
     27#include "channv50.h"
     28#include "rootnv50.h"
     29
     30#include <core/client.h>
     31#include <core/ramht.h>
     32#include <subdev/bios.h>
     33#include <subdev/bios/disp.h>
     34#include <subdev/bios/init.h>
     35#include <subdev/bios/pll.h>
     36#include <subdev/devinit.h>
     37#include <subdev/timer.h>
     38
     39static const struct nvkm_disp_oclass *
     40nv50_disp_root_(struct nvkm_disp *base)
     41{
     42	return nv50_disp(base)->func->root;
     43}
     44
     45static void
     46nv50_disp_intr_(struct nvkm_disp *base)
     47{
     48	struct nv50_disp *disp = nv50_disp(base);
     49	disp->func->intr(disp);
     50}
     51
     52static void
     53nv50_disp_fini_(struct nvkm_disp *base)
     54{
     55	struct nv50_disp *disp = nv50_disp(base);
     56	disp->func->fini(disp);
     57}
     58
     59static int
     60nv50_disp_init_(struct nvkm_disp *base)
     61{
     62	struct nv50_disp *disp = nv50_disp(base);
     63	return disp->func->init(disp);
     64}
     65
     66static void *
     67nv50_disp_dtor_(struct nvkm_disp *base)
     68{
     69	struct nv50_disp *disp = nv50_disp(base);
     70
     71	nvkm_ramht_del(&disp->ramht);
     72	nvkm_gpuobj_del(&disp->inst);
     73
     74	nvkm_event_fini(&disp->uevent);
     75	if (disp->wq)
     76		destroy_workqueue(disp->wq);
     77
     78	return disp;
     79}
     80
     81static int
     82nv50_disp_oneinit_(struct nvkm_disp *base)
     83{
     84	struct nv50_disp *disp = nv50_disp(base);
     85	const struct nv50_disp_func *func = disp->func;
     86	struct nvkm_subdev *subdev = &disp->base.engine.subdev;
     87	struct nvkm_device *device = subdev->device;
     88	int ret, i;
     89
     90	if (func->wndw.cnt) {
     91		disp->wndw.nr = func->wndw.cnt(&disp->base, &disp->wndw.mask);
     92		nvkm_debug(subdev, "Window(s): %d (%08lx)\n",
     93			   disp->wndw.nr, disp->wndw.mask);
     94	}
     95
     96	disp->head.nr = func->head.cnt(&disp->base, &disp->head.mask);
     97	nvkm_debug(subdev, "  Head(s): %d (%02lx)\n",
     98		   disp->head.nr, disp->head.mask);
     99	for_each_set_bit(i, &disp->head.mask, disp->head.nr) {
    100		ret = func->head.new(&disp->base, i);
    101		if (ret)
    102			return ret;
    103	}
    104
    105	if (func->dac.cnt) {
    106		disp->dac.nr = func->dac.cnt(&disp->base, &disp->dac.mask);
    107		nvkm_debug(subdev, "   DAC(s): %d (%02lx)\n",
    108			   disp->dac.nr, disp->dac.mask);
    109		for_each_set_bit(i, &disp->dac.mask, disp->dac.nr) {
    110			ret = func->dac.new(&disp->base, i);
    111			if (ret)
    112				return ret;
    113		}
    114	}
    115
    116	if (func->pior.cnt) {
    117		disp->pior.nr = func->pior.cnt(&disp->base, &disp->pior.mask);
    118		nvkm_debug(subdev, "  PIOR(s): %d (%02lx)\n",
    119			   disp->pior.nr, disp->pior.mask);
    120		for_each_set_bit(i, &disp->pior.mask, disp->pior.nr) {
    121			ret = func->pior.new(&disp->base, i);
    122			if (ret)
    123				return ret;
    124		}
    125	}
    126
    127	disp->sor.nr = func->sor.cnt(&disp->base, &disp->sor.mask);
    128	nvkm_debug(subdev, "   SOR(s): %d (%02lx)\n",
    129		   disp->sor.nr, disp->sor.mask);
    130	for_each_set_bit(i, &disp->sor.mask, disp->sor.nr) {
    131		ret = func->sor.new(&disp->base, i);
    132		if (ret)
    133			return ret;
    134	}
    135
    136	ret = nvkm_gpuobj_new(device, 0x10000, 0x10000, false, NULL,
    137			      &disp->inst);
    138	if (ret)
    139		return ret;
    140
    141	return nvkm_ramht_new(device, func->ramht_size ? func->ramht_size :
    142			      0x1000, 0, disp->inst, &disp->ramht);
    143}
    144
    145static const struct nvkm_disp_func
    146nv50_disp_ = {
    147	.dtor = nv50_disp_dtor_,
    148	.oneinit = nv50_disp_oneinit_,
    149	.init = nv50_disp_init_,
    150	.fini = nv50_disp_fini_,
    151	.intr = nv50_disp_intr_,
    152	.root = nv50_disp_root_,
    153};
    154
    155int
    156nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device,
    157	       enum nvkm_subdev_type type, int inst, struct nvkm_disp **pdisp)
    158{
    159	struct nv50_disp *disp;
    160	int ret;
    161
    162	if (!(disp = kzalloc(sizeof(*disp), GFP_KERNEL)))
    163		return -ENOMEM;
    164	disp->func = func;
    165	*pdisp = &disp->base;
    166
    167	ret = nvkm_disp_ctor(&nv50_disp_, device, type, inst, &disp->base);
    168	if (ret)
    169		return ret;
    170
    171	disp->wq = create_singlethread_workqueue("nvkm-disp");
    172	if (!disp->wq)
    173		return -ENOMEM;
    174
    175	INIT_WORK(&disp->supervisor, func->super);
    176
    177	return nvkm_event_init(func->uevent, 1, ARRAY_SIZE(disp->chan),
    178			       &disp->uevent);
    179}
    180
    181static u32
    182nv50_disp_super_iedt(struct nvkm_head *head, struct nvkm_outp *outp,
    183		     u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
    184		     struct nvbios_outp *iedt)
    185{
    186	struct nvkm_bios *bios = head->disp->engine.subdev.device->bios;
    187	const u8  l = ffs(outp->info.link);
    188	const u16 t = outp->info.hasht;
    189	const u16 m = (0x0100 << head->id) | (l << 6) | outp->info.or;
    190	u32 data = nvbios_outp_match(bios, t, m, ver, hdr, cnt, len, iedt);
    191	if (!data)
    192		OUTP_DBG(outp, "missing IEDT for %04x:%04x", t, m);
    193	return data;
    194}
    195
    196static void
    197nv50_disp_super_ied_on(struct nvkm_head *head,
    198		       struct nvkm_ior *ior, int id, u32 khz)
    199{
    200	struct nvkm_subdev *subdev = &head->disp->engine.subdev;
    201	struct nvkm_bios *bios = subdev->device->bios;
    202	struct nvkm_outp *outp = ior->asy.outp;
    203	struct nvbios_ocfg iedtrs;
    204	struct nvbios_outp iedt;
    205	u8  ver, hdr, cnt, len, flags = 0x00;
    206	u32 data;
    207
    208	if (!outp) {
    209		IOR_DBG(ior, "nothing to attach");
    210		return;
    211	}
    212
    213	/* Lookup IED table for the device. */
    214	data = nv50_disp_super_iedt(head, outp, &ver, &hdr, &cnt, &len, &iedt);
    215	if (!data)
    216		return;
    217
    218	/* Lookup IEDT runtime settings for the current configuration. */
    219	if (ior->type == SOR) {
    220		if (ior->asy.proto == LVDS) {
    221			if (head->asy.or.depth == 24)
    222				flags |= 0x02;
    223		}
    224		if (ior->asy.link == 3)
    225			flags |= 0x01;
    226	}
    227
    228	data = nvbios_ocfg_match(bios, data, ior->asy.proto_evo, flags,
    229				 &ver, &hdr, &cnt, &len, &iedtrs);
    230	if (!data) {
    231		OUTP_DBG(outp, "missing IEDT RS for %02x:%02x",
    232			 ior->asy.proto_evo, flags);
    233		return;
    234	}
    235
    236	/* Execute the OnInt[23] script for the current frequency. */
    237	data = nvbios_oclk_match(bios, iedtrs.clkcmp[id], khz);
    238	if (!data) {
    239		OUTP_DBG(outp, "missing IEDT RSS %d for %02x:%02x %d khz",
    240			 id, ior->asy.proto_evo, flags, khz);
    241		return;
    242	}
    243
    244	nvbios_init(subdev, data,
    245		init.outp = &outp->info;
    246		init.or   = ior->id;
    247		init.link = ior->asy.link;
    248		init.head = head->id;
    249	);
    250}
    251
    252static void
    253nv50_disp_super_ied_off(struct nvkm_head *head, struct nvkm_ior *ior, int id)
    254{
    255	struct nvkm_outp *outp = ior->arm.outp;
    256	struct nvbios_outp iedt;
    257	u8  ver, hdr, cnt, len;
    258	u32 data;
    259
    260	if (!outp) {
    261		IOR_DBG(ior, "nothing attached");
    262		return;
    263	}
    264
    265	data = nv50_disp_super_iedt(head, outp, &ver, &hdr, &cnt, &len, &iedt);
    266	if (!data)
    267		return;
    268
    269	nvbios_init(&head->disp->engine.subdev, iedt.script[id],
    270		init.outp = &outp->info;
    271		init.or   = ior->id;
    272		init.link = ior->arm.link;
    273		init.head = head->id;
    274	);
    275}
    276
    277static struct nvkm_ior *
    278nv50_disp_super_ior_asy(struct nvkm_head *head)
    279{
    280	struct nvkm_ior *ior;
    281	list_for_each_entry(ior, &head->disp->ior, head) {
    282		if (ior->asy.head & (1 << head->id)) {
    283			HEAD_DBG(head, "to %s", ior->name);
    284			return ior;
    285		}
    286	}
    287	HEAD_DBG(head, "nothing to attach");
    288	return NULL;
    289}
    290
    291static struct nvkm_ior *
    292nv50_disp_super_ior_arm(struct nvkm_head *head)
    293{
    294	struct nvkm_ior *ior;
    295	list_for_each_entry(ior, &head->disp->ior, head) {
    296		if (ior->arm.head & (1 << head->id)) {
    297			HEAD_DBG(head, "on %s", ior->name);
    298			return ior;
    299		}
    300	}
    301	HEAD_DBG(head, "nothing attached");
    302	return NULL;
    303}
    304
    305void
    306nv50_disp_super_3_0(struct nv50_disp *disp, struct nvkm_head *head)
    307{
    308	struct nvkm_ior *ior;
    309
    310	/* Determine which OR, if any, we're attaching to the head. */
    311	HEAD_DBG(head, "supervisor 3.0");
    312	ior = nv50_disp_super_ior_asy(head);
    313	if (!ior)
    314		return;
    315
    316	/* Execute OnInt3 IED script. */
    317	nv50_disp_super_ied_on(head, ior, 1, head->asy.hz / 1000);
    318
    319	/* OR-specific handling. */
    320	if (ior->func->war_3)
    321		ior->func->war_3(ior);
    322}
    323
    324static void
    325nv50_disp_super_2_2_dp(struct nvkm_head *head, struct nvkm_ior *ior)
    326{
    327	struct nvkm_subdev *subdev = &head->disp->engine.subdev;
    328	const u32      khz = head->asy.hz / 1000;
    329	const u32 linkKBps = ior->dp.bw * 27000;
    330	const u32   symbol = 100000;
    331	int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
    332	int TU, VTUi, VTUf, VTUa;
    333	u64 link_data_rate, link_ratio, unk;
    334	u32 best_diff = 64 * symbol;
    335	u64 h, v;
    336
    337	/* symbols/hblank - algorithm taken from comments in tegra driver */
    338	h = head->asy.hblanke + head->asy.htotal - head->asy.hblanks - 7;
    339	h = h * linkKBps;
    340	do_div(h, khz);
    341	h = h - (3 * ior->dp.ef) - (12 / ior->dp.nr);
    342
    343	/* symbols/vblank - algorithm taken from comments in tegra driver */
    344	v = head->asy.vblanks - head->asy.vblanke - 25;
    345	v = v * linkKBps;
    346	do_div(v, khz);
    347	v = v - ((36 / ior->dp.nr) + 3) - 1;
    348
    349	ior->func->dp.audio_sym(ior, head->id, h, v);
    350
    351	/* watermark / activesym */
    352	link_data_rate = (khz * head->asy.or.depth / 8) / ior->dp.nr;
    353
    354	/* calculate ratio of packed data rate to link symbol rate */
    355	link_ratio = link_data_rate * symbol;
    356	do_div(link_ratio, linkKBps);
    357
    358	for (TU = 64; ior->func->dp.activesym && TU >= 32; TU--) {
    359		/* calculate average number of valid symbols in each TU */
    360		u32 tu_valid = link_ratio * TU;
    361		u32 calc, diff;
    362
    363		/* find a hw representation for the fraction.. */
    364		VTUi = tu_valid / symbol;
    365		calc = VTUi * symbol;
    366		diff = tu_valid - calc;
    367		if (diff) {
    368			if (diff >= (symbol / 2)) {
    369				VTUf = symbol / (symbol - diff);
    370				if (symbol - (VTUf * diff))
    371					VTUf++;
    372
    373				if (VTUf <= 15) {
    374					VTUa  = 1;
    375					calc += symbol - (symbol / VTUf);
    376				} else {
    377					VTUa  = 0;
    378					VTUf  = 1;
    379					calc += symbol;
    380				}
    381			} else {
    382				VTUa  = 0;
    383				VTUf  = min((int)(symbol / diff), 15);
    384				calc += symbol / VTUf;
    385			}
    386
    387			diff = calc - tu_valid;
    388		} else {
    389			/* no remainder, but the hw doesn't like the fractional
    390			 * part to be zero.  decrement the integer part and
    391			 * have the fraction add a whole symbol back
    392			 */
    393			VTUa = 0;
    394			VTUf = 1;
    395			VTUi--;
    396		}
    397
    398		if (diff < best_diff) {
    399			best_diff = diff;
    400			bestTU = TU;
    401			bestVTUa = VTUa;
    402			bestVTUf = VTUf;
    403			bestVTUi = VTUi;
    404			if (diff == 0)
    405				break;
    406		}
    407	}
    408
    409	if (ior->func->dp.activesym) {
    410		if (!bestTU) {
    411			nvkm_error(subdev, "unable to determine dp config\n");
    412			return;
    413		}
    414		ior->func->dp.activesym(ior, head->id, bestTU,
    415					bestVTUa, bestVTUf, bestVTUi);
    416	} else {
    417		bestTU = 64;
    418	}
    419
    420	/* XXX close to vbios numbers, but not right */
    421	unk  = (symbol - link_ratio) * bestTU;
    422	unk *= link_ratio;
    423	do_div(unk, symbol);
    424	do_div(unk, symbol);
    425	unk += 6;
    426
    427	ior->func->dp.watermark(ior, head->id, unk);
    428}
    429
    430void
    431nv50_disp_super_2_2(struct nv50_disp *disp, struct nvkm_head *head)
    432{
    433	const u32 khz = head->asy.hz / 1000;
    434	struct nvkm_outp *outp;
    435	struct nvkm_ior *ior;
    436
    437	/* Determine which OR, if any, we're attaching from the head. */
    438	HEAD_DBG(head, "supervisor 2.2");
    439	ior = nv50_disp_super_ior_asy(head);
    440	if (!ior)
    441		return;
    442
    443	/* For some reason, NVIDIA decided not to:
    444	 *
    445	 * A) Give dual-link LVDS a separate EVO protocol, like for TMDS.
    446	 *  and
    447	 * B) Use SetControlOutputResource.PixelDepth on LVDS.
    448	 *
    449	 * Override the values we usually read from HW with the same
    450	 * data we pass though an ioctl instead.
    451	 */
    452	if (ior->type == SOR && ior->asy.proto == LVDS) {
    453		head->asy.or.depth = (disp->sor.lvdsconf & 0x0200) ? 24 : 18;
    454		ior->asy.link      = (disp->sor.lvdsconf & 0x0100) ? 3  : 1;
    455	}
    456
    457	/* Handle any link training, etc. */
    458	if ((outp = ior->asy.outp) && outp->func->acquire)
    459		outp->func->acquire(outp);
    460
    461	/* Execute OnInt2 IED script. */
    462	nv50_disp_super_ied_on(head, ior, 0, khz);
    463
    464	/* Program RG clock divider. */
    465	head->func->rgclk(head, ior->asy.rgdiv);
    466
    467	/* Mode-specific internal DP configuration. */
    468	if (ior->type == SOR && ior->asy.proto == DP)
    469		nv50_disp_super_2_2_dp(head, ior);
    470
    471	/* OR-specific handling. */
    472	ior->func->clock(ior);
    473	if (ior->func->war_2)
    474		ior->func->war_2(ior);
    475}
    476
    477void
    478nv50_disp_super_2_1(struct nv50_disp *disp, struct nvkm_head *head)
    479{
    480	struct nvkm_devinit *devinit = disp->base.engine.subdev.device->devinit;
    481	const u32 khz = head->asy.hz / 1000;
    482	HEAD_DBG(head, "supervisor 2.1 - %d khz", khz);
    483	if (khz)
    484		nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head->id, khz);
    485}
    486
    487void
    488nv50_disp_super_2_0(struct nv50_disp *disp, struct nvkm_head *head)
    489{
    490	struct nvkm_outp *outp;
    491	struct nvkm_ior *ior;
    492
    493	/* Determine which OR, if any, we're detaching from the head. */
    494	HEAD_DBG(head, "supervisor 2.0");
    495	ior = nv50_disp_super_ior_arm(head);
    496	if (!ior)
    497		return;
    498
    499	/* Execute OffInt2 IED script. */
    500	nv50_disp_super_ied_off(head, ior, 2);
    501
    502	/* If we're shutting down the OR's only active head, execute
    503	 * the output path's disable function.
    504	 */
    505	if (ior->arm.head == (1 << head->id)) {
    506		if ((outp = ior->arm.outp) && outp->func->disable)
    507			outp->func->disable(outp, ior);
    508	}
    509}
    510
    511void
    512nv50_disp_super_1_0(struct nv50_disp *disp, struct nvkm_head *head)
    513{
    514	struct nvkm_ior *ior;
    515
    516	/* Determine which OR, if any, we're detaching from the head. */
    517	HEAD_DBG(head, "supervisor 1.0");
    518	ior = nv50_disp_super_ior_arm(head);
    519	if (!ior)
    520		return;
    521
    522	/* Execute OffInt1 IED script. */
    523	nv50_disp_super_ied_off(head, ior, 1);
    524}
    525
    526void
    527nv50_disp_super_1(struct nv50_disp *disp)
    528{
    529	struct nvkm_head *head;
    530	struct nvkm_ior *ior;
    531
    532	list_for_each_entry(head, &disp->base.head, head) {
    533		head->func->state(head, &head->arm);
    534		head->func->state(head, &head->asy);
    535	}
    536
    537	list_for_each_entry(ior, &disp->base.ior, head) {
    538		ior->func->state(ior, &ior->arm);
    539		ior->func->state(ior, &ior->asy);
    540	}
    541}
    542
    543void
    544nv50_disp_super(struct work_struct *work)
    545{
    546	struct nv50_disp *disp =
    547		container_of(work, struct nv50_disp, supervisor);
    548	struct nvkm_subdev *subdev = &disp->base.engine.subdev;
    549	struct nvkm_device *device = subdev->device;
    550	struct nvkm_head *head;
    551	u32 super = nvkm_rd32(device, 0x610030);
    552
    553	nvkm_debug(subdev, "supervisor %08x %08x\n", disp->super, super);
    554
    555	if (disp->super & 0x00000010) {
    556		nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG);
    557		nv50_disp_super_1(disp);
    558		list_for_each_entry(head, &disp->base.head, head) {
    559			if (!(super & (0x00000020 << head->id)))
    560				continue;
    561			if (!(super & (0x00000080 << head->id)))
    562				continue;
    563			nv50_disp_super_1_0(disp, head);
    564		}
    565	} else
    566	if (disp->super & 0x00000020) {
    567		list_for_each_entry(head, &disp->base.head, head) {
    568			if (!(super & (0x00000080 << head->id)))
    569				continue;
    570			nv50_disp_super_2_0(disp, head);
    571		}
    572		nvkm_outp_route(&disp->base);
    573		list_for_each_entry(head, &disp->base.head, head) {
    574			if (!(super & (0x00000200 << head->id)))
    575				continue;
    576			nv50_disp_super_2_1(disp, head);
    577		}
    578		list_for_each_entry(head, &disp->base.head, head) {
    579			if (!(super & (0x00000080 << head->id)))
    580				continue;
    581			nv50_disp_super_2_2(disp, head);
    582		}
    583	} else
    584	if (disp->super & 0x00000040) {
    585		list_for_each_entry(head, &disp->base.head, head) {
    586			if (!(super & (0x00000080 << head->id)))
    587				continue;
    588			nv50_disp_super_3_0(disp, head);
    589		}
    590	}
    591
    592	nvkm_wr32(device, 0x610030, 0x80000000);
    593}
    594
    595const struct nvkm_enum
    596nv50_disp_intr_error_type[] = {
    597	{ 0, "NONE" },
    598	{ 1, "PUSHBUFFER_ERR" },
    599	{ 2, "TRAP" },
    600	{ 3, "RESERVED_METHOD" },
    601	{ 4, "INVALID_ARG" },
    602	{ 5, "INVALID_STATE" },
    603	{ 7, "UNRESOLVABLE_HANDLE" },
    604	{}
    605};
    606
    607static const struct nvkm_enum
    608nv50_disp_intr_error_code[] = {
    609	{ 0x00, "" },
    610	{}
    611};
    612
    613static void
    614nv50_disp_intr_error(struct nv50_disp *disp, int chid)
    615{
    616	struct nvkm_subdev *subdev = &disp->base.engine.subdev;
    617	struct nvkm_device *device = subdev->device;
    618	u32 data = nvkm_rd32(device, 0x610084 + (chid * 0x08));
    619	u32 addr = nvkm_rd32(device, 0x610080 + (chid * 0x08));
    620	u32 code = (addr & 0x00ff0000) >> 16;
    621	u32 type = (addr & 0x00007000) >> 12;
    622	u32 mthd = (addr & 0x00000ffc);
    623	const struct nvkm_enum *ec, *et;
    624
    625	et = nvkm_enum_find(nv50_disp_intr_error_type, type);
    626	ec = nvkm_enum_find(nv50_disp_intr_error_code, code);
    627
    628	nvkm_error(subdev,
    629		   "ERROR %d [%s] %02x [%s] chid %d mthd %04x data %08x\n",
    630		   type, et ? et->name : "", code, ec ? ec->name : "",
    631		   chid, mthd, data);
    632
    633	if (chid < ARRAY_SIZE(disp->chan)) {
    634		switch (mthd) {
    635		case 0x0080:
    636			nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR);
    637			break;
    638		default:
    639			break;
    640		}
    641	}
    642
    643	nvkm_wr32(device, 0x610020, 0x00010000 << chid);
    644	nvkm_wr32(device, 0x610080 + (chid * 0x08), 0x90000000);
    645}
    646
    647void
    648nv50_disp_intr(struct nv50_disp *disp)
    649{
    650	struct nvkm_device *device = disp->base.engine.subdev.device;
    651	u32 intr0 = nvkm_rd32(device, 0x610020);
    652	u32 intr1 = nvkm_rd32(device, 0x610024);
    653
    654	while (intr0 & 0x001f0000) {
    655		u32 chid = __ffs(intr0 & 0x001f0000) - 16;
    656		nv50_disp_intr_error(disp, chid);
    657		intr0 &= ~(0x00010000 << chid);
    658	}
    659
    660	while (intr0 & 0x0000001f) {
    661		u32 chid = __ffs(intr0 & 0x0000001f);
    662		nv50_disp_chan_uevent_send(disp, chid);
    663		intr0 &= ~(0x00000001 << chid);
    664	}
    665
    666	if (intr1 & 0x00000004) {
    667		nvkm_disp_vblank(&disp->base, 0);
    668		nvkm_wr32(device, 0x610024, 0x00000004);
    669	}
    670
    671	if (intr1 & 0x00000008) {
    672		nvkm_disp_vblank(&disp->base, 1);
    673		nvkm_wr32(device, 0x610024, 0x00000008);
    674	}
    675
    676	if (intr1 & 0x00000070) {
    677		disp->super = (intr1 & 0x00000070);
    678		queue_work(disp->wq, &disp->supervisor);
    679		nvkm_wr32(device, 0x610024, disp->super);
    680	}
    681}
    682
    683void
    684nv50_disp_fini(struct nv50_disp *disp)
    685{
    686	struct nvkm_device *device = disp->base.engine.subdev.device;
    687	/* disable all interrupts */
    688	nvkm_wr32(device, 0x610024, 0x00000000);
    689	nvkm_wr32(device, 0x610020, 0x00000000);
    690}
    691
    692int
    693nv50_disp_init(struct nv50_disp *disp)
    694{
    695	struct nvkm_device *device = disp->base.engine.subdev.device;
    696	struct nvkm_head *head;
    697	u32 tmp;
    698	int i;
    699
    700	/* The below segments of code copying values from one register to
    701	 * another appear to inform EVO of the display capabilities or
    702	 * something similar.  NFI what the 0x614004 caps are for..
    703	 */
    704	tmp = nvkm_rd32(device, 0x614004);
    705	nvkm_wr32(device, 0x610184, tmp);
    706
    707	/* ... CRTC caps */
    708	list_for_each_entry(head, &disp->base.head, head) {
    709		tmp = nvkm_rd32(device, 0x616100 + (head->id * 0x800));
    710		nvkm_wr32(device, 0x610190 + (head->id * 0x10), tmp);
    711		tmp = nvkm_rd32(device, 0x616104 + (head->id * 0x800));
    712		nvkm_wr32(device, 0x610194 + (head->id * 0x10), tmp);
    713		tmp = nvkm_rd32(device, 0x616108 + (head->id * 0x800));
    714		nvkm_wr32(device, 0x610198 + (head->id * 0x10), tmp);
    715		tmp = nvkm_rd32(device, 0x61610c + (head->id * 0x800));
    716		nvkm_wr32(device, 0x61019c + (head->id * 0x10), tmp);
    717	}
    718
    719	/* ... DAC caps */
    720	for (i = 0; i < disp->dac.nr; i++) {
    721		tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800));
    722		nvkm_wr32(device, 0x6101d0 + (i * 0x04), tmp);
    723	}
    724
    725	/* ... SOR caps */
    726	for (i = 0; i < disp->sor.nr; i++) {
    727		tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800));
    728		nvkm_wr32(device, 0x6101e0 + (i * 0x04), tmp);
    729	}
    730
    731	/* ... PIOR caps */
    732	for (i = 0; i < disp->pior.nr; i++) {
    733		tmp = nvkm_rd32(device, 0x61e000 + (i * 0x800));
    734		nvkm_wr32(device, 0x6101f0 + (i * 0x04), tmp);
    735	}
    736
    737	/* steal display away from vbios, or something like that */
    738	if (nvkm_rd32(device, 0x610024) & 0x00000100) {
    739		nvkm_wr32(device, 0x610024, 0x00000100);
    740		nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000);
    741		if (nvkm_msec(device, 2000,
    742			if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002))
    743				break;
    744		) < 0)
    745			return -EBUSY;
    746	}
    747
    748	/* point at display engine memory area (hash table, objects) */
    749	nvkm_wr32(device, 0x610010, (disp->inst->addr >> 8) | 9);
    750
    751	/* enable supervisor interrupts, disable everything else */
    752	nvkm_wr32(device, 0x61002c, 0x00000370);
    753	nvkm_wr32(device, 0x610028, 0x00000000);
    754	return 0;
    755}
    756
    757static const struct nv50_disp_func
    758nv50_disp = {
    759	.init = nv50_disp_init,
    760	.fini = nv50_disp_fini,
    761	.intr = nv50_disp_intr,
    762	.uevent = &nv50_disp_chan_uevent,
    763	.super = nv50_disp_super,
    764	.root = &nv50_disp_root_oclass,
    765	.head = { .cnt = nv50_head_cnt, .new = nv50_head_new },
    766	.dac = { .cnt = nv50_dac_cnt, .new = nv50_dac_new },
    767	.sor = { .cnt = nv50_sor_cnt, .new = nv50_sor_new },
    768	.pior = { .cnt = nv50_pior_cnt, .new = nv50_pior_new },
    769};
    770
    771int
    772nv50_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
    773	      struct nvkm_disp **pdisp)
    774{
    775	return nv50_disp_new_(&nv50_disp, device, type, inst, pdisp);
    776}