Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/nv50/disp: completely reset disp if master evo channel active at init

Should fix issues with kexec, and as a nice side bonus, the code to avoid
having PDISP disappear will also fix hibernate on those effected systems.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>

+41
+41
drivers/gpu/drm/nouveau/nv50_display.c
··· 50 50 return 4; 51 51 } 52 52 53 + static int 54 + evo_icmd(struct drm_device *dev, int ch, u32 mthd, u32 data) 55 + { 56 + int ret = 0; 57 + if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO) 58 + NV_INFO(dev, "EvoPIO: %d 0x%04x 0x%08x\n", ch, mthd, data); 59 + nv_mask(dev, 0x610300 + (ch * 0x08), 0x00000001, 0x00000001); 60 + nv_wr32(dev, 0x610304 + (ch * 0x08), data); 61 + nv_wr32(dev, 0x610300 + (ch * 0x08), 0x80000001 | mthd); 62 + if (!nv_wait(dev, 0x610300 + (ch * 0x08), 0x80000000, 0x00000000)) 63 + ret = -EBUSY; 64 + nv_mask(dev, 0x610300 + (ch * 0x08), 0x00000001, 0x00000000); 65 + return ret; 66 + } 67 + 53 68 int 54 69 nv50_display_early_init(struct drm_device *dev) 55 70 { 71 + int i; 72 + /* check if master evo channel is already active, a good a sign as any 73 + * that the display engine is in a weird state (hibernate/kexec), if 74 + * it is, do our best to reset the display engine... 75 + */ 76 + if (nv_rd32(dev, 0x610200) & 0x00000001) { 77 + NV_INFO(dev, "PDISP: already active, attempting to reset...\n"); 78 + 79 + /* deactivate both heads first, PDISP will disappear forever 80 + * (well, until you power cycle) on some boards as soon as 81 + * PMC_ENABLE is hit unless they are.. 82 + */ 83 + for (i = 0; i < 2; i++) { 84 + evo_icmd(dev, 0, 0x0880 + (i * 0x400), 0x05000000); 85 + evo_icmd(dev, 0, 0x089c + (i * 0x400), 0); 86 + evo_icmd(dev, 0, 0x0840 + (i * 0x400), 0); 87 + evo_icmd(dev, 0, 0x0844 + (i * 0x400), 0); 88 + evo_icmd(dev, 0, 0x085c + (i * 0x400), 0); 89 + evo_icmd(dev, 0, 0x0874 + (i * 0x400), 0); 90 + } 91 + evo_icmd(dev, 0, 0x0080, 0); 92 + 93 + /* reset PDISP */ 94 + nv_mask(dev, 0x000200, 0x40000000, 0x00000000); 95 + nv_mask(dev, 0x000200, 0x40000000, 0x40000000); 96 + } 56 97 return 0; 57 98 } 58 99