Blob Blame History Raw
From 9c5753bc708da0c2c544fcfe1e94afb399c2b3f6 Mon Sep 17 00:00:00 2001
From: Ben Skeggs <bskeggs@redhat.com>
Date: Fri, 19 May 2017 23:59:35 +1000
Subject: [PATCH] drm/nouveau/disp/nv50-: port OR power state control to nvkm_ior
Git-commit: 9c5753bc708da0c2c544fcfe1e94afb399c2b3f6
Patch-mainline: v4.13-rc1
References: bsc#1095094

Also removes the user-facing methods to these controls, as they're not
currently utilised by the DD anyway.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Acked-by: Takashi Iwai <tiwai@suse.de>

---
 drivers/gpu/drm/nouveau/include/nvif/cl5070.h       |   25 ------
 drivers/gpu/drm/nouveau/nv50_display.c              |   76 --------------------
 drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c |    1 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c  |   50 +++++--------
 drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c      |    6 -
 drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c      |    6 -
 drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c    |    2 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c    |    2 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c    |    2 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c    |    2 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c    |    2 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c    |    1 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c    |    1 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c    |    6 -
 drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c    |    6 -
 drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h      |   12 +++
 drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c    |    6 -
 drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c    |    6 -
 drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c     |    9 --
 drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h     |    7 -
 drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c |   54 +++++---------
 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c |   25 ++++--
 drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c   |    1 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c   |    1 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c |    1 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c |    1 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c |    1 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c |    1 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c |    1 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c |    1 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c |    1 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c  |   49 +++++-------
 32 files changed, 108 insertions(+), 257 deletions(-)

--- a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h
@@ -27,30 +27,18 @@ struct nv50_disp_scanoutpos_v0 {
 
 struct nv50_disp_mthd_v1 {
 	__u8  version;
-#define NV50_DISP_MTHD_V1_DAC_PWR                                          0x10
 #define NV50_DISP_MTHD_V1_DAC_LOAD                                         0x11
-#define NV50_DISP_MTHD_V1_SOR_PWR                                          0x20
 #define NV50_DISP_MTHD_V1_SOR_HDA_ELD                                      0x21
 #define NV50_DISP_MTHD_V1_SOR_HDMI_PWR                                     0x22
 #define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT                                  0x23
 #define NV50_DISP_MTHD_V1_SOR_DP_MST_LINK                                  0x25
 #define NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI                                  0x26
-#define NV50_DISP_MTHD_V1_PIOR_PWR                                         0x30
 	__u8  method;
 	__u16 hasht;
 	__u16 hashm;
 	__u8  pad06[2];
 };
 
-struct nv50_disp_dac_pwr_v0 {
-	__u8  version;
-	__u8  state;
-	__u8  data;
-	__u8  vsync;
-	__u8  hsync;
-	__u8  pad05[3];
-};
-
 struct nv50_disp_dac_load_v0 {
 	__u8  version;
 	__u8  load;
@@ -58,12 +46,6 @@ struct nv50_disp_dac_load_v0 {
 	__u32 data;
 };
 
-struct nv50_disp_sor_pwr_v0 {
-	__u8  version;
-	__u8  state;
-	__u8  pad02[6];
-};
-
 struct nv50_disp_sor_hda_eld_v0 {
 	__u8  version;
 	__u8  pad01[7];
@@ -101,11 +83,4 @@ struct nv50_disp_sor_dp_mst_vcpi_v0 {
 	__u16 pbn;
 	__u16 aligned_pbn;
 };
-
-struct nv50_disp_pior_pwr_v0 {
-	__u8  version;
-	__u8  state;
-	__u8  type;
-	__u8  pad03[5];
-};
 #endif
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -2460,30 +2460,6 @@ nv50_outp_atomic_check(struct drm_encode
  * DAC
  *****************************************************************************/
 static void
-nv50_dac_dpms(struct drm_encoder *encoder, int mode)
-{
-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-	struct nv50_disp *disp = nv50_disp(encoder->dev);
-	struct {
-		struct nv50_disp_mthd_v1 base;
-		struct nv50_disp_dac_pwr_v0 pwr;
-	} args = {
-		.base.version = 1,
-		.base.method = NV50_DISP_MTHD_V1_DAC_PWR,
-		.base.hasht  = nv_encoder->dcb->hasht,
-		.base.hashm  = nv_encoder->dcb->hashm,
-		.pwr.state = 1,
-		.pwr.data  = 1,
-		.pwr.vsync = (mode != DRM_MODE_DPMS_SUSPEND &&
-			      mode != DRM_MODE_DPMS_OFF),
-		.pwr.hsync = (mode != DRM_MODE_DPMS_STANDBY &&
-			      mode != DRM_MODE_DPMS_OFF),
-	};
-
-	nvif_mthd(disp->disp, 0, &args, sizeof(args));
-}
-
-static void
 nv50_dac_disable(struct drm_encoder *encoder)
 {
 	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
@@ -2584,7 +2560,6 @@ nv50_dac_detect(struct drm_encoder *enco
 
 static const struct drm_encoder_helper_funcs
 nv50_dac_help = {
-	.dpms = nv50_dac_dpms,
 	.atomic_check = nv50_outp_atomic_check,
 	.enable = nv50_dac_enable,
 	.disable = nv50_dac_disable,
@@ -3406,25 +3381,6 @@ nv50_mstm_new(struct nouveau_encoder *ou
  * SOR
  *****************************************************************************/
 static void
-nv50_sor_dpms(struct drm_encoder *encoder, int mode)
-{
-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-	struct nv50_disp *disp = nv50_disp(encoder->dev);
-	struct {
-		struct nv50_disp_mthd_v1 base;
-		struct nv50_disp_sor_pwr_v0 pwr;
-	} args = {
-		.base.version = 1,
-		.base.method = NV50_DISP_MTHD_V1_SOR_PWR,
-		.base.hasht  = nv_encoder->dcb->hasht,
-		.base.hashm  = nv_encoder->dcb->hashm,
-		.pwr.state = mode == DRM_MODE_DPMS_ON,
-	};
-
-	nvif_mthd(disp->disp, 0, &args, sizeof(args));
-}
-
-static void
 nv50_sor_update(struct nouveau_encoder *nv_encoder, u8 head,
 		struct drm_display_mode *mode, u8 proto, u8 depth)
 {
@@ -3602,7 +3558,6 @@ nv50_sor_enable(struct drm_encoder *enco
 
 static const struct drm_encoder_helper_funcs
 nv50_sor_help = {
-	.dpms = nv50_sor_dpms,
 	.atomic_check = nv50_outp_atomic_check,
 	.enable = nv50_sor_enable,
 	.disable = nv50_sor_disable,
@@ -3695,26 +3650,6 @@ nv50_sor_create(struct drm_connector *co
 /******************************************************************************
  * PIOR
  *****************************************************************************/
-static void
-nv50_pior_dpms(struct drm_encoder *encoder, int mode)
-{
-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-	struct nv50_disp *disp = nv50_disp(encoder->dev);
-	struct {
-		struct nv50_disp_mthd_v1 base;
-		struct nv50_disp_pior_pwr_v0 pwr;
-	} args = {
-		.base.version = 1,
-		.base.method = NV50_DISP_MTHD_V1_PIOR_PWR,
-		.base.hasht  = nv_encoder->dcb->hasht,
-		.base.hashm  = nv_encoder->dcb->hashm,
-		.pwr.state = mode == DRM_MODE_DPMS_ON,
-		.pwr.type = nv_encoder->dcb->type,
-	};
-
-	nvif_mthd(disp->disp, 0, &args, sizeof(args));
-}
-
 static int
 nv50_pior_atomic_check(struct drm_encoder *encoder,
 		       struct drm_crtc_state *crtc_state,
@@ -3799,7 +3734,6 @@ nv50_pior_enable(struct drm_encoder *enc
 
 static const struct drm_encoder_helper_funcs
 nv50_pior_help = {
-	.dpms = nv50_pior_dpms,
 	.atomic_check = nv50_pior_atomic_check,
 	.enable = nv50_pior_enable,
 	.disable = nv50_pior_disable,
@@ -4367,14 +4301,8 @@ nv50_display_init(struct drm_device *dev
 
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 		if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) {
-			const struct drm_encoder_helper_funcs *help;
-			struct nouveau_encoder *nv_encoder;
-
-			nv_encoder = nouveau_encoder(encoder);
-			help = encoder->helper_private;
-			if (help && help->dpms)
-				help->dpms(encoder, DRM_MODE_DPMS_ON);
-
+			struct nouveau_encoder *nv_encoder =
+				nouveau_encoder(encoder);
 			nv50_mstm_init(nv_encoder->dp.mstm);
 		}
 	}
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c
@@ -42,6 +42,7 @@ gf119_dac_state(struct nvkm_ior *dac, st
 static const struct nvkm_ior_func
 gf119_dac = {
 	.state = gf119_dac_state,
+	.power = nv50_dac_power,
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c
@@ -90,40 +90,31 @@ nv50_dac_sense(NV50_DISP_MTHD_V1)
 	return 0;
 }
 
-int
-nv50_dac_power(NV50_DISP_MTHD_V1)
+static void
+nv50_dac_power_wait(struct nvkm_device *device, const u32 doff)
 {
-	struct nvkm_device *device = disp->base.engine.subdev.device;
-	const u32 doff = outp->or * 0x800;
-	union {
-		struct nv50_disp_dac_pwr_v0 v0;
-	} *args = data;
-	u32 stat;
-	int ret = -ENOSYS;
-
-	nvif_ioctl(object, "disp dac pwr size %d\n", size);
-	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
-		nvif_ioctl(object, "disp dac pwr vers %d state %d data %d "
-				   "vsync %d hsync %d\n",
-			   args->v0.version, args->v0.state, args->v0.data,
-			   args->v0.vsync, args->v0.hsync);
-		stat  = 0x00000040 * !args->v0.state;
-		stat |= 0x00000010 * !args->v0.data;
-		stat |= 0x00000004 * !args->v0.vsync;
-		stat |= 0x00000001 * !args->v0.hsync;
-	} else
-		return ret;
-
-	nvkm_msec(device, 2000,
-		if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000))
-			break;
-	);
-	nvkm_mask(device, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat);
 	nvkm_msec(device, 2000,
 		if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000))
 			break;
 	);
-	return 0;
+}
+
+void
+nv50_dac_power(struct nvkm_ior *dac, bool normal, bool pu,
+	       bool data, bool vsync, bool hsync)
+{
+	struct nvkm_device *device = dac->disp->engine.subdev.device;
+	const u32  doff = nv50_ior_base(dac);
+	const u32 shift = normal ? 0 : 16;
+	const u32 state = 0x80000000 | (0x00000040 * !    pu |
+					0x00000010 * !  data |
+					0x00000004 * ! vsync |
+					0x00000001 * ! hsync) << shift;
+	const u32 field = 0xc0000000 | (0x00000055 << shift);
+
+	nv50_dac_power_wait(device, doff);
+	nvkm_mask(device, 0x61a004 + doff, field, state);
+	nv50_dac_power_wait(device, doff);
 }
 
 static void
@@ -147,6 +138,7 @@ nv50_dac_state(struct nvkm_ior *dac, str
 static const struct nvkm_ior_func
 nv50_dac = {
 	.state = nv50_dac_state,
+	.power = nv50_dac_power,
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
@@ -40,15 +40,11 @@ g84_disp = {
 	.outp.external.dp = nv50_pior_dp_new,
 	.dac.nr = 3,
 	.dac.new = nv50_dac_new,
-	.dac.power = nv50_dac_power,
 	.dac.sense = nv50_dac_sense,
 	.sor.nr = 2,
 	.sor.new = g84_sor_new,
-	.sor.power = nv50_sor_power,
 	.sor.hdmi = g84_hdmi_ctrl,
-	.pior.nr = 3,
-	.pior.new = nv50_pior_new,
-	.pior.power = nv50_pior_power,
+	.pior = { .nr = 3, .new = nv50_pior_new },
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
@@ -41,15 +41,11 @@ g94_disp = {
 	.outp.external.dp = nv50_pior_dp_new,
 	.dac.nr = 3,
 	.dac.new = nv50_dac_new,
-	.dac.power = nv50_dac_power,
 	.dac.sense = nv50_dac_sense,
 	.sor.nr = 4,
 	.sor.new = g94_sor_new,
-	.sor.power = nv50_sor_power,
 	.sor.hdmi = g84_hdmi_ctrl,
-	.pior.nr = 3,
-	.pior.new = nv50_pior_new,
-	.pior.power = nv50_pior_power,
+	.pior = { .nr = 3, .new = nv50_pior_new },
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
@@ -508,11 +508,9 @@ gf119_disp = {
 	.outp.internal.dp = gf119_sor_dp_new,
 	.dac.nr = 3,
 	.dac.new = gf119_dac_new,
-	.dac.power = nv50_dac_power,
 	.dac.sense = nv50_dac_sense,
 	.sor.nr = 4,
 	.sor.new = gf119_sor_new,
-	.sor.power = nv50_sor_power,
 	.sor.hda_eld = gf119_hda_eld,
 	.sor.hdmi = gf119_hdmi_ctrl,
 };
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
@@ -40,11 +40,9 @@ gk104_disp = {
 	.outp.internal.dp = gf119_sor_dp_new,
 	.dac.nr = 3,
 	.dac.new = gf119_dac_new,
-	.dac.power = nv50_dac_power,
 	.dac.sense = nv50_dac_sense,
 	.sor.nr = 4,
 	.sor.new = gk104_sor_new,
-	.sor.power = nv50_sor_power,
 	.sor.hda_eld = gf119_hda_eld,
 	.sor.hdmi = gk104_hdmi_ctrl,
 };
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c
@@ -40,11 +40,9 @@ gk110_disp = {
 	.outp.internal.dp = gf119_sor_dp_new,
 	.dac.nr = 3,
 	.dac.new = gf119_dac_new,
-	.dac.power = nv50_dac_power,
 	.dac.sense = nv50_dac_sense,
 	.sor.nr = 4,
 	.sor.new = gk104_sor_new,
-	.sor.power = nv50_sor_power,
 	.sor.hda_eld = gf119_hda_eld,
 	.sor.hdmi = gk104_hdmi_ctrl,
 };
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
@@ -40,11 +40,9 @@ gm107_disp = {
 	.outp.internal.dp = gm107_sor_dp_new,
 	.dac.nr = 3,
 	.dac.new = gf119_dac_new,
-	.dac.power = nv50_dac_power,
 	.dac.sense = nv50_dac_sense,
 	.sor.nr = 4,
 	.sor.new = gm107_sor_new,
-	.sor.power = nv50_sor_power,
 	.sor.hda_eld = gf119_hda_eld,
 	.sor.hdmi = gk104_hdmi_ctrl,
 };
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c
@@ -40,11 +40,9 @@ gm200_disp = {
 	.outp.internal.dp = gm200_sor_dp_new,
 	.dac.nr = 3,
 	.dac.new = gf119_dac_new,
-	.dac.power = nv50_dac_power,
 	.dac.sense = nv50_dac_sense,
 	.sor.nr = 4,
 	.sor.new = gm200_sor_new,
-	.sor.power = nv50_sor_power,
 	.sor.hda_eld = gf119_hda_eld,
 	.sor.hdmi = gk104_hdmi_ctrl,
 	.sor.magic = gm200_sor_magic,
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c
@@ -39,7 +39,6 @@ gp100_disp = {
 	.outp.internal.dp = gm200_sor_dp_new,
 	.sor.nr = 4,
 	.sor.new = gm200_sor_new,
-	.sor.power = nv50_sor_power,
 	.sor.hda_eld = gf119_hda_eld,
 	.sor.hdmi = gk104_hdmi_ctrl,
 	.sor.magic = gm200_sor_magic,
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c
@@ -65,7 +65,6 @@ gp102_disp = {
 	.outp.internal.dp = gm200_sor_dp_new,
 	.sor.nr = 4,
 	.sor.new = gm200_sor_new,
-	.sor.power = nv50_sor_power,
 	.sor.hda_eld = gf119_hda_eld,
 	.sor.hdmi = gk104_hdmi_ctrl,
 	.sor.magic = gm200_sor_magic,
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c
@@ -40,15 +40,11 @@ gt200_disp = {
 	.outp.external.dp = nv50_pior_dp_new,
 	.dac.nr = 3,
 	.dac.new = nv50_dac_new,
-	.dac.power = nv50_dac_power,
 	.dac.sense = nv50_dac_sense,
 	.sor.nr = 2,
 	.sor.new = g84_sor_new,
-	.sor.power = nv50_sor_power,
 	.sor.hdmi = g84_hdmi_ctrl,
-	.pior.nr = 3,
-	.pior.new = nv50_pior_new,
-	.pior.power = nv50_pior_power,
+	.pior = { .nr = 3, .new = nv50_pior_new },
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
@@ -41,16 +41,12 @@ gt215_disp = {
 	.outp.external.dp = nv50_pior_dp_new,
 	.dac.nr = 3,
 	.dac.new = nv50_dac_new,
-	.dac.power = nv50_dac_power,
 	.dac.sense = nv50_dac_sense,
 	.sor.nr = 4,
 	.sor.new = gt215_sor_new,
-	.sor.power = nv50_sor_power,
 	.sor.hda_eld = gt215_hda_eld,
 	.sor.hdmi = gt215_hdmi_ctrl,
-	.pior.nr = 3,
-	.pior.new = nv50_pior_new,
-	.pior.power = nv50_pior_power,
+	.pior = { .nr = 3, .new = nv50_pior_new },
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
@@ -40,6 +40,8 @@ struct nvkm_ior {
 
 struct nvkm_ior_func {
 	void (*state)(struct nvkm_ior *, struct nvkm_ior_state *);
+	void (*power)(struct nvkm_ior *, bool normal, bool pu,
+		      bool data, bool vsync, bool hsync);
 };
 
 int nvkm_ior_new_(const struct nvkm_ior_func *func, struct nvkm_disp *,
@@ -47,7 +49,17 @@ int nvkm_ior_new_(const struct nvkm_ior_
 void nvkm_ior_del(struct nvkm_ior **);
 struct nvkm_ior *nvkm_ior_find(struct nvkm_disp *, enum nvkm_ior_type, int id);
 
+static inline u32
+nv50_ior_base(struct nvkm_ior *ior)
+{
+	return ior->id * 0x800;
+}
+
+void nv50_dac_power(struct nvkm_ior *, bool, bool, bool, bool, bool);
+
 void nv50_sor_state(struct nvkm_ior *, struct nvkm_ior_state *);
+void nv50_sor_power(struct nvkm_ior *, bool, bool, bool, bool, bool);
+
 void g94_sor_state(struct nvkm_ior *, struct nvkm_ior_state *);
 void gf119_sor_state(struct nvkm_ior *, struct nvkm_ior_state *);
 
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c
@@ -39,15 +39,11 @@ mcp77_disp = {
 	.outp.external.dp = nv50_pior_dp_new,
 	.dac.nr = 3,
 	.dac.new = nv50_dac_new,
-	.dac.power = nv50_dac_power,
 	.dac.sense = nv50_dac_sense,
 	.sor.nr = 4,
 	.sor.new = mcp77_sor_new,
-	.sor.power = nv50_sor_power,
 	.sor.hdmi = g84_hdmi_ctrl,
-	.pior.nr = 3,
-	.pior.new = nv50_pior_new,
-	.pior.power = nv50_pior_power,
+	.pior = { .nr = 3, .new = nv50_pior_new },
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c
@@ -39,16 +39,12 @@ mcp89_disp = {
 	.outp.external.dp = nv50_pior_dp_new,
 	.dac.nr = 3,
 	.dac.new = nv50_dac_new,
-	.dac.power = nv50_dac_power,
 	.dac.sense = nv50_dac_sense,
 	.sor.nr = 4,
 	.sor.new = mcp89_sor_new,
-	.sor.power = nv50_sor_power,
 	.sor.hda_eld = gt215_hda_eld,
 	.sor.hdmi = gt215_hdmi_ctrl,
-	.pior.nr = 3,
-	.pior.new = nv50_pior_new,
-	.pior.power = nv50_pior_power,
+	.pior = { .nr = 3, .new = nv50_pior_new },
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -846,14 +846,9 @@ nv50_disp = {
 	.outp.external.dp = nv50_pior_dp_new,
 	.dac.nr = 3,
 	.dac.new = nv50_dac_new,
-	.dac.power = nv50_dac_power,
 	.dac.sense = nv50_dac_sense,
-	.sor.nr = 2,
-	.sor.new = nv50_sor_new,
-	.sor.power = nv50_sor_power,
-	.pior.nr = 3,
-	.pior.new = nv50_pior_new,
-	.pior.power = nv50_pior_power,
+	.sor = { .nr = 2, .new = nv50_sor_new },
+	.pior = { .nr = 3, .new = nv50_pior_new },
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
@@ -31,7 +31,6 @@ struct nv50_disp {
 
 void nv50_disp_super_1(struct nv50_disp *);
 
-int nv50_dac_power(NV50_DISP_MTHD_V1);
 int nv50_dac_sense(NV50_DISP_MTHD_V1);
 
 int gt215_hda_eld(NV50_DISP_MTHD_V1);
@@ -42,9 +41,6 @@ int gt215_hdmi_ctrl(NV50_DISP_MTHD_V1);
 int gf119_hdmi_ctrl(NV50_DISP_MTHD_V1);
 int gk104_hdmi_ctrl(NV50_DISP_MTHD_V1);
 
-int nv50_sor_power(NV50_DISP_MTHD_V1);
-int nv50_pior_power(NV50_DISP_MTHD_V1);
-
 int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *,
 		   int index, int heads, struct nvkm_disp **);
 int gf119_disp_new_(const struct nv50_disp_func *, struct nvkm_device *,
@@ -84,14 +80,12 @@ struct nv50_disp_func {
 	struct {
 		int nr;
 		int (*new)(struct nvkm_disp *, int id);
-		int (*power)(NV50_DISP_MTHD_V1);
 		int (*sense)(NV50_DISP_MTHD_V1);
 	} dac;
 
 	struct {
 		int nr;
 		int (*new)(struct nvkm_disp *, int id);
-		int (*power)(NV50_DISP_MTHD_V1);
 		int (*hda_eld)(NV50_DISP_MTHD_V1);
 		int (*hdmi)(NV50_DISP_MTHD_V1);
 		void (*magic)(struct nvkm_output *);
@@ -100,7 +94,6 @@ struct nv50_disp_func {
 	struct {
 		int nr;
 		int (*new)(struct nvkm_disp *, int id);
-		int (*power)(NV50_DISP_MTHD_V1);
 	} pior;
 };
 
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
@@ -22,15 +22,11 @@
  * Authors: Ben Skeggs
  */
 #include "ior.h"
-#include "nv50.h"
+#include "dp.h"
 
-#include <core/client.h>
 #include <subdev/i2c.h>
 #include <subdev/timer.h>
 
-#include <nvif/cl5070.h>
-#include <nvif/unpack.h>
-
 /******************************************************************************
  * TMDS
  *****************************************************************************/
@@ -86,39 +82,28 @@ nv50_pior_dp_new(struct nvkm_disp *disp,
 				   index, dcbE, poutp);
 }
 
-int
-nv50_pior_power(NV50_DISP_MTHD_V1)
+static void
+nv50_pior_power_wait(struct nvkm_device *device, u32 poff)
 {
-	struct nvkm_device *device = disp->base.engine.subdev.device;
-	const u32 soff = outp->or * 0x800;
-	union {
-		struct nv50_disp_pior_pwr_v0 v0;
-	} *args = data;
-	u32 ctrl, type;
-	int ret = -ENOSYS;
-
-	nvif_ioctl(object, "disp pior pwr size %d\n", size);
-	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
-		nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n",
-			   args->v0.version, args->v0.state, args->v0.type);
-		if (args->v0.type > 0x0f)
-			return -EINVAL;
-		ctrl = !!args->v0.state;
-		type = args->v0.type;
-	} else
-		return ret;
-
-	nvkm_msec(device, 2000,
-		if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000))
-			break;
-	);
-	nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl);
 	nvkm_msec(device, 2000,
-		if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000))
+		if (!(nvkm_rd32(device, 0x61e004 + poff) & 0x80000000))
 			break;
 	);
-	disp->pior.type[outp->or] = type;
-	return 0;
+}
+
+static void
+nv50_pior_power(struct nvkm_ior *pior, bool normal, bool pu,
+	       bool data, bool vsync, bool hsync)
+{
+	struct nvkm_device *device = pior->disp->engine.subdev.device;
+	const u32  poff = nv50_ior_base(pior);
+	const u32 shift = normal ? 0 : 16;
+	const u32 state = 0x80000000 | (0x00000001 * !!pu) << shift;
+	const u32 field = 0x80000000 | (0x00000101 << shift);
+
+	nv50_pior_power_wait(device, poff);
+	nvkm_mask(device, 0x61e004 + poff, field, state);
+	nv50_pior_power_wait(device, poff);
 }
 
 static void
@@ -143,6 +128,7 @@ nv50_pior_state(struct nvkm_ior *pior, s
 static const struct nvkm_ior_func
 nv50_pior = {
 	.state = nv50_pior_state,
+	.power = nv50_pior_power,
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c
@@ -24,6 +24,7 @@
 #include "rootnv50.h"
 #include "dmacnv50.h"
 #include "head.h"
+#include "ior.h"
 
 #include <core/client.h>
 #include <core/ramht.h>
@@ -94,12 +95,8 @@ nv50_disp_root_mthd_(struct nvkm_object
 	}
 
 	switch (mthd * !!outp) {
-	case NV50_DISP_MTHD_V1_DAC_PWR:
-		return func->dac.power(object, disp, data, size, hidx, outp);
 	case NV50_DISP_MTHD_V1_DAC_LOAD:
 		return func->dac.sense(object, disp, data, size, hidx, outp);
-	case NV50_DISP_MTHD_V1_SOR_PWR:
-		return func->sor.power(object, disp, data, size, hidx, outp);
 	case NV50_DISP_MTHD_V1_SOR_HDA_ELD:
 		if (!func->sor.hda_eld)
 			return -ENODEV;
@@ -163,10 +160,6 @@ nv50_disp_root_mthd_(struct nvkm_object
 			return ret;
 	}
 		break;
-	case NV50_DISP_MTHD_V1_PIOR_PWR:
-		if (!func->pior.power)
-			return -ENODEV;
-		return func->pior.power(object, disp, data, size, hidx, outp);
 	default:
 		break;
 	}
@@ -231,7 +224,21 @@ static int
 nv50_disp_root_init_(struct nvkm_object *object)
 {
 	struct nv50_disp_root *root = nv50_disp_root(object);
-	return root->func->init(root);
+	struct nvkm_ior *ior;
+	int ret;
+
+	ret = root->func->init(root);
+	if (ret)
+		return ret;
+
+	/* Set 'normal' (ie. when it's attached to a head) state for
+	 * each output resource to 'fully enabled'.
+	 */
+	list_for_each_entry(ior, &root->disp->base.ior, head) {
+		ior->func->power(ior, true, true, true, true, true);
+	}
+
+	return 0;
 }
 
 static void *
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c
@@ -24,6 +24,7 @@
 static const struct nvkm_ior_func
 g84_sor = {
 	.state = nv50_sor_state,
+	.power = nv50_sor_power,
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
@@ -304,6 +304,7 @@ g94_sor_state(struct nvkm_ior *sor, stru
 static const struct nvkm_ior_func
 g94_sor = {
 	.state = g94_sor_state,
+	.power = nv50_sor_power,
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c
@@ -156,6 +156,7 @@ gf119_sor_state(struct nvkm_ior *sor, st
 static const struct nvkm_ior_func
 gf119_sor = {
 	.state = gf119_sor_state,
+	.power = nv50_sor_power,
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c
@@ -24,6 +24,7 @@
 static const struct nvkm_ior_func
 gk104_sor = {
 	.state = gf119_sor_state,
+	.power = nv50_sor_power,
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c
@@ -56,6 +56,7 @@ gm107_sor_dp_new(struct nvkm_disp *disp,
 static const struct nvkm_ior_func
 gm107_sor = {
 	.state = gf119_sor_state,
+	.power = nv50_sor_power,
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c
@@ -133,6 +133,7 @@ gm200_sor_magic(struct nvkm_output *outp
 static const struct nvkm_ior_func
 gm200_sor = {
 	.state = gf119_sor_state,
+	.power = nv50_sor_power,
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c
@@ -24,6 +24,7 @@
 static const struct nvkm_ior_func
 gt215_sor = {
 	.state = g94_sor_state,
+	.power = nv50_sor_power,
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c
@@ -24,6 +24,7 @@
 static const struct nvkm_ior_func
 mcp77_sor = {
 	.state = g94_sor_state,
+	.power = nv50_sor_power,
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c
@@ -24,6 +24,7 @@
 static const struct nvkm_ior_func
 mcp89_sor = {
 	.state = g94_sor_state,
+	.power = nv50_sor_power,
 };
 
 int
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c
@@ -22,15 +22,10 @@
  * Authors: Ben Skeggs
  */
 #include "ior.h"
-#include "nv50.h"
 #include "outp.h"
 
-#include <core/client.h>
 #include <subdev/timer.h>
 
-#include <nvif/cl5070.h>
-#include <nvif/unpack.h>
-
 static const struct nvkm_output_func
 nv50_sor_output_func = {
 };
@@ -43,40 +38,33 @@ nv50_sor_output_new(struct nvkm_disp *di
 				index, dcbE, poutp);
 }
 
-int
-nv50_sor_power(NV50_DISP_MTHD_V1)
+static void
+nv50_sor_power_wait(struct nvkm_device *device, u32 soff)
 {
-	struct nvkm_device *device = disp->base.engine.subdev.device;
-	union {
-		struct nv50_disp_sor_pwr_v0 v0;
-	} *args = data;
-	const u32 soff = outp->or * 0x800;
-	u32 stat;
-	int ret = -ENOSYS;
-
-	nvif_ioctl(object, "disp sor pwr size %d\n", size);
-	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
-		nvif_ioctl(object, "disp sor pwr vers %d state %d\n",
-			   args->v0.version, args->v0.state);
-		stat = !!args->v0.state;
-	} else
-		return ret;
-
-
-	nvkm_msec(device, 2000,
-		if (!(nvkm_rd32(device, 0x61c004 + soff) & 0x80000000))
-			break;
-	);
-	nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000000 | stat);
 	nvkm_msec(device, 2000,
 		if (!(nvkm_rd32(device, 0x61c004 + soff) & 0x80000000))
 			break;
 	);
+}
+
+void
+nv50_sor_power(struct nvkm_ior *sor, bool normal, bool pu,
+	       bool data, bool vsync, bool hsync)
+{
+	struct nvkm_device *device = sor->disp->engine.subdev.device;
+	const u32  soff = nv50_ior_base(sor);
+	const u32 shift = normal ? 0 : 16;
+	const u32 state = 0x80000000 | (0x00000001 * !!pu) << shift;
+	const u32 field = 0x80000000 | (0x00000001 << shift);
+
+	nv50_sor_power_wait(device, soff);
+	nvkm_mask(device, 0x61c004 + soff, field, state);
+	nv50_sor_power_wait(device, soff);
+
 	nvkm_msec(device, 2000,
 		if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000))
 			break;
 	);
-	return 0;
 }
 
 void
@@ -103,6 +91,7 @@ nv50_sor_state(struct nvkm_ior *sor, str
 static const struct nvkm_ior_func
 nv50_sor = {
 	.state = nv50_sor_state,
+	.power = nv50_sor_power,
 };
 
 int