brintos

brintos / linux-shallow public Read only

0
0
Text · 13.8 KiB · a5e1f02 Raw
477 lines · c
1/*2 * Copyright 2012 Red Hat Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * 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 OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: Ben Skeggs23 */24#include "nv40.h"25#include "regs.h"26 27#include <core/client.h>28#include <core/gpuobj.h>29#include <subdev/fb.h>30#include <subdev/timer.h>31#include <engine/fifo.h>32 33u6434nv40_gr_units(struct nvkm_gr *gr)35{36	return nvkm_rd32(gr->engine.subdev.device, 0x1540);37}38 39/*******************************************************************************40 * Graphics object classes41 ******************************************************************************/42 43static int44nv40_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent,45		    int align, struct nvkm_gpuobj **pgpuobj)46{47	int ret = nvkm_gpuobj_new(object->engine->subdev.device, 20, align,48				  false, parent, pgpuobj);49	if (ret == 0) {50		nvkm_kmap(*pgpuobj);51		nvkm_wo32(*pgpuobj, 0x00, object->oclass);52		nvkm_wo32(*pgpuobj, 0x04, 0x00000000);53		nvkm_wo32(*pgpuobj, 0x08, 0x00000000);54#ifdef __BIG_ENDIAN55		nvkm_mo32(*pgpuobj, 0x08, 0x01000000, 0x01000000);56#endif57		nvkm_wo32(*pgpuobj, 0x0c, 0x00000000);58		nvkm_wo32(*pgpuobj, 0x10, 0x00000000);59		nvkm_done(*pgpuobj);60	}61	return ret;62}63 64const struct nvkm_object_func65nv40_gr_object = {66	.bind = nv40_gr_object_bind,67};68 69/*******************************************************************************70 * PGRAPH context71 ******************************************************************************/72 73static int74nv40_gr_chan_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent,75		  int align, struct nvkm_gpuobj **pgpuobj)76{77	struct nv40_gr_chan *chan = nv40_gr_chan(object);78	struct nv40_gr *gr = chan->gr;79	int ret = nvkm_gpuobj_new(gr->base.engine.subdev.device, gr->size,80				  align, true, parent, pgpuobj);81	if (ret == 0) {82		chan->inst = (*pgpuobj)->addr;83		nvkm_kmap(*pgpuobj);84		nv40_grctx_fill(gr->base.engine.subdev.device, *pgpuobj);85		nvkm_wo32(*pgpuobj, 0x00000, chan->inst >> 4);86		nvkm_done(*pgpuobj);87	}88	return ret;89}90 91static int92nv40_gr_chan_fini(struct nvkm_object *object, bool suspend)93{94	struct nv40_gr_chan *chan = nv40_gr_chan(object);95	struct nv40_gr *gr = chan->gr;96	struct nvkm_subdev *subdev = &gr->base.engine.subdev;97	struct nvkm_device *device = subdev->device;98	u32 inst = 0x01000000 | chan->inst >> 4;99	int ret = 0;100 101	nvkm_mask(device, 0x400720, 0x00000001, 0x00000000);102 103	if (nvkm_rd32(device, 0x40032c) == inst) {104		if (suspend) {105			nvkm_wr32(device, 0x400720, 0x00000000);106			nvkm_wr32(device, 0x400784, inst);107			nvkm_mask(device, 0x400310, 0x00000020, 0x00000020);108			nvkm_mask(device, 0x400304, 0x00000001, 0x00000001);109			if (nvkm_msec(device, 2000,110				if (!(nvkm_rd32(device, 0x400300) & 0x00000001))111					break;112			) < 0) {113				u32 insn = nvkm_rd32(device, 0x400308);114				nvkm_warn(subdev, "ctxprog timeout %08x\n", insn);115				ret = -EBUSY;116			}117		}118 119		nvkm_mask(device, 0x40032c, 0x01000000, 0x00000000);120	}121 122	if (nvkm_rd32(device, 0x400330) == inst)123		nvkm_mask(device, 0x400330, 0x01000000, 0x00000000);124 125	nvkm_mask(device, 0x400720, 0x00000001, 0x00000001);126	return ret;127}128 129static void *130nv40_gr_chan_dtor(struct nvkm_object *object)131{132	struct nv40_gr_chan *chan = nv40_gr_chan(object);133	unsigned long flags;134	spin_lock_irqsave(&chan->gr->base.engine.lock, flags);135	list_del(&chan->head);136	spin_unlock_irqrestore(&chan->gr->base.engine.lock, flags);137	return chan;138}139 140static const struct nvkm_object_func141nv40_gr_chan = {142	.dtor = nv40_gr_chan_dtor,143	.fini = nv40_gr_chan_fini,144	.bind = nv40_gr_chan_bind,145};146 147int148nv40_gr_chan_new(struct nvkm_gr *base, struct nvkm_chan *fifoch,149		 const struct nvkm_oclass *oclass, struct nvkm_object **pobject)150{151	struct nv40_gr *gr = nv40_gr(base);152	struct nv40_gr_chan *chan;153	unsigned long flags;154 155	if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))156		return -ENOMEM;157	nvkm_object_ctor(&nv40_gr_chan, oclass, &chan->object);158	chan->gr = gr;159	chan->fifo = fifoch;160	*pobject = &chan->object;161 162	spin_lock_irqsave(&chan->gr->base.engine.lock, flags);163	list_add(&chan->head, &gr->chan);164	spin_unlock_irqrestore(&chan->gr->base.engine.lock, flags);165	return 0;166}167 168/*******************************************************************************169 * PGRAPH engine/subdev functions170 ******************************************************************************/171 172static void173nv40_gr_tile(struct nvkm_gr *base, int i, struct nvkm_fb_tile *tile)174{175	struct nv40_gr *gr = nv40_gr(base);176	struct nvkm_device *device = gr->base.engine.subdev.device;177	struct nvkm_fifo *fifo = device->fifo;178	unsigned long flags;179 180	nvkm_fifo_pause(fifo, &flags);181	nv04_gr_idle(&gr->base);182 183	switch (device->chipset) {184	case 0x40:185	case 0x41:186	case 0x42:187	case 0x43:188	case 0x45:189		nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch);190		nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit);191		nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr);192		nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch);193		nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit);194		nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr);195		switch (device->chipset) {196		case 0x40:197		case 0x45:198			nvkm_wr32(device, NV20_PGRAPH_ZCOMP(i), tile->zcomp);199			nvkm_wr32(device, NV40_PGRAPH_ZCOMP1(i), tile->zcomp);200			break;201		case 0x41:202		case 0x42:203		case 0x43:204			nvkm_wr32(device, NV41_PGRAPH_ZCOMP0(i), tile->zcomp);205			nvkm_wr32(device, NV41_PGRAPH_ZCOMP1(i), tile->zcomp);206			break;207		default:208			break;209		}210		break;211	case 0x47:212	case 0x49:213	case 0x4b:214		nvkm_wr32(device, NV47_PGRAPH_TSIZE(i), tile->pitch);215		nvkm_wr32(device, NV47_PGRAPH_TLIMIT(i), tile->limit);216		nvkm_wr32(device, NV47_PGRAPH_TILE(i), tile->addr);217		nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch);218		nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit);219		nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr);220		nvkm_wr32(device, NV47_PGRAPH_ZCOMP0(i), tile->zcomp);221		nvkm_wr32(device, NV47_PGRAPH_ZCOMP1(i), tile->zcomp);222		break;223	default:224		WARN_ON(1);225		break;226	}227 228	nvkm_fifo_start(fifo, &flags);229}230 231void232nv40_gr_intr(struct nvkm_gr *base)233{234	struct nv40_gr *gr = nv40_gr(base);235	struct nv40_gr_chan *temp, *chan = NULL;236	struct nvkm_subdev *subdev = &gr->base.engine.subdev;237	struct nvkm_device *device = subdev->device;238	u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR);239	u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE);240	u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS);241	u32 inst = nvkm_rd32(device, 0x40032c) & 0x000fffff;242	u32 addr = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR);243	u32 subc = (addr & 0x00070000) >> 16;244	u32 mthd = (addr & 0x00001ffc);245	u32 data = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_DATA);246	u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xffff;247	u32 show = stat;248	char msg[128], src[128], sta[128];249	unsigned long flags;250 251	spin_lock_irqsave(&gr->base.engine.lock, flags);252	list_for_each_entry(temp, &gr->chan, head) {253		if (temp->inst >> 4 == inst) {254			chan = temp;255			list_del(&chan->head);256			list_add(&chan->head, &gr->chan);257			break;258		}259	}260 261	if (stat & NV_PGRAPH_INTR_ERROR) {262		if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {263			nvkm_mask(device, 0x402000, 0, 0);264		}265	}266 267	nvkm_wr32(device, NV03_PGRAPH_INTR, stat);268	nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001);269 270	if (show) {271		nvkm_snprintbf(msg, sizeof(msg), nv10_gr_intr_name, show);272		nvkm_snprintbf(src, sizeof(src), nv04_gr_nsource, nsource);273		nvkm_snprintbf(sta, sizeof(sta), nv10_gr_nstatus, nstatus);274		nvkm_error(subdev, "intr %08x [%s] nsource %08x [%s] "275				   "nstatus %08x [%s] ch %d [%08x %s] subc %d "276				   "class %04x mthd %04x data %08x\n",277			   show, msg, nsource, src, nstatus, sta,278			   chan ? chan->fifo->id : -1, inst << 4,279			   chan ? chan->fifo->name : "unknown",280			   subc, class, mthd, data);281	}282 283	spin_unlock_irqrestore(&gr->base.engine.lock, flags);284}285 286int287nv40_gr_init(struct nvkm_gr *base)288{289	struct nv40_gr *gr = nv40_gr(base);290	struct nvkm_device *device = gr->base.engine.subdev.device;291	int ret, i, j;292	u32 vramsz;293 294	/* generate and upload context program */295	ret = nv40_grctx_init(device, &gr->size);296	if (ret)297		return ret;298 299	/* No context present currently */300	nvkm_wr32(device, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);301 302	nvkm_wr32(device, NV03_PGRAPH_INTR   , 0xFFFFFFFF);303	nvkm_wr32(device, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);304 305	nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);306	nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x00000000);307	nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x401287c0);308	nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xe0de8055);309	nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x00008000);310	nvkm_wr32(device, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f);311 312	nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10010100);313	nvkm_wr32(device, NV10_PGRAPH_STATE      , 0xFFFFFFFF);314 315	j = nvkm_rd32(device, 0x1540) & 0xff;316	if (j) {317		for (i = 0; !(j & 1); j >>= 1, i++)318			;319		nvkm_wr32(device, 0x405000, i);320	}321 322	if (device->chipset == 0x40) {323		nvkm_wr32(device, 0x4009b0, 0x83280fff);324		nvkm_wr32(device, 0x4009b4, 0x000000a0);325	} else {326		nvkm_wr32(device, 0x400820, 0x83280eff);327		nvkm_wr32(device, 0x400824, 0x000000a0);328	}329 330	switch (device->chipset) {331	case 0x40:332	case 0x45:333		nvkm_wr32(device, 0x4009b8, 0x0078e366);334		nvkm_wr32(device, 0x4009bc, 0x0000014c);335		break;336	case 0x41:337	case 0x42: /* pciid also 0x00Cx */338	/* case 0x0120: XXX (pciid) */339		nvkm_wr32(device, 0x400828, 0x007596ff);340		nvkm_wr32(device, 0x40082c, 0x00000108);341		break;342	case 0x43:343		nvkm_wr32(device, 0x400828, 0x0072cb77);344		nvkm_wr32(device, 0x40082c, 0x00000108);345		break;346	case 0x44:347	case 0x46: /* G72 */348	case 0x4a:349	case 0x4c: /* G7x-based C51 */350	case 0x4e:351		nvkm_wr32(device, 0x400860, 0);352		nvkm_wr32(device, 0x400864, 0);353		break;354	case 0x47: /* G70 */355	case 0x49: /* G71 */356	case 0x4b: /* G73 */357		nvkm_wr32(device, 0x400828, 0x07830610);358		nvkm_wr32(device, 0x40082c, 0x0000016A);359		break;360	default:361		break;362	}363 364	nvkm_wr32(device, 0x400b38, 0x2ffff800);365	nvkm_wr32(device, 0x400b3c, 0x00006000);366 367	/* Tiling related stuff. */368	switch (device->chipset) {369	case 0x44:370	case 0x4a:371		nvkm_wr32(device, 0x400bc4, 0x1003d888);372		nvkm_wr32(device, 0x400bbc, 0xb7a7b500);373		break;374	case 0x46:375		nvkm_wr32(device, 0x400bc4, 0x0000e024);376		nvkm_wr32(device, 0x400bbc, 0xb7a7b520);377		break;378	case 0x4c:379	case 0x4e:380	case 0x67:381		nvkm_wr32(device, 0x400bc4, 0x1003d888);382		nvkm_wr32(device, 0x400bbc, 0xb7a7b540);383		break;384	default:385		break;386	}387 388	/* begin RAM config */389	vramsz = device->func->resource_size(device, 1) - 1;390	switch (device->chipset) {391	case 0x40:392		nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200));393		nvkm_wr32(device, 0x4009A8, nvkm_rd32(device, 0x100204));394		nvkm_wr32(device, 0x4069A4, nvkm_rd32(device, 0x100200));395		nvkm_wr32(device, 0x4069A8, nvkm_rd32(device, 0x100204));396		nvkm_wr32(device, 0x400820, 0);397		nvkm_wr32(device, 0x400824, 0);398		nvkm_wr32(device, 0x400864, vramsz);399		nvkm_wr32(device, 0x400868, vramsz);400		break;401	default:402		switch (device->chipset) {403		case 0x41:404		case 0x42:405		case 0x43:406		case 0x45:407		case 0x4e:408		case 0x44:409		case 0x4a:410			nvkm_wr32(device, 0x4009F0, nvkm_rd32(device, 0x100200));411			nvkm_wr32(device, 0x4009F4, nvkm_rd32(device, 0x100204));412			break;413		default:414			nvkm_wr32(device, 0x400DF0, nvkm_rd32(device, 0x100200));415			nvkm_wr32(device, 0x400DF4, nvkm_rd32(device, 0x100204));416			break;417		}418		nvkm_wr32(device, 0x4069F0, nvkm_rd32(device, 0x100200));419		nvkm_wr32(device, 0x4069F4, nvkm_rd32(device, 0x100204));420		nvkm_wr32(device, 0x400840, 0);421		nvkm_wr32(device, 0x400844, 0);422		nvkm_wr32(device, 0x4008A0, vramsz);423		nvkm_wr32(device, 0x4008A4, vramsz);424		break;425	}426 427	return 0;428}429 430int431nv40_gr_new_(const struct nvkm_gr_func *func, struct nvkm_device *device,432	     enum nvkm_subdev_type type, int inst, struct nvkm_gr **pgr)433{434	struct nv40_gr *gr;435 436	if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL)))437		return -ENOMEM;438	*pgr = &gr->base;439	INIT_LIST_HEAD(&gr->chan);440 441	return nvkm_gr_ctor(func, device, type, inst, true, &gr->base);442}443 444static const struct nvkm_gr_func445nv40_gr = {446	.init = nv40_gr_init,447	.intr = nv40_gr_intr,448	.tile = nv40_gr_tile,449	.units = nv40_gr_units,450	.chan_new = nv40_gr_chan_new,451	.sclass = {452		{ -1, -1, 0x0012, &nv40_gr_object }, /* beta1 */453		{ -1, -1, 0x0019, &nv40_gr_object }, /* clip */454		{ -1, -1, 0x0030, &nv40_gr_object }, /* null */455		{ -1, -1, 0x0039, &nv40_gr_object }, /* m2mf */456		{ -1, -1, 0x0043, &nv40_gr_object }, /* rop */457		{ -1, -1, 0x0044, &nv40_gr_object }, /* patt */458		{ -1, -1, 0x004a, &nv40_gr_object }, /* gdi */459		{ -1, -1, 0x0062, &nv40_gr_object }, /* surf2d */460		{ -1, -1, 0x0072, &nv40_gr_object }, /* beta4 */461		{ -1, -1, 0x0089, &nv40_gr_object }, /* sifm */462		{ -1, -1, 0x008a, &nv40_gr_object }, /* ifc */463		{ -1, -1, 0x009f, &nv40_gr_object }, /* imageblit */464		{ -1, -1, 0x3062, &nv40_gr_object }, /* surf2d (nv40) */465		{ -1, -1, 0x3089, &nv40_gr_object }, /* sifm (nv40) */466		{ -1, -1, 0x309e, &nv40_gr_object }, /* swzsurf (nv40) */467		{ -1, -1, 0x4097, &nv40_gr_object }, /* curie */468		{}469	}470};471 472int473nv40_gr_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_gr **pgr)474{475	return nv40_gr_new_(&nv40_gr, device, type, inst, pgr);476}477