diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2010-08-04 01:45:33 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-08-05 18:35:31 -0400 |
commit | 68b83a939cf8ed5466d11b7e9bfaa1dd22c11469 (patch) | |
tree | d8423674cb0884faca0779249cfbfecadf2b06ba /drivers/gpu | |
parent | c556d989038a6eba1411acf39163eb660e0a13bc (diff) |
drm/nvc0: rudimentary instmem support
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_instmem.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index c6ffc16dc441..e2a0bb84d910 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c | |||
@@ -30,29 +30,112 @@ int | |||
30 | nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, | 30 | nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, |
31 | uint32_t *size) | 31 | uint32_t *size) |
32 | { | 32 | { |
33 | int ret; | ||
34 | |||
35 | *size = ALIGN(*size, 4096); | ||
36 | if (*size == 0) | ||
37 | return -EINVAL; | ||
38 | |||
39 | ret = nouveau_bo_new(dev, NULL, *size, 0, TTM_PL_FLAG_VRAM, 0, 0x0000, | ||
40 | true, false, &gpuobj->im_backing); | ||
41 | if (ret) { | ||
42 | NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); | ||
43 | return ret; | ||
44 | } | ||
45 | |||
46 | ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM); | ||
47 | if (ret) { | ||
48 | NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret); | ||
49 | nouveau_bo_ref(NULL, &gpuobj->im_backing); | ||
50 | return ret; | ||
51 | } | ||
52 | |||
53 | gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start; | ||
54 | gpuobj->im_backing_start <<= PAGE_SHIFT; | ||
33 | return 0; | 55 | return 0; |
34 | } | 56 | } |
35 | 57 | ||
36 | void | 58 | void |
37 | nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | 59 | nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) |
38 | { | 60 | { |
61 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
62 | |||
63 | if (gpuobj && gpuobj->im_backing) { | ||
64 | if (gpuobj->im_bound) | ||
65 | dev_priv->engine.instmem.unbind(dev, gpuobj); | ||
66 | nouveau_bo_unpin(gpuobj->im_backing); | ||
67 | nouveau_bo_ref(NULL, &gpuobj->im_backing); | ||
68 | gpuobj->im_backing = NULL; | ||
69 | } | ||
39 | } | 70 | } |
40 | 71 | ||
41 | int | 72 | int |
42 | nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | 73 | nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) |
43 | { | 74 | { |
75 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
76 | uint32_t pte, pte_end; | ||
77 | uint64_t vram; | ||
78 | |||
79 | if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) | ||
80 | return -EINVAL; | ||
81 | |||
82 | NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n", | ||
83 | gpuobj->im_pramin->start, gpuobj->im_pramin->size); | ||
84 | |||
85 | pte = gpuobj->im_pramin->start >> 12; | ||
86 | pte_end = (gpuobj->im_pramin->size >> 12) + pte; | ||
87 | vram = gpuobj->im_backing_start; | ||
88 | |||
89 | NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", | ||
90 | gpuobj->im_pramin->start, pte, pte_end); | ||
91 | NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start); | ||
92 | |||
93 | while (pte < pte_end) { | ||
94 | nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1); | ||
95 | nv_wr32(dev, 0x702004 + (pte * 8), 0); | ||
96 | vram += 4096; | ||
97 | pte++; | ||
98 | } | ||
99 | dev_priv->engine.instmem.flush(dev); | ||
100 | |||
101 | if (1) { | ||
102 | u32 chan = nv_rd32(dev, 0x1700) << 16; | ||
103 | nv_wr32(dev, 0x100cb8, (chan + 0x1000) >> 8); | ||
104 | nv_wr32(dev, 0x100cbc, 0x80000005); | ||
105 | } | ||
106 | |||
107 | gpuobj->im_bound = 1; | ||
44 | return 0; | 108 | return 0; |
45 | } | 109 | } |
46 | 110 | ||
47 | int | 111 | int |
48 | nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | 112 | nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) |
49 | { | 113 | { |
114 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
115 | uint32_t pte, pte_end; | ||
116 | |||
117 | if (gpuobj->im_bound == 0) | ||
118 | return -EINVAL; | ||
119 | |||
120 | pte = gpuobj->im_pramin->start >> 12; | ||
121 | pte_end = (gpuobj->im_pramin->size >> 12) + pte; | ||
122 | while (pte < pte_end) { | ||
123 | nv_wr32(dev, 0x702000 + (pte * 8), 0); | ||
124 | nv_wr32(dev, 0x702004 + (pte * 8), 0); | ||
125 | pte++; | ||
126 | } | ||
127 | dev_priv->engine.instmem.flush(dev); | ||
128 | |||
129 | gpuobj->im_bound = 0; | ||
50 | return 0; | 130 | return 0; |
51 | } | 131 | } |
52 | 132 | ||
53 | void | 133 | void |
54 | nvc0_instmem_flush(struct drm_device *dev) | 134 | nvc0_instmem_flush(struct drm_device *dev) |
55 | { | 135 | { |
136 | nv_wr32(dev, 0x070000, 1); | ||
137 | if (!nv_wait(0x070000, 0x00000001, 0x00000000)) | ||
138 | NV_ERROR(dev, "PRAMIN flush timeout\n"); | ||
56 | } | 139 | } |
57 | 140 | ||
58 | int | 141 | int |
@@ -69,6 +152,54 @@ nvc0_instmem_resume(struct drm_device *dev) | |||
69 | int | 152 | int |
70 | nvc0_instmem_init(struct drm_device *dev) | 153 | nvc0_instmem_init(struct drm_device *dev) |
71 | { | 154 | { |
155 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
156 | u64 chan, pgt3, imem, lim3 = dev_priv->ramin_size - 1; | ||
157 | int ret, i; | ||
158 | |||
159 | dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024; | ||
160 | chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; | ||
161 | imem = 4096 + 4096 + 32768; | ||
162 | |||
163 | nv_wr32(dev, 0x001700, chan >> 16); | ||
164 | |||
165 | /* channel setup */ | ||
166 | nv_wr32(dev, 0x700200, lower_32_bits(chan + 0x1000)); | ||
167 | nv_wr32(dev, 0x700204, upper_32_bits(chan + 0x1000)); | ||
168 | nv_wr32(dev, 0x700208, lower_32_bits(lim3)); | ||
169 | nv_wr32(dev, 0x70020c, upper_32_bits(lim3)); | ||
170 | |||
171 | /* point pgd -> pgt */ | ||
172 | nv_wr32(dev, 0x701000, 0); | ||
173 | nv_wr32(dev, 0x701004, ((chan + 0x2000) >> 8) | 1); | ||
174 | |||
175 | /* point pgt -> physical vram for channel */ | ||
176 | pgt3 = 0x2000; | ||
177 | for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4096, pgt3 += 8) { | ||
178 | nv_wr32(dev, 0x700000 + pgt3, ((chan + i) >> 8) | 1); | ||
179 | nv_wr32(dev, 0x700004 + pgt3, 0); | ||
180 | } | ||
181 | |||
182 | /* clear rest of pgt */ | ||
183 | for (; i < dev_priv->ramin_size; i += 4096, pgt3 += 8) { | ||
184 | nv_wr32(dev, 0x700000 + pgt3, 0); | ||
185 | nv_wr32(dev, 0x700004 + pgt3, 0); | ||
186 | } | ||
187 | |||
188 | /* point bar3 at the channel */ | ||
189 | nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); | ||
190 | |||
191 | /* Global PRAMIN heap */ | ||
192 | ret = drm_mm_init(&dev_priv->ramin_heap, imem, | ||
193 | dev_priv->ramin_size - imem); | ||
194 | if (ret) { | ||
195 | NV_ERROR(dev, "Failed to init RAMIN heap\n"); | ||
196 | return -ENOMEM; | ||
197 | } | ||
198 | |||
199 | /*XXX: incorrect, but needed to make hash func "work" */ | ||
200 | dev_priv->ramht_offset = 0x10000; | ||
201 | dev_priv->ramht_bits = 9; | ||
202 | dev_priv->ramht_size = (1 << dev_priv->ramht_bits); | ||
72 | return 0; | 203 | return 0; |
73 | } | 204 | } |
74 | 205 | ||