summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nv04_instmem.c
blob: a20c206625a2616f64b6601efa959ee4b9badd77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"

/* returns the size of fifo context */
static int
nouveau_fifo_ctx_size(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;

	if (dev_priv->chipset >= 0x40)
		return 128;
	else
	if (dev_priv->chipset >= 0x17)
		return 64;

	return 32;
}

static void
nv04_instmem_determine_amount(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	int i;

	/* Figure out how much instance memory we need */
	if (dev_priv->card_type >= NV_40) {
		/* We'll want more instance memory than this on some NV4x cards.
		 * There's a 16MB aperture to play with that maps onto the end
		 * of vram.  For now, only reserve a small piece until we know
		 * more about what each chipset requires.
		 */
		switch (dev_priv->chipset & 0xf0) {
		case 0x40:
		case 0x47:
		case 0x49:
		case 0x4b:
			dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024);
			break;
		default:
			dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024);
			break;
		}
	} else {
		/*XXX: what *are* the limits on <NV40 cards?
		 */
		dev_priv->ramin_rsvd_vram = (512 * 1024);
	}
	NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10);

	/* Clear all of it, except the BIOS image that's in the first 64KiB */
	dev_priv->engine.instmem.prepare_access(dev, true);
	for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4)
		nv_wi32(dev, i, 0x00000000);
	dev_priv->engine.instmem.finish_access(dev);
}

static void
nv04_instmem_configure_fixed_tables(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_engine *engine = &dev_priv->engine;

	/* FIFO hash table (RAMHT)
	 *   use 4k hash table at RAMIN+0x10000
	 *   TODO: extend the hash table
	 */
	dev_priv->ramht_offset = 0x10000;
	dev_priv->ramht_bits   = 9;
	dev_priv->ramht_size   = (1 << dev_priv->ramht_bits); /* nr entries */
	dev_priv->ramht_size  *= 8; /* 2 32-bit values per entry in RAMHT */
	NV_DEBUG(dev, "RAMHT offset=0x%x, size=%d\n", dev_priv->ramht_offset,
						      dev_priv->ramht_size);

	/* FIFO runout table (RAMRO) - 512k at 0x11200 */
	dev_priv->ramro_offset = 0x11200;
	dev_priv->ramro_size   = 512;
	NV_DEBUG(dev, "RAMRO offset=0x%x, size=%d\n", dev_priv->ramro_offset,
						      dev_priv->ramro_size);

	/* FIFO context table (RAMFC)
	 *   NV40  : Not sure exactly how to position RAMFC on some cards,
	 *           0x30002 seems to position it at RAMIN+0x20000 on these
	 *           cards.  RAMFC is 4kb (32 fifos, 128byte entries).
	 *   Others: Position RAMFC at RAMIN+0x11400
	 */
	dev_priv->ramfc_size = engine->fifo.channels *
						nouveau_fifo_ctx_size(dev);
	switch (dev_priv->card_type) {
	case NV_40:
		dev_priv->ramfc_offset = 0x20000;
		break;
	case NV_30:
	case NV_20:
	case NV_10:
	case NV_04:
	default:
		dev_priv->ramfc_offset = 0x11400;
		break;
	}
	NV_DEBUG(dev, "RAMFC offset=0x%x, size=%d\n", dev_priv->ramfc_offset,
						      dev_priv->ramfc_size);
}

int nv04_instmem_init(struct drm_device *dev)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	uint32_t offset;
	int ret = 0;

	nv04_instmem_determine_amount(dev);
	nv04_instmem_configure_fixed_tables(dev);

	/* Create a heap to manage RAMIN allocations, we don't allocate
	 * the space that was reserved for RAMHT/FC/RO.
	 */
	offset = dev_priv->ramfc_offset + dev_priv->ramfc_size;

	/* It appears RAMRO (or something?) is controlled by 0x2220/0x2230
	 * on certain NV4x chipsets as well as RAMFC.  When 0x2230 == 0
	 * ("new style" control) the upper 16-bits of 0x2220 points at this
	 * other mysterious table that's clobbering important things.
	 *
	 * We're now pointing this at RAMIN+0x30000 to avoid RAMFC getting
	 * smashed to pieces on us, so reserve 0x30000-0x40000 too..
	 */
	if (dev_priv->card_type >= NV_40) {
		if (offset < 0x40000)
			offset = 0x40000;
	}

	ret = nouveau_mem_init_heap(&dev_priv->ramin_heap,
				    offset, dev_priv->ramin_rsvd_vram - offset);
	if (ret) {
		dev_priv->ramin_heap = NULL;
		NV_ERROR(dev, "Failed to init RAMIN heap\n");
	}

	return ret;
}

void
nv04_instmem_takedown(struct drm_device *dev)
{
}

int
nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, uint32_t *sz)
{
	if (gpuobj->im_backing)
		return -EINVAL;

	return 0;
}

void
nv04_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;

	if (gpuobj && gpuobj->im_backing) {
		if (gpuobj->im_bound)
			dev_priv->engine.instmem.unbind(dev, gpuobj);
		gpuobj->im_backing = NULL;
	}
}

int
nv04_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
{
	if (!gpuobj->im_pramin || gpuobj->im_bound)
		return -EINVAL;

	gpuobj->im_bound = 1;
	return 0;
}

int
nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
{
	if (gpuobj->im_bound == 0)
		return -EINVAL;

	gpuobj->im_bound = 0;
	return 0;
}

void
nv04_instmem_prepare_access(struct drm_device *dev, bool write)
{
}

void
nv04_instmem_finish_access(struct drm_device *dev)
{
}

int
nv04_instmem_suspend(struct drm_device *dev)
{
	return 0;
}

void
nv04_instmem_resume(struct drm_device *dev)
{
}

OpenPOWER on IntegriCloud