diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c')
| -rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 91 |
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 | |||
| 29 | void | 33 | void |
| 30 | gf119_disp_super(struct work_struct *work) | 34 | gf119_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 | ||
| 171 | void | ||
| 172 | gf119_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 | |||
| 167 | int | 179 | int |
| 168 | gf119_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, | 180 | gf119_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 | ||
| 175 | static const struct nv50_disp_func | 248 | static const struct nv50_disp_func |
| 176 | gf119_disp = { | 249 | gf119_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 | ||
| 187 | int | 262 | int |
| 188 | gf119_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) | 263 | gf119_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 | } |
