aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c91
1 files changed, 83 insertions, 8 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
index d8765b57180b..794e90982641 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
@@ -24,8 +24,12 @@
24#include "nv50.h" 24#include "nv50.h"
25#include "head.h" 25#include "head.h"
26#include "ior.h" 26#include "ior.h"
27#include "channv50.h"
27#include "rootnv50.h" 28#include "rootnv50.h"
28 29
30#include <core/ramht.h>
31#include <subdev/timer.h>
32
29void 33void
30gf119_disp_super(struct work_struct *work) 34gf119_disp_super(struct work_struct *work)
31{ 35{
@@ -164,28 +168,99 @@ gf119_disp_intr(struct nv50_disp *disp)
164 } 168 }
165} 169}
166 170
171void
172gf119_disp_fini(struct nv50_disp *disp)
173{
174 struct nvkm_device *device = disp->base.engine.subdev.device;
175 /* disable all interrupts */
176 nvkm_wr32(device, 0x6100b0, 0x00000000);
177}
178
167int 179int
168gf119_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, 180gf119_disp_init(struct nv50_disp *disp)
169 int index, struct nvkm_disp **pdisp)
170{ 181{
171 u32 heads = nvkm_rd32(device, 0x022448); 182 struct nvkm_device *device = disp->base.engine.subdev.device;
172 return nv50_disp_new_(func, device, index, heads, pdisp); 183 struct nvkm_head *head;
184 u32 tmp;
185 int i;
186
187 /* The below segments of code copying values from one register to
188 * another appear to inform EVO of the display capabilities or
189 * something similar.
190 */
191
192 /* ... CRTC caps */
193 list_for_each_entry(head, &disp->base.head, head) {
194 const u32 hoff = head->id * 0x800;
195 tmp = nvkm_rd32(device, 0x616104 + hoff);
196 nvkm_wr32(device, 0x6101b4 + hoff, tmp);
197 tmp = nvkm_rd32(device, 0x616108 + hoff);
198 nvkm_wr32(device, 0x6101b8 + hoff, tmp);
199 tmp = nvkm_rd32(device, 0x61610c + hoff);
200 nvkm_wr32(device, 0x6101bc + hoff, tmp);
201 }
202
203 /* ... DAC caps */
204 for (i = 0; i < disp->dac.nr; i++) {
205 tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800));
206 nvkm_wr32(device, 0x6101c0 + (i * 0x800), tmp);
207 }
208
209 /* ... SOR caps */
210 for (i = 0; i < disp->sor.nr; i++) {
211 tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800));
212 nvkm_wr32(device, 0x6301c4 + (i * 0x800), tmp);
213 }
214
215 /* steal display away from vbios, or something like that */
216 if (nvkm_rd32(device, 0x6100ac) & 0x00000100) {
217 nvkm_wr32(device, 0x6100ac, 0x00000100);
218 nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000);
219 if (nvkm_msec(device, 2000,
220 if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002))
221 break;
222 ) < 0)
223 return -EBUSY;
224 }
225
226 /* point at display engine memory area (hash table, objects) */
227 nvkm_wr32(device, 0x610010, (disp->inst->addr >> 8) | 9);
228
229 /* enable supervisor interrupts, disable everything else */
230 nvkm_wr32(device, 0x610090, 0x00000000);
231 nvkm_wr32(device, 0x6100a0, 0x00000000);
232 nvkm_wr32(device, 0x6100b0, 0x00000307);
233
234 /* disable underflow reporting, preventing an intermittent issue
235 * on some gk104 boards where the production vbios left this
236 * setting enabled by default.
237 *
238 * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt
239 */
240 list_for_each_entry(head, &disp->base.head, head) {
241 const u32 hoff = head->id * 0x800;
242 nvkm_mask(device, 0x616308 + hoff, 0x00000111, 0x00000010);
243 }
244
245 return 0;
173} 246}
174 247
175static const struct nv50_disp_func 248static const struct nv50_disp_func
176gf119_disp = { 249gf119_disp = {
250 .init = gf119_disp_init,
251 .fini = gf119_disp_fini,
177 .intr = gf119_disp_intr, 252 .intr = gf119_disp_intr,
178 .intr_error = gf119_disp_intr_error, 253 .intr_error = gf119_disp_intr_error,
179 .uevent = &gf119_disp_chan_uevent, 254 .uevent = &gf119_disp_chan_uevent,
180 .super = gf119_disp_super, 255 .super = gf119_disp_super,
181 .root = &gf119_disp_root_oclass, 256 .root = &gf119_disp_root_oclass,
182 .head.new = gf119_head_new, 257 .head = { .cnt = gf119_head_cnt, .new = gf119_head_new },
183 .dac = { .nr = 3, .new = gf119_dac_new }, 258 .dac = { .cnt = gf119_dac_cnt, .new = gf119_dac_new },
184 .sor = { .nr = 4, .new = gf119_sor_new }, 259 .sor = { .cnt = gf119_sor_cnt, .new = gf119_sor_new },
185}; 260};
186 261
187int 262int
188gf119_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) 263gf119_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp)
189{ 264{
190 return gf119_disp_new_(&gf119_disp, device, index, pdisp); 265 return nv50_disp_new_(&gf119_disp, device, index, pdisp);
191} 266}