All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/18] Separating vcn power management by instance
@ 2024-10-04 18:44 boyuan.zhang
  2024-10-04 18:44 ` [PATCH 01/18] drm/amd/pm: add inst to dpm_set_vcn_enable boyuan.zhang
                   ` (17 more replies)
  0 siblings, 18 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

Previously, all vcn instance will be powered on/off at the same time
even only one of the instance requests power status change. This patch set
enables vcn to ONLY power on/off the instance that requires power status
change. Other vcn instances will remain the original power status.

v2: complete re-work for all PM changes as suggested-by Christian König and
Alex Deucher. Adding instance to all existing functions, instead of create
new functions. Remove all duplicated PM functions in previous patch set.
Use a new logic to track instance for ip_block with same type as
suggested by Alex. Also, fix wrong ip block index and remove redundant logic
suggested by Christian. Finally rebase all patches based on Sunil's ip block
changes.

Patch 1-6 are SMU changes to only power ON/OFF given VCN instance.
v2: Remove all duplicated PM functions in v1.

Patch 7 is VCN change to separate gating status for each VCN instance.
v2: Remove redundant logic.

Patch 8 is VCN change to handle idle work separately for each VCN instance.

Patch 9 is to pass ip_block in set_powergating_state() callback function.
v2: fix wrong ip block index for AMD_IP_BLOCK_TYPE_GFX

Patch 10 is to track VCN instance in VCN ip_block.
v2: use a new logic to track vcn instance

Patch 11 is to set_powergating_state by instance in amdgpu_device.

Patch 12-17 are to handle ip callback functions separately for each
VCN instance, so that only the given instance will be powered on/off.

Patch 18 is to set powergating state by VCN instance in amdgpu_vcn.

Boyuan Zhang (18):
  drm/amd/pm: add inst to dpm_set_vcn_enable
  drm/amd/pm: power up or down vcn by instance
  drm/amd/pm: add inst to smu_dpm_set_vcn_enable
  drm/amd/pm: add inst to set_powergating_by_smu
  drm/amd/pm: add inst to amdgpu_dpm_set_powergating_by_smu
  add inst to amdgpu_dpm_enable_vcn
  drm/amdgpu: pass ip_block in set_powergating_state
  drm/amdgpu: track instances of the same IP block
  drm/amdgpu: add set_powergating_state_instance
  drm/amdgpu/vcn: separate gating state by instance
  drm/amdgpu: power vcn 2_5 by instance
  drm/amdgpu: power vcn 3_0 by instance
  drm/amdgpu: power vcn 4_0 by instance
  drm/amdgpu: power vcn 4_0_3 by instance
  drm/amdgpu: power vcn 4_0_5 by instance
  drm/amdgpu: power vcn 5_0_0 by instance
  drm/amdgpu/vcn: separate idle work by instance
  drm/amdgpu: set powergating state by vcn instance

 drivers/gpu/drm/amd/amdgpu/amdgpu.h           |   5 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c       |  18 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c    |   5 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c    |  68 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |  19 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c       |   4 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c       |   2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c       |   2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c       |  82 +--
 drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h       |   6 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c      |   2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c       |   4 +-
 drivers/gpu/drm/amd/amdgpu/cik.c              |   2 +-
 drivers/gpu/drm/amd/amdgpu/cik_ih.c           |   2 +-
 drivers/gpu/drm/amd/amdgpu/cik_sdma.c         |   2 +-
 drivers/gpu/drm/amd/amdgpu/cz_ih.c            |   2 +-
 drivers/gpu/drm/amd/amdgpu/dce_v10_0.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/dce_v11_0.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/dce_v6_0.c         |   2 +-
 drivers/gpu/drm/amd/amdgpu/dce_v8_0.c         |   2 +-
 drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c        |   8 +-
 drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c        |   4 +-
 drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c        |   4 +-
 drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c         |   4 +-
 drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c         |   4 +-
 drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c         |   6 +-
 drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c         |   4 +-
 drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c       |   2 +-
 drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c         |   2 +-
 drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c         |   2 +-
 drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c         |   2 +-
 drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c         |   2 +-
 drivers/gpu/drm/amd/amdgpu/iceland_ih.c       |   2 +-
 drivers/gpu/drm/amd/amdgpu/ih_v6_0.c          |   4 +-
 drivers/gpu/drm/amd/amdgpu/ih_v6_1.c          |   4 +-
 drivers/gpu/drm/amd/amdgpu/ih_v7_0.c          |   4 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c        |  10 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c        |  10 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c        |  10 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c        |  10 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c      |   8 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c      |  10 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c      |  10 +-
 drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c       |   2 +-
 drivers/gpu/drm/amd/amdgpu/navi10_ih.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/nv.c               |   2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c        |   8 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c      |   2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/si.c               |   2 +-
 drivers/gpu/drm/amd/amdgpu/si_dma.c           |   4 +-
 drivers/gpu/drm/amd/amdgpu/si_ih.c            |   2 +-
 drivers/gpu/drm/amd/amdgpu/soc15.c            |   2 +-
 drivers/gpu/drm/amd/amdgpu/soc21.c            |   4 +-
 drivers/gpu/drm/amd/amdgpu/soc24.c            |   4 +-
 drivers/gpu/drm/amd/amdgpu/tonga_ih.c         |   2 +-
 drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c         |   2 +-
 drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c         |   4 +-
 drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c         |   4 +-
 drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c         |   4 +-
 drivers/gpu/drm/amd/amdgpu/vce_v2_0.c         |   4 +-
 drivers/gpu/drm/amd/amdgpu/vce_v3_0.c         |   4 +-
 drivers/gpu/drm/amd/amdgpu/vce_v4_0.c         |   4 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c         |  36 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c         |  23 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 593 +++++++++--------
 drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c         | 610 +++++++++---------
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c         | 541 ++++++++--------
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c       | 476 +++++++-------
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c       | 549 ++++++++--------
 drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c       | 459 +++++++------
 drivers/gpu/drm/amd/amdgpu/vega10_ih.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/vega20_ih.c        |   2 +-
 drivers/gpu/drm/amd/amdgpu/vi.c               |   2 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |   2 +-
 drivers/gpu/drm/amd/include/amd_shared.h      |   2 +-
 .../gpu/drm/amd/include/kgd_pp_interface.h    |   4 +-
 drivers/gpu/drm/amd/pm/amdgpu_dpm.c           |  49 +-
 drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h       |   3 +-
 drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c    |   6 +-
 drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c    |   2 +-
 .../gpu/drm/amd/pm/powerplay/amd_powerplay.c  |   6 +-
 drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c     |  59 +-
 drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h |   4 +-
 drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h  |   3 +-
 drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h  |   3 +-
 .../gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c |   4 +-
 .../gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c   |   4 +-
 .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c   |  24 +-
 .../gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c  |   4 +-
 .../gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c   |   4 +-
 .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c    |  19 +-
 .../drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c  |   4 +-
 .../drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c  |   4 +-
 .../gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c    |  38 +-
 104 files changed, 2053 insertions(+), 1929 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 01/18] drm/amd/pm: add inst to dpm_set_vcn_enable
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 18:44 ` [PATCH 02/18] drm/amd/pm: power up or down vcn by instance boyuan.zhang
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

Add an instance parameter to the existing function dpm_set_vcn_enable()
for future implementation. Re-write all pptable functions accordingly.

v2: Remove duplicated dpm_set_vcn_enable() functions in v1. Instead,
adding instance parameter to existing functions.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
Suggested-by: Christian König <christian.koenig@amd.com>
Suggested-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c               | 2 +-
 drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h           | 2 +-
 drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h            | 3 ++-
 drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h            | 3 ++-
 drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c       | 4 +++-
 drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c         | 4 +++-
 drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 4 +++-
 drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c        | 4 +++-
 drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c         | 4 +++-
 drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c          | 3 ++-
 drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c    | 4 +++-
 drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c    | 4 +++-
 drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c          | 3 ++-
 13 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index 5b0cdda96b38..6305fd7d2573 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -251,7 +251,7 @@ static int smu_dpm_set_vcn_enable(struct smu_context *smu,
 	if (atomic_read(&power_gate->vcn_gated) ^ enable)
 		return 0;
 
-	ret = smu->ppt_funcs->dpm_set_vcn_enable(smu, enable);
+	ret = smu->ppt_funcs->dpm_set_vcn_enable(smu, enable, 0xff);
 	if (!ret)
 		atomic_set(&power_gate->vcn_gated, !enable);
 
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index 727da0c37e06..0f074b6c8b58 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -739,7 +739,7 @@ struct pptable_funcs {
 	 * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power
 	 *                      management.
 	 */
-	int (*dpm_set_vcn_enable)(struct smu_context *smu, bool enable);
+	int (*dpm_set_vcn_enable)(struct smu_context *smu, bool enable, int inst);
 
 	/**
 	 * @dpm_set_jpeg_enable: Enable/disable JPEG engine dynamic power
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
index e58220a7ee2f..229b9d16452f 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
@@ -255,7 +255,8 @@ int smu_v13_0_wait_for_event(struct smu_context *smu, enum smu_event_type event,
 			     uint64_t event_arg);
 
 int smu_v13_0_set_vcn_enable(struct smu_context *smu,
-			     bool enable);
+			      bool enable,
+			      int inst);
 
 int smu_v13_0_set_jpeg_enable(struct smu_context *smu,
 			      bool enable);
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h
index 46b456590a08..c7071159f8ec 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h
@@ -210,7 +210,8 @@ int smu_v14_0_wait_for_event(struct smu_context *smu, enum smu_event_type event,
 			     uint64_t event_arg);
 
 int smu_v14_0_set_vcn_enable(struct smu_context *smu,
-			     bool enable);
+			      bool enable,
+			      int inst);
 
 int smu_v14_0_set_jpeg_enable(struct smu_context *smu,
 			      bool enable);
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
index 5ad09323a29d..6c8e80f6b592 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
@@ -1571,7 +1571,9 @@ static bool arcturus_is_dpm_running(struct smu_context *smu)
 	return !!(feature_enabled & SMC_DPM_FEATURE);
 }
 
-static int arcturus_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
+static int arcturus_dpm_set_vcn_enable(struct smu_context *smu,
+					bool enable,
+					int inst)
 {
 	int ret = 0;
 
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index 16af1a329621..29a3b96ffaec 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -1135,7 +1135,9 @@ static int navi10_set_default_dpm_table(struct smu_context *smu)
 	return 0;
 }
 
-static int navi10_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
+static int navi10_dpm_set_vcn_enable(struct smu_context *smu,
+				      bool enable,
+				      int inst)
 {
 	int ret = 0;
 
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index 3b29cb74c47b..2438f813d6db 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -1152,7 +1152,9 @@ static int sienna_cichlid_set_default_dpm_table(struct smu_context *smu)
 	return 0;
 }
 
-static int sienna_cichlid_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
+static int sienna_cichlid_dpm_set_vcn_enable(struct smu_context *smu,
+					      bool enable,
+					      int inst)
 {
 	struct amdgpu_device *adev = smu->adev;
 	int i, ret = 0;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
index 22737b11b1bf..656505d2404b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
@@ -459,7 +459,9 @@ static int vangogh_init_smc_tables(struct smu_context *smu)
 	return smu_v11_0_init_smc_tables(smu);
 }
 
-static int vangogh_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
+static int vangogh_dpm_set_vcn_enable(struct smu_context *smu,
+				       bool enable,
+				       int inst)
 {
 	int ret = 0;
 
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
index cc0504b063fa..8d9fb80f36f7 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
@@ -645,7 +645,9 @@ static enum amd_pm_state_type renoir_get_current_power_state(struct smu_context
 	return pm_type;
 }
 
-static int renoir_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
+static int renoir_dpm_set_vcn_enable(struct smu_context *smu,
+				      bool enable,
+				      int inst)
 {
 	int ret = 0;
 
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
index e17466cc1952..1d37b9e251d4 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
@@ -2088,7 +2088,8 @@ int smu_v13_0_get_current_pcie_link_speed(struct smu_context *smu)
 }
 
 int smu_v13_0_set_vcn_enable(struct smu_context *smu,
-			     bool enable)
+			      bool enable,
+			      int inst)
 {
 	struct amdgpu_device *adev = smu->adev;
 	int i, ret = 0;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c
index 9c2c43bfed0b..3204917f91bf 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c
@@ -193,7 +193,9 @@ static int smu_v13_0_5_system_features_control(struct smu_context *smu, bool en)
 	return ret;
 }
 
-static int smu_v13_0_5_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
+static int smu_v13_0_5_dpm_set_vcn_enable(struct smu_context *smu,
+					   bool enable,
+					   int inst)
 {
 	int ret = 0;
 
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
index 260c339f89c5..0890951351f9 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
@@ -220,7 +220,9 @@ static int yellow_carp_system_features_control(struct smu_context *smu, bool en)
 	return ret;
 }
 
-static int yellow_carp_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
+static int yellow_carp_dpm_set_vcn_enable(struct smu_context *smu,
+					   bool enable,
+					   int inst)
 {
 	int ret = 0;
 
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
index 865e916fc425..5e1165ecdf7b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
@@ -1492,7 +1492,8 @@ int smu_v14_0_set_single_dpm_table(struct smu_context *smu,
 }
 
 int smu_v14_0_set_vcn_enable(struct smu_context *smu,
-			     bool enable)
+			      bool enable,
+			      int inst)
 {
 	struct amdgpu_device *adev = smu->adev;
 	int i, ret = 0;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 02/18] drm/amd/pm: power up or down vcn by instance
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
  2024-10-04 18:44 ` [PATCH 01/18] drm/amd/pm: add inst to dpm_set_vcn_enable boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 18:44 ` [PATCH 03/18] drm/amd/pm: add inst to smu_dpm_set_vcn_enable boyuan.zhang
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

For smu ip with multiple vcn instances (smu 11/13/14), remove all the
for loop in dpm_set_vcn_enable() functions. And use the instance
argument to power up/down vcn for the given instance only, instead
of powering up/down for all vcn instances.

v2: remove all duplicated functions in v1.

remove for-loop from each ip, and temporarily move to dpm_set_vcn_enable,
in order to keep the exact same logic as before, until further separation
in the next patch.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c     |  7 +++-
 .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c   | 20 +++++------
 .../gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c    | 16 ++++-----
 .../gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c    | 35 ++++++++-----------
 4 files changed, 35 insertions(+), 43 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index 6305fd7d2573..410d5baedfbc 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -237,6 +237,7 @@ static int smu_dpm_set_vcn_enable(struct smu_context *smu,
 {
 	struct smu_power_context *smu_power = &smu->smu_power;
 	struct smu_power_gate *power_gate = &smu_power->power_gate;
+	struct amdgpu_device *adev = smu->adev;
 	int ret = 0;
 
 	/*
@@ -251,7 +252,11 @@ static int smu_dpm_set_vcn_enable(struct smu_context *smu,
 	if (atomic_read(&power_gate->vcn_gated) ^ enable)
 		return 0;
 
-	ret = smu->ppt_funcs->dpm_set_vcn_enable(smu, enable, 0xff);
+	for (int i = 0; i < adev->vcn.num_vcn_inst; i++) {
+		ret = smu->ppt_funcs->dpm_set_vcn_enable(smu, enable, i);
+		if (ret)
+			return ret;
+	}
 	if (!ret)
 		atomic_set(&power_gate->vcn_gated, !enable);
 
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index 2438f813d6db..f41d8fd09bce 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -1157,19 +1157,15 @@ static int sienna_cichlid_dpm_set_vcn_enable(struct smu_context *smu,
 					      int inst)
 {
 	struct amdgpu_device *adev = smu->adev;
-	int i, ret = 0;
+	int ret = 0;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
-		/* vcn dpm on is a prerequisite for vcn power gate messages */
-		if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) {
-			ret = smu_cmn_send_smc_msg_with_param(smu, enable ?
-							      SMU_MSG_PowerUpVcn : SMU_MSG_PowerDownVcn,
-							      0x10000 * i, NULL);
-			if (ret)
-				return ret;
-		}
+	if (adev->vcn.harvest_config & (1 << inst))
+		return ret;
+	/* vcn dpm on is a prerequisite for vcn power gate messages */
+	if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) {
+		ret = smu_cmn_send_smc_msg_with_param(smu, enable ?
+                                            SMU_MSG_PowerUpVcn : SMU_MSG_PowerDownVcn,
+                                            0x10000 * inst, NULL);
 	}
 
 	return ret;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
index 1d37b9e251d4..e57d4926250e 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
@@ -2092,18 +2092,14 @@ int smu_v13_0_set_vcn_enable(struct smu_context *smu,
 			      int inst)
 {
 	struct amdgpu_device *adev = smu->adev;
-	int i, ret = 0;
+	int ret = 0;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
+	if (adev->vcn.harvest_config & (1 << inst))
+		return ret;
 
-		ret = smu_cmn_send_smc_msg_with_param(smu, enable ?
-						      SMU_MSG_PowerUpVcn : SMU_MSG_PowerDownVcn,
-						      i << 16U, NULL);
-		if (ret)
-			return ret;
-	}
+	ret = smu_cmn_send_smc_msg_with_param(smu, enable ?
+					      SMU_MSG_PowerUpVcn : SMU_MSG_PowerDownVcn,
+					      inst << 16U, NULL);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
index 5e1165ecdf7b..20822ac623c7 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
@@ -1496,29 +1496,24 @@ int smu_v14_0_set_vcn_enable(struct smu_context *smu,
 			      int inst)
 {
 	struct amdgpu_device *adev = smu->adev;
-	int i, ret = 0;
+	int ret = 0;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
+	if (adev->vcn.harvest_config & (1 << inst))
+		return ret;
 
-		if (smu->is_apu) {
-			if (i == 0)
-				ret = smu_cmn_send_smc_msg_with_param(smu, enable ?
-								      SMU_MSG_PowerUpVcn0 : SMU_MSG_PowerDownVcn0,
-								      i << 16U, NULL);
-			else if (i == 1)
-				ret = smu_cmn_send_smc_msg_with_param(smu, enable ?
-								      SMU_MSG_PowerUpVcn1 : SMU_MSG_PowerDownVcn1,
-								      i << 16U, NULL);
-		} else {
+	if (smu->is_apu) {
+		if (inst == 0)
 			ret = smu_cmn_send_smc_msg_with_param(smu, enable ?
-							      SMU_MSG_PowerUpVcn : SMU_MSG_PowerDownVcn,
-							      i << 16U, NULL);
-		}
-
-		if (ret)
-			return ret;
+							      SMU_MSG_PowerUpVcn0 : SMU_MSG_PowerDownVcn0,
+							      inst << 16U, NULL);
+		else if (inst == 1)
+			ret = smu_cmn_send_smc_msg_with_param(smu, enable ?
+							      SMU_MSG_PowerUpVcn1 : SMU_MSG_PowerDownVcn1,
+							      inst << 16U, NULL);
+	} else {
+		ret = smu_cmn_send_smc_msg_with_param(smu, enable ?
+						      SMU_MSG_PowerUpVcn : SMU_MSG_PowerDownVcn,
+						      inst << 16U, NULL);
 	}
 
 	return ret;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 03/18] drm/amd/pm: add inst to smu_dpm_set_vcn_enable
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
  2024-10-04 18:44 ` [PATCH 01/18] drm/amd/pm: add inst to dpm_set_vcn_enable boyuan.zhang
  2024-10-04 18:44 ` [PATCH 02/18] drm/amd/pm: power up or down vcn by instance boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 18:44 ` [PATCH 04/18] drm/amd/pm: add inst to set_powergating_by_smu boyuan.zhang
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

First, add an instance parameter to smu_dpm_set_vcn_enable() function,
and calling dpm_set_vcn_enable() with this given instance.

Second, modify vcn_gated to be an array, to track the gating status
for each vcn instance separately.

With these 2 changes, smu_dpm_set_vcn_enable() will check and set the
gating status for the given vcn instance ONLY.

v2: remove duplicated functions.

remove for-loop in dpm_set_vcn_enable(), and temporarily move it to
to smu_dpm_set_power_gate(), in order to keep the exact same logic as
before, until further separation in next patch.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c     | 65 ++++++++++++-------
 drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h |  2 +-
 2 files changed, 41 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index 410d5baedfbc..786241fa8d2c 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -233,11 +233,11 @@ static bool is_vcn_enabled(struct amdgpu_device *adev)
 }
 
 static int smu_dpm_set_vcn_enable(struct smu_context *smu,
-				  bool enable)
+				   bool enable,
+				   int inst)
 {
 	struct smu_power_context *smu_power = &smu->smu_power;
 	struct smu_power_gate *power_gate = &smu_power->power_gate;
-	struct amdgpu_device *adev = smu->adev;
 	int ret = 0;
 
 	/*
@@ -249,16 +249,12 @@ static int smu_dpm_set_vcn_enable(struct smu_context *smu,
 	if (!smu->ppt_funcs->dpm_set_vcn_enable)
 		return 0;
 
-	if (atomic_read(&power_gate->vcn_gated) ^ enable)
+	if (atomic_read(&power_gate->vcn_gated[inst]) ^ enable)
 		return 0;
 
-	for (int i = 0; i < adev->vcn.num_vcn_inst; i++) {
-		ret = smu->ppt_funcs->dpm_set_vcn_enable(smu, enable, i);
-		if (ret)
-			return ret;
-	}
+	ret = smu->ppt_funcs->dpm_set_vcn_enable(smu, enable, inst);
 	if (!ret)
-		atomic_set(&power_gate->vcn_gated, !enable);
+		atomic_set(&power_gate->vcn_gated[inst], !enable);
 
 	return ret;
 }
@@ -360,6 +356,7 @@ static int smu_dpm_set_power_gate(void *handle,
 				  bool gate)
 {
 	struct smu_context *smu = handle;
+	struct amdgpu_device *adev = smu->adev;
 	int ret = 0;
 
 	if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) {
@@ -376,10 +373,12 @@ static int smu_dpm_set_power_gate(void *handle,
 	 */
 	case AMD_IP_BLOCK_TYPE_UVD:
 	case AMD_IP_BLOCK_TYPE_VCN:
-		ret = smu_dpm_set_vcn_enable(smu, !gate);
-		if (ret)
-			dev_err(smu->adev->dev, "Failed to power %s VCN!\n",
-				gate ? "gate" : "ungate");
+		for (int i = 0; i < adev->vcn.num_vcn_inst; i++) {
+			ret = smu_dpm_set_vcn_enable(smu, !gate, i);
+			if (ret)
+				dev_err(smu->adev->dev, "Failed to power %s VCN!\n",
+					gate ? "gate" : "ungate");
+		}
 		break;
 	case AMD_IP_BLOCK_TYPE_GFX:
 		ret = smu_gfx_off_control(smu, gate);
@@ -781,21 +780,25 @@ static int smu_set_default_dpm_table(struct smu_context *smu)
 	struct amdgpu_device *adev = smu->adev;
 	struct smu_power_context *smu_power = &smu->smu_power;
 	struct smu_power_gate *power_gate = &smu_power->power_gate;
-	int vcn_gate, jpeg_gate;
+	int vcn_gate[AMDGPU_MAX_VCN_INSTANCES], jpeg_gate, i;
 	int ret = 0;
 
 	if (!smu->ppt_funcs->set_default_dpm_table)
 		return 0;
 
-	if (adev->pg_flags & AMD_PG_SUPPORT_VCN)
-		vcn_gate = atomic_read(&power_gate->vcn_gated);
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN) {
+		for (i = 0; i < adev->vcn.num_vcn_inst; i++)
+			vcn_gate[i] = atomic_read(&power_gate->vcn_gated[i]);
+	}
 	if (adev->pg_flags & AMD_PG_SUPPORT_JPEG)
 		jpeg_gate = atomic_read(&power_gate->jpeg_gated);
 
 	if (adev->pg_flags & AMD_PG_SUPPORT_VCN) {
-		ret = smu_dpm_set_vcn_enable(smu, true);
-		if (ret)
-			return ret;
+		for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
+			ret = smu_dpm_set_vcn_enable(smu, true, i);
+			if (ret)
+				return ret;
+		}
 	}
 
 	if (adev->pg_flags & AMD_PG_SUPPORT_JPEG) {
@@ -812,8 +815,10 @@ static int smu_set_default_dpm_table(struct smu_context *smu)
 	if (adev->pg_flags & AMD_PG_SUPPORT_JPEG)
 		smu_dpm_set_jpeg_enable(smu, !jpeg_gate);
 err_out:
-	if (adev->pg_flags & AMD_PG_SUPPORT_VCN)
-		smu_dpm_set_vcn_enable(smu, !vcn_gate);
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN) {
+		for (i = 0; i < adev->vcn.num_vcn_inst; i++)
+			smu_dpm_set_vcn_enable(smu, !vcn_gate[i], i);
+	}
 
 	return ret;
 }
@@ -1258,7 +1263,8 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
 	smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
 	smu->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
 
-	atomic_set(&smu->smu_power.power_gate.vcn_gated, 1);
+	for (int i = 0; i < adev->vcn.num_vcn_inst; i++)
+		atomic_set(&smu->smu_power.power_gate.vcn_gated[i], 1);
 	atomic_set(&smu->smu_power.power_gate.jpeg_gated, 1);
 	atomic_set(&smu->smu_power.power_gate.vpe_gated, 1);
 	atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
@@ -1820,7 +1826,8 @@ static int smu_hw_init(struct amdgpu_ip_block *ip_block)
 		ret = smu_set_gfx_imu_enable(smu);
 		if (ret)
 			return ret;
-		smu_dpm_set_vcn_enable(smu, true);
+		for (int i = 0; i < adev->vcn.num_vcn_inst; i++)
+			smu_dpm_set_vcn_enable(smu, true, i);
 		smu_dpm_set_jpeg_enable(smu, true);
 		smu_dpm_set_vpe_enable(smu, true);
 		smu_dpm_set_umsch_mm_enable(smu, true);
@@ -2023,7 +2030,8 @@ static int smu_hw_fini(struct amdgpu_ip_block *ip_block)
 	if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev))
 		return 0;
 
-	smu_dpm_set_vcn_enable(smu, false);
+	for (int i = 0; i < adev->vcn.num_vcn_inst; i++)
+		smu_dpm_set_vcn_enable(smu, false, i);
 	smu_dpm_set_jpeg_enable(smu, false);
 	smu_dpm_set_vpe_enable(smu, false);
 	smu_dpm_set_umsch_mm_enable(smu, false);
@@ -2937,6 +2945,7 @@ static int smu_read_sensor(void *handle,
 			   int *size_arg)
 {
 	struct smu_context *smu = handle;
+	struct amdgpu_device *adev = smu->adev;
 	struct smu_umd_pstate_table *pstate_table =
 				&smu->pstate_table;
 	int ret = 0;
@@ -2985,7 +2994,13 @@ static int smu_read_sensor(void *handle,
 		*size = 4;
 		break;
 	case AMDGPU_PP_SENSOR_VCN_POWER_STATE:
-		*(uint32_t *)data = atomic_read(&smu->smu_power.power_gate.vcn_gated) ? 0 : 1;
+		*(uint32_t *)data = 0;
+		for (int i = 0; i < adev->vcn.num_vcn_inst; i++) {
+			if (!atomic_read(&smu->smu_power.power_gate.vcn_gated[i])) {
+				*(uint32_t *)data = 1;
+				break;
+			}
+		}
 		*size = 4;
 		break;
 	case AMDGPU_PP_SENSOR_MIN_FAN_RPM:
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index 0f074b6c8b58..427441b469e0 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -399,7 +399,7 @@ struct smu_dpm_context {
 struct smu_power_gate {
 	bool uvd_gated;
 	bool vce_gated;
-	atomic_t vcn_gated;
+	atomic_t vcn_gated[AMDGPU_MAX_VCN_INSTANCES];
 	atomic_t jpeg_gated;
 	atomic_t vpe_gated;
 	atomic_t umsch_mm_gated;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 04/18] drm/amd/pm: add inst to set_powergating_by_smu
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (2 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 03/18] drm/amd/pm: add inst to smu_dpm_set_vcn_enable boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 19:14   ` Alex Deucher
  2024-10-04 18:44 ` [PATCH 05/18] drm/amd/pm: add inst to amdgpu_dpm_set_powergating_by_smu boyuan.zhang
                   ` (13 subsequent siblings)
  17 siblings, 1 reply; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

Add an instance parameter to set_powergating_by_smu() function, and
re-write all amd_pm functions accordingly. Then use the instance to
call smu_dpm_set_vcn_enable().

v2: remove duplicated functions.

remove for-loop in smu_dpm_set_power_gate(), and temporarily move it to
to amdgpu_dpm_set_powergating_by_smu(), in order to keep the exact same
logic as before, until further separation in next patch.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/include/kgd_pp_interface.h   |  4 +++-
 drivers/gpu/drm/amd/pm/amdgpu_dpm.c              | 10 ++++++++--
 drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c       |  4 +++-
 drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c |  4 +++-
 drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c        | 14 ++++++--------
 5 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
index 2fa71f68205e..f24bc61df9a7 100644
--- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h
+++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
@@ -405,7 +405,9 @@ struct amd_pm_funcs {
 	int (*load_firmware)(void *handle);
 	int (*wait_for_fw_loading_complete)(void *handle);
 	int (*set_powergating_by_smu)(void *handle,
-				uint32_t block_type, bool gate);
+				uint32_t block_type,
+				bool gate,
+				int inst);
 	int (*set_clockgating_by_smu)(void *handle, uint32_t msg_id);
 	int (*set_power_limit)(void *handle, uint32_t n);
 	int (*get_power_limit)(void *handle, uint32_t *limit,
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
index 9dc82f4d7c93..bcedbeec082f 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
@@ -88,7 +88,6 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, uint32_t block
 	case AMD_IP_BLOCK_TYPE_UVD:
 	case AMD_IP_BLOCK_TYPE_VCE:
 	case AMD_IP_BLOCK_TYPE_GFX:
-	case AMD_IP_BLOCK_TYPE_VCN:
 	case AMD_IP_BLOCK_TYPE_SDMA:
 	case AMD_IP_BLOCK_TYPE_JPEG:
 	case AMD_IP_BLOCK_TYPE_GMC:
@@ -96,7 +95,14 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, uint32_t block
 	case AMD_IP_BLOCK_TYPE_VPE:
 		if (pp_funcs && pp_funcs->set_powergating_by_smu)
 			ret = (pp_funcs->set_powergating_by_smu(
-				(adev)->powerplay.pp_handle, block_type, gate));
+				(adev)->powerplay.pp_handle, block_type, gate, 0));
+		break;
+	case AMD_IP_BLOCK_TYPE_VCN:
+		if (pp_funcs && pp_funcs->set_powergating_by_smu) {
+			for (int i = 0; i < adev->vcn.num_vcn_inst; i++)
+				ret = (pp_funcs->set_powergating_by_smu(
+					(adev)->powerplay.pp_handle, block_type, gate, i));
+		}
 		break;
 	default:
 		break;
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
index 2cd6cb991f29..af7da780b58b 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
@@ -3287,7 +3287,9 @@ static int kv_dpm_read_sensor(void *handle, int idx,
 }
 
 static int kv_set_powergating_by_smu(void *handle,
-				uint32_t block_type, bool gate)
+				uint32_t block_type,
+				bool gate,
+				int inst)
 {
 	switch (block_type) {
 	case AMD_IP_BLOCK_TYPE_UVD:
diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
index f193c77cc141..de5ee1c5503f 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
@@ -1241,7 +1241,9 @@ static void pp_dpm_powergate_sdma(void *handle, bool gate)
 }
 
 static int pp_set_powergating_by_smu(void *handle,
-				uint32_t block_type, bool gate)
+				uint32_t block_type,
+				bool gate,
+				int inst)
 {
 	int ret = 0;
 
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index 786241fa8d2c..0da84e390d0d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -353,10 +353,10 @@ static int smu_set_mall_enable(struct smu_context *smu)
  */
 static int smu_dpm_set_power_gate(void *handle,
 				  uint32_t block_type,
-				  bool gate)
+				  bool gate,
+				  int inst)
 {
 	struct smu_context *smu = handle;
-	struct amdgpu_device *adev = smu->adev;
 	int ret = 0;
 
 	if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) {
@@ -373,12 +373,10 @@ static int smu_dpm_set_power_gate(void *handle,
 	 */
 	case AMD_IP_BLOCK_TYPE_UVD:
 	case AMD_IP_BLOCK_TYPE_VCN:
-		for (int i = 0; i < adev->vcn.num_vcn_inst; i++) {
-			ret = smu_dpm_set_vcn_enable(smu, !gate, i);
-			if (ret)
-				dev_err(smu->adev->dev, "Failed to power %s VCN!\n",
-					gate ? "gate" : "ungate");
-		}
+		ret = smu_dpm_set_vcn_enable(smu, !gate, inst);
+		if (ret)
+			dev_err(smu->adev->dev, "Failed to power %s VCN!\n",
+				gate ? "gate" : "ungate");
 		break;
 	case AMD_IP_BLOCK_TYPE_GFX:
 		ret = smu_gfx_off_control(smu, gate);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 05/18] drm/amd/pm: add inst to amdgpu_dpm_set_powergating_by_smu
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (3 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 04/18] drm/amd/pm: add inst to set_powergating_by_smu boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 18:44 ` [PATCH 06/18] add inst to amdgpu_dpm_enable_vcn boyuan.zhang
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

Add an instance parameter to amdgpu_dpm_set_powergating_by_smu() function,
and use the instance to call set_powergating_by_smu().

v2: remove duplicated functions.

remove for-loop in amdgpu_dpm_set_powergating_by_smu(), and temporarily
move it to amdgpu_dpm_enable_vcn(), in order to keep the exact same logic
as before, until further separation in next patch.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c    | 14 +++---
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c |  2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c    |  4 +-
 drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c      |  2 +-
 drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c    |  2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c     |  4 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c      |  6 +--
 drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c      |  4 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c      |  4 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c      |  4 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c      |  4 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c    |  4 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c    |  4 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c    |  4 +-
 drivers/gpu/drm/amd/pm/amdgpu_dpm.c        | 51 +++++++++++++++++-----
 drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h    |  3 +-
 16 files changed, 73 insertions(+), 43 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
index 8e0725198dae..575826d220b8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
@@ -140,7 +140,7 @@ static int acp_poweroff(struct generic_pm_domain *genpd)
 	 * 2. power off the acp tiles
 	 * 3. check and enter ulv state
 	 */
-	amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
+	amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true, 0);
 	return 0;
 }
 
@@ -157,7 +157,7 @@ static int acp_poweron(struct generic_pm_domain *genpd)
 	 * 2. turn on acp clock
 	 * 3. power on acp tiles
 	 */
-	amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
+	amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false, 0);
 	return 0;
 }
 
@@ -236,7 +236,7 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block)
 			    ip_block->version->major, ip_block->version->minor);
 	/* -ENODEV means board uses AZ rather than ACP */
 	if (r == -ENODEV) {
-		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
+		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true, 0);
 		return 0;
 	} else if (r) {
 		return r;
@@ -508,7 +508,7 @@ static int acp_hw_fini(struct amdgpu_ip_block *ip_block)
 
 	/* return early if no ACP */
 	if (!adev->acp.acp_genpd) {
-		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
+		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false, 0);
 		return 0;
 	}
 
@@ -565,7 +565,7 @@ static int acp_suspend(struct amdgpu_ip_block *ip_block)
 
 	/* power up on suspend */
 	if (!adev->acp.acp_cell)
-		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
+		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false, 0);
 	return 0;
 }
 
@@ -575,7 +575,7 @@ static int acp_resume(struct amdgpu_ip_block *ip_block)
 
 	/* power down again on resume */
 	if (!adev->acp.acp_cell)
-		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
+		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true, 0);
 	return 0;
 }
 
@@ -606,7 +606,7 @@ static int acp_set_powergating_state(void *handle,
 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 	bool enable = (state == AMD_PG_STATE_GATE);
 
-	amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, enable);
+	amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, enable, 0);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 38a7423101f3..dbe4c26f63e6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -3425,7 +3425,7 @@ static void amdgpu_device_delay_enable_gfx_off(struct work_struct *work)
 	WARN_ON_ONCE(adev->gfx.gfx_off_state);
 	WARN_ON_ONCE(adev->gfx.gfx_off_req_count);
 
-	if (!amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, true))
+	if (!amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, true, 0))
 		adev->gfx.gfx_off_state = true;
 }
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
index 2fe75c920a73..94ca2da07cec 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -787,7 +787,7 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable)
 			/* If going to s2idle, no need to wait */
 			if (adev->in_s0ix) {
 				if (!amdgpu_dpm_set_powergating_by_smu(adev,
-						AMD_IP_BLOCK_TYPE_GFX, true))
+						AMD_IP_BLOCK_TYPE_GFX, true, 0))
 					adev->gfx.gfx_off_state = true;
 			} else {
 				schedule_delayed_work(&adev->gfx.gfx_off_delay_work,
@@ -799,7 +799,7 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable)
 			cancel_delayed_work_sync(&adev->gfx.gfx_off_delay_work);
 
 			if (adev->gfx.gfx_off_state &&
-			    !amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, false)) {
+			    !amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, false, 0)) {
 				adev->gfx.gfx_off_state = false;
 
 				if (adev->gfx.funcs->init_spm_golden) {
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index 88acf34e16fc..cb59ba3a6d1b 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -5314,7 +5314,7 @@ static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *ade
 	    (adev->asic_type == CHIP_POLARIS12) ||
 	    (adev->asic_type == CHIP_VEGAM))
 		/* Send msg to SMU via Powerplay */
-		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, enable);
+		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, enable, 0);
 
 	WREG32_FIELD(RLC_PG_CNTL, STATIC_PER_CU_PG_ENABLE, enable ? 1 : 0);
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
index e3ddd22aa172..21e66f81c5c2 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
@@ -307,7 +307,7 @@ static void mmhub_v1_0_update_power_gating(struct amdgpu_device *adev,
 	if (adev->pg_flags & AMD_PG_SUPPORT_MMHUB)
 		amdgpu_dpm_set_powergating_by_smu(adev,
 						  AMD_IP_BLOCK_TYPE_GMC,
-						  enable);
+						  enable, 0);
 }
 
 static int mmhub_v1_0_gart_enable(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
index c1f98f6cf20d..3f5959557727 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
@@ -1956,7 +1956,7 @@ static int sdma_v4_0_hw_init(struct amdgpu_ip_block *ip_block)
 	struct amdgpu_device *adev = ip_block->adev;
 
 	if (adev->flags & AMD_IS_APU)
-		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_SDMA, false);
+		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_SDMA, false, 0);
 
 	if (!amdgpu_sriov_vf(adev))
 		sdma_v4_0_init_golden_registers(adev);
@@ -1983,7 +1983,7 @@ static int sdma_v4_0_hw_fini(struct amdgpu_ip_block *ip_block)
 	sdma_v4_0_enable(adev, false);
 
 	if (adev->flags & AMD_IS_APU)
-		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_SDMA, true);
+		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_SDMA, true, 0);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
index 129c759772c2..746b3d282ca3 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
@@ -303,7 +303,7 @@ static int vcn_v1_0_suspend(struct amdgpu_ip_block *ip_block)
 	idle_work_unexecuted = cancel_delayed_work_sync(&adev->vcn.idle_work);
 	if (idle_work_unexecuted) {
 		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_uvd(adev, false);
+			amdgpu_dpm_enable_vcn(adev, false);
 	}
 
 	r = vcn_v1_0_hw_fini(ip_block);
@@ -1856,7 +1856,7 @@ static void vcn_v1_0_idle_work_handler(struct work_struct *work)
 	if (fences == 0) {
 		amdgpu_gfx_off_ctrl(adev, true);
 		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_uvd(adev, false);
+			amdgpu_dpm_enable_vcn(adev, false);
 		else
 			amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN,
 			       AMD_PG_STATE_GATE);
@@ -1886,7 +1886,7 @@ void vcn_v1_0_set_pg_for_begin_use(struct amdgpu_ring *ring, bool set_clocks)
 	if (set_clocks) {
 		amdgpu_gfx_off_ctrl(adev, false);
 		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_uvd(adev, true);
+			amdgpu_dpm_enable_vcn(adev, true);
 		else
 			amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN,
 			       AMD_PG_STATE_UNGATE);
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
index 19bbd49f760e..d0c3895dcf6b 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
@@ -978,7 +978,7 @@ static int vcn_v2_0_start(struct amdgpu_device *adev)
 	int i, j, r;
 
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_uvd(adev, true);
+		amdgpu_dpm_enable_vcn(adev, true);
 
 	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
 		return vcn_v2_0_start_dpg_mode(adev, adev->vcn.indirect_sram);
@@ -1235,7 +1235,7 @@ static int vcn_v2_0_stop(struct amdgpu_device *adev)
 
 power_off:
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_uvd(adev, false);
+		amdgpu_dpm_enable_vcn(adev, false);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
index 30420ead7fc4..d4c062983bfe 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
@@ -1013,7 +1013,7 @@ static int vcn_v2_5_start(struct amdgpu_device *adev)
 	int i, j, k, r;
 
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_uvd(adev, true);
+		amdgpu_dpm_enable_vcn(adev, true);
 
 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
 		if (adev->vcn.harvest_config & (1 << i))
@@ -1486,7 +1486,7 @@ static int vcn_v2_5_stop(struct amdgpu_device *adev)
 	}
 
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_uvd(adev, false);
+		amdgpu_dpm_enable_vcn(adev, false);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
index 13632c22d2f9..1da9a7dfb667 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
@@ -1142,7 +1142,7 @@ static int vcn_v3_0_start(struct amdgpu_device *adev)
 	int i, j, k, r;
 
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_uvd(adev, true);
+		amdgpu_dpm_enable_vcn(adev, true);
 
 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
 		if (adev->vcn.harvest_config & (1 << i))
@@ -1633,7 +1633,7 @@ static int vcn_v3_0_stop(struct amdgpu_device *adev)
 	}
 
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_uvd(adev, false);
+		amdgpu_dpm_enable_vcn(adev, false);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index e7b7a8150ea7..a04a64442809 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -1089,7 +1089,7 @@ static int vcn_v4_0_start(struct amdgpu_device *adev)
 	int i, j, k, r;
 
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_uvd(adev, true);
+		amdgpu_dpm_enable_vcn(adev, true);
 
 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
 		if (adev->vcn.harvest_config & (1 << i))
@@ -1615,7 +1615,7 @@ static int vcn_v4_0_stop(struct amdgpu_device *adev)
 	}
 
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_uvd(adev, false);
+		amdgpu_dpm_enable_vcn(adev, false);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
index 6dcae398b2dc..d433d2703995 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
@@ -1092,7 +1092,7 @@ static int vcn_v4_0_3_start(struct amdgpu_device *adev)
 	uint32_t tmp;
 
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_uvd(adev, true);
+		amdgpu_dpm_enable_vcn(adev, true);
 
 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
 		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
@@ -1366,7 +1366,7 @@ static int vcn_v4_0_3_stop(struct amdgpu_device *adev)
 	}
 Done:
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_uvd(adev, false);
+		amdgpu_dpm_enable_vcn(adev, false);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
index edb9cd8390b6..133ebb3c14db 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
@@ -1001,7 +1001,7 @@ static int vcn_v4_0_5_start(struct amdgpu_device *adev)
 	int i, j, k, r;
 
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_uvd(adev, true);
+		amdgpu_dpm_enable_vcn(adev, true);
 
 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
 		if (adev->vcn.harvest_config & (1 << i))
@@ -1278,7 +1278,7 @@ static int vcn_v4_0_5_stop(struct amdgpu_device *adev)
 	}
 
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_uvd(adev, false);
+		amdgpu_dpm_enable_vcn(adev, false);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
index 89bf29fa6f8d..c57894f1734a 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
@@ -762,7 +762,7 @@ static int vcn_v5_0_0_start(struct amdgpu_device *adev)
 	int i, j, k, r;
 
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_uvd(adev, true);
+		amdgpu_dpm_enable_vcn(adev, true);
 
 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
 		if (adev->vcn.harvest_config & (1 << i))
@@ -1009,7 +1009,7 @@ static int vcn_v5_0_0_stop(struct amdgpu_device *adev)
 	}
 
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_uvd(adev, false);
+		amdgpu_dpm_enable_vcn(adev, false);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
index bcedbeec082f..8531e0993b17 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
@@ -70,13 +70,18 @@ int amdgpu_dpm_get_mclk(struct amdgpu_device *adev, bool low)
 	return ret;
 }
 
-int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, uint32_t block_type, bool gate)
+int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev,
+				       uint32_t block_type,
+				       bool gate,
+				       int inst)
 {
 	int ret = 0;
 	const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
 	enum ip_power_state pwr_state = gate ? POWER_STATE_OFF : POWER_STATE_ON;
+	bool is_vcn = (block_type == AMD_IP_BLOCK_TYPE_UVD || block_type == AMD_IP_BLOCK_TYPE_VCN);
 
-	if (atomic_read(&adev->pm.pwr_state[block_type]) == pwr_state) {
+	if (atomic_read(&adev->pm.pwr_state[block_type]) == pwr_state &&
+			(!is_vcn || adev->vcn.num_vcn_inst == 1)) {
 		dev_dbg(adev->dev, "IP block%d already in the target %s state!",
 				block_type, gate ? "gate" : "ungate");
 		return 0;
@@ -98,11 +103,9 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, uint32_t block
 				(adev)->powerplay.pp_handle, block_type, gate, 0));
 		break;
 	case AMD_IP_BLOCK_TYPE_VCN:
-		if (pp_funcs && pp_funcs->set_powergating_by_smu) {
-			for (int i = 0; i < adev->vcn.num_vcn_inst; i++)
-				ret = (pp_funcs->set_powergating_by_smu(
-					(adev)->powerplay.pp_handle, block_type, gate, i));
-		}
+		if (pp_funcs && pp_funcs->set_powergating_by_smu)
+			ret = (pp_funcs->set_powergating_by_smu(
+				(adev)->powerplay.pp_handle, block_type, gate, inst));
 		break;
 	default:
 		break;
@@ -572,12 +575,38 @@ void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable)
 		return;
 	}
 
-	ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_UVD, !enable);
+	ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_UVD, !enable, 0);
 	if (ret)
 		DRM_ERROR("Dpm %s uvd failed, ret = %d. \n",
 			  enable ? "enable" : "disable", ret);
 }
 
+void amdgpu_dpm_enable_vcn(struct amdgpu_device *adev, bool enable)
+{
+	int ret = 0;
+
+	if (adev->family == AMDGPU_FAMILY_SI) {
+		mutex_lock(&adev->pm.mutex);
+		if (enable) {
+			adev->pm.dpm.uvd_active = true;
+			adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD;
+		} else {
+			adev->pm.dpm.uvd_active = false;
+		}
+		mutex_unlock(&adev->pm.mutex);
+
+		amdgpu_dpm_compute_clocks(adev);
+		return;
+	}
+
+	for (int i = 0; i < adev->vcn.num_vcn_inst; i++) {
+		ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCN, !enable, i);
+		if (ret)
+			DRM_ERROR("Dpm %s uvd failed, ret = %d. \n",
+				  enable ? "enable" : "disable", ret);
+	}
+}
+
 void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable)
 {
 	int ret = 0;
@@ -597,7 +626,7 @@ void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable)
 		return;
 	}
 
-	ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCE, !enable);
+	ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCE, !enable, 0);
 	if (ret)
 		DRM_ERROR("Dpm %s vce failed, ret = %d. \n",
 			  enable ? "enable" : "disable", ret);
@@ -607,7 +636,7 @@ void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable)
 {
 	int ret = 0;
 
-	ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_JPEG, !enable);
+	ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_JPEG, !enable, 0);
 	if (ret)
 		DRM_ERROR("Dpm %s jpeg failed, ret = %d. \n",
 			  enable ? "enable" : "disable", ret);
@@ -617,7 +646,7 @@ void amdgpu_dpm_enable_vpe(struct amdgpu_device *adev, bool enable)
 {
 	int ret = 0;
 
-	ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VPE, !enable);
+	ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VPE, !enable, 0);
 	if (ret)
 		DRM_ERROR("Dpm %s vpe failed, ret = %d.\n",
 			  enable ? "enable" : "disable", ret);
diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
index f5bf41f21c41..e7c84d4a431a 100644
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
@@ -393,7 +393,7 @@ int amdgpu_dpm_get_apu_thermal_limit(struct amdgpu_device *adev, uint32_t *limit
 int amdgpu_dpm_set_apu_thermal_limit(struct amdgpu_device *adev, uint32_t limit);
 
 int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev,
-				      uint32_t block_type, bool gate);
+				      uint32_t block_type, bool gate, int inst);
 
 extern int amdgpu_dpm_get_sclk(struct amdgpu_device *adev, bool low);
 
@@ -442,6 +442,7 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev);
 
 void amdgpu_dpm_compute_clocks(struct amdgpu_device *adev);
 void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable);
+void amdgpu_dpm_enable_vcn(struct amdgpu_device *adev, bool enable);
 void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable);
 void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable);
 void amdgpu_dpm_enable_vpe(struct amdgpu_device *adev, bool enable);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 06/18] add inst to amdgpu_dpm_enable_vcn
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (4 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 05/18] drm/amd/pm: add inst to amdgpu_dpm_set_powergating_by_smu boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 18:44 ` [PATCH 07/18] drm/amdgpu: pass ip_block in set_powergating_state boyuan.zhang
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

Add an instance parameter to amdgpu_dpm_enable_vcn() function, and change
all calls from vcn ip functions to add instance argument. vcn generations
with only one instance (v1.0, v2.0) always use 0 as instance number. vcn
generations with multiple instances (v2.5, v3.0, v4.0, v4.0.3, v4.0.5,
v5.0.0) use the actual instance number.

v2: remove for-loop in amdgpu_dpm_enable_vcn(), and temporarily move it
to vcn ip with multiple instances, in order to keep the exact same logic
as before, until further separation in next patch.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c   |  6 +++---
 drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c   |  4 ++--
 drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c   | 12 ++++++++----
 drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c   | 12 ++++++++----
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c   | 12 ++++++++----
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 12 ++++++++----
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c | 12 ++++++++----
 drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c | 12 ++++++++----
 drivers/gpu/drm/amd/pm/amdgpu_dpm.c     | 12 +++++-------
 drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h |  2 +-
 10 files changed, 59 insertions(+), 37 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
index 746b3d282ca3..1d5b0f4e5b1a 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
@@ -303,7 +303,7 @@ static int vcn_v1_0_suspend(struct amdgpu_ip_block *ip_block)
 	idle_work_unexecuted = cancel_delayed_work_sync(&adev->vcn.idle_work);
 	if (idle_work_unexecuted) {
 		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, false);
+			amdgpu_dpm_enable_vcn(adev, false, 0);
 	}
 
 	r = vcn_v1_0_hw_fini(ip_block);
@@ -1856,7 +1856,7 @@ static void vcn_v1_0_idle_work_handler(struct work_struct *work)
 	if (fences == 0) {
 		amdgpu_gfx_off_ctrl(adev, true);
 		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, false);
+			amdgpu_dpm_enable_vcn(adev, false, 0);
 		else
 			amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN,
 			       AMD_PG_STATE_GATE);
@@ -1886,7 +1886,7 @@ void vcn_v1_0_set_pg_for_begin_use(struct amdgpu_ring *ring, bool set_clocks)
 	if (set_clocks) {
 		amdgpu_gfx_off_ctrl(adev, false);
 		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, true);
+			amdgpu_dpm_enable_vcn(adev, true, 0);
 		else
 			amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN,
 			       AMD_PG_STATE_UNGATE);
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
index d0c3895dcf6b..d87e5505cf51 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
@@ -978,7 +978,7 @@ static int vcn_v2_0_start(struct amdgpu_device *adev)
 	int i, j, r;
 
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_vcn(adev, true);
+		amdgpu_dpm_enable_vcn(adev, true, 0);
 
 	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
 		return vcn_v2_0_start_dpg_mode(adev, adev->vcn.indirect_sram);
@@ -1235,7 +1235,7 @@ static int vcn_v2_0_stop(struct amdgpu_device *adev)
 
 power_off:
 	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_vcn(adev, false);
+		amdgpu_dpm_enable_vcn(adev, false, 0);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
index d4c062983bfe..ad0922eb16c0 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
@@ -1012,8 +1012,10 @@ static int vcn_v2_5_start(struct amdgpu_device *adev)
 	uint32_t rb_bufsz, tmp;
 	int i, j, k, r;
 
-	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_vcn(adev, true);
+	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+		if (adev->pm.dpm_enabled)
+			amdgpu_dpm_enable_vcn(adev, true, i);
+	}
 
 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
 		if (adev->vcn.harvest_config & (1 << i))
@@ -1485,8 +1487,10 @@ static int vcn_v2_5_stop(struct amdgpu_device *adev)
 			~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
 	}
 
-	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_vcn(adev, false);
+	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+		if (adev->pm.dpm_enabled)
+			amdgpu_dpm_enable_vcn(adev, false, i);
+	}
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
index 1da9a7dfb667..19c7f9cd4c15 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
@@ -1141,8 +1141,10 @@ static int vcn_v3_0_start(struct amdgpu_device *adev)
 	uint32_t rb_bufsz, tmp;
 	int i, j, k, r;
 
-	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_vcn(adev, true);
+	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+		if (adev->pm.dpm_enabled)
+			amdgpu_dpm_enable_vcn(adev, true, i);
+	}
 
 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
 		if (adev->vcn.harvest_config & (1 << i))
@@ -1632,8 +1634,10 @@ static int vcn_v3_0_stop(struct amdgpu_device *adev)
 		vcn_v3_0_enable_static_power_gating(adev, i);
 	}
 
-	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_vcn(adev, false);
+	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+		if (adev->pm.dpm_enabled)
+			amdgpu_dpm_enable_vcn(adev, false, i);
+	}
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index a04a64442809..e97d7f4ae371 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -1088,8 +1088,10 @@ static int vcn_v4_0_start(struct amdgpu_device *adev)
 	uint32_t tmp;
 	int i, j, k, r;
 
-	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_vcn(adev, true);
+	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+		if (adev->pm.dpm_enabled)
+			amdgpu_dpm_enable_vcn(adev, true, i);
+	}
 
 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
 		if (adev->vcn.harvest_config & (1 << i))
@@ -1614,8 +1616,10 @@ static int vcn_v4_0_stop(struct amdgpu_device *adev)
 		vcn_v4_0_enable_static_power_gating(adev, i);
 	}
 
-	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_vcn(adev, false);
+	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+		if (adev->pm.dpm_enabled)
+			amdgpu_dpm_enable_vcn(adev, false, i);
+	}
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
index d433d2703995..ba22913398ec 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
@@ -1091,8 +1091,10 @@ static int vcn_v4_0_3_start(struct amdgpu_device *adev)
 	int i, j, k, r, vcn_inst;
 	uint32_t tmp;
 
-	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_vcn(adev, true);
+	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+		if (adev->pm.dpm_enabled)
+			amdgpu_dpm_enable_vcn(adev, true, i);
+	}
 
 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
 		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
@@ -1365,8 +1367,10 @@ static int vcn_v4_0_3_stop(struct amdgpu_device *adev)
 		vcn_v4_0_3_enable_clock_gating(adev, i);
 	}
 Done:
-	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_vcn(adev, false);
+	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+		if (adev->pm.dpm_enabled)
+			amdgpu_dpm_enable_vcn(adev, false, i);
+	}
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
index 133ebb3c14db..873672f64778 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
@@ -1000,8 +1000,10 @@ static int vcn_v4_0_5_start(struct amdgpu_device *adev)
 	uint32_t tmp;
 	int i, j, k, r;
 
-	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_vcn(adev, true);
+	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+		if (adev->pm.dpm_enabled)
+			amdgpu_dpm_enable_vcn(adev, true, i);
+	}
 
 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
 		if (adev->vcn.harvest_config & (1 << i))
@@ -1277,8 +1279,10 @@ static int vcn_v4_0_5_stop(struct amdgpu_device *adev)
 		vcn_v4_0_5_enable_static_power_gating(adev, i);
 	}
 
-	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_vcn(adev, false);
+	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+		if (adev->pm.dpm_enabled)
+			amdgpu_dpm_enable_vcn(adev, false, i);
+	}
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
index c57894f1734a..893e66c2b9a5 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
@@ -761,8 +761,10 @@ static int vcn_v5_0_0_start(struct amdgpu_device *adev)
 	uint32_t tmp;
 	int i, j, k, r;
 
-	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_vcn(adev, true);
+	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+		if (adev->pm.dpm_enabled)
+			amdgpu_dpm_enable_vcn(adev, true, i);
+	}
 
 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
 		if (adev->vcn.harvest_config & (1 << i))
@@ -1008,8 +1010,10 @@ static int vcn_v5_0_0_stop(struct amdgpu_device *adev)
 		vcn_v5_0_0_enable_static_power_gating(adev, i);
 	}
 
-	if (adev->pm.dpm_enabled)
-		amdgpu_dpm_enable_vcn(adev, false);
+	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+		if (adev->pm.dpm_enabled)
+			amdgpu_dpm_enable_vcn(adev, false, i);
+	}
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
index 8531e0993b17..5a9006bfc3cd 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
@@ -581,7 +581,7 @@ void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable)
 			  enable ? "enable" : "disable", ret);
 }
 
-void amdgpu_dpm_enable_vcn(struct amdgpu_device *adev, bool enable)
+void amdgpu_dpm_enable_vcn(struct amdgpu_device *adev, bool enable, int inst)
 {
 	int ret = 0;
 
@@ -599,12 +599,10 @@ void amdgpu_dpm_enable_vcn(struct amdgpu_device *adev, bool enable)
 		return;
 	}
 
-	for (int i = 0; i < adev->vcn.num_vcn_inst; i++) {
-		ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCN, !enable, i);
-		if (ret)
-			DRM_ERROR("Dpm %s uvd failed, ret = %d. \n",
-				  enable ? "enable" : "disable", ret);
-	}
+	ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCN, !enable, inst);
+	if (ret)
+		DRM_ERROR("Dpm %s uvd failed, ret = %d. \n",
+			  enable ? "enable" : "disable", ret);
 }
 
 void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable)
diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
index e7c84d4a431a..251b389dcf6e 100644
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
@@ -442,7 +442,7 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev);
 
 void amdgpu_dpm_compute_clocks(struct amdgpu_device *adev);
 void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable);
-void amdgpu_dpm_enable_vcn(struct amdgpu_device *adev, bool enable);
+void amdgpu_dpm_enable_vcn(struct amdgpu_device *adev, bool enable, int inst);
 void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable);
 void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable);
 void amdgpu_dpm_enable_vpe(struct amdgpu_device *adev, bool enable);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 07/18] drm/amdgpu: pass ip_block in set_powergating_state
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (5 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 06/18] add inst to amdgpu_dpm_enable_vcn boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 18:44 ` [PATCH 08/18] drm/amdgpu: track instances of the same IP block boyuan.zhang
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

Pass ip_block instead of adev in set_powergating_state callback function.
Modify set_powergating_state ip functions for all correspoding ip blocks.

v2: fix a ip block index error.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
Suggested-by: Christian König <christian.koenig@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c           |  4 ++--
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c        |  5 ++++-
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c        |  4 ++--
 drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c           |  2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c           |  2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c          |  2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c           |  4 ++--
 drivers/gpu/drm/amd/amdgpu/cik.c                  |  2 +-
 drivers/gpu/drm/amd/amdgpu/cik_ih.c               |  2 +-
 drivers/gpu/drm/amd/amdgpu/cik_sdma.c             |  2 +-
 drivers/gpu/drm/amd/amdgpu/cz_ih.c                |  2 +-
 drivers/gpu/drm/amd/amdgpu/dce_v10_0.c            |  2 +-
 drivers/gpu/drm/amd/amdgpu/dce_v11_0.c            |  2 +-
 drivers/gpu/drm/amd/amdgpu/dce_v6_0.c             |  2 +-
 drivers/gpu/drm/amd/amdgpu/dce_v8_0.c             |  2 +-
 drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c            |  8 ++++----
 drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c            |  4 ++--
 drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c            |  4 ++--
 drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c             |  4 ++--
 drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c             |  4 ++--
 drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c             |  4 ++--
 drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c             |  4 ++--
 drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c           |  2 +-
 drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c            |  2 +-
 drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c            |  2 +-
 drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c            |  2 +-
 drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c             |  2 +-
 drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c             |  2 +-
 drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c             |  2 +-
 drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c             |  2 +-
 drivers/gpu/drm/amd/amdgpu/iceland_ih.c           |  2 +-
 drivers/gpu/drm/amd/amdgpu/ih_v6_0.c              |  4 ++--
 drivers/gpu/drm/amd/amdgpu/ih_v6_1.c              |  4 ++--
 drivers/gpu/drm/amd/amdgpu/ih_v7_0.c              |  4 ++--
 drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c            |  8 ++++----
 drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c            |  8 ++++----
 drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c            |  8 ++++----
 drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c            |  8 ++++----
 drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c          |  8 ++++----
 drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c          |  8 ++++----
 drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c          |  8 ++++----
 drivers/gpu/drm/amd/amdgpu/navi10_ih.c            |  2 +-
 drivers/gpu/drm/amd/amdgpu/nv.c                   |  2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c            |  2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c            |  2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c            |  4 ++--
 drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c          |  2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c            |  2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c            |  2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c            |  2 +-
 drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c            |  2 +-
 drivers/gpu/drm/amd/amdgpu/si.c                   |  2 +-
 drivers/gpu/drm/amd/amdgpu/si_dma.c               |  4 ++--
 drivers/gpu/drm/amd/amdgpu/si_ih.c                |  2 +-
 drivers/gpu/drm/amd/amdgpu/soc15.c                |  2 +-
 drivers/gpu/drm/amd/amdgpu/soc21.c                |  4 ++--
 drivers/gpu/drm/amd/amdgpu/soc24.c                |  4 ++--
 drivers/gpu/drm/amd/amdgpu/tonga_ih.c             |  2 +-
 drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c             |  2 +-
 drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c             |  4 ++--
 drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c             |  4 ++--
 drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c             |  4 ++--
 drivers/gpu/drm/amd/amdgpu/vce_v2_0.c             |  4 ++--
 drivers/gpu/drm/amd/amdgpu/vce_v3_0.c             |  4 ++--
 drivers/gpu/drm/amd/amdgpu/vce_v4_0.c             |  4 ++--
 drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c             |  9 +++++----
 drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c             |  8 ++++----
 drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c             | 11 ++++++-----
 drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c             | 12 ++++++------
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c             | 13 +++++++------
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c           |  8 ++++----
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c           |  9 +++++----
 drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c           |  9 +++++----
 drivers/gpu/drm/amd/amdgpu/vega10_ih.c            |  2 +-
 drivers/gpu/drm/amd/amdgpu/vega20_ih.c            |  2 +-
 drivers/gpu/drm/amd/amdgpu/vi.c                   |  2 +-
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  2 +-
 drivers/gpu/drm/amd/include/amd_shared.h          |  2 +-
 drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c        |  2 +-
 drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c        |  2 +-
 drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c  |  2 +-
 drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c         |  2 +-
 82 files changed, 165 insertions(+), 157 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
index 575826d220b8..64828cb7c2f1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
@@ -600,10 +600,10 @@ static int acp_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int acp_set_powergating_state(void *handle,
+static int acp_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				     enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	bool enable = (state == AMD_PG_STATE_GATE);
 
 	amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, enable, 0);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index b545940e512b..dd3ae5d74436 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -724,7 +724,10 @@ void amdgpu_amdkfd_set_compute_idle(struct amdgpu_device *adev, bool idle)
 		/* Disable GFXOFF and PG. Temporary workaround
 		 * to fix some compute applications issue on GFX9.
 		 */
-		adev->ip_blocks[AMD_IP_BLOCK_TYPE_GFX].version->funcs->set_powergating_state((void *)adev, state);
+		for (int i = 0; i < adev->num_ip_blocks; i++) {
+			if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX)
+				adev->ip_blocks[i].version->funcs->set_powergating_state((void *)&adev->ip_blocks[i], state);
+		}
 	}
 	amdgpu_dpm_switch_power_profile(adev,
 					PP_SMC_POWER_PROFILE_COMPUTE,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index dbe4c26f63e6..fe5de35eef64 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -2154,7 +2154,7 @@ int amdgpu_device_ip_set_powergating_state(void *dev,
 		if (!adev->ip_blocks[i].version->funcs->set_powergating_state)
 			continue;
 		r = adev->ip_blocks[i].version->funcs->set_powergating_state(
-			(void *)adev, state);
+			(void *)&adev->ip_blocks[i], state);
 		if (r)
 			DRM_ERROR("set_powergating_state of IP block <%s> failed %d\n",
 				  adev->ip_blocks[i].version->funcs->name, r);
@@ -3128,7 +3128,7 @@ int amdgpu_device_set_pg_state(struct amdgpu_device *adev,
 		    adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_JPEG &&
 		    adev->ip_blocks[i].version->funcs->set_powergating_state) {
 			/* enable powergating to save power */
-			r = adev->ip_blocks[i].version->funcs->set_powergating_state((void *)adev,
+			r = adev->ip_blocks[i].version->funcs->set_powergating_state((void *)&adev->ip_blocks[i],
 											state);
 			if (r) {
 				DRM_ERROR("set_powergating_state(gate) of IP block <%s> failed %d\n",
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
index adc0b80ca5db..844f71eeea27 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c
@@ -164,7 +164,7 @@ static int isp_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int isp_set_powergating_state(void *handle,
+static int isp_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				     enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
index 8ef6bf7c6b65..527470323c33 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
@@ -3793,7 +3793,7 @@ static int psp_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int psp_set_powergating_state(void *handle,
+static int psp_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				     enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
index fd31e2e9feb9..f44ce5edba6a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
@@ -647,7 +647,7 @@ static int amdgpu_vkms_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int amdgpu_vkms_set_powergating_state(void *handle,
+static int amdgpu_vkms_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c
index 6d96e1f21e20..f3a9ea3f6044 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c
@@ -644,10 +644,10 @@ static int vpe_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int vpe_set_powergating_state(void *handle,
+static int vpe_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				     enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	struct amdgpu_vpe *vpe = &adev->vpe;
 
 	if (!adev->pm.dpm_enabled)
diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c
index 6c18ab35cf69..08b398aa6c6d 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik.c
@@ -2185,7 +2185,7 @@ static int cik_common_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int cik_common_set_powergating_state(void *handle,
+static int cik_common_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					    enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_ih.c b/drivers/gpu/drm/amd/amdgpu/cik_ih.c
index 9e9a58fd86ce..42c3eb8b6a95 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik_ih.c
@@ -408,7 +408,7 @@ static int cik_ih_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int cik_ih_set_powergating_state(void *handle,
+static int cik_ih_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
index df3f429e003e..5283b0e94f02 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
@@ -1204,7 +1204,7 @@ static int cik_sdma_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int cik_sdma_set_powergating_state(void *handle,
+static int cik_sdma_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ih.c b/drivers/gpu/drm/amd/amdgpu/cz_ih.c
index cadd69a243af..4bf5402bd3aa 100644
--- a/drivers/gpu/drm/amd/amdgpu/cz_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/cz_ih.c
@@ -405,7 +405,7 @@ static int cz_ih_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int cz_ih_set_powergating_state(void *handle,
+static int cz_ih_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	// TODO
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
index 2d0a24a343f7..e7505934cce2 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
@@ -3313,7 +3313,7 @@ static int dce_v10_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int dce_v10_0_set_powergating_state(void *handle,
+static int dce_v10_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
index 386ece7bc389..8adee675f4d5 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
@@ -3445,7 +3445,7 @@ static int dce_v11_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int dce_v11_0_set_powergating_state(void *handle,
+static int dce_v11_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
index cd3e0118988d..66cb19f9b073 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
@@ -3135,7 +3135,7 @@ static int dce_v6_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int dce_v6_0_set_powergating_state(void *handle,
+static int dce_v6_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
index 295bc1d47095..57a5207b4e76 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
@@ -3223,7 +3223,7 @@ static int dce_v8_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int dce_v8_0_set_powergating_state(void *handle,
+static int dce_v8_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
index bf5c739c7058..b5da9a1e8216 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
@@ -3673,7 +3673,7 @@ static void gfx_v10_0_ring_invalidate_tlbs(struct amdgpu_ring *ring,
 static void gfx_v10_0_update_spm_vmid_internal(struct amdgpu_device *adev,
 					       unsigned int vmid);
 
-static int gfx_v10_0_set_powergating_state(void *handle,
+static int gfx_v10_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state);
 static void gfx10_kiq_set_resources(struct amdgpu_ring *kiq_ring, uint64_t queue_mask)
 {
@@ -7451,7 +7451,7 @@ static int gfx_v10_0_hw_fini(struct amdgpu_ip_block *ip_block)
 	 * otherwise the gfxoff disallowing will be failed to set.
 	 */
 	if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(10, 3, 1))
-		gfx_v10_0_set_powergating_state(ip_block->adev, AMD_PG_STATE_UNGATE);
+		gfx_v10_0_set_powergating_state(ip_block, AMD_PG_STATE_UNGATE);
 
 	if (!adev->no_hw_access) {
 		if (amdgpu_async_gfx_ring) {
@@ -8339,10 +8339,10 @@ static const struct amdgpu_rlc_funcs gfx_v10_0_rlc_funcs_sriov = {
 	.is_rlcg_access_range = gfx_v10_0_is_rlcg_access_range,
 };
 
-static int gfx_v10_0_set_powergating_state(void *handle,
+static int gfx_v10_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	bool enable = (state == AMD_PG_STATE_GATE);
 
 	if (amdgpu_sriov_vf(adev))
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
index c78a63da8d2e..92786e3bbf0e 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
@@ -5424,10 +5424,10 @@ static void gfx_v11_cntl_pg(struct amdgpu_device *adev, bool enable)
 	amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
 }
 
-static int gfx_v11_0_set_powergating_state(void *handle,
+static int gfx_v11_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					   enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	bool enable = (state == AMD_PG_STATE_GATE);
 
 	if (amdgpu_sriov_vf(adev))
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
index dc25fcb89b13..4ff78c9e3e43 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
@@ -3846,10 +3846,10 @@ static void gfx_v12_cntl_pg(struct amdgpu_device *adev, bool enable)
 }
 #endif
 
-static int gfx_v12_0_set_powergating_state(void *handle,
+static int gfx_v12_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					   enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	bool enable = (state == AMD_PG_STATE_GATE);
 
 	if (amdgpu_sriov_vf(adev))
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index 6ac6d4dfa49f..429aa895d6bf 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -3400,11 +3400,11 @@ static int gfx_v6_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int gfx_v6_0_set_powergating_state(void *handle,
+static int gfx_v6_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	bool gate = false;
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 
 	if (state == AMD_PG_STATE_GATE)
 		gate = true;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
index 77150c9f1e18..7c04dccec8d7 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
@@ -4869,11 +4869,11 @@ static int gfx_v7_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int gfx_v7_0_set_powergating_state(void *handle,
+static int gfx_v7_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	bool gate = false;
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 
 	if (state == AMD_PG_STATE_GATE)
 		gate = true;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index cb59ba3a6d1b..22ada2ede46b 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -5360,10 +5360,10 @@ static void cz_update_gfx_cg_power_gating(struct amdgpu_device *adev,
 	}
 }
 
-static int gfx_v8_0_set_powergating_state(void *handle,
+static int gfx_v8_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	bool enable = (state == AMD_PG_STATE_GATE);
 
 	if (amdgpu_sriov_vf(adev))
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
index d85b2968a7cf..6516e88c55aa 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
@@ -5214,10 +5214,10 @@ static const struct amdgpu_rlc_funcs gfx_v9_0_rlc_funcs = {
 	.is_rlcg_access_range = gfx_v9_0_is_rlcg_access_range,
 };
 
-static int gfx_v9_0_set_powergating_state(void *handle,
+static int gfx_v9_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	bool enable = (state == AMD_PG_STATE_GATE);
 
 	switch (amdgpu_ip_version(adev, GC_HWIP, 0)) {
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
index 7d425d2e7ab0..627652cab308 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
@@ -2760,7 +2760,7 @@ static const struct amdgpu_rlc_funcs gfx_v9_4_3_rlc_funcs = {
 	.is_rlcg_access_range = gfx_v9_4_3_is_rlcg_access_range,
 };
 
-static int gfx_v9_4_3_set_powergating_state(void *handle,
+static int gfx_v9_4_3_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
index 5cf2002fcba8..b398021d5b90 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
@@ -1133,7 +1133,7 @@ static void gmc_v10_0_get_clockgating_state(void *handle, u64 *flags)
 		athub_v2_0_get_clockgating(adev, flags);
 }
 
-static int gmc_v10_0_set_powergating_state(void *handle,
+static int gmc_v10_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					   enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
index 4df4d73038f8..36e2f4e5a865 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
@@ -1020,7 +1020,7 @@ static void gmc_v11_0_get_clockgating_state(void *handle, u64 *flags)
 	athub_v3_0_get_clockgating(adev, flags);
 }
 
-static int gmc_v11_0_set_powergating_state(void *handle,
+static int gmc_v11_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					   enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
index e33f9e9058cc..c6510f12afb4 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
@@ -1004,7 +1004,7 @@ static void gmc_v12_0_get_clockgating_state(void *handle, u64 *flags)
 	athub_v4_1_0_get_clockgating(adev, flags);
 }
 
-static int gmc_v12_0_set_powergating_state(void *handle,
+static int gmc_v12_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					   enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
index c1e2f1d79e74..3965b9ca8e9c 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
@@ -1100,7 +1100,7 @@ static int gmc_v6_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int gmc_v6_0_set_powergating_state(void *handle,
+static int gmc_v6_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
index 54a48662f3b5..b43eaa42e5c7 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
@@ -1327,7 +1327,7 @@ static int gmc_v7_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int gmc_v7_0_set_powergating_state(void *handle,
+static int gmc_v7_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
index c4f2ad32c078..d36cf90d4133 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
@@ -1679,7 +1679,7 @@ static int gmc_v8_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int gmc_v8_0_set_powergating_state(void *handle,
+static int gmc_v8_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
index 94600e5c8ea3..5aac51d9db2f 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -2485,7 +2485,7 @@ static void gmc_v9_0_get_clockgating_state(void *handle, u64 *flags)
 	athub_v1_0_get_clockgating(adev, flags);
 }
 
-static int gmc_v9_0_set_powergating_state(void *handle,
+static int gmc_v9_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
index a3fb01f905d4..879d34e88014 100644
--- a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c
@@ -398,7 +398,7 @@ static int iceland_ih_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int iceland_ih_set_powergating_state(void *handle,
+static int iceland_ih_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c b/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c
index 09403eac483b..4f271d9f43ba 100644
--- a/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c
@@ -756,10 +756,10 @@ static void ih_v6_0_update_ih_mem_power_gating(struct amdgpu_device *adev,
 	WREG32_SOC15(OSSSYS, 0, regIH_MEM_POWER_CTRL, ih_mem_pwr_cntl);
 }
 
-static int ih_v6_0_set_powergating_state(void *handle,
+static int ih_v6_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					 enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	bool enable = (state == AMD_PG_STATE_GATE);
 
 	if (adev->pg_flags & AMD_PG_SUPPORT_IH_SRAM_PG)
diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c b/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c
index 9706d7593d26..5b0a1eaa1fd0 100644
--- a/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c
@@ -737,10 +737,10 @@ static void ih_v6_1_update_ih_mem_power_gating(struct amdgpu_device *adev,
 	WREG32_SOC15(OSSSYS, 0, regIH_MEM_POWER_CTRL, ih_mem_pwr_cntl);
 }
 
-static int ih_v6_1_set_powergating_state(void *handle,
+static int ih_v6_1_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					 enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	bool enable = (state == AMD_PG_STATE_GATE);
 
 	if (adev->pg_flags & AMD_PG_SUPPORT_IH_SRAM_PG)
diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c b/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c
index 9657145d7cce..a584863f1bed 100644
--- a/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c
@@ -727,10 +727,10 @@ static void ih_v7_0_update_ih_mem_power_gating(struct amdgpu_device *adev,
 	WREG32_SOC15(OSSSYS, 0, regIH_MEM_POWER_CTRL, ih_mem_pwr_cntl);
 }
 
-static int ih_v7_0_set_powergating_state(void *handle,
+static int ih_v7_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					 enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	bool enable = (state == AMD_PG_STATE_GATE);
 
 	if (adev->pg_flags & AMD_PG_SUPPORT_IH_SRAM_PG)
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
index 6762b5c64ccb..c5f692a45bee 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
@@ -35,7 +35,7 @@
 
 static void jpeg_v2_0_set_dec_ring_funcs(struct amdgpu_device *adev);
 static void jpeg_v2_0_set_irq_funcs(struct amdgpu_device *adev);
-static int jpeg_v2_0_set_powergating_state(void *handle,
+static int jpeg_v2_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				enum amd_powergating_state state);
 
 /**
@@ -154,7 +154,7 @@ static int jpeg_v2_0_hw_fini(struct amdgpu_ip_block *ip_block)
 
 	if (adev->jpeg.cur_state != AMD_PG_STATE_GATE &&
 	      RREG32_SOC15(JPEG, 0, mmUVD_JRBC_STATUS))
-		jpeg_v2_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
+		jpeg_v2_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 
 	return 0;
 }
@@ -692,10 +692,10 @@ static int jpeg_v2_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int jpeg_v2_0_set_powergating_state(void *handle,
+static int jpeg_v2_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret;
 
 	if (state == adev->jpeg.cur_state)
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
index 4b8c801f204d..f1ddef8e60ee 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
@@ -38,7 +38,7 @@
 
 static void jpeg_v2_5_set_dec_ring_funcs(struct amdgpu_device *adev);
 static void jpeg_v2_5_set_irq_funcs(struct amdgpu_device *adev);
-static int jpeg_v2_5_set_powergating_state(void *handle,
+static int jpeg_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				enum amd_powergating_state state);
 static void jpeg_v2_5_set_ras_funcs(struct amdgpu_device *adev);
 
@@ -219,7 +219,7 @@ static int jpeg_v2_5_hw_fini(struct amdgpu_ip_block *ip_block)
 
 		if (adev->jpeg.cur_state != AMD_PG_STATE_GATE &&
 		      RREG32_SOC15(JPEG, i, mmUVD_JRBC_STATUS))
-			jpeg_v2_5_set_powergating_state(adev, AMD_PG_STATE_GATE);
+			jpeg_v2_5_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 
 		if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__JPEG))
 			amdgpu_irq_put(adev, &adev->jpeg.inst[i].ras_poison_irq, 0);
@@ -541,10 +541,10 @@ static int jpeg_v2_5_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int jpeg_v2_5_set_powergating_state(void *handle,
+static int jpeg_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret;
 
 	if (state == adev->jpeg.cur_state)
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
index 7996209818b6..69f0a9006b96 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
@@ -36,7 +36,7 @@
 
 static void jpeg_v3_0_set_dec_ring_funcs(struct amdgpu_device *adev);
 static void jpeg_v3_0_set_irq_funcs(struct amdgpu_device *adev);
-static int jpeg_v3_0_set_powergating_state(void *handle,
+static int jpeg_v3_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				enum amd_powergating_state state);
 
 /**
@@ -168,7 +168,7 @@ static int jpeg_v3_0_hw_fini(struct amdgpu_ip_block *ip_block)
 
 	if (adev->jpeg.cur_state != AMD_PG_STATE_GATE &&
 	      RREG32_SOC15(JPEG, 0, mmUVD_JRBC_STATUS))
-		jpeg_v3_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
+		jpeg_v3_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 
 	return 0;
 }
@@ -483,10 +483,10 @@ static int jpeg_v3_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int jpeg_v3_0_set_powergating_state(void *handle,
+static int jpeg_v3_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret;
 
 	if(state == adev->jpeg.cur_state)
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
index 20e1fe89c463..e304108d7024 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
@@ -39,7 +39,7 @@
 static int jpeg_v4_0_start_sriov(struct amdgpu_device *adev);
 static void jpeg_v4_0_set_dec_ring_funcs(struct amdgpu_device *adev);
 static void jpeg_v4_0_set_irq_funcs(struct amdgpu_device *adev);
-static int jpeg_v4_0_set_powergating_state(void *handle,
+static int jpeg_v4_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				enum amd_powergating_state state);
 static void jpeg_v4_0_set_ras_funcs(struct amdgpu_device *adev);
 
@@ -199,7 +199,7 @@ static int jpeg_v4_0_hw_fini(struct amdgpu_ip_block *ip_block)
 	if (!amdgpu_sriov_vf(adev)) {
 		if (adev->jpeg.cur_state != AMD_PG_STATE_GATE &&
 			RREG32_SOC15(JPEG, 0, regUVD_JRBC_STATUS))
-			jpeg_v4_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
+			jpeg_v4_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 	}
 	if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__JPEG))
 		amdgpu_irq_put(adev, &adev->jpeg.inst->ras_poison_irq, 0);
@@ -645,10 +645,10 @@ static int jpeg_v4_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int jpeg_v4_0_set_powergating_state(void *handle,
+static int jpeg_v4_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret;
 
 	if (amdgpu_sriov_vf(adev)) {
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
index 2a53537db135..f4d6a4768ee2 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
@@ -43,7 +43,7 @@ enum jpeg_engin_status {
 
 static void jpeg_v4_0_3_set_dec_ring_funcs(struct amdgpu_device *adev);
 static void jpeg_v4_0_3_set_irq_funcs(struct amdgpu_device *adev);
-static int jpeg_v4_0_3_set_powergating_state(void *handle,
+static int jpeg_v4_0_3_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				enum amd_powergating_state state);
 static void jpeg_v4_0_3_set_ras_funcs(struct amdgpu_device *adev);
 static void jpeg_v4_0_3_dec_ring_set_wptr(struct amdgpu_ring *ring);
@@ -371,7 +371,7 @@ static int jpeg_v4_0_3_hw_fini(struct amdgpu_ip_block *ip_block)
 
 	if (!amdgpu_sriov_vf(adev)) {
 		if (adev->jpeg.cur_state != AMD_PG_STATE_GATE)
-			ret = jpeg_v4_0_3_set_powergating_state(adev, AMD_PG_STATE_GATE);
+			ret = jpeg_v4_0_3_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 	}
 
 	return ret;
@@ -960,10 +960,10 @@ static int jpeg_v4_0_3_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int jpeg_v4_0_3_set_powergating_state(void *handle,
+static int jpeg_v4_0_3_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret;
 
 	if (amdgpu_sriov_vf(adev)) {
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
index ef2d4237925b..2a28eb479a34 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
@@ -48,7 +48,7 @@
 
 static void jpeg_v4_0_5_set_dec_ring_funcs(struct amdgpu_device *adev);
 static void jpeg_v4_0_5_set_irq_funcs(struct amdgpu_device *adev);
-static int jpeg_v4_0_5_set_powergating_state(void *handle,
+static int jpeg_v4_0_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				enum amd_powergating_state state);
 
 static void jpeg_v4_0_5_dec_ring_set_wptr(struct amdgpu_ring *ring);
@@ -228,7 +228,7 @@ static int jpeg_v4_0_5_hw_fini(struct amdgpu_ip_block *ip_block)
 		if (!amdgpu_sriov_vf(adev)) {
 			if (adev->jpeg.cur_state != AMD_PG_STATE_GATE &&
 			    RREG32_SOC15(JPEG, i, regUVD_JRBC_STATUS))
-				jpeg_v4_0_5_set_powergating_state(adev, AMD_PG_STATE_GATE);
+				jpeg_v4_0_5_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 		}
 	}
 	return 0;
@@ -676,10 +676,10 @@ static int jpeg_v4_0_5_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int jpeg_v4_0_5_set_powergating_state(void *handle,
+static int jpeg_v4_0_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret;
 
 	if (amdgpu_sriov_vf(adev)) {
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
index 7954a6fae464..692d0083b5f7 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
@@ -36,7 +36,7 @@
 
 static void jpeg_v5_0_0_set_dec_ring_funcs(struct amdgpu_device *adev);
 static void jpeg_v5_0_0_set_irq_funcs(struct amdgpu_device *adev);
-static int jpeg_v5_0_0_set_powergating_state(void *handle,
+static int jpeg_v5_0_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				enum amd_powergating_state state);
 
 /**
@@ -165,7 +165,7 @@ static int jpeg_v5_0_0_hw_fini(struct amdgpu_ip_block *ip_block)
 
 	if (adev->jpeg.cur_state != AMD_PG_STATE_GATE &&
 	      RREG32_SOC15(JPEG, 0, regUVD_JRBC_STATUS))
-		jpeg_v5_0_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
+		jpeg_v5_0_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 
 	return 0;
 }
@@ -570,10 +570,10 @@ static int jpeg_v5_0_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int jpeg_v5_0_0_set_powergating_state(void *handle,
+static int jpeg_v5_0_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret;
 
 	if (state == adev->jpeg.cur_state)
diff --git a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c
index 93da900b7ee2..9ca248ea3428 100644
--- a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c
@@ -677,7 +677,7 @@ static int navi10_ih_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int navi10_ih_set_powergating_state(void *handle,
+static int navi10_ih_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					   enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c
index 4e8f9af1e2be..6481f72b32d6 100644
--- a/drivers/gpu/drm/amd/amdgpu/nv.c
+++ b/drivers/gpu/drm/amd/amdgpu/nv.c
@@ -1085,7 +1085,7 @@ static int nv_common_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int nv_common_set_powergating_state(void *handle,
+static int nv_common_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					   enum amd_powergating_state state)
 {
 	/* TODO */
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
index 10fd772cb80f..6a1028baf16d 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
@@ -1087,7 +1087,7 @@ static int sdma_v2_4_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int sdma_v2_4_set_powergating_state(void *handle,
+static int sdma_v2_4_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
index 69fba087e09c..42d996d4136f 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
@@ -1506,7 +1506,7 @@ static int sdma_v3_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int sdma_v3_0_set_powergating_state(void *handle,
+static int sdma_v3_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
index 3f5959557727..a2f5f2be699b 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
@@ -2312,10 +2312,10 @@ static int sdma_v4_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int sdma_v4_0_set_powergating_state(void *handle,
+static int sdma_v4_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 
 	switch (amdgpu_ip_version(adev, SDMA0_HWIP, 0)) {
 	case IP_VERSION(4, 1, 0):
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
index 9c7cea0890c9..95d5de2bd186 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
@@ -1830,7 +1830,7 @@ static int sdma_v4_4_2_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int sdma_v4_4_2_set_powergating_state(void *handle,
+static int sdma_v4_4_2_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
index 6a675daf5620..82a8bbd53d49 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
@@ -1859,7 +1859,7 @@ static int sdma_v5_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int sdma_v5_0_set_powergating_state(void *handle,
+static int sdma_v5_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
index e1413ccaf7e4..b84d5c27bb94 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
@@ -1818,7 +1818,7 @@ static int sdma_v5_2_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int sdma_v5_2_set_powergating_state(void *handle,
+static int sdma_v5_2_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
index 4b33bd6b776d..bc9fe03ab145 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
@@ -1589,7 +1589,7 @@ static int sdma_v6_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int sdma_v6_0_set_powergating_state(void *handle,
+static int sdma_v6_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
index 24f24974ac1d..c224e7e7e103 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
@@ -1524,7 +1524,7 @@ static int sdma_v7_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int sdma_v7_0_set_powergating_state(void *handle,
+static int sdma_v7_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c
index b9934661a92e..6b0211c94836 100644
--- a/drivers/gpu/drm/amd/amdgpu/si.c
+++ b/drivers/gpu/drm/amd/amdgpu/si.c
@@ -2681,7 +2681,7 @@ static int si_common_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int si_common_set_powergating_state(void *handle,
+static int si_common_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					    enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.c b/drivers/gpu/drm/amd/amdgpu/si_dma.c
index d44483ed3363..26782dad9311 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_dma.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_dma.c
@@ -672,12 +672,12 @@ static int si_dma_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int si_dma_set_powergating_state(void *handle,
+static int si_dma_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	u32 tmp;
 
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 
 	WREG32(DMA_PGFSM_WRITE,  0x00002000);
 	WREG32(DMA_PGFSM_CONFIG, 0x100010ff);
diff --git a/drivers/gpu/drm/amd/amdgpu/si_ih.c b/drivers/gpu/drm/amd/amdgpu/si_ih.c
index b018a3b90401..976d803bef8c 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_ih.c
@@ -269,7 +269,7 @@ static int si_ih_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int si_ih_set_powergating_state(void *handle,
+static int si_ih_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c
index 6ab34c526c86..9fbada694cd7 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc15.c
+++ b/drivers/gpu/drm/amd/amdgpu/soc15.c
@@ -1481,7 +1481,7 @@ static void soc15_common_get_clockgating_state(void *handle, u64 *flags)
 		adev->df.funcs->get_clockgating_state(adev, flags);
 }
 
-static int soc15_common_set_powergating_state(void *handle,
+static int soc15_common_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					    enum amd_powergating_state state)
 {
 	/* todo */
diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c
index c4b950e75133..6497a65f9738 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc21.c
+++ b/drivers/gpu/drm/amd/amdgpu/soc21.c
@@ -968,10 +968,10 @@ static int soc21_common_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int soc21_common_set_powergating_state(void *handle,
+static int soc21_common_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					   enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 
 	switch (amdgpu_ip_version(adev, LSDMA_HWIP, 0)) {
 	case IP_VERSION(6, 0, 0):
diff --git a/drivers/gpu/drm/amd/amdgpu/soc24.c b/drivers/gpu/drm/amd/amdgpu/soc24.c
index b20dc81dc257..7b43d8908448 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc24.c
+++ b/drivers/gpu/drm/amd/amdgpu/soc24.c
@@ -557,10 +557,10 @@ static int soc24_common_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int soc24_common_set_powergating_state(void *handle,
+static int soc24_common_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					      enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 
 	switch (amdgpu_ip_version(adev, LSDMA_HWIP, 0)) {
 	case IP_VERSION(7, 0, 0):
diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
index 45fb5140c8b7..77fba40e1dbc 100644
--- a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c
@@ -454,7 +454,7 @@ static int tonga_ih_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int tonga_ih_set_powergating_state(void *handle,
+static int tonga_ih_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c
index 3011b5853fb4..561fc15173b6 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c
@@ -796,7 +796,7 @@ static int uvd_v3_1_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int uvd_v3_1_set_powergating_state(void *handle,
+static int uvd_v3_1_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
index 4852a2ab128f..6bd728153b4c 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
@@ -714,7 +714,7 @@ static int uvd_v4_2_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int uvd_v4_2_set_powergating_state(void *handle,
+static int uvd_v4_2_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	/* This doesn't actually powergate the UVD block.
@@ -724,7 +724,7 @@ static int uvd_v4_2_set_powergating_state(void *handle,
 	 * revisit this when there is a cleaner line between
 	 * the smc and the hw blocks
 	 */
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 
 	if (state == AMD_PG_STATE_GATE) {
 		uvd_v4_2_stop(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
index a24b210c79ac..02e0e5c9e701 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
@@ -817,7 +817,7 @@ static int uvd_v5_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int uvd_v5_0_set_powergating_state(void *handle,
+static int uvd_v5_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	/* This doesn't actually powergate the UVD block.
@@ -827,7 +827,7 @@ static int uvd_v5_0_set_powergating_state(void *handle,
 	 * revisit this when there is a cleaner line between
 	 * the smc and the hw blocks
 	 */
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret = 0;
 
 	if (state == AMD_PG_STATE_GATE) {
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
index b4eeeebfe095..fdf23d2b0e42 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
@@ -1476,7 +1476,7 @@ static int uvd_v6_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int uvd_v6_0_set_powergating_state(void *handle,
+static int uvd_v6_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	/* This doesn't actually powergate the UVD block.
@@ -1486,7 +1486,7 @@ static int uvd_v6_0_set_powergating_state(void *handle,
 	 * revisit this when there is a cleaner line between
 	 * the smc and the hw blocks
 	 */
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret = 0;
 
 	WREG32(mmUVD_POWER_STATUS, UVD_POWER_STATUS__UVD_PG_EN_MASK);
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
index a4531000ec0b..836643c99572 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
@@ -596,7 +596,7 @@ static int vce_v2_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int vce_v2_0_set_powergating_state(void *handle,
+static int vce_v2_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	/* This doesn't actually powergate the VCE block.
@@ -606,7 +606,7 @@ static int vce_v2_0_set_powergating_state(void *handle,
 	 * revisit this when there is a cleaner line between
 	 * the smc and the hw blocks
 	 */
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 
 	if (state == AMD_PG_STATE_GATE)
 		return vce_v2_0_stop(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
index 9f9a9d89bcdc..e985cf1e63f1 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
@@ -801,7 +801,7 @@ static int vce_v3_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int vce_v3_0_set_powergating_state(void *handle,
+static int vce_v3_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	/* This doesn't actually powergate the VCE block.
@@ -811,7 +811,7 @@ static int vce_v3_0_set_powergating_state(void *handle,
 	 * revisit this when there is a cleaner line between
 	 * the smc and the hw blocks
 	 */
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret = 0;
 
 	if (state == AMD_PG_STATE_GATE) {
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
index f4d2650e6b7a..30d64672f3c5 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c
@@ -958,7 +958,7 @@ static int vce_v4_0_set_clockgating_state(void *handle,
 }
 #endif
 
-static int vce_v4_0_set_powergating_state(void *handle,
+static int vce_v4_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	/* This doesn't actually powergate the VCE block.
@@ -968,7 +968,7 @@ static int vce_v4_0_set_powergating_state(void *handle,
 	 * revisit this when there is a cleaner line between
 	 * the smc and the hw blocks
 	 */
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 
 	if (state == AMD_PG_STATE_GATE)
 		return vce_v4_0_stop(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
index 1d5b0f4e5b1a..34b1e55a907a 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
@@ -85,7 +85,8 @@ static int vcn_v1_0_stop(struct amdgpu_device *adev);
 static void vcn_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev);
 static void vcn_v1_0_set_enc_ring_funcs(struct amdgpu_device *adev);
 static void vcn_v1_0_set_irq_funcs(struct amdgpu_device *adev);
-static int vcn_v1_0_set_powergating_state(void *handle, enum amd_powergating_state state);
+static int vcn_v1_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
+				enum amd_powergating_state state);
 static int vcn_v1_0_pause_dpg_mode(struct amdgpu_device *adev,
 				int inst_idx, struct dpg_pause_state *new_state);
 
@@ -281,7 +282,7 @@ static int vcn_v1_0_hw_fini(struct amdgpu_ip_block *ip_block)
 	if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
 		(adev->vcn.cur_state != AMD_PG_STATE_GATE &&
 		 RREG32_SOC15(VCN, 0, mmUVD_STATUS))) {
-		vcn_v1_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
+		vcn_v1_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 	}
 
 	return 0;
@@ -1799,7 +1800,7 @@ static void vcn_v1_0_dec_ring_insert_nop(struct amdgpu_ring *ring, uint32_t coun
 	}
 }
 
-static int vcn_v1_0_set_powergating_state(void *handle,
+static int vcn_v1_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	/* This doesn't actually powergate the VCN block.
@@ -1810,7 +1811,7 @@ static int vcn_v1_0_set_powergating_state(void *handle,
 	 * the smc and the hw blocks
 	 */
 	int ret;
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 
 	if (state == adev->vcn.cur_state)
 		return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
index d87e5505cf51..6c1f5d05f90a 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
@@ -92,7 +92,7 @@ static const struct amdgpu_hwip_reg_entry vcn_reg_list_2_0[] = {
 static void vcn_v2_0_set_dec_ring_funcs(struct amdgpu_device *adev);
 static void vcn_v2_0_set_enc_ring_funcs(struct amdgpu_device *adev);
 static void vcn_v2_0_set_irq_funcs(struct amdgpu_device *adev);
-static int vcn_v2_0_set_powergating_state(void *handle,
+static int vcn_v2_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				enum amd_powergating_state state);
 static int vcn_v2_0_pause_dpg_mode(struct amdgpu_device *adev,
 				int inst_idx, struct dpg_pause_state *new_state);
@@ -318,7 +318,7 @@ static int vcn_v2_0_hw_fini(struct amdgpu_ip_block *ip_block)
 	if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
 	    (adev->vcn.cur_state != AMD_PG_STATE_GATE &&
 	      RREG32_SOC15(VCN, 0, mmUVD_STATUS)))
-		vcn_v2_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
+		vcn_v2_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 
 	return 0;
 }
@@ -1796,7 +1796,7 @@ int vcn_v2_0_dec_ring_test_ring(struct amdgpu_ring *ring)
 }
 
 
-static int vcn_v2_0_set_powergating_state(void *handle,
+static int vcn_v2_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	/* This doesn't actually powergate the VCN block.
@@ -1807,7 +1807,7 @@ static int vcn_v2_0_set_powergating_state(void *handle,
 	 * the smc and the hw blocks
 	 */
 	int ret;
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 
 	if (amdgpu_sriov_vf(adev)) {
 		adev->vcn.cur_state = AMD_PG_STATE_UNGATE;
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
index ad0922eb16c0..35ded346771d 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
@@ -95,7 +95,7 @@ static const struct amdgpu_hwip_reg_entry vcn_reg_list_2_5[] = {
 static void vcn_v2_5_set_dec_ring_funcs(struct amdgpu_device *adev);
 static void vcn_v2_5_set_enc_ring_funcs(struct amdgpu_device *adev);
 static void vcn_v2_5_set_irq_funcs(struct amdgpu_device *adev);
-static int vcn_v2_5_set_powergating_state(void *handle,
+static int vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				enum amd_powergating_state state);
 static int vcn_v2_5_pause_dpg_mode(struct amdgpu_device *adev,
 				int inst_idx, struct dpg_pause_state *new_state);
@@ -398,8 +398,9 @@ static int vcn_v2_5_hw_fini(struct amdgpu_ip_block *ip_block)
 
 		if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
 		    (adev->vcn.cur_state != AMD_PG_STATE_GATE &&
-		     RREG32_SOC15(VCN, i, mmUVD_STATUS)))
-			vcn_v2_5_set_powergating_state(adev, AMD_PG_STATE_GATE);
+		     RREG32_SOC15(VCN, i, mmUVD_STATUS))) {
+			vcn_v2_5_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
+		}
 
 		if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN))
 			amdgpu_irq_put(adev, &adev->vcn.inst[i].ras_poison_irq, 0);
@@ -1825,10 +1826,10 @@ static int vcn_v2_5_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int vcn_v2_5_set_powergating_state(void *handle,
+static int vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret;
 
 	if (amdgpu_sriov_vf(adev))
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
index 19c7f9cd4c15..c02c9ef8ddeb 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
@@ -105,7 +105,7 @@ static int vcn_v3_0_start_sriov(struct amdgpu_device *adev);
 static void vcn_v3_0_set_dec_ring_funcs(struct amdgpu_device *adev);
 static void vcn_v3_0_set_enc_ring_funcs(struct amdgpu_device *adev);
 static void vcn_v3_0_set_irq_funcs(struct amdgpu_device *adev);
-static int vcn_v3_0_set_powergating_state(void *handle,
+static int vcn_v3_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 			enum amd_powergating_state state);
 static int vcn_v3_0_pause_dpg_mode(struct amdgpu_device *adev,
 			int inst_idx, struct dpg_pause_state *new_state);
@@ -430,9 +430,9 @@ static int vcn_v3_0_hw_fini(struct amdgpu_ip_block *ip_block)
 
 		if (!amdgpu_sriov_vf(adev)) {
 			if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
-					(adev->vcn.cur_state != AMD_PG_STATE_GATE &&
-					 RREG32_SOC15(VCN, i, mmUVD_STATUS))) {
-				vcn_v3_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
+				(adev->vcn.cur_state != AMD_PG_STATE_GATE &&
+				 RREG32_SOC15(VCN, i, mmUVD_STATUS))) {
+				vcn_v3_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 			}
 		}
 	}
@@ -2159,10 +2159,10 @@ static int vcn_v3_0_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int vcn_v3_0_set_powergating_state(void *handle,
+static int vcn_v3_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret;
 
 	/* for SRIOV, guest should not control VCN Power-gating
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index e97d7f4ae371..319eb5a3d061 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -96,7 +96,7 @@ static int amdgpu_ih_clientid_vcns[] = {
 static int vcn_v4_0_start_sriov(struct amdgpu_device *adev);
 static void vcn_v4_0_set_unified_ring_funcs(struct amdgpu_device *adev);
 static void vcn_v4_0_set_irq_funcs(struct amdgpu_device *adev);
-static int vcn_v4_0_set_powergating_state(void *handle,
+static int vcn_v4_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
         enum amd_powergating_state state);
 static int vcn_v4_0_pause_dpg_mode(struct amdgpu_device *adev,
         int inst_idx, struct dpg_pause_state *new_state);
@@ -357,9 +357,9 @@ static int vcn_v4_0_hw_fini(struct amdgpu_ip_block *ip_block)
 			continue;
 		if (!amdgpu_sriov_vf(adev)) {
 			if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
-                        (adev->vcn.cur_state != AMD_PG_STATE_GATE &&
-                                RREG32_SOC15(VCN, i, regUVD_STATUS))) {
-                        vcn_v4_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
+				(adev->vcn.cur_state != AMD_PG_STATE_GATE &&
+				 RREG32_SOC15(VCN, i, regUVD_STATUS))) {
+				vcn_v4_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 			}
 		}
 		if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN))
@@ -2037,9 +2037,10 @@ static int vcn_v4_0_set_clockgating_state(void *handle, enum amd_clockgating_sta
  *
  * Set VCN block powergating state
  */
-static int vcn_v4_0_set_powergating_state(void *handle, enum amd_powergating_state state)
+static int vcn_v4_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
+					  enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret;
 
 	/* for SRIOV, guest should not control VCN Power-gating
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
index ba22913398ec..b6c1135d6fec 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
@@ -87,7 +87,7 @@ static const struct amdgpu_hwip_reg_entry vcn_reg_list_4_0_3[] = {
 static int vcn_v4_0_3_start_sriov(struct amdgpu_device *adev);
 static void vcn_v4_0_3_set_unified_ring_funcs(struct amdgpu_device *adev);
 static void vcn_v4_0_3_set_irq_funcs(struct amdgpu_device *adev);
-static int vcn_v4_0_3_set_powergating_state(void *handle,
+static int vcn_v4_0_3_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		enum amd_powergating_state state);
 static int vcn_v4_0_3_pause_dpg_mode(struct amdgpu_device *adev,
 		int inst_idx, struct dpg_pause_state *new_state);
@@ -319,7 +319,7 @@ static int vcn_v4_0_3_hw_fini(struct amdgpu_ip_block *ip_block)
 	cancel_delayed_work_sync(&adev->vcn.idle_work);
 
 	if (adev->vcn.cur_state != AMD_PG_STATE_GATE)
-		vcn_v4_0_3_set_powergating_state(adev, AMD_PG_STATE_GATE);
+		vcn_v4_0_3_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 
 	return 0;
 }
@@ -1623,10 +1623,10 @@ static int vcn_v4_0_3_set_clockgating_state(void *handle,
  *
  * Set VCN block powergating state
  */
-static int vcn_v4_0_3_set_powergating_state(void *handle,
+static int vcn_v4_0_3_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret;
 
 	/* for SRIOV, guest should not control VCN Power-gating
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
index 873672f64778..ebf6301b13be 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
@@ -95,7 +95,7 @@ static int amdgpu_ih_clientid_vcns[] = {
 
 static void vcn_v4_0_5_set_unified_ring_funcs(struct amdgpu_device *adev);
 static void vcn_v4_0_5_set_irq_funcs(struct amdgpu_device *adev);
-static int vcn_v4_0_5_set_powergating_state(void *handle,
+static int vcn_v4_0_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		enum amd_powergating_state state);
 static int vcn_v4_0_5_pause_dpg_mode(struct amdgpu_device *adev,
 		int inst_idx, struct dpg_pause_state *new_state);
@@ -309,7 +309,7 @@ static int vcn_v4_0_5_hw_fini(struct amdgpu_ip_block *ip_block)
 			if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
 				(adev->vcn.cur_state != AMD_PG_STATE_GATE &&
 				RREG32_SOC15(VCN, i, regUVD_STATUS))) {
-				vcn_v4_0_5_set_powergating_state(adev, AMD_PG_STATE_GATE);
+				vcn_v4_0_5_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 			}
 		}
 	}
@@ -1531,9 +1531,10 @@ static int vcn_v4_0_5_set_clockgating_state(void *handle, enum amd_clockgating_s
  *
  * Set VCN block powergating state
  */
-static int vcn_v4_0_5_set_powergating_state(void *handle, enum amd_powergating_state state)
+static int vcn_v4_0_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
+		enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret;
 
 	if (state == adev->vcn.cur_state)
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
index 893e66c2b9a5..50c102f1b5fe 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
@@ -78,7 +78,7 @@ static int amdgpu_ih_clientid_vcns[] = {
 
 static void vcn_v5_0_0_set_unified_ring_funcs(struct amdgpu_device *adev);
 static void vcn_v5_0_0_set_irq_funcs(struct amdgpu_device *adev);
-static int vcn_v5_0_0_set_powergating_state(void *handle,
+static int vcn_v5_0_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		enum amd_powergating_state state);
 static int vcn_v5_0_0_pause_dpg_mode(struct amdgpu_device *adev,
 		int inst_idx, struct dpg_pause_state *new_state);
@@ -273,7 +273,7 @@ static int vcn_v5_0_0_hw_fini(struct amdgpu_ip_block *ip_block)
 			if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
 				(adev->vcn.cur_state != AMD_PG_STATE_GATE &&
 				RREG32_SOC15(VCN, i, regUVD_STATUS))) {
-				vcn_v5_0_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
+				vcn_v5_0_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 			}
 		}
 	}
@@ -1258,9 +1258,10 @@ static int vcn_v5_0_0_set_clockgating_state(void *handle, enum amd_clockgating_s
  *
  * Set VCN block powergating state
  */
-static int vcn_v5_0_0_set_powergating_state(void *handle, enum amd_powergating_state state)
+static int vcn_v5_0_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
+		enum amd_powergating_state state)
 {
-	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+	struct amdgpu_device *adev = ip_block->adev;
 	int ret;
 
 	if (state == adev->vcn.cur_state)
diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c
index 73de5909f655..8df4f4352d65 100644
--- a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c
@@ -616,7 +616,7 @@ static int vega10_ih_set_clockgating_state(void *handle,
 
 }
 
-static int vega10_ih_set_powergating_state(void *handle,
+static int vega10_ih_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c
index a42404a58015..4ac43aeb85c1 100644
--- a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c
@@ -681,7 +681,7 @@ static int vega20_ih_set_clockgating_state(void *handle,
 
 }
 
-static int vega20_ih_set_powergating_state(void *handle,
+static int vega20_ih_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c
index 4996049dc199..6b58723f0b2e 100644
--- a/drivers/gpu/drm/amd/amdgpu/vi.c
+++ b/drivers/gpu/drm/amd/amdgpu/vi.c
@@ -2003,7 +2003,7 @@ static int vi_common_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int vi_common_set_powergating_state(void *handle,
+static int vi_common_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					    enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 7616d7a509b9..d5a0417f95df 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -961,7 +961,7 @@ static int dm_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int dm_set_powergating_state(void *handle,
+static int dm_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h
index f98b3a544477..03c77bbc2e6d 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -398,7 +398,7 @@ struct amd_ip_funcs {
 	int (*post_soft_reset)(struct amdgpu_ip_block *ip_block);
 	int (*set_clockgating_state)(void *handle,
 				     enum amd_clockgating_state state);
-	int (*set_powergating_state)(void *handle,
+	int (*set_powergating_state)(struct amdgpu_ip_block *ip_block,
 				     enum amd_powergating_state state);
 	void (*get_clockgating_state)(void *handle, u64 *flags);
 	void (*dump_ip_state)(struct amdgpu_ip_block *ip_block);
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
index af7da780b58b..d5130da88162 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
@@ -3194,7 +3194,7 @@ static int kv_dpm_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int kv_dpm_set_powergating_state(void *handle,
+static int kv_dpm_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
index a4908f0402f1..18c47fa89bc1 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
@@ -7860,7 +7860,7 @@ static int si_dpm_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int si_dpm_set_powergating_state(void *handle,
+static int si_dpm_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
index de5ee1c5503f..069b604d6e7a 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
@@ -254,7 +254,7 @@ static int pp_sw_reset(struct amdgpu_ip_block *ip_block)
 	return 0;
 }
 
-static int pp_set_powergating_state(void *handle,
+static int pp_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				    enum amd_powergating_state state)
 {
 	return 0;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index 0da84e390d0d..c58a377a5146 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -2184,7 +2184,7 @@ static int smu_set_clockgating_state(void *handle,
 	return 0;
 }
 
-static int smu_set_powergating_state(void *handle,
+static int smu_set_powergating_state(struct amdgpu_ip_block *ip_block,
 				     enum amd_powergating_state state)
 {
 	return 0;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 08/18] drm/amdgpu: track instances of the same IP block
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (6 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 07/18] drm/amdgpu: pass ip_block in set_powergating_state boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 18:44 ` [PATCH 09/18] drm/amdgpu: add set_powergating_state_instance boyuan.zhang
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

Add a new function to count the number of instance of the same IP block
in the current ip_block list, then use the returned count value to set
the newly defined instance variable in ip_block, to track the instance
number of each ip_block.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Suggested-by: Christian König <christian.koenig@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h        |  1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 25 +++++++++++++++++++++-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 48c9b9b06905..3442564fe174 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -387,6 +387,7 @@ struct amdgpu_ip_block {
 	struct amdgpu_ip_block_status status;
 	const struct amdgpu_ip_block_version *version;
 	struct amdgpu_device *adev;
+	unsigned int instance;
 };
 
 int amdgpu_device_ip_block_version_cmp(struct amdgpu_device *adev,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index fe5de35eef64..35a3e71a5a84 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -2283,6 +2283,28 @@ int amdgpu_device_ip_block_version_cmp(struct amdgpu_device *adev,
 	return 1;
 }
 
+/**
+ * amdgpu_device_ip_get_num_instances - get number of instances of an IP block
+ *
+ * @adev: amdgpu_device pointer
+ * @type: Type of hardware IP (SMU, GFX, UVD, etc.)
+ *
+ * Returns the count of the hardware IP blocks structure for that type.
+ */
+static unsigned int
+amdgpu_device_ip_get_num_instances(struct amdgpu_device *adev,
+				    enum amd_ip_block_type type)
+{
+	unsigned int i, count = 0;
+
+	for (i = 0; i < adev->num_ip_blocks; i++) {
+		if (adev->ip_blocks[i].version->type == type)
+			count++;
+	}
+
+	return count;
+}
+
 /**
  * amdgpu_device_ip_block_add
  *
@@ -2315,7 +2337,8 @@ int amdgpu_device_ip_block_add(struct amdgpu_device *adev,
 		  ip_block_version->funcs->name);
 
 	adev->ip_blocks[adev->num_ip_blocks].adev = adev;
-
+	adev->ip_blocks[adev->num_ip_blocks].instance =
+		amdgpu_device_ip_get_num_instances(adev, ip_block_version->type);
 	adev->ip_blocks[adev->num_ip_blocks++].version = ip_block_version;
 
 	return 0;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 09/18] drm/amdgpu: add set_powergating_state_instance
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (7 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 08/18] drm/amdgpu: track instances of the same IP block boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 19:40   ` Alex Deucher
  2024-10-04 18:44 ` [PATCH 10/18] drm/amdgpu/vcn: separate gating state by instance boyuan.zhang
                   ` (8 subsequent siblings)
  17 siblings, 1 reply; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

Add a new function to allow setting requested powergating state for the
given instance. If the instance value doesn't match with the one inside
ip_block, then do nothing since this request is for other instances with
the same block type.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h        |  4 +++
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 37 ++++++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 3442564fe174..ae59497f3074 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -358,6 +358,10 @@ int amdgpu_device_ip_set_clockgating_state(void *dev,
 int amdgpu_device_ip_set_powergating_state(void *dev,
 					   enum amd_ip_block_type block_type,
 					   enum amd_powergating_state state);
+int amdgpu_device_ip_set_powergating_state_instance(void *dev,
+					   enum amd_ip_block_type block_type,
+					   enum amd_powergating_state state,
+					   unsigned int inst);
 void amdgpu_device_ip_get_clockgating_state(struct amdgpu_device *adev,
 					    u64 *flags);
 int amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 35a3e71a5a84..f0b6a9675405 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -2162,6 +2162,43 @@ int amdgpu_device_ip_set_powergating_state(void *dev,
 	return r;
 }
 
+/**
+ * amdgpu_device_ip_set_powergating_state_instance - set the PG state
+ *
+ * @dev: amdgpu_device pointer
+ * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.)
+ * @state: powergating state (gate or ungate)
+ *
+ * Sets the requested powergating state for the given instance of
+ * the hardware IP specified.
+ * Returns the error code from the last instance.
+ */
+int amdgpu_device_ip_set_powergating_state_instance(void *dev,
+					   enum amd_ip_block_type block_type,
+					   enum amd_powergating_state state,
+					   unsigned int inst)
+{
+	struct amdgpu_device *adev = dev;
+	int i, r = 0;
+
+	for (i = 0; i < adev->num_ip_blocks; i++) {
+		if (!adev->ip_blocks[i].status.valid)
+			continue;
+		if (adev->ip_blocks[i].version->type != block_type)
+			continue;
+		if (adev->ip_blocks[i].instance != inst)
+			continue;
+		if (!adev->ip_blocks[i].version->funcs->set_powergating_state)
+			continue;
+		r = adev->ip_blocks[i].version->funcs->set_powergating_state(
+			(void *)&adev->ip_blocks[i], state);
+		if (r)
+			DRM_ERROR("set_powergating_state of IP block <%s> failed %d\n",
+				  adev->ip_blocks[i].version->funcs->name, r);
+	}
+	return r;
+}
+
 /**
  * amdgpu_device_ip_get_clockgating_state - get the CG state
  *
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 10/18] drm/amdgpu/vcn: separate gating state by instance
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (8 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 09/18] drm/amdgpu: add set_powergating_state_instance boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 18:44 ` [PATCH 11/18] drm/amdgpu: power vcn 2_5 " boyuan.zhang
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

vcn gating state should now be based on instance. For example, instance 0
can be gated while instance 1 is ungated, or vice versa.

Therefore, change the cur_state to be an array, so that it can track the
gating status for each vcn instance now.

v2: remove redundant codes in v1.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h   |  2 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c     |  7 ++---
 drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c     |  9 ++++---
 drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c     | 29 ++++++++++-----------
 drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c     | 25 +++++++++---------
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c     | 31 ++++++++++++-----------
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c   | 10 +++++---
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c   | 24 +++++++++---------
 drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c   | 24 +++++++++---------
 drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c |  3 ++-
 10 files changed, 84 insertions(+), 80 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
index 2a1f3dbb14d3..f6717f780acd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
@@ -308,7 +308,7 @@ struct amdgpu_vcn {
 	struct delayed_work	idle_work;
 	const struct firmware	*fw[AMDGPU_MAX_VCN_INSTANCES];	/* VCN firmware */
 	unsigned		num_enc_rings;
-	enum amd_powergating_state cur_state;
+	enum amd_powergating_state cur_state[AMDGPU_MAX_VCN_INSTANCES];
 	bool			indirect_sram;
 
 	uint8_t	num_vcn_inst;
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
index 34b1e55a907a..4f768c6097d8 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
@@ -280,7 +280,7 @@ static int vcn_v1_0_hw_fini(struct amdgpu_ip_block *ip_block)
 	cancel_delayed_work_sync(&adev->vcn.idle_work);
 
 	if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
-		(adev->vcn.cur_state != AMD_PG_STATE_GATE &&
+		(adev->vcn.cur_state[0] != AMD_PG_STATE_GATE &&
 		 RREG32_SOC15(VCN, 0, mmUVD_STATUS))) {
 		vcn_v1_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 	}
@@ -1813,7 +1813,7 @@ static int vcn_v1_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 	int ret;
 	struct amdgpu_device *adev = ip_block->adev;
 
-	if (state == adev->vcn.cur_state)
+	if (state == adev->vcn.cur_state[0])
 		return 0;
 
 	if (state == AMD_PG_STATE_GATE)
@@ -1822,7 +1822,8 @@ static int vcn_v1_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		ret = vcn_v1_0_start(adev);
 
 	if (!ret)
-		adev->vcn.cur_state = state;
+		adev->vcn.cur_state[0] = state;
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
index 6c1f5d05f90a..1b9085ddc00f 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
@@ -316,7 +316,7 @@ static int vcn_v2_0_hw_fini(struct amdgpu_ip_block *ip_block)
 	cancel_delayed_work_sync(&adev->vcn.idle_work);
 
 	if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
-	    (adev->vcn.cur_state != AMD_PG_STATE_GATE &&
+	    (adev->vcn.cur_state[0] != AMD_PG_STATE_GATE &&
 	      RREG32_SOC15(VCN, 0, mmUVD_STATUS)))
 		vcn_v2_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 
@@ -1810,11 +1810,11 @@ static int vcn_v2_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 	struct amdgpu_device *adev = ip_block->adev;
 
 	if (amdgpu_sriov_vf(adev)) {
-		adev->vcn.cur_state = AMD_PG_STATE_UNGATE;
+		adev->vcn.cur_state[0] = AMD_PG_STATE_UNGATE;
 		return 0;
 	}
 
-	if (state == adev->vcn.cur_state)
+	if (state == adev->vcn.cur_state[0])
 		return 0;
 
 	if (state == AMD_PG_STATE_GATE)
@@ -1823,7 +1823,8 @@ static int vcn_v2_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		ret = vcn_v2_0_start(adev);
 
 	if (!ret)
-		adev->vcn.cur_state = state;
+		adev->vcn.cur_state[0] = state;
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
index 35ded346771d..d00df51bc400 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
@@ -388,24 +388,22 @@ static int vcn_v2_5_hw_init(struct amdgpu_ip_block *ip_block)
 static int vcn_v2_5_hw_fini(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
-	int i;
+	int inst = ip_block->instance;
 
 	cancel_delayed_work_sync(&adev->vcn.idle_work);
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
-
-		if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
-		    (adev->vcn.cur_state != AMD_PG_STATE_GATE &&
-		     RREG32_SOC15(VCN, i, mmUVD_STATUS))) {
-			vcn_v2_5_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
-		}
+	if (adev->vcn.harvest_config & (1 << inst))
+		return 0;
 
-		if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN))
-			amdgpu_irq_put(adev, &adev->vcn.inst[i].ras_poison_irq, 0);
+	if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
+	    (adev->vcn.cur_state[inst] != AMD_PG_STATE_GATE &&
+	     RREG32_SOC15(VCN, inst, mmUVD_STATUS))) {
+		vcn_v2_5_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 	}
 
+	if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN))
+		amdgpu_irq_put(adev, &adev->vcn.inst[inst].ras_poison_irq, 0);
+
 	return 0;
 }
 
@@ -1830,12 +1828,13 @@ static int vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	struct amdgpu_device *adev = ip_block->adev;
+	int inst = ip_block->instance;
 	int ret;
 
 	if (amdgpu_sriov_vf(adev))
 		return 0;
 
-	if(state == adev->vcn.cur_state)
+	if (state == adev->vcn.cur_state[inst])
 		return 0;
 
 	if (state == AMD_PG_STATE_GATE)
@@ -1843,8 +1842,8 @@ static int vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
 	else
 		ret = vcn_v2_5_start(adev);
 
-	if(!ret)
-		adev->vcn.cur_state = state;
+	if (!ret)
+		adev->vcn.cur_state[inst] = state;
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
index c02c9ef8ddeb..e7d681773b62 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
@@ -420,20 +420,18 @@ static int vcn_v3_0_hw_init(struct amdgpu_ip_block *ip_block)
 static int vcn_v3_0_hw_fini(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
-	int i;
+	int inst = ip_block->instance;
 
 	cancel_delayed_work_sync(&adev->vcn.idle_work);
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
+	if (adev->vcn.harvest_config & (1 << inst))
+		return 0;
 
-		if (!amdgpu_sriov_vf(adev)) {
-			if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
-				(adev->vcn.cur_state != AMD_PG_STATE_GATE &&
-				 RREG32_SOC15(VCN, i, mmUVD_STATUS))) {
-				vcn_v3_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
-			}
+	if (!amdgpu_sriov_vf(adev)) {
+		if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
+		    (adev->vcn.cur_state[inst] != AMD_PG_STATE_GATE &&
+		     RREG32_SOC15(VCN, inst, mmUVD_STATUS))) {
+			vcn_v3_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 		}
 	}
 
@@ -2163,6 +2161,7 @@ static int vcn_v3_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	struct amdgpu_device *adev = ip_block->adev;
+	int inst = ip_block->instance;
 	int ret;
 
 	/* for SRIOV, guest should not control VCN Power-gating
@@ -2170,11 +2169,11 @@ static int vcn_v3_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 	 * guest should avoid touching CGC and PG
 	 */
 	if (amdgpu_sriov_vf(adev)) {
-		adev->vcn.cur_state = AMD_PG_STATE_UNGATE;
+		adev->vcn.cur_state[inst] = AMD_PG_STATE_UNGATE;
 		return 0;
 	}
 
-	if (state == adev->vcn.cur_state)
+	if (state == adev->vcn.cur_state[inst])
 		return 0;
 
 	if (state == AMD_PG_STATE_GATE)
@@ -2183,7 +2182,7 @@ static int vcn_v3_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		ret = vcn_v3_0_start(adev);
 
 	if (!ret)
-		adev->vcn.cur_state = state;
+		adev->vcn.cur_state[inst] = state;
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index 319eb5a3d061..535d513752f4 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -348,24 +348,24 @@ static int vcn_v4_0_hw_init(struct amdgpu_ip_block *ip_block)
 static int vcn_v4_0_hw_fini(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
-	int i;
+	int inst = ip_block->instance;
 
 	cancel_delayed_work_sync(&adev->vcn.idle_work);
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
-		if (!amdgpu_sriov_vf(adev)) {
-			if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
-				(adev->vcn.cur_state != AMD_PG_STATE_GATE &&
-				 RREG32_SOC15(VCN, i, regUVD_STATUS))) {
-				vcn_v4_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
-			}
+	if (adev->vcn.harvest_config & (1 << inst))
+		return 0;
+
+	if (!amdgpu_sriov_vf(adev)) {
+		if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
+		    (adev->vcn.cur_state[inst] != AMD_PG_STATE_GATE &&
+		     RREG32_SOC15(VCN, inst, regUVD_STATUS))) {
+			vcn_v4_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 		}
-		if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN))
-			amdgpu_irq_put(adev, &adev->vcn.inst[i].ras_poison_irq, 0);
 	}
 
+	if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN))
+		amdgpu_irq_put(adev, &adev->vcn.inst[inst].ras_poison_irq, 0);
+
 	return 0;
 }
 
@@ -2041,6 +2041,7 @@ static int vcn_v4_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	struct amdgpu_device *adev = ip_block->adev;
+	int inst = ip_block->instance;
 	int ret;
 
 	/* for SRIOV, guest should not control VCN Power-gating
@@ -2048,11 +2049,11 @@ static int vcn_v4_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 	 * guest should avoid touching CGC and PG
 	 */
 	if (amdgpu_sriov_vf(adev)) {
-		adev->vcn.cur_state = AMD_PG_STATE_UNGATE;
+		adev->vcn.cur_state[inst] = AMD_PG_STATE_UNGATE;
 		return 0;
 	}
 
-	if (state == adev->vcn.cur_state)
+	if (state == adev->vcn.cur_state[inst])
 		return 0;
 
 	if (state == AMD_PG_STATE_GATE)
@@ -2061,7 +2062,7 @@ static int vcn_v4_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		ret = vcn_v4_0_start(adev);
 
 	if (!ret)
-		adev->vcn.cur_state = state;
+		adev->vcn.cur_state[inst] = state;
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
index b6c1135d6fec..deb13a376c6d 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
@@ -315,10 +315,11 @@ static int vcn_v4_0_3_hw_init(struct amdgpu_ip_block *ip_block)
 static int vcn_v4_0_3_hw_fini(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
+	int inst = ip_block->instance;
 
 	cancel_delayed_work_sync(&adev->vcn.idle_work);
 
-	if (adev->vcn.cur_state != AMD_PG_STATE_GATE)
+	if (adev->vcn.cur_state[inst] != AMD_PG_STATE_GATE)
 		vcn_v4_0_3_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 
 	return 0;
@@ -1627,6 +1628,7 @@ static int vcn_v4_0_3_set_powergating_state(struct amdgpu_ip_block *ip_block,
 					  enum amd_powergating_state state)
 {
 	struct amdgpu_device *adev = ip_block->adev;
+	int inst = ip_block->instance;
 	int ret;
 
 	/* for SRIOV, guest should not control VCN Power-gating
@@ -1634,11 +1636,11 @@ static int vcn_v4_0_3_set_powergating_state(struct amdgpu_ip_block *ip_block,
 	 * guest should avoid touching CGC and PG
 	 */
 	if (amdgpu_sriov_vf(adev)) {
-		adev->vcn.cur_state = AMD_PG_STATE_UNGATE;
+		adev->vcn.cur_state[inst] = AMD_PG_STATE_UNGATE;
 		return 0;
 	}
 
-	if (state == adev->vcn.cur_state)
+	if (state == adev->vcn.cur_state[inst])
 		return 0;
 
 	if (state == AMD_PG_STATE_GATE)
@@ -1647,7 +1649,7 @@ static int vcn_v4_0_3_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		ret = vcn_v4_0_3_start(adev);
 
 	if (!ret)
-		adev->vcn.cur_state = state;
+		adev->vcn.cur_state[inst] = state;
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
index ebf6301b13be..fe2f57bb389f 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
@@ -298,19 +298,18 @@ static int vcn_v4_0_5_hw_init(struct amdgpu_ip_block *ip_block)
 static int vcn_v4_0_5_hw_fini(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
-	int i;
+	int inst = ip_block->instance;
 
 	cancel_delayed_work_sync(&adev->vcn.idle_work);
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
-		if (!amdgpu_sriov_vf(adev)) {
-			if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
-				(adev->vcn.cur_state != AMD_PG_STATE_GATE &&
-				RREG32_SOC15(VCN, i, regUVD_STATUS))) {
-				vcn_v4_0_5_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
-			}
+	if (adev->vcn.harvest_config & (1 << inst))
+		return 0;
+
+	if (!amdgpu_sriov_vf(adev)) {
+		if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
+		    (adev->vcn.cur_state[inst] != AMD_PG_STATE_GATE &&
+		     RREG32_SOC15(VCN, inst, regUVD_STATUS))) {
+			vcn_v4_0_5_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 		}
 	}
 
@@ -1535,9 +1534,10 @@ static int vcn_v4_0_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		enum amd_powergating_state state)
 {
 	struct amdgpu_device *adev = ip_block->adev;
+	int inst = ip_block->instance;
 	int ret;
 
-	if (state == adev->vcn.cur_state)
+	if (state == adev->vcn.cur_state[inst])
 		return 0;
 
 	if (state == AMD_PG_STATE_GATE)
@@ -1546,7 +1546,7 @@ static int vcn_v4_0_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		ret = vcn_v4_0_5_start(adev);
 
 	if (!ret)
-		adev->vcn.cur_state = state;
+		adev->vcn.cur_state[inst] = state;
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
index 50c102f1b5fe..1af137e98070 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
@@ -262,19 +262,18 @@ static int vcn_v5_0_0_hw_init(struct amdgpu_ip_block *ip_block)
 static int vcn_v5_0_0_hw_fini(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
-	int i;
+	int inst = ip_block->instance;
 
 	cancel_delayed_work_sync(&adev->vcn.idle_work);
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
-		if (!amdgpu_sriov_vf(adev)) {
-			if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
-				(adev->vcn.cur_state != AMD_PG_STATE_GATE &&
-				RREG32_SOC15(VCN, i, regUVD_STATUS))) {
-				vcn_v5_0_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
-			}
+	if (adev->vcn.harvest_config & (1 << inst))
+		return 0;
+
+	if (!amdgpu_sriov_vf(adev)) {
+		if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
+		    (adev->vcn.cur_state[inst] != AMD_PG_STATE_GATE &&
+		     RREG32_SOC15(VCN, inst, regUVD_STATUS))) {
+			vcn_v5_0_0_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
 		}
 	}
 
@@ -1262,9 +1261,10 @@ static int vcn_v5_0_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		enum amd_powergating_state state)
 {
 	struct amdgpu_device *adev = ip_block->adev;
+	int inst = ip_block->instance;
 	int ret;
 
-	if (state == adev->vcn.cur_state)
+	if (state == adev->vcn.cur_state[inst])
 		return 0;
 
 	if (state == AMD_PG_STATE_GATE)
@@ -1273,7 +1273,7 @@ static int vcn_v5_0_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		ret = vcn_v5_0_0_start(adev);
 
 	if (!ret)
-		adev->vcn.cur_state = state;
+		adev->vcn.cur_state[inst] = state;
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index c58a377a5146..10f4473d91ca 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -2034,7 +2034,8 @@ static int smu_hw_fini(struct amdgpu_ip_block *ip_block)
 	smu_dpm_set_vpe_enable(smu, false);
 	smu_dpm_set_umsch_mm_enable(smu, false);
 
-	adev->vcn.cur_state = AMD_PG_STATE_GATE;
+	for (int i = 0; i < adev->vcn.num_vcn_inst; ++i)
+		adev->vcn.cur_state[i] = AMD_PG_STATE_GATE;
 	adev->jpeg.cur_state = AMD_PG_STATE_GATE;
 
 	if (!smu->pm_enabled)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (9 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 10/18] drm/amdgpu/vcn: separate gating state by instance boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 19:52   ` Alex Deucher
  2024-10-07  5:22   ` Lazar, Lijo
  2024-10-04 18:44 ` [PATCH 12/18] drm/amdgpu: power vcn 3_0 " boyuan.zhang
                   ` (6 subsequent siblings)
  17 siblings, 2 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

For vcn 2_5, add ip_block for each vcn instance during discovery stage.

And only powering on/off one of the vcn instance using the
instance value stored in ip_block, instead of powering on/off all
vcn instances. Modify the existing functions to use the instance value
in ip_block, and remove the original for loop for all vcn instances.

v2: rename "i"/"j" to "inst" for instance value.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565 +++++++++---------
 2 files changed, 280 insertions(+), 289 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 9f9a1867da72..de1053cc2a2b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -2278,6 +2278,7 @@ static int amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
 
 static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
 {
+	int i;
 	if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
 		switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
 		case IP_VERSION(7, 0, 0):
@@ -2321,7 +2322,8 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
 		case IP_VERSION(2, 0, 3):
 			break;
 		case IP_VERSION(2, 5, 0):
-			amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
+			for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
+				amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
 			amdgpu_device_ip_block_add(adev, &jpeg_v2_5_ip_block);
 			break;
 		case IP_VERSION(2, 6, 0):
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
index d00df51bc400..1f8738ae360a 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
@@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct amdgpu_ip_block *ip_block)
 static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_ring *ring;
-	int i, j, r;
+	int i, r;
 	uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
 	uint32_t *ptr;
 	struct amdgpu_device *adev = ip_block->adev;
+	int inst = ip_block->instance;
 
-	for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
-		if (adev->vcn.harvest_config & (1 << j))
-			continue;
-		/* VCN DEC TRAP */
-		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
-				VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->vcn.inst[j].irq);
-		if (r)
-			return r;
-
-		/* VCN ENC TRAP */
-		for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
-			r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
-				i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[j].irq);
-			if (r)
-				return r;
-		}
+	if (adev->vcn.harvest_config & (1 << inst))
+		goto sw_init;
+	/* VCN DEC TRAP */
+	r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
+			VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->vcn.inst[inst].irq);
+	if (r)
+		return r;
 
-		/* VCN POISON TRAP */
-		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
-			VCN_2_6__SRCID_UVD_POISON, &adev->vcn.inst[j].ras_poison_irq);
+	/* VCN ENC TRAP */
+	for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
+		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
+			i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[inst].irq);
 		if (r)
 			return r;
 	}
 
+	/* VCN POISON TRAP */
+	r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
+		VCN_2_6__SRCID_UVD_POISON, &adev->vcn.inst[inst].ras_poison_irq);
+	if (r)
+		return r;
+sw_init:
 	r = amdgpu_vcn_sw_init(adev);
 	if (r)
 		return r;
@@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
 	if (r)
 		return r;
 
-	for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
-		volatile struct amdgpu_fw_shared *fw_shared;
+	volatile struct amdgpu_fw_shared *fw_shared;
 
-		if (adev->vcn.harvest_config & (1 << j))
-			continue;
-		adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
-		adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
-		adev->vcn.internal.ib_bar_low = mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
-		adev->vcn.internal.ib_bar_high = mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
-		adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
-		adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
-
-		adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
-		adev->vcn.inst[j].external.scratch9 = SOC15_REG_OFFSET(VCN, j, mmUVD_SCRATCH9);
-		adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
-		adev->vcn.inst[j].external.data0 = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_DATA0);
-		adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
-		adev->vcn.inst[j].external.data1 = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_DATA1);
-		adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
-		adev->vcn.inst[j].external.cmd = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_CMD);
-		adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
-		adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(VCN, j, mmUVD_NO_OP);
-
-		ring = &adev->vcn.inst[j].ring_dec;
+	if (adev->vcn.harvest_config & (1 << inst))
+		goto done;
+	adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
+	adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
+	adev->vcn.internal.ib_bar_low = mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
+	adev->vcn.internal.ib_bar_high = mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
+	adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
+	adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
+
+	adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
+	adev->vcn.inst[inst].external.scratch9 = SOC15_REG_OFFSET(VCN, inst, mmUVD_SCRATCH9);
+	adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
+	adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_DATA0);
+	adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
+	adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_DATA1);
+	adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
+	adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_CMD);
+	adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
+	adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN, inst, mmUVD_NO_OP);
+
+	ring = &adev->vcn.inst[inst].ring_dec;
+	ring->use_doorbell = true;
+
+	ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
+			(amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
+
+	if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
+		ring->vm_hub = AMDGPU_MMHUB1(0);
+	else
+		ring->vm_hub = AMDGPU_MMHUB0(0);
+
+	sprintf(ring->name, "vcn_dec_%d", inst);
+	r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq,
+				 0, AMDGPU_RING_PRIO_DEFAULT, NULL);
+	if (r)
+		return r;
+
+	for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
+		enum amdgpu_ring_priority_level hw_prio = amdgpu_vcn_get_enc_ring_prio(i);
+
+		ring = &adev->vcn.inst[inst].ring_enc[i];
 		ring->use_doorbell = true;
 
 		ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
-				(amdgpu_sriov_vf(adev) ? 2*j : 8*j);
+				(amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2 + i + 8*inst));
 
-		if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
+		if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
+			IP_VERSION(2, 5, 0))
 			ring->vm_hub = AMDGPU_MMHUB1(0);
 		else
 			ring->vm_hub = AMDGPU_MMHUB0(0);
 
-		sprintf(ring->name, "vcn_dec_%d", j);
-		r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq,
-				     0, AMDGPU_RING_PRIO_DEFAULT, NULL);
+		sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
+		r = amdgpu_ring_init(adev, ring, 512,
+					 &adev->vcn.inst[inst].irq, 0,
+					 hw_prio, NULL);
 		if (r)
 			return r;
-
-		for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
-			enum amdgpu_ring_priority_level hw_prio = amdgpu_vcn_get_enc_ring_prio(i);
-
-			ring = &adev->vcn.inst[j].ring_enc[i];
-			ring->use_doorbell = true;
-
-			ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
-					(amdgpu_sriov_vf(adev) ? (1 + i + 2*j) : (2 + i + 8*j));
-
-			if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
-			    IP_VERSION(2, 5, 0))
-				ring->vm_hub = AMDGPU_MMHUB1(0);
-			else
-				ring->vm_hub = AMDGPU_MMHUB0(0);
-
-			sprintf(ring->name, "vcn_enc_%d.%d", j, i);
-			r = amdgpu_ring_init(adev, ring, 512,
-					     &adev->vcn.inst[j].irq, 0,
-					     hw_prio, NULL);
-			if (r)
-				return r;
-		}
-
-		fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
-		fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
-
-		if (amdgpu_vcnfw_log)
-			amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
 	}
 
+	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
+	fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
+
+	if (amdgpu_vcnfw_log)
+		amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
+done:
 	if (amdgpu_sriov_vf(adev)) {
 		r = amdgpu_virt_alloc_mm_table(adev);
 		if (r)
@@ -1005,197 +1002,192 @@ static int vcn_v2_5_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, boo
 	return 0;
 }
 
-static int vcn_v2_5_start(struct amdgpu_device *adev)
+static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned int inst)
 {
 	struct amdgpu_ring *ring;
 	uint32_t rb_bufsz, tmp;
-	int i, j, k, r;
+	int j, k, r;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, true, i);
-	}
-
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
-		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
-			r = vcn_v2_5_start_dpg_mode(adev, i, adev->vcn.indirect_sram);
-			continue;
-		}
+	if (adev->pm.dpm_enabled)
+		amdgpu_dpm_enable_vcn(adev, true, inst);
 
-		/* disable register anti-hang mechanism */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS), 0,
-			~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
+	if (adev->vcn.harvest_config & (1 << inst))
+		return 0;
 
-		/* set uvd status busy */
-		tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
-		WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
+		r = vcn_v2_5_start_dpg_mode(adev, inst, adev->vcn.indirect_sram);
+		return r;
 	}
 
+	/* disable register anti-hang mechanism */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS), 0,
+		~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
+
+	/* set uvd status busy */
+	tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
+	WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
+
 	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
 		return 0;
 
 	/*SW clock gating */
 	vcn_v2_5_disable_clock_gating(adev);
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
-		/* enable VCPU clock */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
-			UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
-
-		/* disable master interrupt */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
-			~UVD_MASTINT_EN__VCPU_EN_MASK);
-
-		/* setup mmUVD_LMI_CTRL */
-		tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
-		tmp &= ~0xff;
-		WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
-			UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK	|
-			UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
-			UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
-			UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
-
-		/* setup mmUVD_MPC_CNTL */
-		tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
-		tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
-		tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
-		WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
-
-		/* setup UVD_MPC_SET_MUXA0 */
-		WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
-			((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
-			(0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
-			(0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
-			(0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
-
-		/* setup UVD_MPC_SET_MUXB0 */
-		WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
-			((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
-			(0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
-			(0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
-			(0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
-
-		/* setup mmUVD_MPC_SET_MUX */
-		WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
-			((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
-			(0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
-			(0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
-	}
+	if (adev->vcn.harvest_config & (1 << inst))
+		return 0;
+
+	/* enable VCPU clock */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
+		UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
+
+	/* disable master interrupt */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
+		~UVD_MASTINT_EN__VCPU_EN_MASK);
+
+	/* setup mmUVD_LMI_CTRL */
+	tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
+	tmp &= ~0xff;
+	WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
+		UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK	|
+		UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
+		UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
+		UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
+
+	/* setup mmUVD_MPC_CNTL */
+	tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
+	tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
+	tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
+	WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
+
+	/* setup UVD_MPC_SET_MUXA0 */
+	WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
+		((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
+		(0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
+		(0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
+		(0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
+
+	/* setup UVD_MPC_SET_MUXB0 */
+	WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
+		((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
+		(0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
+		(0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
+		(0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
+
+	/* setup mmUVD_MPC_SET_MUX */
+	WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
+		((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
+		(0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
+		(0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
 
 	vcn_v2_5_mc_resume(adev);
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		volatile struct amdgpu_fw_shared *fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
-		/* VCN global tiling registers */
-		WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
-			adev->gfx.config.gb_addr_config);
-		WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
-			adev->gfx.config.gb_addr_config);
+	volatile struct amdgpu_fw_shared *fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
+	if (adev->vcn.harvest_config & (1 << inst))
+		return 0;
+
+	/* VCN global tiling registers */
+	WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
+		adev->gfx.config.gb_addr_config);
+	WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
+		adev->gfx.config.gb_addr_config);
 
-		/* enable LMI MC and UMC channels */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
-			~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
+	/* enable LMI MC and UMC channels */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
+		~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
 
-		/* unblock VCPU register access */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
-			~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
+	/* unblock VCPU register access */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
+		~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
 
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
-			~UVD_VCPU_CNTL__BLK_RST_MASK);
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
+		~UVD_VCPU_CNTL__BLK_RST_MASK);
 
-		for (k = 0; k < 10; ++k) {
-			uint32_t status;
-
-			for (j = 0; j < 100; ++j) {
-				status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
-				if (status & 2)
-					break;
-				if (amdgpu_emu_mode == 1)
-					msleep(500);
-				else
-					mdelay(10);
-			}
-			r = 0;
+	for (k = 0; k < 10; ++k) {
+		uint32_t status;
+
+		for (j = 0; j < 100; ++j) {
+			status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
 			if (status & 2)
 				break;
+			if (amdgpu_emu_mode == 1)
+				msleep(500);
+			else
+				mdelay(10);
+		}
+		r = 0;
+		if (status & 2)
+			break;
 
-			DRM_ERROR("VCN decode not responding, trying to reset the VCPU!!!\n");
-			WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
-				UVD_VCPU_CNTL__BLK_RST_MASK,
-				~UVD_VCPU_CNTL__BLK_RST_MASK);
-			mdelay(10);
-			WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
-				~UVD_VCPU_CNTL__BLK_RST_MASK);
+		DRM_ERROR("VCN decode not responding, trying to reset the VCPU!!!\n");
+		WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
+			UVD_VCPU_CNTL__BLK_RST_MASK,
+			~UVD_VCPU_CNTL__BLK_RST_MASK);
+		mdelay(10);
+		WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
+			~UVD_VCPU_CNTL__BLK_RST_MASK);
 
-			mdelay(10);
-			r = -1;
-		}
+		mdelay(10);
+		r = -1;
+	}
 
-		if (r) {
-			DRM_ERROR("VCN decode not responding, giving up!!!\n");
-			return r;
-		}
+	if (r) {
+		DRM_ERROR("VCN decode not responding, giving up!!!\n");
+		return r;
+	}
 
-		/* enable master interrupt */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
-			UVD_MASTINT_EN__VCPU_EN_MASK,
-			~UVD_MASTINT_EN__VCPU_EN_MASK);
+	/* enable master interrupt */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
+		UVD_MASTINT_EN__VCPU_EN_MASK,
+		~UVD_MASTINT_EN__VCPU_EN_MASK);
 
-		/* clear the busy bit of VCN_STATUS */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
-			~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
+	/* clear the busy bit of VCN_STATUS */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
+		~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
 
-		WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
+	WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
 
-		ring = &adev->vcn.inst[i].ring_dec;
-		/* force RBC into idle state */
-		rb_bufsz = order_base_2(ring->ring_size);
-		tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
-		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
-		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
-		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
-		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
-		WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
+	ring = &adev->vcn.inst[inst].ring_dec;
+	/* force RBC into idle state */
+	rb_bufsz = order_base_2(ring->ring_size);
+	tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
+	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
+	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
+	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
+	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
+	WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
 
-		fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
-		/* program the RB_BASE for ring buffer */
-		WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
-			lower_32_bits(ring->gpu_addr));
-		WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
-			upper_32_bits(ring->gpu_addr));
+	fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
+	/* program the RB_BASE for ring buffer */
+	WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
+		lower_32_bits(ring->gpu_addr));
+	WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
+		upper_32_bits(ring->gpu_addr));
 
-		/* Initialize the ring buffer's read and write pointers */
-		WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
+	/* Initialize the ring buffer's read and write pointers */
+	WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
 
-		ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
-		WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
-				lower_32_bits(ring->wptr));
-		fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
+	ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
+	WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
+			lower_32_bits(ring->wptr));
+	fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
 
-		fw_shared->multi_queue.encode_generalpurpose_queue_mode |= FW_QUEUE_RING_RESET;
-		ring = &adev->vcn.inst[i].ring_enc[0];
-		WREG32_SOC15(VCN, i, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
-		WREG32_SOC15(VCN, i, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
-		WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
-		WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
-		WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
-		fw_shared->multi_queue.encode_generalpurpose_queue_mode &= ~FW_QUEUE_RING_RESET;
-
-		fw_shared->multi_queue.encode_lowlatency_queue_mode |= FW_QUEUE_RING_RESET;
-		ring = &adev->vcn.inst[i].ring_enc[1];
-		WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
-		WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
-		WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
-		WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
-		WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4);
-		fw_shared->multi_queue.encode_lowlatency_queue_mode &= ~FW_QUEUE_RING_RESET;
-	}
+	fw_shared->multi_queue.encode_generalpurpose_queue_mode |= FW_QUEUE_RING_RESET;
+	ring = &adev->vcn.inst[inst].ring_enc[0];
+	WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
+	WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
+	WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
+	WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
+	WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
+	fw_shared->multi_queue.encode_generalpurpose_queue_mode &= ~FW_QUEUE_RING_RESET;
+
+	fw_shared->multi_queue.encode_lowlatency_queue_mode |= FW_QUEUE_RING_RESET;
+	ring = &adev->vcn.inst[inst].ring_enc[1];
+	WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
+	WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
+	WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
+	WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
+	WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
+	fw_shared->multi_queue.encode_lowlatency_queue_mode &= ~FW_QUEUE_RING_RESET;
 
 	return 0;
 }
@@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
 	return 0;
 }
 
-static int vcn_v2_5_stop(struct amdgpu_device *adev)
+static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned int inst)
 {
 	uint32_t tmp;
-	int i, r = 0;
+	int r = 0;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
-		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
-			r = vcn_v2_5_stop_dpg_mode(adev, i);
-			continue;
-		}
+	if (adev->vcn.harvest_config & (1 << inst))
+		goto done;
 
-		/* wait for vcn idle */
-		r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS, UVD_STATUS__IDLE, 0x7);
-		if (r)
-			return r;
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
+		r = vcn_v2_5_stop_dpg_mode(adev, inst);
+		goto done;
+	}
 
-		tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
-			UVD_LMI_STATUS__READ_CLEAN_MASK |
-			UVD_LMI_STATUS__WRITE_CLEAN_MASK |
-			UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
-		r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
-		if (r)
-			return r;
+	/* wait for vcn idle */
+	r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS, UVD_STATUS__IDLE, 0x7);
+	if (r)
+		return r;
 
-		/* block LMI UMC channel */
-		tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
-		tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
-		WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
+	tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
+		UVD_LMI_STATUS__READ_CLEAN_MASK |
+		UVD_LMI_STATUS__WRITE_CLEAN_MASK |
+		UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
+	r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
+	if (r)
+		return r;
 
-		tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
-			UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
-		r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
-		if (r)
-			return r;
+	/* block LMI UMC channel */
+	tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
+	tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
+	WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
 
-		/* block VCPU register access */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
-			UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
-			~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
+	tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
+		UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
+	r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
+	if (r)
+		return r;
 
-		/* reset VCPU */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
-			UVD_VCPU_CNTL__BLK_RST_MASK,
-			~UVD_VCPU_CNTL__BLK_RST_MASK);
+	/* block VCPU register access */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
+		UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
+		~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
 
-		/* disable VCPU clock */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
-			~(UVD_VCPU_CNTL__CLK_EN_MASK));
+	/* reset VCPU */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
+		UVD_VCPU_CNTL__BLK_RST_MASK,
+		~UVD_VCPU_CNTL__BLK_RST_MASK);
 
-		/* clear status */
-		WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
+	/* disable VCPU clock */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
+		~(UVD_VCPU_CNTL__CLK_EN_MASK));
 
-		vcn_v2_5_enable_clock_gating(adev);
+	/* clear status */
+	WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
 
-		/* enable register anti-hang mechanism */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
-			UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
-			~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
-	}
+	vcn_v2_5_enable_clock_gating(adev);
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, false, i);
-	}
+	/* enable register anti-hang mechanism */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
+		UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
+		~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
+done:
+	if (adev->pm.dpm_enabled)
+		amdgpu_dpm_enable_vcn(adev, false, inst);
 
 	return 0;
 }
@@ -1838,9 +1827,9 @@ static int vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		return 0;
 
 	if (state == AMD_PG_STATE_GATE)
-		ret = vcn_v2_5_stop(adev);
+		ret = vcn_v2_5_stop(adev, inst);
 	else
-		ret = vcn_v2_5_start(adev);
+		ret = vcn_v2_5_start(adev, inst);
 
 	if (!ret)
 		adev->vcn.cur_state[inst] = state;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 12/18] drm/amdgpu: power vcn 3_0 by instance
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (10 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 11/18] drm/amdgpu: power vcn 2_5 " boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 18:44 ` [PATCH 13/18] drm/amdgpu: power vcn 4_0 " boyuan.zhang
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

For vcn 3_0, add ip_block for each vcn instance during discovery stage.

And only powering on/off one of the vcn instance using the
instance value stored in ip_block, instead of powering on/off all
vcn instances. Modify the existing functions to use the instance value
in ip_block, and remove the original for loop for all vcn instances.

v2: rename "i"/"j" to "inst" for instance value.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   3 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c         | 583 +++++++++---------
 2 files changed, 289 insertions(+), 297 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index de1053cc2a2b..1690e19b3269 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -2335,7 +2335,8 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
 		case IP_VERSION(3, 1, 1):
 		case IP_VERSION(3, 1, 2):
 		case IP_VERSION(3, 0, 2):
-			amdgpu_device_ip_block_add(adev, &vcn_v3_0_ip_block);
+			for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
+				amdgpu_device_ip_block_add(adev, &vcn_v3_0_ip_block);
 			if (!amdgpu_sriov_vf(adev))
 				amdgpu_device_ip_block_add(adev, &jpeg_v3_0_ip_block);
 			break;
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
index e7d681773b62..ea79c83aa21d 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
@@ -160,7 +160,7 @@ static int vcn_v3_0_early_init(struct amdgpu_ip_block *ip_block)
 static int vcn_v3_0_sw_init(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_ring *ring;
-	int i, j, r;
+	int inst = ip_block->instance, j, r;
 	int vcn_doorbell_index = 0;
 	uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_3_0);
 	uint32_t *ptr;
@@ -189,93 +189,91 @@ static int vcn_v3_0_sw_init(struct amdgpu_ip_block *ip_block)
 		vcn_doorbell_index = vcn_doorbell_index << 1;
 	}
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
-		volatile struct amdgpu_fw_shared *fw_shared;
+	volatile struct amdgpu_fw_shared *fw_shared;
 
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
+	if (adev->vcn.harvest_config & (1 << inst))
+		goto done;
+
+	adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
+	adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
+	adev->vcn.internal.ib_bar_low = mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
+	adev->vcn.internal.ib_bar_high = mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
+	adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
+	adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
+
+	adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
+	adev->vcn.inst[inst].external.scratch9 = SOC15_REG_OFFSET(VCN, inst, mmUVD_SCRATCH9);
+	adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
+	adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_DATA0);
+	adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
+	adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_DATA1);
+	adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
+	adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_CMD);
+	adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
+	adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN, inst, mmUVD_NO_OP);
+
+	/* VCN DEC TRAP */
+	r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
+			VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->vcn.inst[inst].irq);
+	if (r)
+		return r;
+
+	atomic_set(&adev->vcn.inst[inst].sched_score, 0);
 
-		adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
-		adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
-		adev->vcn.internal.ib_bar_low = mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
-		adev->vcn.internal.ib_bar_high = mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
-		adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
-		adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
-
-		adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
-		adev->vcn.inst[i].external.scratch9 = SOC15_REG_OFFSET(VCN, i, mmUVD_SCRATCH9);
-		adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
-		adev->vcn.inst[i].external.data0 = SOC15_REG_OFFSET(VCN, i, mmUVD_GPCOM_VCPU_DATA0);
-		adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
-		adev->vcn.inst[i].external.data1 = SOC15_REG_OFFSET(VCN, i, mmUVD_GPCOM_VCPU_DATA1);
-		adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
-		adev->vcn.inst[i].external.cmd = SOC15_REG_OFFSET(VCN, i, mmUVD_GPCOM_VCPU_CMD);
-		adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
-		adev->vcn.inst[i].external.nop = SOC15_REG_OFFSET(VCN, i, mmUVD_NO_OP);
-
-		/* VCN DEC TRAP */
-		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[i],
-				VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->vcn.inst[i].irq);
+	ring = &adev->vcn.inst[inst].ring_dec;
+	ring->use_doorbell = true;
+	if (amdgpu_sriov_vf(adev)) {
+		ring->doorbell_index = vcn_doorbell_index + inst * (adev->vcn.num_enc_rings + 1);
+	} else {
+		ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 8 * inst;
+	}
+	ring->vm_hub = AMDGPU_MMHUB0(0);
+	sprintf(ring->name, "vcn_dec_%d", inst);
+	r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq, 0,
+				 AMDGPU_RING_PRIO_DEFAULT,
+				 &adev->vcn.inst[inst].sched_score);
+	if (r)
+		return r;
+
+	for (j = 0; j < adev->vcn.num_enc_rings; ++j) {
+		enum amdgpu_ring_priority_level hw_prio = amdgpu_vcn_get_enc_ring_prio(j);
+
+		/* VCN ENC TRAP */
+		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
+			j + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[inst].irq);
 		if (r)
 			return r;
 
-		atomic_set(&adev->vcn.inst[i].sched_score, 0);
-
-		ring = &adev->vcn.inst[i].ring_dec;
+		ring = &adev->vcn.inst[inst].ring_enc[j];
 		ring->use_doorbell = true;
 		if (amdgpu_sriov_vf(adev)) {
-			ring->doorbell_index = vcn_doorbell_index + i * (adev->vcn.num_enc_rings + 1);
+			ring->doorbell_index = vcn_doorbell_index + inst * (adev->vcn.num_enc_rings + 1) + 1 + j;
 		} else {
-			ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 8 * i;
+			ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 2 + j + 8 * inst;
 		}
 		ring->vm_hub = AMDGPU_MMHUB0(0);
-		sprintf(ring->name, "vcn_dec_%d", i);
-		r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[i].irq, 0,
-				     AMDGPU_RING_PRIO_DEFAULT,
-				     &adev->vcn.inst[i].sched_score);
+		sprintf(ring->name, "vcn_enc_%d.%d", inst, j);
+		r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq, 0,
+					 hw_prio, &adev->vcn.inst[inst].sched_score);
 		if (r)
 			return r;
-
-		for (j = 0; j < adev->vcn.num_enc_rings; ++j) {
-			enum amdgpu_ring_priority_level hw_prio = amdgpu_vcn_get_enc_ring_prio(j);
-
-			/* VCN ENC TRAP */
-			r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[i],
-				j + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[i].irq);
-			if (r)
-				return r;
-
-			ring = &adev->vcn.inst[i].ring_enc[j];
-			ring->use_doorbell = true;
-			if (amdgpu_sriov_vf(adev)) {
-				ring->doorbell_index = vcn_doorbell_index + i * (adev->vcn.num_enc_rings + 1) + 1 + j;
-			} else {
-				ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 2 + j + 8 * i;
-			}
-			ring->vm_hub = AMDGPU_MMHUB0(0);
-			sprintf(ring->name, "vcn_enc_%d.%d", i, j);
-			r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[i].irq, 0,
-					     hw_prio, &adev->vcn.inst[i].sched_score);
-			if (r)
-				return r;
-		}
-
-		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
-		fw_shared->present_flag_0 |= cpu_to_le32(AMDGPU_VCN_SW_RING_FLAG) |
-					     cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG) |
-					     cpu_to_le32(AMDGPU_VCN_FW_SHARED_FLAG_0_RB);
-		fw_shared->sw_ring.is_enabled = cpu_to_le32(DEC_SW_RING_ENABLED);
-		fw_shared->present_flag_0 |= AMDGPU_VCN_SMU_VERSION_INFO_FLAG;
-		if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(3, 1, 2))
-			fw_shared->smu_interface_info.smu_interface_type = 2;
-		else if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
-			 IP_VERSION(3, 1, 1))
-			fw_shared->smu_interface_info.smu_interface_type = 1;
-
-		if (amdgpu_vcnfw_log)
-			amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
 	}
 
+	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
+	fw_shared->present_flag_0 |= cpu_to_le32(AMDGPU_VCN_SW_RING_FLAG) |
+					 cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG) |
+					 cpu_to_le32(AMDGPU_VCN_FW_SHARED_FLAG_0_RB);
+	fw_shared->sw_ring.is_enabled = cpu_to_le32(DEC_SW_RING_ENABLED);
+	fw_shared->present_flag_0 |= AMDGPU_VCN_SMU_VERSION_INFO_FLAG;
+	if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(3, 1, 2))
+		fw_shared->smu_interface_info.smu_interface_type = 2;
+	else if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
+		 IP_VERSION(3, 1, 1))
+		fw_shared->smu_interface_info.smu_interface_type = 1;
+
+	if (amdgpu_vcnfw_log)
+		amdgpu_vcn_fwlog_init(&adev->vcn.inst[inst]);
+done:
 	if (amdgpu_sriov_vf(adev)) {
 		r = amdgpu_virt_alloc_mm_table(adev);
 		if (r)
@@ -1132,192 +1130,188 @@ static int vcn_v3_0_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, boo
 	return 0;
 }
 
-static int vcn_v3_0_start(struct amdgpu_device *adev)
+static int vcn_v3_0_start(struct amdgpu_device *adev, unsigned int inst)
 {
 	volatile struct amdgpu_fw_shared *fw_shared;
 	struct amdgpu_ring *ring;
 	uint32_t rb_bufsz, tmp;
-	int i, j, k, r;
+	int j, k, r;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, true, i);
+	if (adev->pm.dpm_enabled)
+		amdgpu_dpm_enable_vcn(adev, true, inst);
+
+	if (adev->vcn.harvest_config & (1 << inst))
+		return 0;
+
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
+		r = vcn_v3_0_start_dpg_mode(adev, inst, adev->vcn.indirect_sram);
+		return r;
 	}
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
+	/* disable VCN power gating */
+	vcn_v3_0_disable_static_power_gating(adev, inst);
 
-		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
-			r = vcn_v3_0_start_dpg_mode(adev, i, adev->vcn.indirect_sram);
-			continue;
-		}
+	/* set VCN status busy */
+	tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
+	WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
 
-		/* disable VCN power gating */
-		vcn_v3_0_disable_static_power_gating(adev, i);
-
-		/* set VCN status busy */
-		tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
-		WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
-
-		/*SW clock gating */
-		vcn_v3_0_disable_clock_gating(adev, i);
-
-		/* enable VCPU clock */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
-			UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
-
-		/* disable master interrupt */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
-			~UVD_MASTINT_EN__VCPU_EN_MASK);
-
-		/* enable LMI MC and UMC channels */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
-			~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
-
-		tmp = RREG32_SOC15(VCN, i, mmUVD_SOFT_RESET);
-		tmp &= ~UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
-		tmp &= ~UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, i, mmUVD_SOFT_RESET, tmp);
-
-		/* setup mmUVD_LMI_CTRL */
-		tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
-		WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp |
-			UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK	|
-			UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
-			UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
-			UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
-
-		/* setup mmUVD_MPC_CNTL */
-		tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
-		tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
-		tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
-		WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
-
-		/* setup UVD_MPC_SET_MUXA0 */
-		WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
-			((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
-			(0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
-			(0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
-			(0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
-
-		/* setup UVD_MPC_SET_MUXB0 */
-		WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
-			((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
-			(0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
-			(0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
-			(0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
-
-		/* setup mmUVD_MPC_SET_MUX */
-		WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
-			((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
-			(0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
-			(0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
-
-		vcn_v3_0_mc_resume(adev, i);
-
-		/* VCN global tiling registers */
-		WREG32_SOC15(VCN, i, mmUVD_GFX10_ADDR_CONFIG,
-			adev->gfx.config.gb_addr_config);
-
-		/* unblock VCPU register access */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
-			~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
-
-		/* release VCPU reset to boot */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
-			~UVD_VCPU_CNTL__BLK_RST_MASK);
+	/*SW clock gating */
+	vcn_v3_0_disable_clock_gating(adev, inst);
 
-		for (j = 0; j < 10; ++j) {
-			uint32_t status;
+	/* enable VCPU clock */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
+		UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
 
-			for (k = 0; k < 100; ++k) {
-				status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
-				if (status & 2)
-					break;
-				mdelay(10);
-			}
-			r = 0;
-			if (status & 2)
-				break;
+	/* disable master interrupt */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
+		~UVD_MASTINT_EN__VCPU_EN_MASK);
 
-			DRM_ERROR("VCN[%d] decode not responding, trying to reset the VCPU!!!\n", i);
-			WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
-				UVD_VCPU_CNTL__BLK_RST_MASK,
-				~UVD_VCPU_CNTL__BLK_RST_MASK);
-			mdelay(10);
-			WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
-				~UVD_VCPU_CNTL__BLK_RST_MASK);
+	/* enable LMI MC and UMC channels */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
+		~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
+
+	tmp = RREG32_SOC15(VCN, inst, mmUVD_SOFT_RESET);
+	tmp &= ~UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
+	tmp &= ~UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, inst, mmUVD_SOFT_RESET, tmp);
+
+	/* setup mmUVD_LMI_CTRL */
+	tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
+	WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp |
+		UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK	|
+		UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
+		UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
+		UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
+
+	/* setup mmUVD_MPC_CNTL */
+	tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
+	tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
+	tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
+	WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
+
+	/* setup UVD_MPC_SET_MUXA0 */
+	WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
+		((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
+		(0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
+		(0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
+		(0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
+
+	/* setup UVD_MPC_SET_MUXB0 */
+	WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
+		((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
+		(0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
+		(0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
+		(0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
+
+	/* setup mmUVD_MPC_SET_MUX */
+	WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
+		((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
+		(0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
+		(0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
+
+	vcn_v3_0_mc_resume(adev, inst);
+
+	/* VCN global tiling registers */
+	WREG32_SOC15(VCN, inst, mmUVD_GFX10_ADDR_CONFIG,
+		adev->gfx.config.gb_addr_config);
+
+	/* unblock VCPU register access */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
+		~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
+
+	/* release VCPU reset to boot */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
+		~UVD_VCPU_CNTL__BLK_RST_MASK);
+
+	for (j = 0; j < 10; ++j) {
+		uint32_t status;
 
+		for (k = 0; k < 100; ++k) {
+			status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
+			if (status & 2)
+				break;
 			mdelay(10);
-			r = -1;
 		}
+		r = 0;
+		if (status & 2)
+			break;
 
-		if (r) {
-			DRM_ERROR("VCN[%d] decode not responding, giving up!!!\n", i);
-			return r;
-		}
+		DRM_ERROR("VCN[%d] decode not responding, trying to reset the VCPU!!!\n", inst);
+		WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
+			UVD_VCPU_CNTL__BLK_RST_MASK,
+			~UVD_VCPU_CNTL__BLK_RST_MASK);
+		mdelay(10);
+		WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
+			~UVD_VCPU_CNTL__BLK_RST_MASK);
 
-		/* enable master interrupt */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
-			UVD_MASTINT_EN__VCPU_EN_MASK,
-			~UVD_MASTINT_EN__VCPU_EN_MASK);
+		mdelay(10);
+		r = -1;
+	}
 
-		/* clear the busy bit of VCN_STATUS */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
-			~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
+	if (r) {
+		DRM_ERROR("VCN[%d] decode not responding, giving up!!!\n", inst);
+		return r;
+	}
 
-		WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
+	/* enable master interrupt */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
+		UVD_MASTINT_EN__VCPU_EN_MASK,
+		~UVD_MASTINT_EN__VCPU_EN_MASK);
 
-		ring = &adev->vcn.inst[i].ring_dec;
-		/* force RBC into idle state */
-		rb_bufsz = order_base_2(ring->ring_size);
-		tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
-		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
-		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
-		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
-		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
-		WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
+	/* clear the busy bit of VCN_STATUS */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
+		~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
 
-		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
-		fw_shared->multi_queue.decode_queue_mode |= cpu_to_le32(FW_QUEUE_RING_RESET);
+	WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
 
-		/* programm the RB_BASE for ring buffer */
-		WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
-			lower_32_bits(ring->gpu_addr));
-		WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
-			upper_32_bits(ring->gpu_addr));
+	ring = &adev->vcn.inst[inst].ring_dec;
+	/* force RBC into idle state */
+	rb_bufsz = order_base_2(ring->ring_size);
+	tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
+	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
+	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
+	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
+	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
+	WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
 
-		/* Initialize the ring buffer's read and write pointers */
-		WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
+	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
+	fw_shared->multi_queue.decode_queue_mode |= cpu_to_le32(FW_QUEUE_RING_RESET);
 
-		WREG32_SOC15(VCN, i, mmUVD_SCRATCH2, 0);
-		ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
-		WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
-			lower_32_bits(ring->wptr));
-		fw_shared->rb.wptr = lower_32_bits(ring->wptr);
-		fw_shared->multi_queue.decode_queue_mode &= cpu_to_le32(~FW_QUEUE_RING_RESET);
-
-		if (amdgpu_ip_version(adev, UVD_HWIP, 0) !=
-		    IP_VERSION(3, 0, 33)) {
-			fw_shared->multi_queue.encode_generalpurpose_queue_mode |= cpu_to_le32(FW_QUEUE_RING_RESET);
-			ring = &adev->vcn.inst[i].ring_enc[0];
-			WREG32_SOC15(VCN, i, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
-			WREG32_SOC15(VCN, i, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
-			WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
-			WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
-			WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
-			fw_shared->multi_queue.encode_generalpurpose_queue_mode &= cpu_to_le32(~FW_QUEUE_RING_RESET);
-
-			fw_shared->multi_queue.encode_lowlatency_queue_mode |= cpu_to_le32(FW_QUEUE_RING_RESET);
-			ring = &adev->vcn.inst[i].ring_enc[1];
-			WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
-			WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
-			WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
-			WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
-			WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4);
-			fw_shared->multi_queue.encode_lowlatency_queue_mode &= cpu_to_le32(~FW_QUEUE_RING_RESET);
-		}
+	/* programm the RB_BASE for ring buffer */
+	WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
+		lower_32_bits(ring->gpu_addr));
+	WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
+		upper_32_bits(ring->gpu_addr));
+
+	/* Initialize the ring buffer's read and write pointers */
+	WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
+
+	WREG32_SOC15(VCN, inst, mmUVD_SCRATCH2, 0);
+	ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
+	WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
+		lower_32_bits(ring->wptr));
+	fw_shared->rb.wptr = lower_32_bits(ring->wptr);
+	fw_shared->multi_queue.decode_queue_mode &= cpu_to_le32(~FW_QUEUE_RING_RESET);
+
+	if (amdgpu_ip_version(adev, UVD_HWIP, 0) !=
+		IP_VERSION(3, 0, 33)) {
+		fw_shared->multi_queue.encode_generalpurpose_queue_mode |= cpu_to_le32(FW_QUEUE_RING_RESET);
+		ring = &adev->vcn.inst[inst].ring_enc[0];
+		WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
+		WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
+		WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
+		WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
+		WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
+		fw_shared->multi_queue.encode_generalpurpose_queue_mode &= cpu_to_le32(~FW_QUEUE_RING_RESET);
+
+		fw_shared->multi_queue.encode_lowlatency_queue_mode |= cpu_to_le32(FW_QUEUE_RING_RESET);
+		ring = &adev->vcn.inst[inst].ring_enc[1];
+		WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
+		WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
+		WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
+		WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
+		WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
+		fw_shared->multi_queue.encode_lowlatency_queue_mode &= cpu_to_le32(~FW_QUEUE_RING_RESET);
 	}
 
 	return 0;
@@ -1563,79 +1557,76 @@ static int vcn_v3_0_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
 	return 0;
 }
 
-static int vcn_v3_0_stop(struct amdgpu_device *adev)
+static int vcn_v3_0_stop(struct amdgpu_device *adev, unsigned int inst)
 {
 	uint32_t tmp;
-	int i, r = 0;
+	int r = 0;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
+	if (adev->vcn.harvest_config & (1 << inst))
+		goto done;
 
-		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
-			r = vcn_v3_0_stop_dpg_mode(adev, i);
-			continue;
-		}
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
+		r = vcn_v3_0_stop_dpg_mode(adev, inst);
+		goto done;
+	}
 
-		/* wait for vcn idle */
-		r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS, UVD_STATUS__IDLE, 0x7);
-		if (r)
-			return r;
+	/* wait for vcn idle */
+	r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS, UVD_STATUS__IDLE, 0x7);
+	if (r)
+		return r;
 
-		tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
-			UVD_LMI_STATUS__READ_CLEAN_MASK |
-			UVD_LMI_STATUS__WRITE_CLEAN_MASK |
-			UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
-		r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
-		if (r)
-			return r;
+	tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
+		UVD_LMI_STATUS__READ_CLEAN_MASK |
+		UVD_LMI_STATUS__WRITE_CLEAN_MASK |
+		UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
+	r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
+	if (r)
+		return r;
 
-		/* disable LMI UMC channel */
-		tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
-		tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
-		WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
-		tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
-			UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
-		r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
-		if (r)
-			return r;
+	/* disable LMI UMC channel */
+	tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
+	tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
+	WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
+	tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
+		UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
+	r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
+	if (r)
+		return r;
 
-		/* block VCPU register access */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
-			UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
-			~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
+	/* block VCPU register access */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
+		UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
+		~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
 
-		/* reset VCPU */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
-			UVD_VCPU_CNTL__BLK_RST_MASK,
-			~UVD_VCPU_CNTL__BLK_RST_MASK);
+	/* reset VCPU */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
+		UVD_VCPU_CNTL__BLK_RST_MASK,
+		~UVD_VCPU_CNTL__BLK_RST_MASK);
 
-		/* disable VCPU clock */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
-			~(UVD_VCPU_CNTL__CLK_EN_MASK));
+	/* disable VCPU clock */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
+		~(UVD_VCPU_CNTL__CLK_EN_MASK));
 
-		/* apply soft reset */
-		tmp = RREG32_SOC15(VCN, i, mmUVD_SOFT_RESET);
-		tmp |= UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, i, mmUVD_SOFT_RESET, tmp);
-		tmp = RREG32_SOC15(VCN, i, mmUVD_SOFT_RESET);
-		tmp |= UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, i, mmUVD_SOFT_RESET, tmp);
+	/* apply soft reset */
+	tmp = RREG32_SOC15(VCN, inst, mmUVD_SOFT_RESET);
+	tmp |= UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, inst, mmUVD_SOFT_RESET, tmp);
+	tmp = RREG32_SOC15(VCN, inst, mmUVD_SOFT_RESET);
+	tmp |= UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, inst, mmUVD_SOFT_RESET, tmp);
 
-		/* clear status */
-		WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
+	/* clear status */
+	WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
 
-		/* apply HW clock gating */
-		vcn_v3_0_enable_clock_gating(adev, i);
+	/* apply HW clock gating */
+	vcn_v3_0_enable_clock_gating(adev, inst);
 
-		/* enable VCN power gating */
-		vcn_v3_0_enable_static_power_gating(adev, i);
-	}
+	/* enable VCN power gating */
+	vcn_v3_0_enable_static_power_gating(adev, inst);
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, false, i);
-	}
+done:
+	if (adev->pm.dpm_enabled)
+		amdgpu_dpm_enable_vcn(adev, false, inst);
 
 	return 0;
 }
@@ -2177,9 +2168,9 @@ static int vcn_v3_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		return 0;
 
 	if (state == AMD_PG_STATE_GATE)
-		ret = vcn_v3_0_stop(adev);
+		ret = vcn_v3_0_stop(adev, inst);
 	else
-		ret = vcn_v3_0_start(adev);
+		ret = vcn_v3_0_start(adev, inst);
 
 	if (!ret)
 		adev->vcn.cur_state[inst] = state;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 13/18] drm/amdgpu: power vcn 4_0 by instance
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (11 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 12/18] drm/amdgpu: power vcn 3_0 " boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 18:44 ` [PATCH 14/18] drm/amdgpu: power vcn 4_0_3 " boyuan.zhang
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

For vcn 4_0, add ip_block for each vcn instance during discovery stage.

And only powering on/off one of the vcn instance using the
instance value stored in ip_block, instead of powering on/off all
vcn instances. Modify the existing functions to use the instance value
in ip_block, and remove the original for loop for all vcn instances.

v2: rename "i"/"j" to "inst" for instance value.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   3 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c         | 495 +++++++++---------
 2 files changed, 245 insertions(+), 253 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 1690e19b3269..54b70255bdfe 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -2346,7 +2346,8 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
 		case IP_VERSION(4, 0, 0):
 		case IP_VERSION(4, 0, 2):
 		case IP_VERSION(4, 0, 4):
-			amdgpu_device_ip_block_add(adev, &vcn_v4_0_ip_block);
+			for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
+				amdgpu_device_ip_block_add(adev, &vcn_v4_0_ip_block);
 			amdgpu_device_ip_block_add(adev, &jpeg_v4_0_ip_block);
 			break;
 		case IP_VERSION(4, 0, 3):
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index 535d513752f4..1555e823abe2 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -172,7 +172,8 @@ static int vcn_v4_0_sw_init(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_ring *ring;
 	struct amdgpu_device *adev = ip_block->adev;
-	int i, r;
+	int inst = ip_block->instance, r;
+
 	uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_4_0);
 	uint32_t *ptr;
 
@@ -186,45 +187,43 @@ static int vcn_v4_0_sw_init(struct amdgpu_ip_block *ip_block)
 	if (r)
 		return r;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
+	if (adev->vcn.harvest_config & (1 << inst))
+		goto done;
 
-		/* Init instance 0 sched_score to 1, so it's scheduled after other instances */
-		if (i == 0)
-			atomic_set(&adev->vcn.inst[i].sched_score, 1);
-		else
-			atomic_set(&adev->vcn.inst[i].sched_score, 0);
+	/* Init instance 0 sched_score to 1, so it's scheduled after other instances */
+	if (inst == 0)
+		atomic_set(&adev->vcn.inst[inst].sched_score, 1);
+	else
+		atomic_set(&adev->vcn.inst[inst].sched_score, 0);
 
-		/* VCN UNIFIED TRAP */
-		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[i],
-				VCN_4_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[i].irq);
-		if (r)
-			return r;
+	/* VCN UNIFIED TRAP */
+	r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
+			VCN_4_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[inst].irq);
+	if (r)
+		return r;
 
-		/* VCN POISON TRAP */
-		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[i],
-				VCN_4_0__SRCID_UVD_POISON, &adev->vcn.inst[i].ras_poison_irq);
-		if (r)
-			return r;
+	/* VCN POISON TRAP */
+	r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
+			VCN_4_0__SRCID_UVD_POISON, &adev->vcn.inst[inst].ras_poison_irq);
+	if (r)
+		return r;
 
-		ring = &adev->vcn.inst[i].ring_enc[0];
-		ring->use_doorbell = true;
-		if (amdgpu_sriov_vf(adev))
-			ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + i * (adev->vcn.num_enc_rings + 1) + 1;
-		else
-			ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 2 + 8 * i;
-		ring->vm_hub = AMDGPU_MMHUB0(0);
-		sprintf(ring->name, "vcn_unified_%d", i);
-
-		r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[i].irq, 0,
-						AMDGPU_RING_PRIO_0, &adev->vcn.inst[i].sched_score);
-		if (r)
-			return r;
+	ring = &adev->vcn.inst[inst].ring_enc[0];
+	ring->use_doorbell = true;
+	if (amdgpu_sriov_vf(adev))
+		ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + inst * (adev->vcn.num_enc_rings + 1) + 1;
+	else
+		ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 2 + 8 * inst;
+	ring->vm_hub = AMDGPU_MMHUB0(0);
+	sprintf(ring->name, "vcn_unified_%d", inst);
 
-		vcn_v4_0_fw_shared_init(adev, i);
-	}
+	r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq, 0,
+					AMDGPU_RING_PRIO_0, &adev->vcn.inst[inst].sched_score);
+	if (r)
+		return r;
 
+	vcn_v4_0_fw_shared_init(adev, inst);
+done:
 	if (amdgpu_sriov_vf(adev)) {
 		r = amdgpu_virt_alloc_mm_table(adev);
 		if (r)
@@ -1081,180 +1080,176 @@ static int vcn_v4_0_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, boo
  *
  * Start VCN block
  */
-static int vcn_v4_0_start(struct amdgpu_device *adev)
+static int vcn_v4_0_start(struct amdgpu_device *adev, unsigned int inst)
 {
 	volatile struct amdgpu_vcn4_fw_shared *fw_shared;
 	struct amdgpu_ring *ring;
 	uint32_t tmp;
-	int i, j, k, r;
+	int j, k, r;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, true, i);
+	if (adev->pm.dpm_enabled)
+		amdgpu_dpm_enable_vcn(adev, true, inst);
+
+	if (adev->vcn.harvest_config & (1 << inst))
+		return 0;
+
+	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
+
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
+		r = vcn_v4_0_start_dpg_mode(adev, inst, adev->vcn.indirect_sram);
+		return r;
 	}
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
+	/* disable VCN power gating */
+	vcn_v4_0_disable_static_power_gating(adev, inst);
 
-		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
+	/* set VCN status busy */
+	tmp = RREG32_SOC15(VCN, inst, regUVD_STATUS) | UVD_STATUS__UVD_BUSY;
+	WREG32_SOC15(VCN, inst, regUVD_STATUS, tmp);
 
-		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
-			r = vcn_v4_0_start_dpg_mode(adev, i, adev->vcn.indirect_sram);
-			continue;
+	/*SW clock gating */
+	vcn_v4_0_disable_clock_gating(adev, inst);
+
+	/* enable VCPU clock */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL),
+			UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
+
+	/* disable master interrupt */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_MASTINT_EN), 0,
+			~UVD_MASTINT_EN__VCPU_EN_MASK);
+
+	/* enable LMI MC and UMC channels */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_LMI_CTRL2), 0,
+			~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
+
+	tmp = RREG32_SOC15(VCN, inst, regUVD_SOFT_RESET);
+	tmp &= ~UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
+	tmp &= ~UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, inst, regUVD_SOFT_RESET, tmp);
+
+	/* setup regUVD_LMI_CTRL */
+	tmp = RREG32_SOC15(VCN, inst, regUVD_LMI_CTRL);
+	WREG32_SOC15(VCN, inst, regUVD_LMI_CTRL, tmp |
+			UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK |
+			UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
+			UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
+			UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
+
+	/* setup regUVD_MPC_CNTL */
+	tmp = RREG32_SOC15(VCN, inst, regUVD_MPC_CNTL);
+	tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
+	tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
+	WREG32_SOC15(VCN, inst, regUVD_MPC_CNTL, tmp);
+
+	/* setup UVD_MPC_SET_MUXA0 */
+	WREG32_SOC15(VCN, inst, regUVD_MPC_SET_MUXA0,
+			((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
+			 (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
+			 (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
+			 (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
+
+	/* setup UVD_MPC_SET_MUXB0 */
+	WREG32_SOC15(VCN, inst, regUVD_MPC_SET_MUXB0,
+			((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
+			 (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
+			 (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
+			 (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
+
+	/* setup UVD_MPC_SET_MUX */
+	WREG32_SOC15(VCN, inst, regUVD_MPC_SET_MUX,
+			((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
+			 (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
+			 (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
+
+	vcn_v4_0_mc_resume(adev, inst);
+
+	/* VCN global tiling registers */
+	WREG32_SOC15(VCN, inst, regUVD_GFX10_ADDR_CONFIG,
+			adev->gfx.config.gb_addr_config);
+
+	/* unblock VCPU register access */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_RB_ARB_CTRL), 0,
+			~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
+
+	/* release VCPU reset to boot */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL), 0,
+			~UVD_VCPU_CNTL__BLK_RST_MASK);
+
+	for (j = 0; j < 10; ++j) {
+		uint32_t status;
+
+		for (k = 0; k < 100; ++k) {
+			status = RREG32_SOC15(VCN, inst, regUVD_STATUS);
+			if (status & 2)
+				break;
+			mdelay(10);
+			if (amdgpu_emu_mode == 1)
+				msleep(1);
 		}
 
-		/* disable VCN power gating */
-		vcn_v4_0_disable_static_power_gating(adev, i);
-
-		/* set VCN status busy */
-		tmp = RREG32_SOC15(VCN, i, regUVD_STATUS) | UVD_STATUS__UVD_BUSY;
-		WREG32_SOC15(VCN, i, regUVD_STATUS, tmp);
-
-		/*SW clock gating */
-		vcn_v4_0_disable_clock_gating(adev, i);
-
-		/* enable VCPU clock */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL),
-				UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
-
-		/* disable master interrupt */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_MASTINT_EN), 0,
-				~UVD_MASTINT_EN__VCPU_EN_MASK);
-
-		/* enable LMI MC and UMC channels */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_LMI_CTRL2), 0,
-				~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
-
-		tmp = RREG32_SOC15(VCN, i, regUVD_SOFT_RESET);
-		tmp &= ~UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
-		tmp &= ~UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, i, regUVD_SOFT_RESET, tmp);
-
-		/* setup regUVD_LMI_CTRL */
-		tmp = RREG32_SOC15(VCN, i, regUVD_LMI_CTRL);
-		WREG32_SOC15(VCN, i, regUVD_LMI_CTRL, tmp |
-				UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK |
-				UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
-				UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
-				UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
-
-		/* setup regUVD_MPC_CNTL */
-		tmp = RREG32_SOC15(VCN, i, regUVD_MPC_CNTL);
-		tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
-		tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
-		WREG32_SOC15(VCN, i, regUVD_MPC_CNTL, tmp);
-
-		/* setup UVD_MPC_SET_MUXA0 */
-		WREG32_SOC15(VCN, i, regUVD_MPC_SET_MUXA0,
-				((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
-				 (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
-				 (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
-				 (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
-
-		/* setup UVD_MPC_SET_MUXB0 */
-		WREG32_SOC15(VCN, i, regUVD_MPC_SET_MUXB0,
-				((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
-				 (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
-				 (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
-				 (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
-
-		/* setup UVD_MPC_SET_MUX */
-		WREG32_SOC15(VCN, i, regUVD_MPC_SET_MUX,
-				((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
-				 (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
-				 (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
-
-		vcn_v4_0_mc_resume(adev, i);
-
-		/* VCN global tiling registers */
-		WREG32_SOC15(VCN, i, regUVD_GFX10_ADDR_CONFIG,
-				adev->gfx.config.gb_addr_config);
-
-		/* unblock VCPU register access */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_RB_ARB_CTRL), 0,
-				~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
-
-		/* release VCPU reset to boot */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL), 0,
-				~UVD_VCPU_CNTL__BLK_RST_MASK);
-
-		for (j = 0; j < 10; ++j) {
-			uint32_t status;
-
-			for (k = 0; k < 100; ++k) {
-				status = RREG32_SOC15(VCN, i, regUVD_STATUS);
-				if (status & 2)
-					break;
-				mdelay(10);
-				if (amdgpu_emu_mode == 1)
-					msleep(1);
+		if (amdgpu_emu_mode == 1) {
+			r = -1;
+			if (status & 2) {
+				r = 0;
+				break;
 			}
+		} else {
+			r = 0;
+			if (status & 2)
+				break;
 
-			if (amdgpu_emu_mode == 1) {
-				r = -1;
-				if (status & 2) {
-					r = 0;
-					break;
-				}
-			} else {
-				r = 0;
-				if (status & 2)
-					break;
-
-				dev_err(adev->dev, "VCN[%d] is not responding, trying to reset the VCPU!!!\n", i);
-				WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL),
-							UVD_VCPU_CNTL__BLK_RST_MASK,
-							~UVD_VCPU_CNTL__BLK_RST_MASK);
-				mdelay(10);
-				WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL), 0,
+			dev_err(adev->dev, "VCN[%d] is not responding, trying to reset the VCPU!!!\n", inst);
+			WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL),
+						UVD_VCPU_CNTL__BLK_RST_MASK,
 						~UVD_VCPU_CNTL__BLK_RST_MASK);
+			mdelay(10);
+			WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL), 0,
+					~UVD_VCPU_CNTL__BLK_RST_MASK);
 
-				mdelay(10);
-				r = -1;
-			}
-		}
-
-		if (r) {
-			dev_err(adev->dev, "VCN[%d] is not responding, giving up!!!\n", i);
-			return r;
+			mdelay(10);
+			r = -1;
 		}
+	}
 
-		/* enable master interrupt */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_MASTINT_EN),
-				UVD_MASTINT_EN__VCPU_EN_MASK,
-				~UVD_MASTINT_EN__VCPU_EN_MASK);
-
-		/* clear the busy bit of VCN_STATUS */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_STATUS), 0,
-				~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
-
-		ring = &adev->vcn.inst[i].ring_enc[0];
-		WREG32_SOC15(VCN, i, regVCN_RB1_DB_CTRL,
-				ring->doorbell_index << VCN_RB1_DB_CTRL__OFFSET__SHIFT |
-				VCN_RB1_DB_CTRL__EN_MASK);
-
-		WREG32_SOC15(VCN, i, regUVD_RB_BASE_LO, ring->gpu_addr);
-		WREG32_SOC15(VCN, i, regUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
-		WREG32_SOC15(VCN, i, regUVD_RB_SIZE, ring->ring_size / 4);
-
-		tmp = RREG32_SOC15(VCN, i, regVCN_RB_ENABLE);
-		tmp &= ~(VCN_RB_ENABLE__RB1_EN_MASK);
-		WREG32_SOC15(VCN, i, regVCN_RB_ENABLE, tmp);
-		fw_shared->sq.queue_mode |= FW_QUEUE_RING_RESET;
-		WREG32_SOC15(VCN, i, regUVD_RB_RPTR, 0);
-		WREG32_SOC15(VCN, i, regUVD_RB_WPTR, 0);
-
-		tmp = RREG32_SOC15(VCN, i, regUVD_RB_RPTR);
-		WREG32_SOC15(VCN, i, regUVD_RB_WPTR, tmp);
-		ring->wptr = RREG32_SOC15(VCN, i, regUVD_RB_WPTR);
-
-		tmp = RREG32_SOC15(VCN, i, regVCN_RB_ENABLE);
-		tmp |= VCN_RB_ENABLE__RB1_EN_MASK;
-		WREG32_SOC15(VCN, i, regVCN_RB_ENABLE, tmp);
-		fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF);
+	if (r) {
+		dev_err(adev->dev, "VCN[%d] is not responding, giving up!!!\n", inst);
+		return r;
 	}
 
+	/* enable master interrupt */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_MASTINT_EN),
+			UVD_MASTINT_EN__VCPU_EN_MASK,
+			~UVD_MASTINT_EN__VCPU_EN_MASK);
+
+	/* clear the busy bit of VCN_STATUS */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_STATUS), 0,
+			~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
+
+	ring = &adev->vcn.inst[inst].ring_enc[0];
+	WREG32_SOC15(VCN, inst, regVCN_RB1_DB_CTRL,
+			ring->doorbell_index << VCN_RB1_DB_CTRL__OFFSET__SHIFT |
+			VCN_RB1_DB_CTRL__EN_MASK);
+
+	WREG32_SOC15(VCN, inst, regUVD_RB_BASE_LO, ring->gpu_addr);
+	WREG32_SOC15(VCN, inst, regUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
+	WREG32_SOC15(VCN, inst, regUVD_RB_SIZE, ring->ring_size / 4);
+
+	tmp = RREG32_SOC15(VCN, inst, regVCN_RB_ENABLE);
+	tmp &= ~(VCN_RB_ENABLE__RB1_EN_MASK);
+	WREG32_SOC15(VCN, inst, regVCN_RB_ENABLE, tmp);
+	fw_shared->sq.queue_mode |= FW_QUEUE_RING_RESET;
+	WREG32_SOC15(VCN, inst, regUVD_RB_RPTR, 0);
+	WREG32_SOC15(VCN, inst, regUVD_RB_WPTR, 0);
+
+	tmp = RREG32_SOC15(VCN, inst, regUVD_RB_RPTR);
+	WREG32_SOC15(VCN, inst, regUVD_RB_WPTR, tmp);
+	ring->wptr = RREG32_SOC15(VCN, inst, regUVD_RB_WPTR);
+
+	tmp = RREG32_SOC15(VCN, inst, regVCN_RB_ENABLE);
+	tmp |= VCN_RB_ENABLE__RB1_EN_MASK;
+	WREG32_SOC15(VCN, inst, regVCN_RB_ENABLE, tmp);
+	fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF);
+
 	return 0;
 }
 
@@ -1543,83 +1538,79 @@ static void vcn_v4_0_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
  *
  * Stop VCN block
  */
-static int vcn_v4_0_stop(struct amdgpu_device *adev)
+static int vcn_v4_0_stop(struct amdgpu_device *adev, unsigned int inst)
 {
 	volatile struct amdgpu_vcn4_fw_shared *fw_shared;
 	uint32_t tmp;
-	int i, r = 0;
-
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
+	int r = 0;
 
-		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
-		fw_shared->sq.queue_mode |= FW_QUEUE_DPG_HOLD_OFF;
+	if (adev->vcn.harvest_config & (1 << inst))
+		goto done;
 
-		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
-			vcn_v4_0_stop_dpg_mode(adev, i);
-			continue;
-		}
+	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
+	fw_shared->sq.queue_mode |= FW_QUEUE_DPG_HOLD_OFF;
 
-		/* wait for vcn idle */
-		r = SOC15_WAIT_ON_RREG(VCN, i, regUVD_STATUS, UVD_STATUS__IDLE, 0x7);
-		if (r)
-			return r;
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
+		vcn_v4_0_stop_dpg_mode(adev, inst);
+		goto done;
+	}
 
-		tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
-			UVD_LMI_STATUS__READ_CLEAN_MASK |
-			UVD_LMI_STATUS__WRITE_CLEAN_MASK |
-			UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
-		r = SOC15_WAIT_ON_RREG(VCN, i, regUVD_LMI_STATUS, tmp, tmp);
-		if (r)
-			return r;
+	/* wait for vcn idle */
+	r = SOC15_WAIT_ON_RREG(VCN, inst, regUVD_STATUS, UVD_STATUS__IDLE, 0x7);
+	if (r)
+		return r;
 
-		/* disable LMI UMC channel */
-		tmp = RREG32_SOC15(VCN, i, regUVD_LMI_CTRL2);
-		tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
-		WREG32_SOC15(VCN, i, regUVD_LMI_CTRL2, tmp);
-		tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK |
-			UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
-		r = SOC15_WAIT_ON_RREG(VCN, i, regUVD_LMI_STATUS, tmp, tmp);
-		if (r)
-			return r;
+	tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
+		UVD_LMI_STATUS__READ_CLEAN_MASK |
+		UVD_LMI_STATUS__WRITE_CLEAN_MASK |
+		UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
+	r = SOC15_WAIT_ON_RREG(VCN, inst, regUVD_LMI_STATUS, tmp, tmp);
+	if (r)
+		return r;
 
-		/* block VCPU register access */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_RB_ARB_CTRL),
-				UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
-				~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
+	/* disable LMI UMC channel */
+	tmp = RREG32_SOC15(VCN, inst, regUVD_LMI_CTRL2);
+	tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
+	WREG32_SOC15(VCN, inst, regUVD_LMI_CTRL2, tmp);
+	tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK |
+		UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
+	r = SOC15_WAIT_ON_RREG(VCN, inst, regUVD_LMI_STATUS, tmp, tmp);
+	if (r)
+		return r;
 
-		/* reset VCPU */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL),
-				UVD_VCPU_CNTL__BLK_RST_MASK,
-				~UVD_VCPU_CNTL__BLK_RST_MASK);
+	/* block VCPU register access */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_RB_ARB_CTRL),
+			UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
+			~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
 
-		/* disable VCPU clock */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL), 0,
-				~(UVD_VCPU_CNTL__CLK_EN_MASK));
+	/* reset VCPU */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL),
+			UVD_VCPU_CNTL__BLK_RST_MASK,
+			~UVD_VCPU_CNTL__BLK_RST_MASK);
 
-		/* apply soft reset */
-		tmp = RREG32_SOC15(VCN, i, regUVD_SOFT_RESET);
-		tmp |= UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, i, regUVD_SOFT_RESET, tmp);
-		tmp = RREG32_SOC15(VCN, i, regUVD_SOFT_RESET);
-		tmp |= UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, i, regUVD_SOFT_RESET, tmp);
+	/* disable VCPU clock */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL), 0,
+			~(UVD_VCPU_CNTL__CLK_EN_MASK));
 
-		/* clear status */
-		WREG32_SOC15(VCN, i, regUVD_STATUS, 0);
+	/* apply soft reset */
+	tmp = RREG32_SOC15(VCN, inst, regUVD_SOFT_RESET);
+	tmp |= UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, inst, regUVD_SOFT_RESET, tmp);
+	tmp = RREG32_SOC15(VCN, inst, regUVD_SOFT_RESET);
+	tmp |= UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, inst, regUVD_SOFT_RESET, tmp);
 
-		/* apply HW clock gating */
-		vcn_v4_0_enable_clock_gating(adev, i);
+	/* clear status */
+	WREG32_SOC15(VCN, inst, regUVD_STATUS, 0);
 
-		/* enable VCN power gating */
-		vcn_v4_0_enable_static_power_gating(adev, i);
-	}
+	/* apply HW clock gating */
+	vcn_v4_0_enable_clock_gating(adev, inst);
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, false, i);
-	}
+	/* enable VCN power gating */
+	vcn_v4_0_enable_static_power_gating(adev, inst);
+done:
+	if (adev->pm.dpm_enabled)
+		amdgpu_dpm_enable_vcn(adev, false, inst);
 
 	return 0;
 }
@@ -2057,9 +2048,9 @@ static int vcn_v4_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		return 0;
 
 	if (state == AMD_PG_STATE_GATE)
-		ret = vcn_v4_0_stop(adev);
+		ret = vcn_v4_0_stop(adev, inst);
 	else
-		ret = vcn_v4_0_start(adev);
+		ret = vcn_v4_0_start(adev, inst);
 
 	if (!ret)
 		adev->vcn.cur_state[inst] = state;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 14/18] drm/amdgpu: power vcn 4_0_3 by instance
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (12 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 13/18] drm/amdgpu: power vcn 4_0 " boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 18:44 ` [PATCH 15/18] drm/amdgpu: power vcn 4_0_5 " boyuan.zhang
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

For vcn 4_0_3, add ip_block for each vcn instance during discovery stage.

And only powering on/off one of the vcn instance using the
instance value stored in ip_block, instead of powering on/off all
vcn instances. Modify the existing functions to use the instance value
in ip_block, and remove the original for loop for all vcn instances.

v2: rename "i"/"j" to "inst" for instance value.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   3 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c       | 462 +++++++++---------
 2 files changed, 228 insertions(+), 237 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 54b70255bdfe..084bd487b934 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -2351,7 +2351,8 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
 			amdgpu_device_ip_block_add(adev, &jpeg_v4_0_ip_block);
 			break;
 		case IP_VERSION(4, 0, 3):
-			amdgpu_device_ip_block_add(adev, &vcn_v4_0_3_ip_block);
+			for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
+				amdgpu_device_ip_block_add(adev, &vcn_v4_0_3_ip_block);
 			amdgpu_device_ip_block_add(adev, &jpeg_v4_0_3_ip_block);
 			break;
 		case IP_VERSION(4, 0, 5):
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
index deb13a376c6d..97e3b10ba414 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
@@ -127,7 +127,7 @@ static int vcn_v4_0_3_sw_init(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
 	struct amdgpu_ring *ring;
-	int i, r, vcn_inst;
+	int inst = ip_block->instance, r, vcn_inst;
 	uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_4_0_3);
 	uint32_t *ptr;
 
@@ -147,38 +147,36 @@ static int vcn_v4_0_3_sw_init(struct amdgpu_ip_block *ip_block)
 	if (r)
 		return r;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
-		volatile struct amdgpu_vcn4_fw_shared *fw_shared;
+	volatile struct amdgpu_vcn4_fw_shared *fw_shared;
 
-		vcn_inst = GET_INST(VCN, i);
+	vcn_inst = GET_INST(VCN, inst);
 
-		ring = &adev->vcn.inst[i].ring_enc[0];
-		ring->use_doorbell = true;
-
-		if (!amdgpu_sriov_vf(adev))
-			ring->doorbell_index =
-				(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
-				9 * vcn_inst;
-		else
-			ring->doorbell_index =
-				(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
-				32 * vcn_inst;
-
-		ring->vm_hub = AMDGPU_MMHUB0(adev->vcn.inst[i].aid_id);
-		sprintf(ring->name, "vcn_unified_%d", adev->vcn.inst[i].aid_id);
-		r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst->irq, 0,
-				     AMDGPU_RING_PRIO_DEFAULT,
-				     &adev->vcn.inst[i].sched_score);
-		if (r)
-			return r;
+	ring = &adev->vcn.inst[inst].ring_enc[0];
+	ring->use_doorbell = true;
 
-		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
-		fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE);
-		fw_shared->sq.is_enabled = true;
+	if (!amdgpu_sriov_vf(adev))
+		ring->doorbell_index =
+			(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
+			9 * vcn_inst;
+	else
+		ring->doorbell_index =
+			(adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
+			32 * vcn_inst;
+
+	ring->vm_hub = AMDGPU_MMHUB0(adev->vcn.inst[inst].aid_id);
+	sprintf(ring->name, "vcn_unified_%d", adev->vcn.inst[inst].aid_id);
+	r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst->irq, 0,
+				 AMDGPU_RING_PRIO_DEFAULT,
+				 &adev->vcn.inst[inst].sched_score);
+	if (r)
+		return r;
 
-		if (amdgpu_vcnfw_log)
-			amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
-	}
+	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
+	fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE);
+	fw_shared->sq.is_enabled = true;
+
+	if (amdgpu_vcnfw_log)
+		amdgpu_vcn_fwlog_init(&adev->vcn.inst[inst]);
 
 	if (amdgpu_sriov_vf(adev)) {
 		r = amdgpu_virt_alloc_mm_table(adev);
@@ -1085,174 +1083,170 @@ static int vcn_v4_0_3_start_sriov(struct amdgpu_device *adev)
  *
  * Start VCN block
  */
-static int vcn_v4_0_3_start(struct amdgpu_device *adev)
+static int vcn_v4_0_3_start(struct amdgpu_device *adev, unsigned int inst)
 {
 	volatile struct amdgpu_vcn4_fw_shared *fw_shared;
 	struct amdgpu_ring *ring;
-	int i, j, k, r, vcn_inst;
+	int j, k, r, vcn_inst;
 	uint32_t tmp;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, true, i);
+	if (adev->pm.dpm_enabled)
+		amdgpu_dpm_enable_vcn(adev, true, inst);
+
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
+		r = vcn_v4_0_3_start_dpg_mode(adev, inst, adev->vcn.indirect_sram);
+		return r;
 	}
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
-			r = vcn_v4_0_3_start_dpg_mode(adev, i, adev->vcn.indirect_sram);
-			continue;
-		}
+	vcn_inst = GET_INST(VCN, inst);
+	/* set VCN status busy */
+	tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS) |
+		  UVD_STATUS__UVD_BUSY;
+	WREG32_SOC15(VCN, vcn_inst, regUVD_STATUS, tmp);
 
-		vcn_inst = GET_INST(VCN, i);
-		/* set VCN status busy */
-		tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS) |
-		      UVD_STATUS__UVD_BUSY;
-		WREG32_SOC15(VCN, vcn_inst, regUVD_STATUS, tmp);
-
-		/*SW clock gating */
-		vcn_v4_0_3_disable_clock_gating(adev, i);
-
-		/* enable VCPU clock */
-		WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_VCPU_CNTL),
-			 UVD_VCPU_CNTL__CLK_EN_MASK,
-			 ~UVD_VCPU_CNTL__CLK_EN_MASK);
-
-		/* disable master interrupt */
-		WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_MASTINT_EN), 0,
-			 ~UVD_MASTINT_EN__VCPU_EN_MASK);
-
-		/* enable LMI MC and UMC channels */
-		WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_LMI_CTRL2), 0,
-			 ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
-
-		tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET);
-		tmp &= ~UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
-		tmp &= ~UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET, tmp);
-
-		/* setup regUVD_LMI_CTRL */
-		tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_LMI_CTRL);
-		WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_CTRL,
-			     tmp | UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK |
-				     UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
-				     UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
-				     UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
-
-		/* setup regUVD_MPC_CNTL */
-		tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_MPC_CNTL);
-		tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
-		tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
-		WREG32_SOC15(VCN, vcn_inst, regUVD_MPC_CNTL, tmp);
-
-		/* setup UVD_MPC_SET_MUXA0 */
-		WREG32_SOC15(VCN, vcn_inst, regUVD_MPC_SET_MUXA0,
-			     ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
-			      (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
-			      (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
-			      (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
-
-		/* setup UVD_MPC_SET_MUXB0 */
-		WREG32_SOC15(VCN, vcn_inst, regUVD_MPC_SET_MUXB0,
-			     ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
-			      (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
-			      (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
-			      (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
-
-		/* setup UVD_MPC_SET_MUX */
-		WREG32_SOC15(VCN, vcn_inst, regUVD_MPC_SET_MUX,
-			     ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
-			      (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
-			      (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
-
-		vcn_v4_0_3_mc_resume(adev, i);
-
-		/* VCN global tiling registers */
-		WREG32_SOC15(VCN, vcn_inst, regUVD_GFX8_ADDR_CONFIG,
-			     adev->gfx.config.gb_addr_config);
-		WREG32_SOC15(VCN, vcn_inst, regUVD_GFX10_ADDR_CONFIG,
-			     adev->gfx.config.gb_addr_config);
-
-		/* unblock VCPU register access */
-		WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_RB_ARB_CTRL), 0,
-			 ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
-
-		/* release VCPU reset to boot */
-		WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_VCPU_CNTL), 0,
-			 ~UVD_VCPU_CNTL__BLK_RST_MASK);
+	/*SW clock gating */
+	vcn_v4_0_3_disable_clock_gating(adev, inst);
+
+	/* enable VCPU clock */
+	WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_VCPU_CNTL),
+		 UVD_VCPU_CNTL__CLK_EN_MASK,
+		 ~UVD_VCPU_CNTL__CLK_EN_MASK);
 
-		for (j = 0; j < 10; ++j) {
-			uint32_t status;
+	/* disable master interrupt */
+	WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_MASTINT_EN), 0,
+		 ~UVD_MASTINT_EN__VCPU_EN_MASK);
 
-			for (k = 0; k < 100; ++k) {
-				status = RREG32_SOC15(VCN, vcn_inst,
-						      regUVD_STATUS);
-				if (status & 2)
-					break;
-				mdelay(10);
-			}
-			r = 0;
-			if (status & 2)
-				break;
+	/* enable LMI MC and UMC channels */
+	WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_LMI_CTRL2), 0,
+		 ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
 
-			DRM_DEV_ERROR(adev->dev,
-				"VCN decode not responding, trying to reset the VCPU!!!\n");
-			WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst,
-						  regUVD_VCPU_CNTL),
-				 UVD_VCPU_CNTL__BLK_RST_MASK,
-				 ~UVD_VCPU_CNTL__BLK_RST_MASK);
-			mdelay(10);
-			WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst,
-						  regUVD_VCPU_CNTL),
-				 0, ~UVD_VCPU_CNTL__BLK_RST_MASK);
+	tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET);
+	tmp &= ~UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
+	tmp &= ~UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET, tmp);
+
+	/* setup regUVD_LMI_CTRL */
+	tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_LMI_CTRL);
+	WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_CTRL,
+			 tmp | UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK |
+				 UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
+				 UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
+				 UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
+
+	/* setup regUVD_MPC_CNTL */
+	tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_MPC_CNTL);
+	tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
+	tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
+	WREG32_SOC15(VCN, vcn_inst, regUVD_MPC_CNTL, tmp);
+
+	/* setup UVD_MPC_SET_MUXA0 */
+	WREG32_SOC15(VCN, vcn_inst, regUVD_MPC_SET_MUXA0,
+			 ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
+			  (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
+			  (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
+			  (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
+
+	/* setup UVD_MPC_SET_MUXB0 */
+	WREG32_SOC15(VCN, vcn_inst, regUVD_MPC_SET_MUXB0,
+			 ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
+			  (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
+			  (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
+			  (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
+
+	/* setup UVD_MPC_SET_MUX */
+	WREG32_SOC15(VCN, vcn_inst, regUVD_MPC_SET_MUX,
+			 ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
+			  (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
+			  (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
+
+	vcn_v4_0_3_mc_resume(adev, inst);
+
+	/* VCN global tiling registers */
+	WREG32_SOC15(VCN, vcn_inst, regUVD_GFX8_ADDR_CONFIG,
+			 adev->gfx.config.gb_addr_config);
+	WREG32_SOC15(VCN, vcn_inst, regUVD_GFX10_ADDR_CONFIG,
+			 adev->gfx.config.gb_addr_config);
+
+	/* unblock VCPU register access */
+	WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_RB_ARB_CTRL), 0,
+		 ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
+
+	/* release VCPU reset to boot */
+	WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_VCPU_CNTL), 0,
+		 ~UVD_VCPU_CNTL__BLK_RST_MASK);
 
+	for (j = 0; j < 10; ++j) {
+		uint32_t status;
+
+		for (k = 0; k < 100; ++k) {
+			status = RREG32_SOC15(VCN, vcn_inst,
+						  regUVD_STATUS);
+			if (status & 2)
+				break;
 			mdelay(10);
-			r = -1;
 		}
+		r = 0;
+		if (status & 2)
+			break;
 
-		if (r) {
-			DRM_DEV_ERROR(adev->dev, "VCN decode not responding, giving up!!!\n");
-			return r;
-		}
+		DRM_DEV_ERROR(adev->dev,
+			"VCN decode not responding, trying to reset the VCPU!!!\n");
+		WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst,
+					  regUVD_VCPU_CNTL),
+			 UVD_VCPU_CNTL__BLK_RST_MASK,
+			 ~UVD_VCPU_CNTL__BLK_RST_MASK);
+		mdelay(10);
+		WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst,
+					  regUVD_VCPU_CNTL),
+			 0, ~UVD_VCPU_CNTL__BLK_RST_MASK);
 
-		/* enable master interrupt */
-		WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_MASTINT_EN),
-			 UVD_MASTINT_EN__VCPU_EN_MASK,
-			 ~UVD_MASTINT_EN__VCPU_EN_MASK);
+		mdelay(10);
+		r = -1;
+	}
 
-		/* clear the busy bit of VCN_STATUS */
-		WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_STATUS), 0,
-			 ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
+	if (r) {
+		DRM_DEV_ERROR(adev->dev, "VCN decode not responding, giving up!!!\n");
+		return r;
+	}
 
-		ring = &adev->vcn.inst[i].ring_enc[0];
-		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
+	/* enable master interrupt */
+	WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_MASTINT_EN),
+		 UVD_MASTINT_EN__VCPU_EN_MASK,
+		 ~UVD_MASTINT_EN__VCPU_EN_MASK);
 
-		/* program the RB_BASE for ring buffer */
-		WREG32_SOC15(VCN, vcn_inst, regUVD_RB_BASE_LO,
-			     lower_32_bits(ring->gpu_addr));
-		WREG32_SOC15(VCN, vcn_inst, regUVD_RB_BASE_HI,
-			     upper_32_bits(ring->gpu_addr));
+	/* clear the busy bit of VCN_STATUS */
+	WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_STATUS), 0,
+		 ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
 
-		WREG32_SOC15(VCN, vcn_inst, regUVD_RB_SIZE,
-			     ring->ring_size / sizeof(uint32_t));
+	ring = &adev->vcn.inst[inst].ring_enc[0];
+	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
 
-		/* resetting ring, fw should not check RB ring */
-		tmp = RREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE);
-		tmp &= ~(VCN_RB_ENABLE__RB_EN_MASK);
-		WREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE, tmp);
+	/* program the RB_BASE for ring buffer */
+	WREG32_SOC15(VCN, vcn_inst, regUVD_RB_BASE_LO,
+			 lower_32_bits(ring->gpu_addr));
+	WREG32_SOC15(VCN, vcn_inst, regUVD_RB_BASE_HI,
+			 upper_32_bits(ring->gpu_addr));
 
-		/* Initialize the ring buffer's read and write pointers */
-		WREG32_SOC15(VCN, vcn_inst, regUVD_RB_RPTR, 0);
-		WREG32_SOC15(VCN, vcn_inst, regUVD_RB_WPTR, 0);
+	WREG32_SOC15(VCN, vcn_inst, regUVD_RB_SIZE,
+			 ring->ring_size / sizeof(uint32_t));
 
-		tmp = RREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE);
-		tmp |= VCN_RB_ENABLE__RB_EN_MASK;
-		WREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE, tmp);
+	/* resetting ring, fw should not check RB ring */
+	tmp = RREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE);
+	tmp &= ~(VCN_RB_ENABLE__RB_EN_MASK);
+	WREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE, tmp);
 
-		ring->wptr = RREG32_SOC15(VCN, vcn_inst, regUVD_RB_WPTR);
-		fw_shared->sq.queue_mode &=
-			cpu_to_le32(~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF));
+	/* Initialize the ring buffer's read and write pointers */
+	WREG32_SOC15(VCN, vcn_inst, regUVD_RB_RPTR, 0);
+	WREG32_SOC15(VCN, vcn_inst, regUVD_RB_WPTR, 0);
+
+	tmp = RREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE);
+	tmp |= VCN_RB_ENABLE__RB_EN_MASK;
+	WREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE, tmp);
+
+	ring->wptr = RREG32_SOC15(VCN, vcn_inst, regUVD_RB_WPTR);
+	fw_shared->sq.queue_mode &=
+		cpu_to_le32(~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF));
 
-	}
 	return 0;
 }
 
@@ -1295,83 +1289,79 @@ static int vcn_v4_0_3_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
  *
  * Stop VCN block
  */
-static int vcn_v4_0_3_stop(struct amdgpu_device *adev)
+static int vcn_v4_0_3_stop(struct amdgpu_device *adev, unsigned int inst)
 {
 	volatile struct amdgpu_vcn4_fw_shared *fw_shared;
-	int i, r = 0, vcn_inst;
+	int r = 0, vcn_inst;
 	uint32_t tmp;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		vcn_inst = GET_INST(VCN, i);
+	vcn_inst = GET_INST(VCN, inst);
 
-		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
-		fw_shared->sq.queue_mode |= FW_QUEUE_DPG_HOLD_OFF;
+	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
+	fw_shared->sq.queue_mode |= FW_QUEUE_DPG_HOLD_OFF;
 
-		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
-			vcn_v4_0_3_stop_dpg_mode(adev, i);
-			continue;
-		}
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
+		vcn_v4_0_3_stop_dpg_mode(adev, inst);
+		goto Done;
+	}
 
-		/* wait for vcn idle */
-		r = SOC15_WAIT_ON_RREG(VCN, vcn_inst, regUVD_STATUS,
-				       UVD_STATUS__IDLE, 0x7);
-		if (r)
-			goto Done;
-
-		tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
-			UVD_LMI_STATUS__READ_CLEAN_MASK |
-			UVD_LMI_STATUS__WRITE_CLEAN_MASK |
-			UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
-		r = SOC15_WAIT_ON_RREG(VCN, vcn_inst, regUVD_LMI_STATUS, tmp,
-				       tmp);
-		if (r)
-			goto Done;
-
-		/* stall UMC channel */
-		tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_LMI_CTRL2);
-		tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
-		WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_CTRL2, tmp);
-		tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK |
-			UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
-		r = SOC15_WAIT_ON_RREG(VCN, vcn_inst, regUVD_LMI_STATUS, tmp,
-				       tmp);
-		if (r)
-			goto Done;
+	/* wait for vcn idle */
+	r = SOC15_WAIT_ON_RREG(VCN, vcn_inst, regUVD_STATUS,
+				   UVD_STATUS__IDLE, 0x7);
+	if (r)
+		goto Done;
+
+	tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
+		UVD_LMI_STATUS__READ_CLEAN_MASK |
+		UVD_LMI_STATUS__WRITE_CLEAN_MASK |
+		UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
+	r = SOC15_WAIT_ON_RREG(VCN, vcn_inst, regUVD_LMI_STATUS, tmp,
+				   tmp);
+	if (r)
+		goto Done;
+
+	/* stall UMC channel */
+	tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_LMI_CTRL2);
+	tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
+	WREG32_SOC15(VCN, vcn_inst, regUVD_LMI_CTRL2, tmp);
+	tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK |
+		UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
+	r = SOC15_WAIT_ON_RREG(VCN, vcn_inst, regUVD_LMI_STATUS, tmp,
+				   tmp);
+	if (r)
+		goto Done;
 
-		/* Unblock VCPU Register access */
-		WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_RB_ARB_CTRL),
-			 UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
-			 ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
+	/* Unblock VCPU Register access */
+	WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_RB_ARB_CTRL),
+		 UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
+		 ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
 
-		/* release VCPU reset to boot */
-		WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_VCPU_CNTL),
-			 UVD_VCPU_CNTL__BLK_RST_MASK,
-			 ~UVD_VCPU_CNTL__BLK_RST_MASK);
+	/* release VCPU reset to boot */
+	WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_VCPU_CNTL),
+		 UVD_VCPU_CNTL__BLK_RST_MASK,
+		 ~UVD_VCPU_CNTL__BLK_RST_MASK);
 
-		/* disable VCPU clock */
-		WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_VCPU_CNTL), 0,
-			 ~(UVD_VCPU_CNTL__CLK_EN_MASK));
+	/* disable VCPU clock */
+	WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_VCPU_CNTL), 0,
+		 ~(UVD_VCPU_CNTL__CLK_EN_MASK));
 
-		/* reset LMI UMC/LMI/VCPU */
-		tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET);
-		tmp |= UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET, tmp);
+	/* reset LMI UMC/LMI/VCPU */
+	tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET);
+	tmp |= UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET, tmp);
 
-		tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET);
-		tmp |= UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET, tmp);
+	tmp = RREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET);
+	tmp |= UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, vcn_inst, regUVD_SOFT_RESET, tmp);
 
-		/* clear VCN status */
-		WREG32_SOC15(VCN, vcn_inst, regUVD_STATUS, 0);
+	/* clear VCN status */
+	WREG32_SOC15(VCN, vcn_inst, regUVD_STATUS, 0);
 
-		/* apply HW clock gating */
-		vcn_v4_0_3_enable_clock_gating(adev, i);
-	}
+	/* apply HW clock gating */
+	vcn_v4_0_3_enable_clock_gating(adev, inst);
 Done:
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, false, i);
-	}
+	if (adev->pm.dpm_enabled)
+		amdgpu_dpm_enable_vcn(adev, false, inst);
 
 	return 0;
 }
@@ -1644,9 +1634,9 @@ static int vcn_v4_0_3_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		return 0;
 
 	if (state == AMD_PG_STATE_GATE)
-		ret = vcn_v4_0_3_stop(adev);
+		ret = vcn_v4_0_3_stop(adev, inst);
 	else
-		ret = vcn_v4_0_3_start(adev);
+		ret = vcn_v4_0_3_start(adev, inst);
 
 	if (!ret)
 		adev->vcn.cur_state[inst] = state;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 15/18] drm/amdgpu: power vcn 4_0_5 by instance
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (13 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 14/18] drm/amdgpu: power vcn 4_0_3 " boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 18:44 ` [PATCH 16/18] drm/amdgpu: power vcn 5_0_0 " boyuan.zhang
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

For vcn 4_0_5, add ip_block for each vcn instance during discovery stage.

And only powering on/off one of the vcn instance using the
instance value stored in ip_block, instead of powering on/off all
vcn instances. Modify the existing functions to use the instance value
in ip_block, and remove the original for loop for all vcn instances.

v2: rename "i"/"j" to "inst" for instance value.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   3 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c       | 510 +++++++++---------
 2 files changed, 252 insertions(+), 261 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 084bd487b934..3c4b56efdef3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -2357,7 +2357,8 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
 			break;
 		case IP_VERSION(4, 0, 5):
 		case IP_VERSION(4, 0, 6):
-			amdgpu_device_ip_block_add(adev, &vcn_v4_0_5_ip_block);
+			for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
+				amdgpu_device_ip_block_add(adev, &vcn_v4_0_5_ip_block);
 			amdgpu_device_ip_block_add(adev, &jpeg_v4_0_5_ip_block);
 			break;
 		case IP_VERSION(5, 0, 0):
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
index fe2f57bb389f..b91a64de66ea 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
@@ -132,7 +132,7 @@ static int vcn_v4_0_5_sw_init(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_ring *ring;
 	struct amdgpu_device *adev = ip_block->adev;
-	int i, r;
+	int inst = ip_block->instance, r;
 	uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_4_0_5);
 	uint32_t *ptr;
 
@@ -146,57 +146,55 @@ static int vcn_v4_0_5_sw_init(struct amdgpu_ip_block *ip_block)
 	if (r)
 		return r;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
-		volatile struct amdgpu_vcn4_fw_shared *fw_shared;
+	volatile struct amdgpu_vcn4_fw_shared *fw_shared;
 
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
+	if (adev->vcn.harvest_config & (1 << inst))
+		goto done;
 
-		atomic_set(&adev->vcn.inst[i].sched_score, 0);
+	atomic_set(&adev->vcn.inst[inst].sched_score, 0);
 
-		/* VCN UNIFIED TRAP */
-		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[i],
-				VCN_4_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[i].irq);
-		if (r)
-			return r;
+	/* VCN UNIFIED TRAP */
+	r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
+			VCN_4_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[inst].irq);
+	if (r)
+		return r;
 
-		/* VCN POISON TRAP */
-		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[i],
-				VCN_4_0__SRCID_UVD_POISON, &adev->vcn.inst[i].irq);
-		if (r)
-			return r;
+	/* VCN POISON TRAP */
+	r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
+			VCN_4_0__SRCID_UVD_POISON, &adev->vcn.inst[inst].irq);
+	if (r)
+		return r;
 
-		ring = &adev->vcn.inst[i].ring_enc[0];
-		ring->use_doorbell = true;
-		if (amdgpu_sriov_vf(adev))
-			ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
-						i * (adev->vcn.num_enc_rings + 1) + 1;
-		else
-			ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
-						2 + 8 * i;
-		ring->vm_hub = AMDGPU_MMHUB0(0);
-		sprintf(ring->name, "vcn_unified_%d", i);
-
-		r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[i].irq, 0,
-				AMDGPU_RING_PRIO_0, &adev->vcn.inst[i].sched_score);
-		if (r)
-			return r;
+	ring = &adev->vcn.inst[inst].ring_enc[0];
+	ring->use_doorbell = true;
+	if (amdgpu_sriov_vf(adev))
+		ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
+					inst * (adev->vcn.num_enc_rings + 1) + 1;
+	else
+		ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
+					2 + 8 * inst;
+	ring->vm_hub = AMDGPU_MMHUB0(0);
+	sprintf(ring->name, "vcn_unified_%d", inst);
 
-		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
-		fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE);
-		fw_shared->sq.is_enabled = 1;
+	r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq, 0,
+			AMDGPU_RING_PRIO_0, &adev->vcn.inst[inst].sched_score);
+	if (r)
+		return r;
 
-		fw_shared->present_flag_0 |= cpu_to_le32(AMDGPU_VCN_SMU_DPM_INTERFACE_FLAG);
-		fw_shared->smu_dpm_interface.smu_interface_type = (adev->flags & AMD_IS_APU) ?
-			AMDGPU_VCN_SMU_DPM_INTERFACE_APU : AMDGPU_VCN_SMU_DPM_INTERFACE_DGPU;
+	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
+	fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE);
+	fw_shared->sq.is_enabled = 1;
 
-		if (amdgpu_sriov_vf(adev))
-			fw_shared->present_flag_0 |= cpu_to_le32(AMDGPU_VCN_VF_RB_SETUP_FLAG);
+	fw_shared->present_flag_0 |= cpu_to_le32(AMDGPU_VCN_SMU_DPM_INTERFACE_FLAG);
+	fw_shared->smu_dpm_interface.smu_interface_type = (adev->flags & AMD_IS_APU) ?
+		AMDGPU_VCN_SMU_DPM_INTERFACE_APU : AMDGPU_VCN_SMU_DPM_INTERFACE_DGPU;
 
-		if (amdgpu_vcnfw_log)
-			amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
-	}
+	if (amdgpu_sriov_vf(adev))
+		fw_shared->present_flag_0 |= cpu_to_le32(AMDGPU_VCN_VF_RB_SETUP_FLAG);
 
+	if (amdgpu_vcnfw_log)
+		amdgpu_vcn_fwlog_init(&adev->vcn.inst[inst]);
+done:
 	if (amdgpu_sriov_vf(adev)) {
 		r = amdgpu_virt_alloc_mm_table(adev);
 		if (r)
@@ -992,180 +990,176 @@ static int vcn_v4_0_5_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, b
  *
  * Start VCN block
  */
-static int vcn_v4_0_5_start(struct amdgpu_device *adev)
+static int vcn_v4_0_5_start(struct amdgpu_device *adev, unsigned int inst)
 {
 	volatile struct amdgpu_vcn4_fw_shared *fw_shared;
 	struct amdgpu_ring *ring;
 	uint32_t tmp;
-	int i, j, k, r;
+	int j, k, r;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, true, i);
+	if (adev->pm.dpm_enabled)
+		amdgpu_dpm_enable_vcn(adev, true, inst);
+
+	if (adev->vcn.harvest_config & (1 << inst))
+		return 0;
+
+	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
+
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
+		r = vcn_v4_0_5_start_dpg_mode(adev, inst, adev->vcn.indirect_sram);
+		return r;
 	}
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
+	/* disable VCN power gating */
+	vcn_v4_0_5_disable_static_power_gating(adev, inst);
 
-		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
+	/* set VCN status busy */
+	tmp = RREG32_SOC15(VCN, inst, regUVD_STATUS) | UVD_STATUS__UVD_BUSY;
+	WREG32_SOC15(VCN, inst, regUVD_STATUS, tmp);
 
-		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
-			r = vcn_v4_0_5_start_dpg_mode(adev, i, adev->vcn.indirect_sram);
-			continue;
-		}
+	/*SW clock gating */
+	vcn_v4_0_5_disable_clock_gating(adev, inst);
 
-		/* disable VCN power gating */
-		vcn_v4_0_5_disable_static_power_gating(adev, i);
-
-		/* set VCN status busy */
-		tmp = RREG32_SOC15(VCN, i, regUVD_STATUS) | UVD_STATUS__UVD_BUSY;
-		WREG32_SOC15(VCN, i, regUVD_STATUS, tmp);
-
-		/*SW clock gating */
-		vcn_v4_0_5_disable_clock_gating(adev, i);
-
-		/* enable VCPU clock */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL),
-				UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
-
-		/* disable master interrupt */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_MASTINT_EN), 0,
-				~UVD_MASTINT_EN__VCPU_EN_MASK);
-
-		/* enable LMI MC and UMC channels */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_LMI_CTRL2), 0,
-				~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
-
-		tmp = RREG32_SOC15(VCN, i, regUVD_SOFT_RESET);
-		tmp &= ~UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
-		tmp &= ~UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, i, regUVD_SOFT_RESET, tmp);
-
-		/* setup regUVD_LMI_CTRL */
-		tmp = RREG32_SOC15(VCN, i, regUVD_LMI_CTRL);
-		WREG32_SOC15(VCN, i, regUVD_LMI_CTRL, tmp |
-				UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK |
-				UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
-				UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
-				UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
-
-		/* setup regUVD_MPC_CNTL */
-		tmp = RREG32_SOC15(VCN, i, regUVD_MPC_CNTL);
-		tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
-		tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
-		WREG32_SOC15(VCN, i, regUVD_MPC_CNTL, tmp);
-
-		/* setup UVD_MPC_SET_MUXA0 */
-		WREG32_SOC15(VCN, i, regUVD_MPC_SET_MUXA0,
-				((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
-				 (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
-				 (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
-				 (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
-
-		/* setup UVD_MPC_SET_MUXB0 */
-		WREG32_SOC15(VCN, i, regUVD_MPC_SET_MUXB0,
-				((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
-				 (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
-				 (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
-				 (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
-
-		/* setup UVD_MPC_SET_MUX */
-		WREG32_SOC15(VCN, i, regUVD_MPC_SET_MUX,
-				((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
-				 (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
-				 (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
-
-		vcn_v4_0_5_mc_resume(adev, i);
-
-		/* VCN global tiling registers */
-		WREG32_SOC15(VCN, i, regUVD_GFX10_ADDR_CONFIG,
-				adev->gfx.config.gb_addr_config);
-
-		/* unblock VCPU register access */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_RB_ARB_CTRL), 0,
-				~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
-
-		/* release VCPU reset to boot */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL), 0,
-				~UVD_VCPU_CNTL__BLK_RST_MASK);
-
-		for (j = 0; j < 10; ++j) {
-			uint32_t status;
-
-			for (k = 0; k < 100; ++k) {
-				status = RREG32_SOC15(VCN, i, regUVD_STATUS);
-				if (status & 2)
-					break;
-				mdelay(10);
-				if (amdgpu_emu_mode == 1)
-					msleep(1);
-			}
+	/* enable VCPU clock */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL),
+			UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
+
+	/* disable master interrupt */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_MASTINT_EN), 0,
+			~UVD_MASTINT_EN__VCPU_EN_MASK);
+
+	/* enable LMI MC and UMC channels */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_LMI_CTRL2), 0,
+			~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
 
-			if (amdgpu_emu_mode == 1) {
-				r = -1;
-				if (status & 2) {
-					r = 0;
-					break;
-				}
-			} else {
+	tmp = RREG32_SOC15(VCN, inst, regUVD_SOFT_RESET);
+	tmp &= ~UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
+	tmp &= ~UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, inst, regUVD_SOFT_RESET, tmp);
+
+	/* setup regUVD_LMI_CTRL */
+	tmp = RREG32_SOC15(VCN, inst, regUVD_LMI_CTRL);
+	WREG32_SOC15(VCN, inst, regUVD_LMI_CTRL, tmp |
+			UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK |
+			UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
+			UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
+			UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
+
+	/* setup regUVD_MPC_CNTL */
+	tmp = RREG32_SOC15(VCN, inst, regUVD_MPC_CNTL);
+	tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
+	tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
+	WREG32_SOC15(VCN, inst, regUVD_MPC_CNTL, tmp);
+
+	/* setup UVD_MPC_SET_MUXA0 */
+	WREG32_SOC15(VCN, inst, regUVD_MPC_SET_MUXA0,
+			((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
+			 (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
+			 (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
+			 (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
+
+	/* setup UVD_MPC_SET_MUXB0 */
+	WREG32_SOC15(VCN, inst, regUVD_MPC_SET_MUXB0,
+			((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
+			 (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
+			 (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
+			 (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
+
+	/* setup UVD_MPC_SET_MUX */
+	WREG32_SOC15(VCN, inst, regUVD_MPC_SET_MUX,
+			((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
+			 (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
+			 (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
+
+	vcn_v4_0_5_mc_resume(adev, inst);
+
+	/* VCN global tiling registers */
+	WREG32_SOC15(VCN, inst, regUVD_GFX10_ADDR_CONFIG,
+			adev->gfx.config.gb_addr_config);
+
+	/* unblock VCPU register access */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_RB_ARB_CTRL), 0,
+			~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
+
+	/* release VCPU reset to boot */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL), 0,
+			~UVD_VCPU_CNTL__BLK_RST_MASK);
+
+	for (j = 0; j < 10; ++j) {
+		uint32_t status;
+
+		for (k = 0; k < 100; ++k) {
+			status = RREG32_SOC15(VCN, inst, regUVD_STATUS);
+			if (status & 2)
+				break;
+			mdelay(10);
+			if (amdgpu_emu_mode == 1)
+				msleep(1);
+		}
+
+		if (amdgpu_emu_mode == 1) {
+			r = -1;
+			if (status & 2) {
 				r = 0;
-				if (status & 2)
-					break;
-
-				dev_err(adev->dev,
-					"VCN[%d] is not responding, trying to reset VCPU!!!\n", i);
-				WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL),
-							UVD_VCPU_CNTL__BLK_RST_MASK,
-							~UVD_VCPU_CNTL__BLK_RST_MASK);
-				mdelay(10);
-				WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL), 0,
+				break;
+			}
+		} else {
+			r = 0;
+			if (status & 2)
+				break;
+
+			dev_err(adev->dev,
+				"VCN[%d] is not responding, trying to reset VCPU!!!\n", inst);
+			WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL),
+						UVD_VCPU_CNTL__BLK_RST_MASK,
 						~UVD_VCPU_CNTL__BLK_RST_MASK);
+			mdelay(10);
+			WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL), 0,
+					~UVD_VCPU_CNTL__BLK_RST_MASK);
 
-				mdelay(10);
-				r = -1;
-			}
+			mdelay(10);
+			r = -1;
 		}
+	}
 
-		if (r) {
-			dev_err(adev->dev, "VCN[%d] is not responding, giving up!!!\n", i);
-			return r;
-		}
+	if (r) {
+		dev_err(adev->dev, "VCN[%d] is not responding, giving up!!!\n", inst);
+		return r;
+	}
 
-		/* enable master interrupt */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_MASTINT_EN),
-				UVD_MASTINT_EN__VCPU_EN_MASK,
-				~UVD_MASTINT_EN__VCPU_EN_MASK);
+	/* enable master interrupt */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_MASTINT_EN),
+			UVD_MASTINT_EN__VCPU_EN_MASK,
+			~UVD_MASTINT_EN__VCPU_EN_MASK);
 
-		/* clear the busy bit of VCN_STATUS */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_STATUS), 0,
-				~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
+	/* clear the busy bit of VCN_STATUS */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_STATUS), 0,
+			~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
 
-		ring = &adev->vcn.inst[i].ring_enc[0];
-		WREG32_SOC15(VCN, i, regVCN_RB1_DB_CTRL,
-				ring->doorbell_index << VCN_RB1_DB_CTRL__OFFSET__SHIFT |
-				VCN_RB1_DB_CTRL__EN_MASK);
-
-		WREG32_SOC15(VCN, i, regUVD_RB_BASE_LO, ring->gpu_addr);
-		WREG32_SOC15(VCN, i, regUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
-		WREG32_SOC15(VCN, i, regUVD_RB_SIZE, ring->ring_size / 4);
-
-		tmp = RREG32_SOC15(VCN, i, regVCN_RB_ENABLE);
-		tmp &= ~(VCN_RB_ENABLE__RB1_EN_MASK);
-		WREG32_SOC15(VCN, i, regVCN_RB_ENABLE, tmp);
-		fw_shared->sq.queue_mode |= FW_QUEUE_RING_RESET;
-		WREG32_SOC15(VCN, i, regUVD_RB_RPTR, 0);
-		WREG32_SOC15(VCN, i, regUVD_RB_WPTR, 0);
-
-		tmp = RREG32_SOC15(VCN, i, regUVD_RB_RPTR);
-		WREG32_SOC15(VCN, i, regUVD_RB_WPTR, tmp);
-		ring->wptr = RREG32_SOC15(VCN, i, regUVD_RB_WPTR);
-
-		tmp = RREG32_SOC15(VCN, i, regVCN_RB_ENABLE);
-		tmp |= VCN_RB_ENABLE__RB1_EN_MASK;
-		WREG32_SOC15(VCN, i, regVCN_RB_ENABLE, tmp);
-		fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF);
-	}
+	ring = &adev->vcn.inst[inst].ring_enc[0];
+	WREG32_SOC15(VCN, inst, regVCN_RB1_DB_CTRL,
+			ring->doorbell_index << VCN_RB1_DB_CTRL__OFFSET__SHIFT |
+			VCN_RB1_DB_CTRL__EN_MASK);
+
+	WREG32_SOC15(VCN, inst, regUVD_RB_BASE_LO, ring->gpu_addr);
+	WREG32_SOC15(VCN, inst, regUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
+	WREG32_SOC15(VCN, inst, regUVD_RB_SIZE, ring->ring_size / 4);
+
+	tmp = RREG32_SOC15(VCN, inst, regVCN_RB_ENABLE);
+	tmp &= ~(VCN_RB_ENABLE__RB1_EN_MASK);
+	WREG32_SOC15(VCN, inst, regVCN_RB_ENABLE, tmp);
+	fw_shared->sq.queue_mode |= FW_QUEUE_RING_RESET;
+	WREG32_SOC15(VCN, inst, regUVD_RB_RPTR, 0);
+	WREG32_SOC15(VCN, inst, regUVD_RB_WPTR, 0);
+
+	tmp = RREG32_SOC15(VCN, inst, regUVD_RB_RPTR);
+	WREG32_SOC15(VCN, inst, regUVD_RB_WPTR, tmp);
+	ring->wptr = RREG32_SOC15(VCN, inst, regUVD_RB_WPTR);
+
+	tmp = RREG32_SOC15(VCN, inst, regVCN_RB_ENABLE);
+	tmp |= VCN_RB_ENABLE__RB1_EN_MASK;
+	WREG32_SOC15(VCN, inst, regVCN_RB_ENABLE, tmp);
+	fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF);
 
 	return 0;
 }
@@ -1205,83 +1199,79 @@ static void vcn_v4_0_5_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
  *
  * Stop VCN block
  */
-static int vcn_v4_0_5_stop(struct amdgpu_device *adev)
+static int vcn_v4_0_5_stop(struct amdgpu_device *adev, unsigned int inst)
 {
 	volatile struct amdgpu_vcn4_fw_shared *fw_shared;
 	uint32_t tmp;
-	int i, r = 0;
+	int r = 0;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
-
-		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
-		fw_shared->sq.queue_mode |= FW_QUEUE_DPG_HOLD_OFF;
+	if (adev->vcn.harvest_config & (1 << inst))
+		goto done;
 
-		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
-			vcn_v4_0_5_stop_dpg_mode(adev, i);
-			continue;
-		}
+	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
+	fw_shared->sq.queue_mode |= FW_QUEUE_DPG_HOLD_OFF;
 
-		/* wait for vcn idle */
-		r = SOC15_WAIT_ON_RREG(VCN, i, regUVD_STATUS, UVD_STATUS__IDLE, 0x7);
-		if (r)
-			return r;
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
+		vcn_v4_0_5_stop_dpg_mode(adev, inst);
+		goto done;
+	}
 
-		tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
-			UVD_LMI_STATUS__READ_CLEAN_MASK |
-			UVD_LMI_STATUS__WRITE_CLEAN_MASK |
-			UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
-		r = SOC15_WAIT_ON_RREG(VCN, i, regUVD_LMI_STATUS, tmp, tmp);
-		if (r)
-			return r;
+	/* wait for vcn idle */
+	r = SOC15_WAIT_ON_RREG(VCN, inst, regUVD_STATUS, UVD_STATUS__IDLE, 0x7);
+	if (r)
+		return r;
 
-		/* disable LMI UMC channel */
-		tmp = RREG32_SOC15(VCN, i, regUVD_LMI_CTRL2);
-		tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
-		WREG32_SOC15(VCN, i, regUVD_LMI_CTRL2, tmp);
-		tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK |
-			UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
-		r = SOC15_WAIT_ON_RREG(VCN, i, regUVD_LMI_STATUS, tmp, tmp);
-		if (r)
-			return r;
+	tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
+		UVD_LMI_STATUS__READ_CLEAN_MASK |
+		UVD_LMI_STATUS__WRITE_CLEAN_MASK |
+		UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
+	r = SOC15_WAIT_ON_RREG(VCN, inst, regUVD_LMI_STATUS, tmp, tmp);
+	if (r)
+		return r;
 
-		/* block VCPU register access */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_RB_ARB_CTRL),
-				UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
-				~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
+	/* disable LMI UMC channel */
+	tmp = RREG32_SOC15(VCN, inst, regUVD_LMI_CTRL2);
+	tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
+	WREG32_SOC15(VCN, inst, regUVD_LMI_CTRL2, tmp);
+	tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK |
+		UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
+	r = SOC15_WAIT_ON_RREG(VCN, inst, regUVD_LMI_STATUS, tmp, tmp);
+	if (r)
+		return r;
 
-		/* reset VCPU */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL),
-				UVD_VCPU_CNTL__BLK_RST_MASK,
-				~UVD_VCPU_CNTL__BLK_RST_MASK);
+	/* block VCPU register access */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_RB_ARB_CTRL),
+			UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
+			~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
 
-		/* disable VCPU clock */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL), 0,
-				~(UVD_VCPU_CNTL__CLK_EN_MASK));
+	/* reset VCPU */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL),
+			UVD_VCPU_CNTL__BLK_RST_MASK,
+			~UVD_VCPU_CNTL__BLK_RST_MASK);
 
-		/* apply soft reset */
-		tmp = RREG32_SOC15(VCN, i, regUVD_SOFT_RESET);
-		tmp |= UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, i, regUVD_SOFT_RESET, tmp);
-		tmp = RREG32_SOC15(VCN, i, regUVD_SOFT_RESET);
-		tmp |= UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, i, regUVD_SOFT_RESET, tmp);
+	/* disable VCPU clock */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL), 0,
+			~(UVD_VCPU_CNTL__CLK_EN_MASK));
 
-		/* clear status */
-		WREG32_SOC15(VCN, i, regUVD_STATUS, 0);
+	/* apply soft reset */
+	tmp = RREG32_SOC15(VCN, inst, regUVD_SOFT_RESET);
+	tmp |= UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, inst, regUVD_SOFT_RESET, tmp);
+	tmp = RREG32_SOC15(VCN, inst, regUVD_SOFT_RESET);
+	tmp |= UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, inst, regUVD_SOFT_RESET, tmp);
 
-		/* apply HW clock gating */
-		vcn_v4_0_5_enable_clock_gating(adev, i);
+	/* clear status */
+	WREG32_SOC15(VCN, inst, regUVD_STATUS, 0);
 
-		/* enable VCN power gating */
-		vcn_v4_0_5_enable_static_power_gating(adev, i);
-	}
+	/* apply HW clock gating */
+	vcn_v4_0_5_enable_clock_gating(adev, inst);
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, false, i);
-	}
+	/* enable VCN power gating */
+	vcn_v4_0_5_enable_static_power_gating(adev, inst);
+done:
+	if (adev->pm.dpm_enabled)
+		amdgpu_dpm_enable_vcn(adev, false, inst);
 
 	return 0;
 }
@@ -1541,9 +1531,9 @@ static int vcn_v4_0_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		return 0;
 
 	if (state == AMD_PG_STATE_GATE)
-		ret = vcn_v4_0_5_stop(adev);
+		ret = vcn_v4_0_5_stop(adev, inst);
 	else
-		ret = vcn_v4_0_5_start(adev);
+		ret = vcn_v4_0_5_start(adev, inst);
 
 	if (!ret)
 		adev->vcn.cur_state[inst] = state;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 16/18] drm/amdgpu: power vcn 5_0_0 by instance
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (14 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 15/18] drm/amdgpu: power vcn 4_0_5 " boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 18:44 ` [PATCH 17/18] drm/amdgpu/vcn: separate idle work " boyuan.zhang
  2024-10-04 18:44 ` [PATCH 18/18] drm/amdgpu: set powergating state by vcn instance boyuan.zhang
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

For vcn 5_0_0, add ip_block for each vcn instance during discovery stage.

And only powering on/off one of the vcn instance using the
instance value stored in ip_block, instead of powering on/off all
vcn instances. Modify the existing functions to use the instance value
in ip_block, and remove the original for loop for all vcn instances.

v2: rename "i"/"j" to "inst" for instance value.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   3 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c       | 432 +++++++++---------
 2 files changed, 213 insertions(+), 222 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 3c4b56efdef3..b1a868a7e258 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -2362,7 +2362,8 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
 			amdgpu_device_ip_block_add(adev, &jpeg_v4_0_5_ip_block);
 			break;
 		case IP_VERSION(5, 0, 0):
-			amdgpu_device_ip_block_add(adev, &vcn_v5_0_0_ip_block);
+			for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
+				amdgpu_device_ip_block_add(adev, &vcn_v5_0_0_ip_block);
 			amdgpu_device_ip_block_add(adev, &jpeg_v5_0_0_ip_block);
 			break;
 		default:
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
index 1af137e98070..c6f06f778dbf 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
@@ -116,7 +116,7 @@ static int vcn_v5_0_0_sw_init(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_ring *ring;
 	struct amdgpu_device *adev = ip_block->adev;
-	int i, r;
+	int inst = ip_block->instance, r;
 	uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_5_0);
 	uint32_t *ptr;
 
@@ -130,46 +130,44 @@ static int vcn_v5_0_0_sw_init(struct amdgpu_ip_block *ip_block)
 	if (r)
 		return r;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
-		volatile struct amdgpu_vcn5_fw_shared *fw_shared;
-
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
+	volatile struct amdgpu_vcn5_fw_shared *fw_shared;
 
-		atomic_set(&adev->vcn.inst[i].sched_score, 0);
+	if (adev->vcn.harvest_config & (1 << inst))
+		goto done;
 
-		/* VCN UNIFIED TRAP */
-		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[i],
-				VCN_4_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[i].irq);
-		if (r)
-			return r;
+	atomic_set(&adev->vcn.inst[inst].sched_score, 0);
 
-		/* VCN POISON TRAP */
-		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[i],
-				VCN_4_0__SRCID_UVD_POISON, &adev->vcn.inst[i].irq);
-		if (r)
-			return r;
+	/* VCN UNIFIED TRAP */
+	r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
+			VCN_4_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[inst].irq);
+	if (r)
+		return r;
 
-		ring = &adev->vcn.inst[i].ring_enc[0];
-		ring->use_doorbell = true;
-		ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 2 + 8 * i;
+	/* VCN POISON TRAP */
+	r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
+			VCN_4_0__SRCID_UVD_POISON, &adev->vcn.inst[inst].irq);
+	if (r)
+		return r;
 
-		ring->vm_hub = AMDGPU_MMHUB0(0);
-		sprintf(ring->name, "vcn_unified_%d", i);
+	ring = &adev->vcn.inst[inst].ring_enc[0];
+	ring->use_doorbell = true;
+	ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 2 + 8 * inst;
 
-		r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[i].irq, 0,
-						AMDGPU_RING_PRIO_0, &adev->vcn.inst[i].sched_score);
-		if (r)
-			return r;
+	ring->vm_hub = AMDGPU_MMHUB0(0);
+	sprintf(ring->name, "vcn_unified_%d", inst);
 
-		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
-		fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE);
-		fw_shared->sq.is_enabled = 1;
+	r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq, 0,
+					AMDGPU_RING_PRIO_0, &adev->vcn.inst[inst].sched_score);
+	if (r)
+		return r;
 
-		if (amdgpu_vcnfw_log)
-			amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
-	}
+	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
+	fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE);
+	fw_shared->sq.is_enabled = 1;
 
+	if (amdgpu_vcnfw_log)
+		amdgpu_vcn_fwlog_init(&adev->vcn.inst[inst]);
+done:
 	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
 		adev->vcn.pause_dpg_mode = vcn_v5_0_0_pause_dpg_mode;
 
@@ -753,151 +751,147 @@ static int vcn_v5_0_0_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, b
  *
  * Start VCN block
  */
-static int vcn_v5_0_0_start(struct amdgpu_device *adev)
+static int vcn_v5_0_0_start(struct amdgpu_device *adev, unsigned int inst)
 {
 	volatile struct amdgpu_vcn5_fw_shared *fw_shared;
 	struct amdgpu_ring *ring;
 	uint32_t tmp;
-	int i, j, k, r;
+	int j, k, r;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, true, i);
+	if (adev->pm.dpm_enabled)
+		amdgpu_dpm_enable_vcn(adev, true, inst);
+
+	if (adev->vcn.harvest_config & (1 << inst))
+		return 0;
+
+	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
+
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
+		r = vcn_v5_0_0_start_dpg_mode(adev, inst, adev->vcn.indirect_sram);
+		return r;
 	}
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
+	/* disable VCN power gating */
+	vcn_v5_0_0_disable_static_power_gating(adev, inst);
 
-		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
+	/* set VCN status busy */
+	tmp = RREG32_SOC15(VCN, inst, regUVD_STATUS) | UVD_STATUS__UVD_BUSY;
+	WREG32_SOC15(VCN, inst, regUVD_STATUS, tmp);
 
-		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
-			r = vcn_v5_0_0_start_dpg_mode(adev, i, adev->vcn.indirect_sram);
-			continue;
-		}
+	/* enable VCPU clock */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL),
+		UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
 
-		/* disable VCN power gating */
-		vcn_v5_0_0_disable_static_power_gating(adev, i);
+	/* disable master interrupt */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_MASTINT_EN), 0,
+		~UVD_MASTINT_EN__VCPU_EN_MASK);
 
-		/* set VCN status busy */
-		tmp = RREG32_SOC15(VCN, i, regUVD_STATUS) | UVD_STATUS__UVD_BUSY;
-		WREG32_SOC15(VCN, i, regUVD_STATUS, tmp);
+	/* enable LMI MC and UMC channels */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_LMI_CTRL2), 0,
+		~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
 
-		/* enable VCPU clock */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL),
-			UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
+	tmp = RREG32_SOC15(VCN, inst, regUVD_SOFT_RESET);
+	tmp &= ~UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
+	tmp &= ~UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, inst, regUVD_SOFT_RESET, tmp);
 
-		/* disable master interrupt */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_MASTINT_EN), 0,
-			~UVD_MASTINT_EN__VCPU_EN_MASK);
+	/* setup regUVD_LMI_CTRL */
+	tmp = RREG32_SOC15(VCN, inst, regUVD_LMI_CTRL);
+	WREG32_SOC15(VCN, inst, regUVD_LMI_CTRL, tmp |
+		UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK |
+		UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
+		UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
+		UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
 
-		/* enable LMI MC and UMC channels */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_LMI_CTRL2), 0,
-			~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
-
-		tmp = RREG32_SOC15(VCN, i, regUVD_SOFT_RESET);
-		tmp &= ~UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
-		tmp &= ~UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, i, regUVD_SOFT_RESET, tmp);
-
-		/* setup regUVD_LMI_CTRL */
-		tmp = RREG32_SOC15(VCN, i, regUVD_LMI_CTRL);
-		WREG32_SOC15(VCN, i, regUVD_LMI_CTRL, tmp |
-			UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK |
-			UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
-			UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
-			UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
-
-		vcn_v5_0_0_mc_resume(adev, i);
-
-		/* VCN global tiling registers */
-		WREG32_SOC15(VCN, i, regUVD_GFX10_ADDR_CONFIG,
-			adev->gfx.config.gb_addr_config);
-
-		/* unblock VCPU register access */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_RB_ARB_CTRL), 0,
-			~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
-
-		/* release VCPU reset to boot */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL), 0,
-			~UVD_VCPU_CNTL__BLK_RST_MASK);
-
-		for (j = 0; j < 10; ++j) {
-			uint32_t status;
-
-			for (k = 0; k < 100; ++k) {
-				status = RREG32_SOC15(VCN, i, regUVD_STATUS);
-				if (status & 2)
-					break;
-				mdelay(10);
-				if (amdgpu_emu_mode == 1)
-					msleep(1);
-			}
+	vcn_v5_0_0_mc_resume(adev, inst);
+
+	/* VCN global tiling registers */
+	WREG32_SOC15(VCN, inst, regUVD_GFX10_ADDR_CONFIG,
+		adev->gfx.config.gb_addr_config);
+
+	/* unblock VCPU register access */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_RB_ARB_CTRL), 0,
+		~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
+
+	/* release VCPU reset to boot */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL), 0,
+		~UVD_VCPU_CNTL__BLK_RST_MASK);
+
+	for (j = 0; j < 10; ++j) {
+		uint32_t status;
+
+		for (k = 0; k < 100; ++k) {
+			status = RREG32_SOC15(VCN, inst, regUVD_STATUS);
+			if (status & 2)
+				break;
+			mdelay(10);
+			if (amdgpu_emu_mode == 1)
+				msleep(1);
+		}
 
-			if (amdgpu_emu_mode == 1) {
-				r = -1;
-				if (status & 2) {
-					r = 0;
-					break;
-				}
-			} else {
+		if (amdgpu_emu_mode == 1) {
+			r = -1;
+			if (status & 2) {
 				r = 0;
-				if (status & 2)
-					break;
-
-				dev_err(adev->dev,
-					"VCN[%d] is not responding, trying to reset the VCPU!!!\n", i);
-				WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL),
-							UVD_VCPU_CNTL__BLK_RST_MASK,
-							~UVD_VCPU_CNTL__BLK_RST_MASK);
-				mdelay(10);
-				WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL), 0,
-							~UVD_VCPU_CNTL__BLK_RST_MASK);
-
-				mdelay(10);
-				r = -1;
+				break;
 			}
+		} else {
+			r = 0;
+			if (status & 2)
+				break;
+
+			dev_err(adev->dev,
+				"VCN[%d] is not responding, trying to reset the VCPU!!!\n", inst);
+			WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL),
+						UVD_VCPU_CNTL__BLK_RST_MASK,
+						~UVD_VCPU_CNTL__BLK_RST_MASK);
+			mdelay(10);
+			WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL), 0,
+						~UVD_VCPU_CNTL__BLK_RST_MASK);
+
+			mdelay(10);
+			r = -1;
 		}
+	}
 
-		if (r) {
-			dev_err(adev->dev, "VCN[%d] is not responding, giving up!!!\n", i);
-			return r;
-		}
+	if (r) {
+		dev_err(adev->dev, "VCN[%d] is not responding, giving up!!!\n", inst);
+		return r;
+	}
 
-		/* enable master interrupt */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_MASTINT_EN),
-				UVD_MASTINT_EN__VCPU_EN_MASK,
-				~UVD_MASTINT_EN__VCPU_EN_MASK);
+	/* enable master interrupt */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_MASTINT_EN),
+			UVD_MASTINT_EN__VCPU_EN_MASK,
+			~UVD_MASTINT_EN__VCPU_EN_MASK);
 
-		/* clear the busy bit of VCN_STATUS */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_STATUS), 0,
-			~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
+	/* clear the busy bit of VCN_STATUS */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_STATUS), 0,
+		~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
 
-		ring = &adev->vcn.inst[i].ring_enc[0];
-		WREG32_SOC15(VCN, i, regVCN_RB1_DB_CTRL,
-			ring->doorbell_index << VCN_RB1_DB_CTRL__OFFSET__SHIFT |
-			VCN_RB1_DB_CTRL__EN_MASK);
-
-		WREG32_SOC15(VCN, i, regUVD_RB_BASE_LO, ring->gpu_addr);
-		WREG32_SOC15(VCN, i, regUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
-		WREG32_SOC15(VCN, i, regUVD_RB_SIZE, ring->ring_size / 4);
-
-		tmp = RREG32_SOC15(VCN, i, regVCN_RB_ENABLE);
-		tmp &= ~(VCN_RB_ENABLE__RB1_EN_MASK);
-		WREG32_SOC15(VCN, i, regVCN_RB_ENABLE, tmp);
-		fw_shared->sq.queue_mode |= FW_QUEUE_RING_RESET;
-		WREG32_SOC15(VCN, i, regUVD_RB_RPTR, 0);
-		WREG32_SOC15(VCN, i, regUVD_RB_WPTR, 0);
-
-		tmp = RREG32_SOC15(VCN, i, regUVD_RB_RPTR);
-		WREG32_SOC15(VCN, i, regUVD_RB_WPTR, tmp);
-		ring->wptr = RREG32_SOC15(VCN, i, regUVD_RB_WPTR);
-
-		tmp = RREG32_SOC15(VCN, i, regVCN_RB_ENABLE);
-		tmp |= VCN_RB_ENABLE__RB1_EN_MASK;
-		WREG32_SOC15(VCN, i, regVCN_RB_ENABLE, tmp);
-		fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF);
-	}
+	ring = &adev->vcn.inst[inst].ring_enc[0];
+	WREG32_SOC15(VCN, inst, regVCN_RB1_DB_CTRL,
+		ring->doorbell_index << VCN_RB1_DB_CTRL__OFFSET__SHIFT |
+		VCN_RB1_DB_CTRL__EN_MASK);
+
+	WREG32_SOC15(VCN, inst, regUVD_RB_BASE_LO, ring->gpu_addr);
+	WREG32_SOC15(VCN, inst, regUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
+	WREG32_SOC15(VCN, inst, regUVD_RB_SIZE, ring->ring_size / 4);
+
+	tmp = RREG32_SOC15(VCN, inst, regVCN_RB_ENABLE);
+	tmp &= ~(VCN_RB_ENABLE__RB1_EN_MASK);
+	WREG32_SOC15(VCN, inst, regVCN_RB_ENABLE, tmp);
+	fw_shared->sq.queue_mode |= FW_QUEUE_RING_RESET;
+	WREG32_SOC15(VCN, inst, regUVD_RB_RPTR, 0);
+	WREG32_SOC15(VCN, inst, regUVD_RB_WPTR, 0);
+
+	tmp = RREG32_SOC15(VCN, inst, regUVD_RB_RPTR);
+	WREG32_SOC15(VCN, inst, regUVD_RB_WPTR, tmp);
+	ring->wptr = RREG32_SOC15(VCN, inst, regUVD_RB_WPTR);
+
+	tmp = RREG32_SOC15(VCN, inst, regVCN_RB_ENABLE);
+	tmp |= VCN_RB_ENABLE__RB1_EN_MASK;
+	WREG32_SOC15(VCN, inst, regVCN_RB_ENABLE, tmp);
+	fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF);
 
 	return 0;
 }
@@ -939,80 +933,76 @@ static void vcn_v5_0_0_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
  *
  * Stop VCN block
  */
-static int vcn_v5_0_0_stop(struct amdgpu_device *adev)
+static int vcn_v5_0_0_stop(struct amdgpu_device *adev, unsigned int inst)
 {
 	volatile struct amdgpu_vcn5_fw_shared *fw_shared;
 	uint32_t tmp;
-	int i, r = 0;
+	int r = 0;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->vcn.harvest_config & (1 << i))
-			continue;
-
-		fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
-		fw_shared->sq.queue_mode |= FW_QUEUE_DPG_HOLD_OFF;
+	if (adev->vcn.harvest_config & (1 << inst))
+		goto done;
 
-		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
-			vcn_v5_0_0_stop_dpg_mode(adev, i);
-			continue;
-		}
+	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
+	fw_shared->sq.queue_mode |= FW_QUEUE_DPG_HOLD_OFF;
 
-		/* wait for vcn idle */
-		r = SOC15_WAIT_ON_RREG(VCN, i, regUVD_STATUS, UVD_STATUS__IDLE, 0x7);
-		if (r)
-			return r;
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
+		vcn_v5_0_0_stop_dpg_mode(adev, inst);
+		goto done;
+	}
 
-		tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
-		      UVD_LMI_STATUS__READ_CLEAN_MASK |
-		      UVD_LMI_STATUS__WRITE_CLEAN_MASK |
-		      UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
-		r = SOC15_WAIT_ON_RREG(VCN, i, regUVD_LMI_STATUS, tmp, tmp);
-		if (r)
-			return r;
+	/* wait for vcn idle */
+	r = SOC15_WAIT_ON_RREG(VCN, inst, regUVD_STATUS, UVD_STATUS__IDLE, 0x7);
+	if (r)
+		return r;
 
-		/* disable LMI UMC channel */
-		tmp = RREG32_SOC15(VCN, i, regUVD_LMI_CTRL2);
-		tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
-		WREG32_SOC15(VCN, i, regUVD_LMI_CTRL2, tmp);
-		tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK |
-		      UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
-		r = SOC15_WAIT_ON_RREG(VCN, i, regUVD_LMI_STATUS, tmp, tmp);
-		if (r)
-			return r;
+	tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
+		  UVD_LMI_STATUS__READ_CLEAN_MASK |
+		  UVD_LMI_STATUS__WRITE_CLEAN_MASK |
+		  UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
+	r = SOC15_WAIT_ON_RREG(VCN, inst, regUVD_LMI_STATUS, tmp, tmp);
+	if (r)
+		return r;
 
-		/* block VCPU register access */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_RB_ARB_CTRL),
-			UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
-			~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
-
-		/* reset VCPU */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL),
-			UVD_VCPU_CNTL__BLK_RST_MASK,
-			~UVD_VCPU_CNTL__BLK_RST_MASK);
-
-		/* disable VCPU clock */
-		WREG32_P(SOC15_REG_OFFSET(VCN, i, regUVD_VCPU_CNTL), 0,
-			~(UVD_VCPU_CNTL__CLK_EN_MASK));
-
-		/* apply soft reset */
-		tmp = RREG32_SOC15(VCN, i, regUVD_SOFT_RESET);
-		tmp |= UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, i, regUVD_SOFT_RESET, tmp);
-		tmp = RREG32_SOC15(VCN, i, regUVD_SOFT_RESET);
-		tmp |= UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
-		WREG32_SOC15(VCN, i, regUVD_SOFT_RESET, tmp);
-
-		/* clear status */
-		WREG32_SOC15(VCN, i, regUVD_STATUS, 0);
-
-		/* enable VCN power gating */
-		vcn_v5_0_0_enable_static_power_gating(adev, i);
-	}
+	/* disable LMI UMC channel */
+	tmp = RREG32_SOC15(VCN, inst, regUVD_LMI_CTRL2);
+	tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
+	WREG32_SOC15(VCN, inst, regUVD_LMI_CTRL2, tmp);
+	tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK |
+		  UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
+	r = SOC15_WAIT_ON_RREG(VCN, inst, regUVD_LMI_STATUS, tmp, tmp);
+	if (r)
+		return r;
 
-	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
-		if (adev->pm.dpm_enabled)
-			amdgpu_dpm_enable_vcn(adev, false, i);
-	}
+	/* block VCPU register access */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_RB_ARB_CTRL),
+		UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
+		~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
+
+	/* reset VCPU */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL),
+		UVD_VCPU_CNTL__BLK_RST_MASK,
+		~UVD_VCPU_CNTL__BLK_RST_MASK);
+
+	/* disable VCPU clock */
+	WREG32_P(SOC15_REG_OFFSET(VCN, inst, regUVD_VCPU_CNTL), 0,
+		~(UVD_VCPU_CNTL__CLK_EN_MASK));
+
+	/* apply soft reset */
+	tmp = RREG32_SOC15(VCN, inst, regUVD_SOFT_RESET);
+	tmp |= UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, inst, regUVD_SOFT_RESET, tmp);
+	tmp = RREG32_SOC15(VCN, inst, regUVD_SOFT_RESET);
+	tmp |= UVD_SOFT_RESET__LMI_SOFT_RESET_MASK;
+	WREG32_SOC15(VCN, inst, regUVD_SOFT_RESET, tmp);
+
+	/* clear status */
+	WREG32_SOC15(VCN, inst, regUVD_STATUS, 0);
+
+	/* enable VCN power gating */
+	vcn_v5_0_0_enable_static_power_gating(adev, inst);
+done:
+	if (adev->pm.dpm_enabled)
+		amdgpu_dpm_enable_vcn(adev, false, inst);
 
 	return 0;
 }
@@ -1268,9 +1258,9 @@ static int vcn_v5_0_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 		return 0;
 
 	if (state == AMD_PG_STATE_GATE)
-		ret = vcn_v5_0_0_stop(adev);
+		ret = vcn_v5_0_0_stop(adev, inst);
 	else
-		ret = vcn_v5_0_0_start(adev);
+		ret = vcn_v5_0_0_start(adev, inst);
 
 	if (!ret)
 		adev->vcn.cur_state[inst] = state;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 17/18] drm/amdgpu/vcn: separate idle work by instance
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (15 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 16/18] drm/amdgpu: power vcn 5_0_0 " boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  2024-10-04 18:44 ` [PATCH 18/18] drm/amdgpu: set powergating state by vcn instance boyuan.zhang
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

Previously idle working handling is for all VCN instances. As a result, when one
of the instance finishes its job, the idle work can't be triggered if the other
instance is still busy.

Now, move the idle_work from amdgpu_vcn to amdgpu_vcn_inst, in order to
track work by vcn instance. Add work_inst to track the instance number
that the work belongs to. As a result, the idle work can now be triggered
once the job is done on one of the vcn instance, and no need to consider
the work on the other vcn instance.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c  | 66 ++++++++++++------------
 drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h  |  4 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c   |  2 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c   |  2 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c   |  2 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c   |  2 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c   |  2 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c |  2 +-
 drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c |  2 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c    | 14 ++---
 drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c    |  2 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c    |  2 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c    |  2 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c    |  2 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c  |  2 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c  |  2 +-
 drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c  |  2 +-
 17 files changed, 58 insertions(+), 54 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
index 43f44cc201cb..28c5e15d166d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
@@ -118,7 +118,11 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev)
 	unsigned int fw_shared_size, log_offset;
 	int i, r;
 
-	INIT_DELAYED_WORK(&adev->vcn.idle_work, amdgpu_vcn_idle_work_handler);
+	for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
+		adev->vcn.inst[i].adev = adev;
+		adev->vcn.inst[i].work_inst = i;
+		INIT_DELAYED_WORK(&adev->vcn.inst[i].idle_work, amdgpu_vcn_idle_work_handler);
+	}
 	mutex_init(&adev->vcn.vcn_pg_lock);
 	mutex_init(&adev->vcn.vcn1_jpeg1_workaround);
 	atomic_set(&adev->vcn.total_submission_cnt, 0);
@@ -302,7 +306,8 @@ int amdgpu_vcn_suspend(struct amdgpu_device *adev)
 
 	bool in_ras_intr = amdgpu_ras_intr_triggered();
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
+		cancel_delayed_work_sync(&adev->vcn.inst[i].idle_work);
 
 	/* err_event_athub will corrupt VCPU buffer, so we need to
 	 * restore fw data and clear buffer in amdgpu_vcn_resume() */
@@ -376,46 +381,43 @@ int amdgpu_vcn_resume(struct amdgpu_device *adev)
 
 static void amdgpu_vcn_idle_work_handler(struct work_struct *work)
 {
-	struct amdgpu_device *adev =
-		container_of(work, struct amdgpu_device, vcn.idle_work.work);
-	unsigned int fences = 0, fence[AMDGPU_MAX_VCN_INSTANCES] = {0};
-	unsigned int i, j;
+	struct amdgpu_vcn_inst *vcn_inst =
+		container_of(work, struct amdgpu_vcn_inst, idle_work.work);
+	struct amdgpu_device *adev = vcn_inst->adev;
+	unsigned int inst = vcn_inst->work_inst;
+	unsigned int fence = 0;
+	unsigned int i;
 	int r = 0;
 
-	for (j = 0; j < adev->vcn.num_vcn_inst; ++j) {
-		if (adev->vcn.harvest_config & (1 << j))
-			continue;
-
-		for (i = 0; i < adev->vcn.num_enc_rings; ++i)
-			fence[j] += amdgpu_fence_count_emitted(&adev->vcn.inst[j].ring_enc[i]);
-
-		/* Only set DPG pause for VCN3 or below, VCN4 and above will be handled by FW */
-		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG &&
-		    !adev->vcn.using_unified_queue) {
-			struct dpg_pause_state new_state;
-
-			if (fence[j] ||
-				unlikely(atomic_read(&adev->vcn.inst[j].dpg_enc_submission_cnt)))
-				new_state.fw_based = VCN_DPG_STATE__PAUSE;
-			else
-				new_state.fw_based = VCN_DPG_STATE__UNPAUSE;
+	if (adev->vcn.harvest_config & (1 << inst))
+		return;
 
-			adev->vcn.pause_dpg_mode(adev, j, &new_state);
-		}
+	for (i = 0; i < adev->vcn.num_enc_rings; ++i)
+		fence += amdgpu_fence_count_emitted(&adev->vcn.inst[inst].ring_enc[i]);
 
-		fence[j] += amdgpu_fence_count_emitted(&adev->vcn.inst[j].ring_dec);
-		fences += fence[j];
+	/* Only set DPG pause for VCN3 or below, VCN4 and above will be handled by FW */
+	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG &&
+			!adev->vcn.using_unified_queue) {
+		struct dpg_pause_state new_state;
+		if (fence ||
+				unlikely(atomic_read(&adev->vcn.inst[inst].dpg_enc_submission_cnt)))
+			new_state.fw_based = VCN_DPG_STATE__PAUSE;
+		else
+			new_state.fw_based = VCN_DPG_STATE__UNPAUSE;
+		adev->vcn.pause_dpg_mode(adev, inst, &new_state);
 	}
 
-	if (!fences && !atomic_read(&adev->vcn.total_submission_cnt)) {
+	fence += amdgpu_fence_count_emitted(&adev->vcn.inst[inst].ring_dec);
+
+	if (!fence && !atomic_read(&adev->vcn.total_submission_cnt)) {
 		amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN,
 		       AMD_PG_STATE_GATE);
 		r = amdgpu_dpm_switch_power_profile(adev, PP_SMC_POWER_PROFILE_VIDEO,
-				false);
+											false);
 		if (r)
 			dev_warn(adev->dev, "(%d) failed to disable video power profile mode\n", r);
 	} else {
-		schedule_delayed_work(&adev->vcn.idle_work, VCN_IDLE_TIMEOUT);
+		schedule_delayed_work(&adev->vcn.inst[inst].idle_work, VCN_IDLE_TIMEOUT);
 	}
 }
 
@@ -426,7 +428,7 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring)
 
 	atomic_inc(&adev->vcn.total_submission_cnt);
 
-	if (!cancel_delayed_work_sync(&adev->vcn.idle_work)) {
+	if (!cancel_delayed_work_sync(&adev->vcn.inst[ring->me].idle_work)) {
 		r = amdgpu_dpm_switch_power_profile(adev, PP_SMC_POWER_PROFILE_VIDEO,
 				true);
 		if (r)
@@ -475,7 +477,7 @@ void amdgpu_vcn_ring_end_use(struct amdgpu_ring *ring)
 
 	atomic_dec(&ring->adev->vcn.total_submission_cnt);
 
-	schedule_delayed_work(&ring->adev->vcn.idle_work, VCN_IDLE_TIMEOUT);
+	schedule_delayed_work(&ring->adev->vcn.inst[ring->me].idle_work, VCN_IDLE_TIMEOUT);
 }
 
 int amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring *ring)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
index f6717f780acd..5733dda64713 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
@@ -279,6 +279,7 @@ struct amdgpu_vcn_fw_shared {
 };
 
 struct amdgpu_vcn_inst {
+	struct amdgpu_device *adev;
 	struct amdgpu_bo	*vcpu_bo;
 	void			*cpu_addr;
 	uint64_t		gpu_addr;
@@ -297,6 +298,8 @@ struct amdgpu_vcn_inst {
 	atomic_t		dpg_enc_submission_cnt;
 	struct amdgpu_vcn_fw_shared fw_shared;
 	uint8_t			aid_id;
+	struct delayed_work	idle_work;
+	uint8_t 		work_inst;
 };
 
 struct amdgpu_vcn_ras {
@@ -305,7 +308,6 @@ struct amdgpu_vcn_ras {
 
 struct amdgpu_vcn {
 	unsigned		fw_version;
-	struct delayed_work	idle_work;
 	const struct firmware	*fw[AMDGPU_MAX_VCN_INSTANCES];	/* VCN firmware */
 	unsigned		num_enc_rings;
 	enum amd_powergating_state cur_state[AMDGPU_MAX_VCN_INSTANCES];
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c
index 03b8b7cd5229..8031406e20ff 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c
@@ -604,7 +604,7 @@ static void jpeg_v1_0_set_irq_funcs(struct amdgpu_device *adev)
 static void jpeg_v1_0_ring_begin_use(struct amdgpu_ring *ring)
 {
 	struct	amdgpu_device *adev = ring->adev;
-	bool	set_clocks = !cancel_delayed_work_sync(&adev->vcn.idle_work);
+	bool	set_clocks = !cancel_delayed_work_sync(&adev->vcn.inst[0].idle_work);
 	int		cnt = 0;
 
 	mutex_lock(&adev->vcn.vcn1_jpeg1_workaround);
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
index c5f692a45bee..4a8dc87dc6fc 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
@@ -150,7 +150,7 @@ static int jpeg_v2_0_hw_fini(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	cancel_delayed_work_sync(&adev->vcn.inst[0].idle_work);
 
 	if (adev->jpeg.cur_state != AMD_PG_STATE_GATE &&
 	      RREG32_SOC15(JPEG, 0, mmUVD_JRBC_STATUS))
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
index f1ddef8e60ee..7188184f8551 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
@@ -211,7 +211,7 @@ static int jpeg_v2_5_hw_fini(struct amdgpu_ip_block *ip_block)
 	struct amdgpu_device *adev = ip_block->adev;
 	int i;
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	cancel_delayed_work_sync(&adev->vcn.inst[0].idle_work);
 
 	for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) {
 		if (adev->jpeg.harvest_config & (1 << i))
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
index 69f0a9006b96..5af54669091d 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c
@@ -164,7 +164,7 @@ static int jpeg_v3_0_hw_fini(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	cancel_delayed_work_sync(&adev->vcn.inst[0].idle_work);
 
 	if (adev->jpeg.cur_state != AMD_PG_STATE_GATE &&
 	      RREG32_SOC15(JPEG, 0, mmUVD_JRBC_STATUS))
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
index e304108d7024..b369c7f4f122 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
@@ -195,7 +195,7 @@ static int jpeg_v4_0_hw_fini(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	cancel_delayed_work_sync(&adev->vcn.inst[0].idle_work);
 	if (!amdgpu_sriov_vf(adev)) {
 		if (adev->jpeg.cur_state != AMD_PG_STATE_GATE &&
 			RREG32_SOC15(JPEG, 0, regUVD_JRBC_STATUS))
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
index 2a28eb479a34..19a94f837841 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
@@ -219,7 +219,7 @@ static int jpeg_v4_0_5_hw_fini(struct amdgpu_ip_block *ip_block)
 	struct amdgpu_device *adev = ip_block->adev;
 	int i;
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	cancel_delayed_work_sync(&adev->vcn.inst[0].idle_work);
 
 	for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) {
 		if (adev->jpeg.harvest_config & (1 << i))
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
index 692d0083b5f7..685eb88f4c1b 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
@@ -161,7 +161,7 @@ static int jpeg_v5_0_0_hw_fini(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	cancel_delayed_work_sync(&adev->vcn.inst[0].idle_work);
 
 	if (adev->jpeg.cur_state != AMD_PG_STATE_GATE &&
 	      RREG32_SOC15(JPEG, 0, regUVD_JRBC_STATUS))
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
index 4f768c6097d8..f7ea5b289281 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
@@ -150,7 +150,7 @@ static int vcn_v1_0_sw_init(struct amdgpu_ip_block *ip_block)
 		return r;
 
 	/* Override the work func */
-	adev->vcn.idle_work.work.func = vcn_v1_0_idle_work_handler;
+	adev->vcn.inst[0].idle_work.work.func = vcn_v1_0_idle_work_handler;
 
 	amdgpu_vcn_setup_ucode(adev);
 
@@ -277,7 +277,7 @@ static int vcn_v1_0_hw_fini(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	cancel_delayed_work_sync(&adev->vcn.inst[0].idle_work);
 
 	if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
 		(adev->vcn.cur_state[0] != AMD_PG_STATE_GATE &&
@@ -301,7 +301,7 @@ static int vcn_v1_0_suspend(struct amdgpu_ip_block *ip_block)
 	struct amdgpu_device *adev = ip_block->adev;
 	bool idle_work_unexecuted;
 
-	idle_work_unexecuted = cancel_delayed_work_sync(&adev->vcn.idle_work);
+	idle_work_unexecuted = cancel_delayed_work_sync(&adev->vcn.inst[0].idle_work);
 	if (idle_work_unexecuted) {
 		if (adev->pm.dpm_enabled)
 			amdgpu_dpm_enable_vcn(adev, false, 0);
@@ -1830,7 +1830,7 @@ static int vcn_v1_0_set_powergating_state(struct amdgpu_ip_block *ip_block,
 static void vcn_v1_0_idle_work_handler(struct work_struct *work)
 {
 	struct amdgpu_device *adev =
-		container_of(work, struct amdgpu_device, vcn.idle_work.work);
+		container_of(work, struct amdgpu_device, vcn.inst[0].idle_work.work);
 	unsigned int fences = 0, i;
 
 	for (i = 0; i < adev->vcn.num_enc_rings; ++i)
@@ -1863,14 +1863,14 @@ static void vcn_v1_0_idle_work_handler(struct work_struct *work)
 			amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN,
 			       AMD_PG_STATE_GATE);
 	} else {
-		schedule_delayed_work(&adev->vcn.idle_work, VCN_IDLE_TIMEOUT);
+		schedule_delayed_work(&adev->vcn.inst[0].idle_work, VCN_IDLE_TIMEOUT);
 	}
 }
 
 static void vcn_v1_0_ring_begin_use(struct amdgpu_ring *ring)
 {
 	struct	amdgpu_device *adev = ring->adev;
-	bool set_clocks = !cancel_delayed_work_sync(&adev->vcn.idle_work);
+	bool set_clocks = !cancel_delayed_work_sync(&adev->vcn.inst[0].idle_work);
 
 	mutex_lock(&adev->vcn.vcn1_jpeg1_workaround);
 
@@ -1922,7 +1922,7 @@ void vcn_v1_0_set_pg_for_begin_use(struct amdgpu_ring *ring, bool set_clocks)
 
 void vcn_v1_0_ring_end_use(struct amdgpu_ring *ring)
 {
-	schedule_delayed_work(&ring->adev->vcn.idle_work, VCN_IDLE_TIMEOUT);
+	schedule_delayed_work(&ring->adev->vcn.inst[0].idle_work, VCN_IDLE_TIMEOUT);
 	mutex_unlock(&ring->adev->vcn.vcn1_jpeg1_workaround);
 }
 
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
index 1b9085ddc00f..6e3a79b4ae64 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
@@ -313,7 +313,7 @@ static int vcn_v2_0_hw_fini(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	cancel_delayed_work_sync(&adev->vcn.inst[0].idle_work);
 
 	if ((adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) ||
 	    (adev->vcn.cur_state[0] != AMD_PG_STATE_GATE &&
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
index 1f8738ae360a..413fa0c8d0c2 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
@@ -387,7 +387,7 @@ static int vcn_v2_5_hw_fini(struct amdgpu_ip_block *ip_block)
 	struct amdgpu_device *adev = ip_block->adev;
 	int inst = ip_block->instance;
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	cancel_delayed_work_sync(&adev->vcn.inst[inst].idle_work);
 
 	if (adev->vcn.harvest_config & (1 << inst))
 		return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
index ea79c83aa21d..84486438abde 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
@@ -420,7 +420,7 @@ static int vcn_v3_0_hw_fini(struct amdgpu_ip_block *ip_block)
 	struct amdgpu_device *adev = ip_block->adev;
 	int inst = ip_block->instance;
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	cancel_delayed_work_sync(&adev->vcn.inst[inst].idle_work);
 
 	if (adev->vcn.harvest_config & (1 << inst))
 		return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index 1555e823abe2..19783d163be3 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -349,7 +349,7 @@ static int vcn_v4_0_hw_fini(struct amdgpu_ip_block *ip_block)
 	struct amdgpu_device *adev = ip_block->adev;
 	int inst = ip_block->instance;
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	cancel_delayed_work_sync(&adev->vcn.inst[inst].idle_work);
 
 	if (adev->vcn.harvest_config & (1 << inst))
 		return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
index 97e3b10ba414..502cb8d36031 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
@@ -315,7 +315,7 @@ static int vcn_v4_0_3_hw_fini(struct amdgpu_ip_block *ip_block)
 	struct amdgpu_device *adev = ip_block->adev;
 	int inst = ip_block->instance;
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	cancel_delayed_work_sync(&adev->vcn.inst[inst].idle_work);
 
 	if (adev->vcn.cur_state[inst] != AMD_PG_STATE_GATE)
 		vcn_v4_0_3_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
index b91a64de66ea..badb38e8bdc6 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
@@ -298,7 +298,7 @@ static int vcn_v4_0_5_hw_fini(struct amdgpu_ip_block *ip_block)
 	struct amdgpu_device *adev = ip_block->adev;
 	int inst = ip_block->instance;
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	cancel_delayed_work_sync(&adev->vcn.inst[inst].idle_work);
 
 	if (adev->vcn.harvest_config & (1 << inst))
 		return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
index c6f06f778dbf..054d1b9df3f8 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
@@ -262,7 +262,7 @@ static int vcn_v5_0_0_hw_fini(struct amdgpu_ip_block *ip_block)
 	struct amdgpu_device *adev = ip_block->adev;
 	int inst = ip_block->instance;
 
-	cancel_delayed_work_sync(&adev->vcn.idle_work);
+	cancel_delayed_work_sync(&adev->vcn.inst[inst].idle_work);
 
 	if (adev->vcn.harvest_config & (1 << inst))
 		return 0;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 18/18] drm/amdgpu: set powergating state by vcn instance
  2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
                   ` (16 preceding siblings ...)
  2024-10-04 18:44 ` [PATCH 17/18] drm/amdgpu/vcn: separate idle work " boyuan.zhang
@ 2024-10-04 18:44 ` boyuan.zhang
  17 siblings, 0 replies; 37+ messages in thread
From: boyuan.zhang @ 2024-10-04 18:44 UTC (permalink / raw)
  To: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri
  Cc: Boyuan Zhang

From: Boyuan Zhang <boyuan.zhang@amd.com>

Set powergating state by vcn instance in idle_work_handler() and
ring_begin_use() functions for vcn with multiple instances.

Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
index 28c5e15d166d..9a8e8f88e1ad 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
@@ -410,8 +410,12 @@ static void amdgpu_vcn_idle_work_handler(struct work_struct *work)
 	fence += amdgpu_fence_count_emitted(&adev->vcn.inst[inst].ring_dec);
 
 	if (!fence && !atomic_read(&adev->vcn.total_submission_cnt)) {
-		amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN,
-		       AMD_PG_STATE_GATE);
+		if (adev->vcn.num_vcn_inst > 1)
+			amdgpu_device_ip_set_powergating_state_instance(adev,
+				AMD_IP_BLOCK_TYPE_VCN, AMD_PG_STATE_GATE, inst);
+		else
+			amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN,
+				AMD_PG_STATE_GATE);
 		r = amdgpu_dpm_switch_power_profile(adev, PP_SMC_POWER_PROFILE_VIDEO,
 											false);
 		if (r)
@@ -436,8 +440,12 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring)
 	}
 
 	mutex_lock(&adev->vcn.vcn_pg_lock);
-	amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN,
-	       AMD_PG_STATE_UNGATE);
+	if (adev->vcn.num_vcn_inst > 1)
+		amdgpu_device_ip_set_powergating_state_instance(adev,
+			AMD_IP_BLOCK_TYPE_VCN, AMD_PG_STATE_UNGATE, ring->me);
+	else
+		amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCN,
+			AMD_PG_STATE_UNGATE);
 
 	/* Only set DPG pause for VCN3 or below, VCN4 and above will be handled by FW */
 	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG &&
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [PATCH 04/18] drm/amd/pm: add inst to set_powergating_by_smu
  2024-10-04 18:44 ` [PATCH 04/18] drm/amd/pm: add inst to set_powergating_by_smu boyuan.zhang
@ 2024-10-04 19:14   ` Alex Deucher
  2024-10-08 22:06     ` Boyuan Zhang
  0 siblings, 1 reply; 37+ messages in thread
From: Alex Deucher @ 2024-10-04 19:14 UTC (permalink / raw)
  To: boyuan.zhang
  Cc: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri

On Fri, Oct 4, 2024 at 2:45 PM <boyuan.zhang@amd.com> wrote:
>
> From: Boyuan Zhang <boyuan.zhang@amd.com>
>
> Add an instance parameter to set_powergating_by_smu() function, and
> re-write all amd_pm functions accordingly. Then use the instance to
> call smu_dpm_set_vcn_enable().
>
> v2: remove duplicated functions.
>
> remove for-loop in smu_dpm_set_power_gate(), and temporarily move it to
> to amdgpu_dpm_set_powergating_by_smu(), in order to keep the exact same
> logic as before, until further separation in next patch.
>
> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
> ---
>  drivers/gpu/drm/amd/include/kgd_pp_interface.h   |  4 +++-
>  drivers/gpu/drm/amd/pm/amdgpu_dpm.c              | 10 ++++++++--
>  drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c       |  4 +++-
>  drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c |  4 +++-
>  drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c        | 14 ++++++--------
>  5 files changed, 23 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
> index 2fa71f68205e..f24bc61df9a7 100644
> --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h
> +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
> @@ -405,7 +405,9 @@ struct amd_pm_funcs {
>         int (*load_firmware)(void *handle);
>         int (*wait_for_fw_loading_complete)(void *handle);
>         int (*set_powergating_by_smu)(void *handle,
> -                               uint32_t block_type, bool gate);
> +                               uint32_t block_type,
> +                               bool gate,
> +                               int inst);
>         int (*set_clockgating_by_smu)(void *handle, uint32_t msg_id);
>         int (*set_power_limit)(void *handle, uint32_t n);
>         int (*get_power_limit)(void *handle, uint32_t *limit,
> diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
> index 9dc82f4d7c93..bcedbeec082f 100644
> --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
> +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
> @@ -88,7 +88,6 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, uint32_t block
>         case AMD_IP_BLOCK_TYPE_UVD:
>         case AMD_IP_BLOCK_TYPE_VCE:
>         case AMD_IP_BLOCK_TYPE_GFX:
> -       case AMD_IP_BLOCK_TYPE_VCN:
>         case AMD_IP_BLOCK_TYPE_SDMA:
>         case AMD_IP_BLOCK_TYPE_JPEG:
>         case AMD_IP_BLOCK_TYPE_GMC:
> @@ -96,7 +95,14 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, uint32_t block
>         case AMD_IP_BLOCK_TYPE_VPE:
>                 if (pp_funcs && pp_funcs->set_powergating_by_smu)
>                         ret = (pp_funcs->set_powergating_by_smu(
> -                               (adev)->powerplay.pp_handle, block_type, gate));
> +                               (adev)->powerplay.pp_handle, block_type, gate, 0));
> +               break;
> +       case AMD_IP_BLOCK_TYPE_VCN:
> +               if (pp_funcs && pp_funcs->set_powergating_by_smu) {
> +                       for (int i = 0; i < adev->vcn.num_vcn_inst; i++)
> +                               ret = (pp_funcs->set_powergating_by_smu(
> +                                       (adev)->powerplay.pp_handle, block_type, gate, i));
> +               }
>                 break;
>         default:
>                 break;
> diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
> index 2cd6cb991f29..af7da780b58b 100644
> --- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
> +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
> @@ -3287,7 +3287,9 @@ static int kv_dpm_read_sensor(void *handle, int idx,
>  }
>
>  static int kv_set_powergating_by_smu(void *handle,
> -                               uint32_t block_type, bool gate)
> +                               uint32_t block_type,
> +                               bool gate,
> +                               int inst)
>  {
>         switch (block_type) {
>         case AMD_IP_BLOCK_TYPE_UVD:
> diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
> index f193c77cc141..de5ee1c5503f 100644
> --- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
> +++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
> @@ -1241,7 +1241,9 @@ static void pp_dpm_powergate_sdma(void *handle, bool gate)
>  }
>
>  static int pp_set_powergating_by_smu(void *handle,
> -                               uint32_t block_type, bool gate)
> +                               uint32_t block_type,
> +                               bool gate,
> +                               int inst)
>  {
>         int ret = 0;
>
> diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> index 786241fa8d2c..0da84e390d0d 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
> @@ -353,10 +353,10 @@ static int smu_set_mall_enable(struct smu_context *smu)
>   */
>  static int smu_dpm_set_power_gate(void *handle,
>                                   uint32_t block_type,
> -                                 bool gate)
> +                                 bool gate,
> +                                 int inst)
>  {
>         struct smu_context *smu = handle;
> -       struct amdgpu_device *adev = smu->adev;
>         int ret = 0;
>
>         if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) {
> @@ -373,12 +373,10 @@ static int smu_dpm_set_power_gate(void *handle,
>          */
>         case AMD_IP_BLOCK_TYPE_UVD:
>         case AMD_IP_BLOCK_TYPE_VCN:
> -               for (int i = 0; i < adev->vcn.num_vcn_inst; i++) {
> -                       ret = smu_dpm_set_vcn_enable(smu, !gate, i);
> -                       if (ret)
> -                               dev_err(smu->adev->dev, "Failed to power %s VCN!\n",
> -                                       gate ? "gate" : "ungate");
> -               }
> +               ret = smu_dpm_set_vcn_enable(smu, !gate, inst);
> +               if (ret)
> +                       dev_err(smu->adev->dev, "Failed to power %s VCN!\n",
> +                               gate ? "gate" : "ungate");

Might want to note the instance in the error message.

Alex

>                 break;
>         case AMD_IP_BLOCK_TYPE_GFX:
>                 ret = smu_gfx_off_control(smu, gate);
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 09/18] drm/amdgpu: add set_powergating_state_instance
  2024-10-04 18:44 ` [PATCH 09/18] drm/amdgpu: add set_powergating_state_instance boyuan.zhang
@ 2024-10-04 19:40   ` Alex Deucher
  2024-10-08 22:07     ` Boyuan Zhang
  0 siblings, 1 reply; 37+ messages in thread
From: Alex Deucher @ 2024-10-04 19:40 UTC (permalink / raw)
  To: boyuan.zhang
  Cc: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri

On Fri, Oct 4, 2024 at 2:45 PM <boyuan.zhang@amd.com> wrote:
>
> From: Boyuan Zhang <boyuan.zhang@amd.com>
>
> Add a new function to allow setting requested powergating state for the
> given instance. If the instance value doesn't match with the one inside
> ip_block, then do nothing since this request is for other instances with
> the same block type.
>
> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu.h        |  4 +++
>  drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 37 ++++++++++++++++++++++
>  2 files changed, 41 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index 3442564fe174..ae59497f3074 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -358,6 +358,10 @@ int amdgpu_device_ip_set_clockgating_state(void *dev,
>  int amdgpu_device_ip_set_powergating_state(void *dev,
>                                            enum amd_ip_block_type block_type,
>                                            enum amd_powergating_state state);
> +int amdgpu_device_ip_set_powergating_state_instance(void *dev,
> +                                          enum amd_ip_block_type block_type,
> +                                          enum amd_powergating_state state,
> +                                          unsigned int inst);
>  void amdgpu_device_ip_get_clockgating_state(struct amdgpu_device *adev,
>                                             u64 *flags);
>  int amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev,
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> index 35a3e71a5a84..f0b6a9675405 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> @@ -2162,6 +2162,43 @@ int amdgpu_device_ip_set_powergating_state(void *dev,
>         return r;
>  }
>
> +/**
> + * amdgpu_device_ip_set_powergating_state_instance - set the PG state
> + *
> + * @dev: amdgpu_device pointer
> + * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.)
> + * @state: powergating state (gate or ungate)
> + *
> + * Sets the requested powergating state for the given instance of
> + * the hardware IP specified.
> + * Returns the error code from the last instance.
> + */
> +int amdgpu_device_ip_set_powergating_state_instance(void *dev,
> +                                          enum amd_ip_block_type block_type,
> +                                          enum amd_powergating_state state,
> +                                          unsigned int inst)
> +{
> +       struct amdgpu_device *adev = dev;
> +       int i, r = 0;
> +
> +       for (i = 0; i < adev->num_ip_blocks; i++) {
> +               if (!adev->ip_blocks[i].status.valid)
> +                       continue;
> +               if (adev->ip_blocks[i].version->type != block_type)
> +                       continue;
> +               if (adev->ip_blocks[i].instance != inst)
> +                       continue;
> +               if (!adev->ip_blocks[i].version->funcs->set_powergating_state)
> +                       continue;
> +               r = adev->ip_blocks[i].version->funcs->set_powergating_state(
> +                       (void *)&adev->ip_blocks[i], state);
> +               if (r)
> +                       DRM_ERROR("set_powergating_state of IP block <%s> failed %d\n",
> +                                 adev->ip_blocks[i].version->funcs->name, r);
> +       }
> +       return r;
> +}
> +

I think it would also be cleaner to update
amdgpu_device_ip_set_powergating_state() to take the instance as a new
parameter.  Same for amdgpu_device_ip_set_clockgating_state().

Alex

>  /**
>   * amdgpu_device_ip_get_clockgating_state - get the CG state
>   *
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-04 18:44 ` [PATCH 11/18] drm/amdgpu: power vcn 2_5 " boyuan.zhang
@ 2024-10-04 19:52   ` Alex Deucher
  2024-10-08 22:10     ` Boyuan Zhang
  2024-10-07  5:22   ` Lazar, Lijo
  1 sibling, 1 reply; 37+ messages in thread
From: Alex Deucher @ 2024-10-04 19:52 UTC (permalink / raw)
  To: boyuan.zhang
  Cc: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri

On Fri, Oct 4, 2024 at 2:53 PM <boyuan.zhang@amd.com> wrote:
>
> From: Boyuan Zhang <boyuan.zhang@amd.com>
>
> For vcn 2_5, add ip_block for each vcn instance during discovery stage.
>
> And only powering on/off one of the vcn instance using the
> instance value stored in ip_block, instead of powering on/off all
> vcn instances. Modify the existing functions to use the instance value
> in ip_block, and remove the original for loop for all vcn instances.
>
> v2: rename "i"/"j" to "inst" for instance value.
>
> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
>  drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565 +++++++++---------
>  2 files changed, 280 insertions(+), 289 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
> index 9f9a1867da72..de1053cc2a2b 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
> @@ -2278,6 +2278,7 @@ static int amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
>
>  static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>  {
> +       int i;

new line between stack and code.

>         if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
>                 switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
>                 case IP_VERSION(7, 0, 0):
> @@ -2321,7 +2322,8 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>                 case IP_VERSION(2, 0, 3):
>                         break;
>                 case IP_VERSION(2, 5, 0):
> -                       amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
> +                       for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
> +                               amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>                         amdgpu_device_ip_block_add(adev, &jpeg_v2_5_ip_block);
>                         break;
>                 case IP_VERSION(2, 6, 0):
> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
> index d00df51bc400..1f8738ae360a 100644
> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
> @@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct amdgpu_ip_block *ip_block)
>  static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>  {
>         struct amdgpu_ring *ring;
> -       int i, j, r;
> +       int i, r;
>         uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
>         uint32_t *ptr;
>         struct amdgpu_device *adev = ip_block->adev;
> +       int inst = ip_block->instance;
>
> -       for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
> -               if (adev->vcn.harvest_config & (1 << j))
> -                       continue;
> -               /* VCN DEC TRAP */
> -               r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
> -                               VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->vcn.inst[j].irq);
> -               if (r)
> -                       return r;
> -
> -               /* VCN ENC TRAP */
> -               for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> -                       r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
> -                               i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[j].irq);
> -                       if (r)
> -                               return r;
> -               }
> +       if (adev->vcn.harvest_config & (1 << inst))
> +               goto sw_init;
> +       /* VCN DEC TRAP */
> +       r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
> +                       VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->vcn.inst[inst].irq);
> +       if (r)
> +               return r;
>
> -               /* VCN POISON TRAP */
> -               r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
> -                       VCN_2_6__SRCID_UVD_POISON, &adev->vcn.inst[j].ras_poison_irq);
> +       /* VCN ENC TRAP */
> +       for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> +               r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
> +                       i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[inst].irq);
>                 if (r)
>                         return r;
>         }
>
> +       /* VCN POISON TRAP */
> +       r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
> +               VCN_2_6__SRCID_UVD_POISON, &adev->vcn.inst[inst].ras_poison_irq);
> +       if (r)
> +               return r;
> +sw_init:
>         r = amdgpu_vcn_sw_init(adev);

I think the amdgpu_vcn_* helpers will need to be updated to handle
instances as well.  Otherwise we'll end up leaking a bunch of memory
when these gets called for each instance.  While you are at it, we
should move all of the per instance state from struct amdgpu_vcn to
struct amdgpu_vcn_inst.

Alex

>         if (r)
>                 return r;
> @@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>         if (r)
>                 return r;
>
> -       for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
> -               volatile struct amdgpu_fw_shared *fw_shared;
> +       volatile struct amdgpu_fw_shared *fw_shared;
>
> -               if (adev->vcn.harvest_config & (1 << j))
> -                       continue;
> -               adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
> -               adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
> -               adev->vcn.internal.ib_bar_low = mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
> -               adev->vcn.internal.ib_bar_high = mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
> -               adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
> -               adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
> -
> -               adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
> -               adev->vcn.inst[j].external.scratch9 = SOC15_REG_OFFSET(VCN, j, mmUVD_SCRATCH9);
> -               adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
> -               adev->vcn.inst[j].external.data0 = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_DATA0);
> -               adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
> -               adev->vcn.inst[j].external.data1 = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_DATA1);
> -               adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
> -               adev->vcn.inst[j].external.cmd = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_CMD);
> -               adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
> -               adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(VCN, j, mmUVD_NO_OP);
> -
> -               ring = &adev->vcn.inst[j].ring_dec;
> +       if (adev->vcn.harvest_config & (1 << inst))
> +               goto done;
> +       adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
> +       adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
> +       adev->vcn.internal.ib_bar_low = mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
> +       adev->vcn.internal.ib_bar_high = mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
> +       adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
> +       adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
> +
> +       adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
> +       adev->vcn.inst[inst].external.scratch9 = SOC15_REG_OFFSET(VCN, inst, mmUVD_SCRATCH9);
> +       adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
> +       adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_DATA0);
> +       adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
> +       adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_DATA1);
> +       adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
> +       adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_CMD);
> +       adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
> +       adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN, inst, mmUVD_NO_OP);
> +
> +       ring = &adev->vcn.inst[inst].ring_dec;
> +       ring->use_doorbell = true;
> +
> +       ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
> +                       (amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
> +
> +       if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
> +               ring->vm_hub = AMDGPU_MMHUB1(0);
> +       else
> +               ring->vm_hub = AMDGPU_MMHUB0(0);
> +
> +       sprintf(ring->name, "vcn_dec_%d", inst);
> +       r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq,
> +                                0, AMDGPU_RING_PRIO_DEFAULT, NULL);
> +       if (r)
> +               return r;
> +
> +       for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> +               enum amdgpu_ring_priority_level hw_prio = amdgpu_vcn_get_enc_ring_prio(i);
> +
> +               ring = &adev->vcn.inst[inst].ring_enc[i];
>                 ring->use_doorbell = true;
>
>                 ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
> -                               (amdgpu_sriov_vf(adev) ? 2*j : 8*j);
> +                               (amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2 + i + 8*inst));
>
> -               if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
> +               if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
> +                       IP_VERSION(2, 5, 0))
>                         ring->vm_hub = AMDGPU_MMHUB1(0);
>                 else
>                         ring->vm_hub = AMDGPU_MMHUB0(0);
>
> -               sprintf(ring->name, "vcn_dec_%d", j);
> -               r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq,
> -                                    0, AMDGPU_RING_PRIO_DEFAULT, NULL);
> +               sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
> +               r = amdgpu_ring_init(adev, ring, 512,
> +                                        &adev->vcn.inst[inst].irq, 0,
> +                                        hw_prio, NULL);
>                 if (r)
>                         return r;
> -
> -               for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> -                       enum amdgpu_ring_priority_level hw_prio = amdgpu_vcn_get_enc_ring_prio(i);
> -
> -                       ring = &adev->vcn.inst[j].ring_enc[i];
> -                       ring->use_doorbell = true;
> -
> -                       ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
> -                                       (amdgpu_sriov_vf(adev) ? (1 + i + 2*j) : (2 + i + 8*j));
> -
> -                       if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
> -                           IP_VERSION(2, 5, 0))
> -                               ring->vm_hub = AMDGPU_MMHUB1(0);
> -                       else
> -                               ring->vm_hub = AMDGPU_MMHUB0(0);
> -
> -                       sprintf(ring->name, "vcn_enc_%d.%d", j, i);
> -                       r = amdgpu_ring_init(adev, ring, 512,
> -                                            &adev->vcn.inst[j].irq, 0,
> -                                            hw_prio, NULL);
> -                       if (r)
> -                               return r;
> -               }
> -
> -               fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
> -               fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
> -
> -               if (amdgpu_vcnfw_log)
> -                       amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>         }
>
> +       fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
> +       fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
> +
> +       if (amdgpu_vcnfw_log)
> +               amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
> +done:
>         if (amdgpu_sriov_vf(adev)) {
>                 r = amdgpu_virt_alloc_mm_table(adev);
>                 if (r)
> @@ -1005,197 +1002,192 @@ static int vcn_v2_5_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, boo
>         return 0;
>  }
>
> -static int vcn_v2_5_start(struct amdgpu_device *adev)
> +static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned int inst)
>  {
>         struct amdgpu_ring *ring;
>         uint32_t rb_bufsz, tmp;
> -       int i, j, k, r;
> +       int j, k, r;
>
> -       for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> -               if (adev->pm.dpm_enabled)
> -                       amdgpu_dpm_enable_vcn(adev, true, i);
> -       }
> -
> -       for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> -               if (adev->vcn.harvest_config & (1 << i))
> -                       continue;
> -               if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> -                       r = vcn_v2_5_start_dpg_mode(adev, i, adev->vcn.indirect_sram);
> -                       continue;
> -               }
> +       if (adev->pm.dpm_enabled)
> +               amdgpu_dpm_enable_vcn(adev, true, inst);
>
> -               /* disable register anti-hang mechanism */
> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS), 0,
> -                       ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> +       if (adev->vcn.harvest_config & (1 << inst))
> +               return 0;
>
> -               /* set uvd status busy */
> -               tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
> -               WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
> +       if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> +               r = vcn_v2_5_start_dpg_mode(adev, inst, adev->vcn.indirect_sram);
> +               return r;
>         }
>
> +       /* disable register anti-hang mechanism */
> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS), 0,
> +               ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> +
> +       /* set uvd status busy */
> +       tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
> +       WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
> +
>         if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
>                 return 0;
>
>         /*SW clock gating */
>         vcn_v2_5_disable_clock_gating(adev);
>
> -       for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> -               if (adev->vcn.harvest_config & (1 << i))
> -                       continue;
> -               /* enable VCPU clock */
> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
> -                       UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
> -
> -               /* disable master interrupt */
> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
> -                       ~UVD_MASTINT_EN__VCPU_EN_MASK);
> -
> -               /* setup mmUVD_LMI_CTRL */
> -               tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
> -               tmp &= ~0xff;
> -               WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
> -                       UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK |
> -                       UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
> -                       UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
> -                       UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
> -
> -               /* setup mmUVD_MPC_CNTL */
> -               tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
> -               tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
> -               tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
> -               WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
> -
> -               /* setup UVD_MPC_SET_MUXA0 */
> -               WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
> -                       ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
> -                       (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
> -                       (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
> -                       (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
> -
> -               /* setup UVD_MPC_SET_MUXB0 */
> -               WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
> -                       ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
> -                       (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
> -                       (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
> -                       (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
> -
> -               /* setup mmUVD_MPC_SET_MUX */
> -               WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
> -                       ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
> -                       (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
> -                       (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
> -       }
> +       if (adev->vcn.harvest_config & (1 << inst))
> +               return 0;
> +
> +       /* enable VCPU clock */
> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
> +               UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
> +
> +       /* disable master interrupt */
> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
> +               ~UVD_MASTINT_EN__VCPU_EN_MASK);
> +
> +       /* setup mmUVD_LMI_CTRL */
> +       tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
> +       tmp &= ~0xff;
> +       WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
> +               UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK |
> +               UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
> +               UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
> +               UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
> +
> +       /* setup mmUVD_MPC_CNTL */
> +       tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
> +       tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
> +       tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
> +       WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
> +
> +       /* setup UVD_MPC_SET_MUXA0 */
> +       WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
> +               ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
> +               (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
> +               (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
> +               (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
> +
> +       /* setup UVD_MPC_SET_MUXB0 */
> +       WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
> +               ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
> +               (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
> +               (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
> +               (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
> +
> +       /* setup mmUVD_MPC_SET_MUX */
> +       WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
> +               ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
> +               (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
> +               (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>
>         vcn_v2_5_mc_resume(adev);
>
> -       for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> -               volatile struct amdgpu_fw_shared *fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
> -               if (adev->vcn.harvest_config & (1 << i))
> -                       continue;
> -               /* VCN global tiling registers */
> -               WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
> -                       adev->gfx.config.gb_addr_config);
> -               WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
> -                       adev->gfx.config.gb_addr_config);
> +       volatile struct amdgpu_fw_shared *fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
> +       if (adev->vcn.harvest_config & (1 << inst))
> +               return 0;
> +
> +       /* VCN global tiling registers */
> +       WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
> +               adev->gfx.config.gb_addr_config);
> +       WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
> +               adev->gfx.config.gb_addr_config);
>
> -               /* enable LMI MC and UMC channels */
> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
> -                       ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
> +       /* enable LMI MC and UMC channels */
> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
> +               ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>
> -               /* unblock VCPU register access */
> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
> -                       ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
> +       /* unblock VCPU register access */
> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
> +               ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>
> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
> -                       ~UVD_VCPU_CNTL__BLK_RST_MASK);
> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
> +               ~UVD_VCPU_CNTL__BLK_RST_MASK);
>
> -               for (k = 0; k < 10; ++k) {
> -                       uint32_t status;
> -
> -                       for (j = 0; j < 100; ++j) {
> -                               status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
> -                               if (status & 2)
> -                                       break;
> -                               if (amdgpu_emu_mode == 1)
> -                                       msleep(500);
> -                               else
> -                                       mdelay(10);
> -                       }
> -                       r = 0;
> +       for (k = 0; k < 10; ++k) {
> +               uint32_t status;
> +
> +               for (j = 0; j < 100; ++j) {
> +                       status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
>                         if (status & 2)
>                                 break;
> +                       if (amdgpu_emu_mode == 1)
> +                               msleep(500);
> +                       else
> +                               mdelay(10);
> +               }
> +               r = 0;
> +               if (status & 2)
> +                       break;
>
> -                       DRM_ERROR("VCN decode not responding, trying to reset the VCPU!!!\n");
> -                       WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
> -                               UVD_VCPU_CNTL__BLK_RST_MASK,
> -                               ~UVD_VCPU_CNTL__BLK_RST_MASK);
> -                       mdelay(10);
> -                       WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
> -                               ~UVD_VCPU_CNTL__BLK_RST_MASK);
> +               DRM_ERROR("VCN decode not responding, trying to reset the VCPU!!!\n");
> +               WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
> +                       UVD_VCPU_CNTL__BLK_RST_MASK,
> +                       ~UVD_VCPU_CNTL__BLK_RST_MASK);
> +               mdelay(10);
> +               WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
> +                       ~UVD_VCPU_CNTL__BLK_RST_MASK);
>
> -                       mdelay(10);
> -                       r = -1;
> -               }
> +               mdelay(10);
> +               r = -1;
> +       }
>
> -               if (r) {
> -                       DRM_ERROR("VCN decode not responding, giving up!!!\n");
> -                       return r;
> -               }
> +       if (r) {
> +               DRM_ERROR("VCN decode not responding, giving up!!!\n");
> +               return r;
> +       }
>
> -               /* enable master interrupt */
> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
> -                       UVD_MASTINT_EN__VCPU_EN_MASK,
> -                       ~UVD_MASTINT_EN__VCPU_EN_MASK);
> +       /* enable master interrupt */
> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
> +               UVD_MASTINT_EN__VCPU_EN_MASK,
> +               ~UVD_MASTINT_EN__VCPU_EN_MASK);
>
> -               /* clear the busy bit of VCN_STATUS */
> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
> -                       ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
> +       /* clear the busy bit of VCN_STATUS */
> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
> +               ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>
> -               WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
> +       WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
>
> -               ring = &adev->vcn.inst[i].ring_dec;
> -               /* force RBC into idle state */
> -               rb_bufsz = order_base_2(ring->ring_size);
> -               tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
> -               tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
> -               tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
> -               tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
> -               tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
> -               WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
> +       ring = &adev->vcn.inst[inst].ring_dec;
> +       /* force RBC into idle state */
> +       rb_bufsz = order_base_2(ring->ring_size);
> +       tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
> +       tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
> +       tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
> +       tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
> +       tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
> +       WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
>
> -               fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
> -               /* program the RB_BASE for ring buffer */
> -               WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
> -                       lower_32_bits(ring->gpu_addr));
> -               WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
> -                       upper_32_bits(ring->gpu_addr));
> +       fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
> +       /* program the RB_BASE for ring buffer */
> +       WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
> +               lower_32_bits(ring->gpu_addr));
> +       WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
> +               upper_32_bits(ring->gpu_addr));
>
> -               /* Initialize the ring buffer's read and write pointers */
> -               WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
> +       /* Initialize the ring buffer's read and write pointers */
> +       WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
>
> -               ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
> -               WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
> -                               lower_32_bits(ring->wptr));
> -               fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
> +       ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
> +       WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
> +                       lower_32_bits(ring->wptr));
> +       fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
>
> -               fw_shared->multi_queue.encode_generalpurpose_queue_mode |= FW_QUEUE_RING_RESET;
> -               ring = &adev->vcn.inst[i].ring_enc[0];
> -               WREG32_SOC15(VCN, i, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
> -               WREG32_SOC15(VCN, i, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
> -               WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
> -               WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
> -               WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
> -               fw_shared->multi_queue.encode_generalpurpose_queue_mode &= ~FW_QUEUE_RING_RESET;
> -
> -               fw_shared->multi_queue.encode_lowlatency_queue_mode |= FW_QUEUE_RING_RESET;
> -               ring = &adev->vcn.inst[i].ring_enc[1];
> -               WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
> -               WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
> -               WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
> -               WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
> -               WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4);
> -               fw_shared->multi_queue.encode_lowlatency_queue_mode &= ~FW_QUEUE_RING_RESET;
> -       }
> +       fw_shared->multi_queue.encode_generalpurpose_queue_mode |= FW_QUEUE_RING_RESET;
> +       ring = &adev->vcn.inst[inst].ring_enc[0];
> +       WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
> +       WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
> +       WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
> +       WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
> +       WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
> +       fw_shared->multi_queue.encode_generalpurpose_queue_mode &= ~FW_QUEUE_RING_RESET;
> +
> +       fw_shared->multi_queue.encode_lowlatency_queue_mode |= FW_QUEUE_RING_RESET;
> +       ring = &adev->vcn.inst[inst].ring_enc[1];
> +       WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
> +       WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
> +       WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
> +       WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
> +       WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
> +       fw_shared->multi_queue.encode_lowlatency_queue_mode &= ~FW_QUEUE_RING_RESET;
>
>         return 0;
>  }
> @@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
>         return 0;
>  }
>
> -static int vcn_v2_5_stop(struct amdgpu_device *adev)
> +static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned int inst)
>  {
>         uint32_t tmp;
> -       int i, r = 0;
> +       int r = 0;
>
> -       for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> -               if (adev->vcn.harvest_config & (1 << i))
> -                       continue;
> -               if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> -                       r = vcn_v2_5_stop_dpg_mode(adev, i);
> -                       continue;
> -               }
> +       if (adev->vcn.harvest_config & (1 << inst))
> +               goto done;
>
> -               /* wait for vcn idle */
> -               r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS, UVD_STATUS__IDLE, 0x7);
> -               if (r)
> -                       return r;
> +       if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> +               r = vcn_v2_5_stop_dpg_mode(adev, inst);
> +               goto done;
> +       }
>
> -               tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
> -                       UVD_LMI_STATUS__READ_CLEAN_MASK |
> -                       UVD_LMI_STATUS__WRITE_CLEAN_MASK |
> -                       UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
> -               r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
> -               if (r)
> -                       return r;
> +       /* wait for vcn idle */
> +       r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS, UVD_STATUS__IDLE, 0x7);
> +       if (r)
> +               return r;
>
> -               /* block LMI UMC channel */
> -               tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
> -               tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
> -               WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
> +       tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
> +               UVD_LMI_STATUS__READ_CLEAN_MASK |
> +               UVD_LMI_STATUS__WRITE_CLEAN_MASK |
> +               UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
> +       r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
> +       if (r)
> +               return r;
>
> -               tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
> -                       UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
> -               r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
> -               if (r)
> -                       return r;
> +       /* block LMI UMC channel */
> +       tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
> +       tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
> +       WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
>
> -               /* block VCPU register access */
> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
> -                       UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
> -                       ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
> +       tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
> +               UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
> +       r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
> +       if (r)
> +               return r;
>
> -               /* reset VCPU */
> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
> -                       UVD_VCPU_CNTL__BLK_RST_MASK,
> -                       ~UVD_VCPU_CNTL__BLK_RST_MASK);
> +       /* block VCPU register access */
> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
> +               UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
> +               ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>
> -               /* disable VCPU clock */
> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
> -                       ~(UVD_VCPU_CNTL__CLK_EN_MASK));
> +       /* reset VCPU */
> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
> +               UVD_VCPU_CNTL__BLK_RST_MASK,
> +               ~UVD_VCPU_CNTL__BLK_RST_MASK);
>
> -               /* clear status */
> -               WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
> +       /* disable VCPU clock */
> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
> +               ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>
> -               vcn_v2_5_enable_clock_gating(adev);
> +       /* clear status */
> +       WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
>
> -               /* enable register anti-hang mechanism */
> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
> -                       UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
> -                       ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> -       }
> +       vcn_v2_5_enable_clock_gating(adev);
>
> -       for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> -               if (adev->pm.dpm_enabled)
> -                       amdgpu_dpm_enable_vcn(adev, false, i);
> -       }
> +       /* enable register anti-hang mechanism */
> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
> +               UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
> +               ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> +done:
> +       if (adev->pm.dpm_enabled)
> +               amdgpu_dpm_enable_vcn(adev, false, inst);
>
>         return 0;
>  }
> @@ -1838,9 +1827,9 @@ static int vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
>                 return 0;
>
>         if (state == AMD_PG_STATE_GATE)
> -               ret = vcn_v2_5_stop(adev);
> +               ret = vcn_v2_5_stop(adev, inst);
>         else
> -               ret = vcn_v2_5_start(adev);
> +               ret = vcn_v2_5_start(adev, inst);
>
>         if (!ret)
>                 adev->vcn.cur_state[inst] = state;
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-04 18:44 ` [PATCH 11/18] drm/amdgpu: power vcn 2_5 " boyuan.zhang
  2024-10-04 19:52   ` Alex Deucher
@ 2024-10-07  5:22   ` Lazar, Lijo
  2024-10-07 13:33     ` Boyuan Zhang
  1 sibling, 1 reply; 37+ messages in thread
From: Lazar, Lijo @ 2024-10-07  5:22 UTC (permalink / raw)
  To: boyuan.zhang, amd-gfx, leo.liu, christian.koenig,
	alexander.deucher, sunil.khatri



On 10/5/2024 12:14 AM, boyuan.zhang@amd.com wrote:
> From: Boyuan Zhang <boyuan.zhang@amd.com>
> 
> For vcn 2_5, add ip_block for each vcn instance during discovery stage.
> 
> And only powering on/off one of the vcn instance using the
> instance value stored in ip_block, instead of powering on/off all
> vcn instances. Modify the existing functions to use the instance value
> in ip_block, and remove the original for loop for all vcn instances.
> 
> v2: rename "i"/"j" to "inst" for instance value.
> 
> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
>  drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565 +++++++++---------
>  2 files changed, 280 insertions(+), 289 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
> index 9f9a1867da72..de1053cc2a2b 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
> @@ -2278,6 +2278,7 @@ static int amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
>  
>  static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>  {
> +	int i;
>  	if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
>  		switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
>  		case IP_VERSION(7, 0, 0):
> @@ -2321,7 +2322,8 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>  		case IP_VERSION(2, 0, 3):
>  			break;
>  		case IP_VERSION(2, 5, 0):
> -			amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
> +			for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
> +				amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);


This introduces a totally confusing design now. At a higher level an IP
block type manages multiple instances and their power states. Now there
is a mix where no definition can be attributed to an IP block. Or, if
this were to be done uniformly for other IPs, then for some SOCs there
could be 16 SDMA blocks, 8 GFX blocks and so forth.

What is the reason to do this way? Can't VCN IP block maintain the state
of multiple instances within itself?

Thanks,
Lijo

>  			amdgpu_device_ip_block_add(adev, &jpeg_v2_5_ip_block);
>  			break;
>  		case IP_VERSION(2, 6, 0):
> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
> index d00df51bc400..1f8738ae360a 100644
> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
> @@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct amdgpu_ip_block *ip_block)
>  static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>  {
>  	struct amdgpu_ring *ring;
> -	int i, j, r;
> +	int i, r;
>  	uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
>  	uint32_t *ptr;
>  	struct amdgpu_device *adev = ip_block->adev;
> +	int inst = ip_block->instance;
>  
> -	for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
> -		if (adev->vcn.harvest_config & (1 << j))
> -			continue;
> -		/* VCN DEC TRAP */
> -		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
> -				VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->vcn.inst[j].irq);
> -		if (r)
> -			return r;
> -
> -		/* VCN ENC TRAP */
> -		for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> -			r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
> -				i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[j].irq);
> -			if (r)
> -				return r;
> -		}
> +	if (adev->vcn.harvest_config & (1 << inst))
> +		goto sw_init;
> +	/* VCN DEC TRAP */
> +	r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
> +			VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->vcn.inst[inst].irq);
> +	if (r)
> +		return r;
>  
> -		/* VCN POISON TRAP */
> -		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
> -			VCN_2_6__SRCID_UVD_POISON, &adev->vcn.inst[j].ras_poison_irq);
> +	/* VCN ENC TRAP */
> +	for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> +		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
> +			i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[inst].irq);
>  		if (r)
>  			return r;
>  	}
>  
> +	/* VCN POISON TRAP */
> +	r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
> +		VCN_2_6__SRCID_UVD_POISON, &adev->vcn.inst[inst].ras_poison_irq);
> +	if (r)
> +		return r;
> +sw_init:
>  	r = amdgpu_vcn_sw_init(adev);
>  	if (r)
>  		return r;
> @@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>  	if (r)
>  		return r;
>  
> -	for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
> -		volatile struct amdgpu_fw_shared *fw_shared;
> +	volatile struct amdgpu_fw_shared *fw_shared;
>  
> -		if (adev->vcn.harvest_config & (1 << j))
> -			continue;
> -		adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
> -		adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
> -		adev->vcn.internal.ib_bar_low = mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
> -		adev->vcn.internal.ib_bar_high = mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
> -		adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
> -		adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
> -
> -		adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
> -		adev->vcn.inst[j].external.scratch9 = SOC15_REG_OFFSET(VCN, j, mmUVD_SCRATCH9);
> -		adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
> -		adev->vcn.inst[j].external.data0 = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_DATA0);
> -		adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
> -		adev->vcn.inst[j].external.data1 = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_DATA1);
> -		adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
> -		adev->vcn.inst[j].external.cmd = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_CMD);
> -		adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
> -		adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(VCN, j, mmUVD_NO_OP);
> -
> -		ring = &adev->vcn.inst[j].ring_dec;
> +	if (adev->vcn.harvest_config & (1 << inst))
> +		goto done;
> +	adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
> +	adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
> +	adev->vcn.internal.ib_bar_low = mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
> +	adev->vcn.internal.ib_bar_high = mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
> +	adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
> +	adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
> +
> +	adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
> +	adev->vcn.inst[inst].external.scratch9 = SOC15_REG_OFFSET(VCN, inst, mmUVD_SCRATCH9);
> +	adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
> +	adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_DATA0);
> +	adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
> +	adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_DATA1);
> +	adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
> +	adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_CMD);
> +	adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
> +	adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN, inst, mmUVD_NO_OP);
> +
> +	ring = &adev->vcn.inst[inst].ring_dec;
> +	ring->use_doorbell = true;
> +
> +	ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
> +			(amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
> +
> +	if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
> +		ring->vm_hub = AMDGPU_MMHUB1(0);
> +	else
> +		ring->vm_hub = AMDGPU_MMHUB0(0);
> +
> +	sprintf(ring->name, "vcn_dec_%d", inst);
> +	r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq,
> +				 0, AMDGPU_RING_PRIO_DEFAULT, NULL);
> +	if (r)
> +		return r;
> +
> +	for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> +		enum amdgpu_ring_priority_level hw_prio = amdgpu_vcn_get_enc_ring_prio(i);
> +
> +		ring = &adev->vcn.inst[inst].ring_enc[i];
>  		ring->use_doorbell = true;
>  
>  		ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
> -				(amdgpu_sriov_vf(adev) ? 2*j : 8*j);
> +				(amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2 + i + 8*inst));
>  
> -		if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
> +		if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
> +			IP_VERSION(2, 5, 0))
>  			ring->vm_hub = AMDGPU_MMHUB1(0);
>  		else
>  			ring->vm_hub = AMDGPU_MMHUB0(0);
>  
> -		sprintf(ring->name, "vcn_dec_%d", j);
> -		r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq,
> -				     0, AMDGPU_RING_PRIO_DEFAULT, NULL);
> +		sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
> +		r = amdgpu_ring_init(adev, ring, 512,
> +					 &adev->vcn.inst[inst].irq, 0,
> +					 hw_prio, NULL);
>  		if (r)
>  			return r;
> -
> -		for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> -			enum amdgpu_ring_priority_level hw_prio = amdgpu_vcn_get_enc_ring_prio(i);
> -
> -			ring = &adev->vcn.inst[j].ring_enc[i];
> -			ring->use_doorbell = true;
> -
> -			ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
> -					(amdgpu_sriov_vf(adev) ? (1 + i + 2*j) : (2 + i + 8*j));
> -
> -			if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
> -			    IP_VERSION(2, 5, 0))
> -				ring->vm_hub = AMDGPU_MMHUB1(0);
> -			else
> -				ring->vm_hub = AMDGPU_MMHUB0(0);
> -
> -			sprintf(ring->name, "vcn_enc_%d.%d", j, i);
> -			r = amdgpu_ring_init(adev, ring, 512,
> -					     &adev->vcn.inst[j].irq, 0,
> -					     hw_prio, NULL);
> -			if (r)
> -				return r;
> -		}
> -
> -		fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
> -		fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
> -
> -		if (amdgpu_vcnfw_log)
> -			amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>  	}
>  
> +	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
> +	fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
> +
> +	if (amdgpu_vcnfw_log)
> +		amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
> +done:
>  	if (amdgpu_sriov_vf(adev)) {
>  		r = amdgpu_virt_alloc_mm_table(adev);
>  		if (r)
> @@ -1005,197 +1002,192 @@ static int vcn_v2_5_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, boo
>  	return 0;
>  }
>  
> -static int vcn_v2_5_start(struct amdgpu_device *adev)
> +static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned int inst)
>  {
>  	struct amdgpu_ring *ring;
>  	uint32_t rb_bufsz, tmp;
> -	int i, j, k, r;
> +	int j, k, r;
>  
> -	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> -		if (adev->pm.dpm_enabled)
> -			amdgpu_dpm_enable_vcn(adev, true, i);
> -	}
> -
> -	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> -		if (adev->vcn.harvest_config & (1 << i))
> -			continue;
> -		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> -			r = vcn_v2_5_start_dpg_mode(adev, i, adev->vcn.indirect_sram);
> -			continue;
> -		}
> +	if (adev->pm.dpm_enabled)
> +		amdgpu_dpm_enable_vcn(adev, true, inst);
>  
> -		/* disable register anti-hang mechanism */
> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS), 0,
> -			~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> +	if (adev->vcn.harvest_config & (1 << inst))
> +		return 0;
>  
> -		/* set uvd status busy */
> -		tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
> -		WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
> +	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> +		r = vcn_v2_5_start_dpg_mode(adev, inst, adev->vcn.indirect_sram);
> +		return r;
>  	}
>  
> +	/* disable register anti-hang mechanism */
> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS), 0,
> +		~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> +
> +	/* set uvd status busy */
> +	tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
> +	WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
> +
>  	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
>  		return 0;
>  
>  	/*SW clock gating */
>  	vcn_v2_5_disable_clock_gating(adev);
>  
> -	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> -		if (adev->vcn.harvest_config & (1 << i))
> -			continue;
> -		/* enable VCPU clock */
> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
> -			UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
> -
> -		/* disable master interrupt */
> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
> -			~UVD_MASTINT_EN__VCPU_EN_MASK);
> -
> -		/* setup mmUVD_LMI_CTRL */
> -		tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
> -		tmp &= ~0xff;
> -		WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
> -			UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK	|
> -			UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
> -			UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
> -			UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
> -
> -		/* setup mmUVD_MPC_CNTL */
> -		tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
> -		tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
> -		tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
> -		WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
> -
> -		/* setup UVD_MPC_SET_MUXA0 */
> -		WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
> -			((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
> -			(0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
> -			(0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
> -			(0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
> -
> -		/* setup UVD_MPC_SET_MUXB0 */
> -		WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
> -			((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
> -			(0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
> -			(0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
> -			(0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
> -
> -		/* setup mmUVD_MPC_SET_MUX */
> -		WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
> -			((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
> -			(0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
> -			(0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
> -	}
> +	if (adev->vcn.harvest_config & (1 << inst))
> +		return 0;
> +
> +	/* enable VCPU clock */
> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
> +		UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
> +
> +	/* disable master interrupt */
> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
> +		~UVD_MASTINT_EN__VCPU_EN_MASK);
> +
> +	/* setup mmUVD_LMI_CTRL */
> +	tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
> +	tmp &= ~0xff;
> +	WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
> +		UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK	|
> +		UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
> +		UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
> +		UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
> +
> +	/* setup mmUVD_MPC_CNTL */
> +	tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
> +	tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
> +	tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
> +	WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
> +
> +	/* setup UVD_MPC_SET_MUXA0 */
> +	WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
> +		((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
> +		(0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
> +		(0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
> +		(0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
> +
> +	/* setup UVD_MPC_SET_MUXB0 */
> +	WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
> +		((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
> +		(0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
> +		(0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
> +		(0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
> +
> +	/* setup mmUVD_MPC_SET_MUX */
> +	WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
> +		((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
> +		(0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
> +		(0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>  
>  	vcn_v2_5_mc_resume(adev);
>  
> -	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> -		volatile struct amdgpu_fw_shared *fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
> -		if (adev->vcn.harvest_config & (1 << i))
> -			continue;
> -		/* VCN global tiling registers */
> -		WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
> -			adev->gfx.config.gb_addr_config);
> -		WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
> -			adev->gfx.config.gb_addr_config);
> +	volatile struct amdgpu_fw_shared *fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
> +	if (adev->vcn.harvest_config & (1 << inst))
> +		return 0;
> +
> +	/* VCN global tiling registers */
> +	WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
> +		adev->gfx.config.gb_addr_config);
> +	WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
> +		adev->gfx.config.gb_addr_config);
>  
> -		/* enable LMI MC and UMC channels */
> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
> -			~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
> +	/* enable LMI MC and UMC channels */
> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
> +		~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>  
> -		/* unblock VCPU register access */
> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
> -			~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
> +	/* unblock VCPU register access */
> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
> +		~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>  
> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
> -			~UVD_VCPU_CNTL__BLK_RST_MASK);
> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
> +		~UVD_VCPU_CNTL__BLK_RST_MASK);
>  
> -		for (k = 0; k < 10; ++k) {
> -			uint32_t status;
> -
> -			for (j = 0; j < 100; ++j) {
> -				status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
> -				if (status & 2)
> -					break;
> -				if (amdgpu_emu_mode == 1)
> -					msleep(500);
> -				else
> -					mdelay(10);
> -			}
> -			r = 0;
> +	for (k = 0; k < 10; ++k) {
> +		uint32_t status;
> +
> +		for (j = 0; j < 100; ++j) {
> +			status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
>  			if (status & 2)
>  				break;
> +			if (amdgpu_emu_mode == 1)
> +				msleep(500);
> +			else
> +				mdelay(10);
> +		}
> +		r = 0;
> +		if (status & 2)
> +			break;
>  
> -			DRM_ERROR("VCN decode not responding, trying to reset the VCPU!!!\n");
> -			WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
> -				UVD_VCPU_CNTL__BLK_RST_MASK,
> -				~UVD_VCPU_CNTL__BLK_RST_MASK);
> -			mdelay(10);
> -			WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
> -				~UVD_VCPU_CNTL__BLK_RST_MASK);
> +		DRM_ERROR("VCN decode not responding, trying to reset the VCPU!!!\n");
> +		WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
> +			UVD_VCPU_CNTL__BLK_RST_MASK,
> +			~UVD_VCPU_CNTL__BLK_RST_MASK);
> +		mdelay(10);
> +		WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
> +			~UVD_VCPU_CNTL__BLK_RST_MASK);
>  
> -			mdelay(10);
> -			r = -1;
> -		}
> +		mdelay(10);
> +		r = -1;
> +	}
>  
> -		if (r) {
> -			DRM_ERROR("VCN decode not responding, giving up!!!\n");
> -			return r;
> -		}
> +	if (r) {
> +		DRM_ERROR("VCN decode not responding, giving up!!!\n");
> +		return r;
> +	}
>  
> -		/* enable master interrupt */
> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
> -			UVD_MASTINT_EN__VCPU_EN_MASK,
> -			~UVD_MASTINT_EN__VCPU_EN_MASK);
> +	/* enable master interrupt */
> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
> +		UVD_MASTINT_EN__VCPU_EN_MASK,
> +		~UVD_MASTINT_EN__VCPU_EN_MASK);
>  
> -		/* clear the busy bit of VCN_STATUS */
> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
> -			~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
> +	/* clear the busy bit of VCN_STATUS */
> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
> +		~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>  
> -		WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
> +	WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
>  
> -		ring = &adev->vcn.inst[i].ring_dec;
> -		/* force RBC into idle state */
> -		rb_bufsz = order_base_2(ring->ring_size);
> -		tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
> -		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
> -		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
> -		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
> -		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
> -		WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
> +	ring = &adev->vcn.inst[inst].ring_dec;
> +	/* force RBC into idle state */
> +	rb_bufsz = order_base_2(ring->ring_size);
> +	tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
> +	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
> +	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
> +	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
> +	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
> +	WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
>  
> -		fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
> -		/* program the RB_BASE for ring buffer */
> -		WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
> -			lower_32_bits(ring->gpu_addr));
> -		WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
> -			upper_32_bits(ring->gpu_addr));
> +	fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
> +	/* program the RB_BASE for ring buffer */
> +	WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
> +		lower_32_bits(ring->gpu_addr));
> +	WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
> +		upper_32_bits(ring->gpu_addr));
>  
> -		/* Initialize the ring buffer's read and write pointers */
> -		WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
> +	/* Initialize the ring buffer's read and write pointers */
> +	WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
>  
> -		ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
> -		WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
> -				lower_32_bits(ring->wptr));
> -		fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
> +	ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
> +	WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
> +			lower_32_bits(ring->wptr));
> +	fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
>  
> -		fw_shared->multi_queue.encode_generalpurpose_queue_mode |= FW_QUEUE_RING_RESET;
> -		ring = &adev->vcn.inst[i].ring_enc[0];
> -		WREG32_SOC15(VCN, i, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
> -		WREG32_SOC15(VCN, i, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
> -		WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
> -		WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
> -		WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
> -		fw_shared->multi_queue.encode_generalpurpose_queue_mode &= ~FW_QUEUE_RING_RESET;
> -
> -		fw_shared->multi_queue.encode_lowlatency_queue_mode |= FW_QUEUE_RING_RESET;
> -		ring = &adev->vcn.inst[i].ring_enc[1];
> -		WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
> -		WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
> -		WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
> -		WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
> -		WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4);
> -		fw_shared->multi_queue.encode_lowlatency_queue_mode &= ~FW_QUEUE_RING_RESET;
> -	}
> +	fw_shared->multi_queue.encode_generalpurpose_queue_mode |= FW_QUEUE_RING_RESET;
> +	ring = &adev->vcn.inst[inst].ring_enc[0];
> +	WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
> +	WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
> +	WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
> +	WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
> +	WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
> +	fw_shared->multi_queue.encode_generalpurpose_queue_mode &= ~FW_QUEUE_RING_RESET;
> +
> +	fw_shared->multi_queue.encode_lowlatency_queue_mode |= FW_QUEUE_RING_RESET;
> +	ring = &adev->vcn.inst[inst].ring_enc[1];
> +	WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
> +	WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
> +	WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
> +	WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
> +	WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
> +	fw_shared->multi_queue.encode_lowlatency_queue_mode &= ~FW_QUEUE_RING_RESET;
>  
>  	return 0;
>  }
> @@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
>  	return 0;
>  }
>  
> -static int vcn_v2_5_stop(struct amdgpu_device *adev)
> +static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned int inst)
>  {
>  	uint32_t tmp;
> -	int i, r = 0;
> +	int r = 0;
>  
> -	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> -		if (adev->vcn.harvest_config & (1 << i))
> -			continue;
> -		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> -			r = vcn_v2_5_stop_dpg_mode(adev, i);
> -			continue;
> -		}
> +	if (adev->vcn.harvest_config & (1 << inst))
> +		goto done;
>  
> -		/* wait for vcn idle */
> -		r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS, UVD_STATUS__IDLE, 0x7);
> -		if (r)
> -			return r;
> +	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> +		r = vcn_v2_5_stop_dpg_mode(adev, inst);
> +		goto done;
> +	}
>  
> -		tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
> -			UVD_LMI_STATUS__READ_CLEAN_MASK |
> -			UVD_LMI_STATUS__WRITE_CLEAN_MASK |
> -			UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
> -		r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
> -		if (r)
> -			return r;
> +	/* wait for vcn idle */
> +	r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS, UVD_STATUS__IDLE, 0x7);
> +	if (r)
> +		return r;
>  
> -		/* block LMI UMC channel */
> -		tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
> -		tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
> -		WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
> +	tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
> +		UVD_LMI_STATUS__READ_CLEAN_MASK |
> +		UVD_LMI_STATUS__WRITE_CLEAN_MASK |
> +		UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
> +	r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
> +	if (r)
> +		return r;
>  
> -		tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
> -			UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
> -		r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
> -		if (r)
> -			return r;
> +	/* block LMI UMC channel */
> +	tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
> +	tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
> +	WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
>  
> -		/* block VCPU register access */
> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
> -			UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
> -			~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
> +	tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
> +		UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
> +	r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
> +	if (r)
> +		return r;
>  
> -		/* reset VCPU */
> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
> -			UVD_VCPU_CNTL__BLK_RST_MASK,
> -			~UVD_VCPU_CNTL__BLK_RST_MASK);
> +	/* block VCPU register access */
> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
> +		UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
> +		~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>  
> -		/* disable VCPU clock */
> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
> -			~(UVD_VCPU_CNTL__CLK_EN_MASK));
> +	/* reset VCPU */
> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
> +		UVD_VCPU_CNTL__BLK_RST_MASK,
> +		~UVD_VCPU_CNTL__BLK_RST_MASK);
>  
> -		/* clear status */
> -		WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
> +	/* disable VCPU clock */
> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
> +		~(UVD_VCPU_CNTL__CLK_EN_MASK));
>  
> -		vcn_v2_5_enable_clock_gating(adev);
> +	/* clear status */
> +	WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
>  
> -		/* enable register anti-hang mechanism */
> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
> -			UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
> -			~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> -	}
> +	vcn_v2_5_enable_clock_gating(adev);
>  
> -	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> -		if (adev->pm.dpm_enabled)
> -			amdgpu_dpm_enable_vcn(adev, false, i);
> -	}
> +	/* enable register anti-hang mechanism */
> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
> +		UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
> +		~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> +done:
> +	if (adev->pm.dpm_enabled)
> +		amdgpu_dpm_enable_vcn(adev, false, inst);
>  
>  	return 0;
>  }
> @@ -1838,9 +1827,9 @@ static int vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
>  		return 0;
>  
>  	if (state == AMD_PG_STATE_GATE)
> -		ret = vcn_v2_5_stop(adev);
> +		ret = vcn_v2_5_stop(adev, inst);
>  	else
> -		ret = vcn_v2_5_start(adev);
> +		ret = vcn_v2_5_start(adev, inst);
>  
>  	if (!ret)
>  		adev->vcn.cur_state[inst] = state;

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-07  5:22   ` Lazar, Lijo
@ 2024-10-07 13:33     ` Boyuan Zhang
  2024-10-07 13:50       ` Lazar, Lijo
  0 siblings, 1 reply; 37+ messages in thread
From: Boyuan Zhang @ 2024-10-07 13:33 UTC (permalink / raw)
  To: Lazar, Lijo, amd-gfx, leo.liu, christian.koenig,
	alexander.deucher, sunil.khatri


On 2024-10-07 01:22, Lazar, Lijo wrote:
>
> On 10/5/2024 12:14 AM, boyuan.zhang@amd.com wrote:
>> From: Boyuan Zhang <boyuan.zhang@amd.com>
>>
>> For vcn 2_5, add ip_block for each vcn instance during discovery stage.
>>
>> And only powering on/off one of the vcn instance using the
>> instance value stored in ip_block, instead of powering on/off all
>> vcn instances. Modify the existing functions to use the instance value
>> in ip_block, and remove the original for loop for all vcn instances.
>>
>> v2: rename "i"/"j" to "inst" for instance value.
>>
>> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
>> ---
>>   drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
>>   drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565 +++++++++---------
>>   2 files changed, 280 insertions(+), 289 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>> index 9f9a1867da72..de1053cc2a2b 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>> @@ -2278,6 +2278,7 @@ static int amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
>>   
>>   static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>>   {
>> +	int i;
>>   	if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
>>   		switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
>>   		case IP_VERSION(7, 0, 0):
>> @@ -2321,7 +2322,8 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>>   		case IP_VERSION(2, 0, 3):
>>   			break;
>>   		case IP_VERSION(2, 5, 0):
>> -			amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>> +			for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
>> +				amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>
> This introduces a totally confusing design now. At a higher level an IP
> block type manages multiple instances and their power states. Now there
> is a mix where no definition can be attributed to an IP block. Or, if
> this were to be done uniformly for other IPs, then for some SOCs there
> could be 16 SDMA blocks, 8 GFX blocks and so forth.
>
> What is the reason to do this way? Can't VCN IP block maintain the state
> of multiple instances within itself?
>
> Thanks,
> Lijo
This is part of the fundamental design change for separating IP block 
per instance, in order to
handle each instance separately within same IP block (e.g. separate 
power/clock management).

Part 1, Change all adev ptr handle to amdgpu_ip_block ptr in all 
callbacks (hw_init/fini, sw_init/fini,
suspend, etc...) for all IP blocks, so that each IP knows which IP_block 
(and which instance) the
callback is for. Most parts of this changes have been submitted by Sunil.

Part 2, Separate IP block per instance.

Part 3, Since callbacks can pass in IP_block now after Part 1 change and 
instance value can be
obtained from each IP block in Part 2, IP can then choose to handle 
callbacks ONLY for the given
instance of a given IP block (or still handling for all instances as 
before).
For VCN, all callbacks will be handled only for the given one instance, 
instead of the original for-
loop for all instance. As a result, each VCN instance can be 
start/stop/int/fini/suspend separately.

Part 4, Change all VCN helper functions to handle only the given 
instance, instead of the original
for-loop for all instance.

Each instance can have its own states, so we think it makes more sense 
to separate them on IP
block level to handle each of them separately.

Thanks,
Boyuan
>
>>   			amdgpu_device_ip_block_add(adev, &jpeg_v2_5_ip_block);
>>   			break;
>>   		case IP_VERSION(2, 6, 0):
>> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>> index d00df51bc400..1f8738ae360a 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>> @@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct amdgpu_ip_block *ip_block)
>>   static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>>   {
>>   	struct amdgpu_ring *ring;
>> -	int i, j, r;
>> +	int i, r;
>>   	uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
>>   	uint32_t *ptr;
>>   	struct amdgpu_device *adev = ip_block->adev;
>> +	int inst = ip_block->instance;
>>   
>> -	for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>> -		if (adev->vcn.harvest_config & (1 << j))
>> -			continue;
>> -		/* VCN DEC TRAP */
>> -		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>> -				VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->vcn.inst[j].irq);
>> -		if (r)
>> -			return r;
>> -
>> -		/* VCN ENC TRAP */
>> -		for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>> -			r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>> -				i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[j].irq);
>> -			if (r)
>> -				return r;
>> -		}
>> +	if (adev->vcn.harvest_config & (1 << inst))
>> +		goto sw_init;
>> +	/* VCN DEC TRAP */
>> +	r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>> +			VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->vcn.inst[inst].irq);
>> +	if (r)
>> +		return r;
>>   
>> -		/* VCN POISON TRAP */
>> -		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>> -			VCN_2_6__SRCID_UVD_POISON, &adev->vcn.inst[j].ras_poison_irq);
>> +	/* VCN ENC TRAP */
>> +	for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>> +		r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>> +			i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[inst].irq);
>>   		if (r)
>>   			return r;
>>   	}
>>   
>> +	/* VCN POISON TRAP */
>> +	r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>> +		VCN_2_6__SRCID_UVD_POISON, &adev->vcn.inst[inst].ras_poison_irq);
>> +	if (r)
>> +		return r;
>> +sw_init:
>>   	r = amdgpu_vcn_sw_init(adev);
>>   	if (r)
>>   		return r;
>> @@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>>   	if (r)
>>   		return r;
>>   
>> -	for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>> -		volatile struct amdgpu_fw_shared *fw_shared;
>> +	volatile struct amdgpu_fw_shared *fw_shared;
>>   
>> -		if (adev->vcn.harvest_config & (1 << j))
>> -			continue;
>> -		adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>> -		adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>> -		adev->vcn.internal.ib_bar_low = mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>> -		adev->vcn.internal.ib_bar_high = mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>> -		adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>> -		adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>> -
>> -		adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>> -		adev->vcn.inst[j].external.scratch9 = SOC15_REG_OFFSET(VCN, j, mmUVD_SCRATCH9);
>> -		adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>> -		adev->vcn.inst[j].external.data0 = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_DATA0);
>> -		adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>> -		adev->vcn.inst[j].external.data1 = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_DATA1);
>> -		adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>> -		adev->vcn.inst[j].external.cmd = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_CMD);
>> -		adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>> -		adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(VCN, j, mmUVD_NO_OP);
>> -
>> -		ring = &adev->vcn.inst[j].ring_dec;
>> +	if (adev->vcn.harvest_config & (1 << inst))
>> +		goto done;
>> +	adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>> +	adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>> +	adev->vcn.internal.ib_bar_low = mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>> +	adev->vcn.internal.ib_bar_high = mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>> +	adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>> +	adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>> +
>> +	adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>> +	adev->vcn.inst[inst].external.scratch9 = SOC15_REG_OFFSET(VCN, inst, mmUVD_SCRATCH9);
>> +	adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>> +	adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_DATA0);
>> +	adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>> +	adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_DATA1);
>> +	adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>> +	adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_CMD);
>> +	adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>> +	adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN, inst, mmUVD_NO_OP);
>> +
>> +	ring = &adev->vcn.inst[inst].ring_dec;
>> +	ring->use_doorbell = true;
>> +
>> +	ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>> +			(amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
>> +
>> +	if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
>> +		ring->vm_hub = AMDGPU_MMHUB1(0);
>> +	else
>> +		ring->vm_hub = AMDGPU_MMHUB0(0);
>> +
>> +	sprintf(ring->name, "vcn_dec_%d", inst);
>> +	r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq,
>> +				 0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>> +	if (r)
>> +		return r;
>> +
>> +	for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>> +		enum amdgpu_ring_priority_level hw_prio = amdgpu_vcn_get_enc_ring_prio(i);
>> +
>> +		ring = &adev->vcn.inst[inst].ring_enc[i];
>>   		ring->use_doorbell = true;
>>   
>>   		ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>> -				(amdgpu_sriov_vf(adev) ? 2*j : 8*j);
>> +				(amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2 + i + 8*inst));
>>   
>> -		if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
>> +		if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>> +			IP_VERSION(2, 5, 0))
>>   			ring->vm_hub = AMDGPU_MMHUB1(0);
>>   		else
>>   			ring->vm_hub = AMDGPU_MMHUB0(0);
>>   
>> -		sprintf(ring->name, "vcn_dec_%d", j);
>> -		r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq,
>> -				     0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>> +		sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
>> +		r = amdgpu_ring_init(adev, ring, 512,
>> +					 &adev->vcn.inst[inst].irq, 0,
>> +					 hw_prio, NULL);
>>   		if (r)
>>   			return r;
>> -
>> -		for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>> -			enum amdgpu_ring_priority_level hw_prio = amdgpu_vcn_get_enc_ring_prio(i);
>> -
>> -			ring = &adev->vcn.inst[j].ring_enc[i];
>> -			ring->use_doorbell = true;
>> -
>> -			ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>> -					(amdgpu_sriov_vf(adev) ? (1 + i + 2*j) : (2 + i + 8*j));
>> -
>> -			if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>> -			    IP_VERSION(2, 5, 0))
>> -				ring->vm_hub = AMDGPU_MMHUB1(0);
>> -			else
>> -				ring->vm_hub = AMDGPU_MMHUB0(0);
>> -
>> -			sprintf(ring->name, "vcn_enc_%d.%d", j, i);
>> -			r = amdgpu_ring_init(adev, ring, 512,
>> -					     &adev->vcn.inst[j].irq, 0,
>> -					     hw_prio, NULL);
>> -			if (r)
>> -				return r;
>> -		}
>> -
>> -		fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
>> -		fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>> -
>> -		if (amdgpu_vcnfw_log)
>> -			amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>   	}
>>   
>> +	fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
>> +	fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>> +
>> +	if (amdgpu_vcnfw_log)
>> +		amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>> +done:
>>   	if (amdgpu_sriov_vf(adev)) {
>>   		r = amdgpu_virt_alloc_mm_table(adev);
>>   		if (r)
>> @@ -1005,197 +1002,192 @@ static int vcn_v2_5_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, boo
>>   	return 0;
>>   }
>>   
>> -static int vcn_v2_5_start(struct amdgpu_device *adev)
>> +static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned int inst)
>>   {
>>   	struct amdgpu_ring *ring;
>>   	uint32_t rb_bufsz, tmp;
>> -	int i, j, k, r;
>> +	int j, k, r;
>>   
>> -	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>> -		if (adev->pm.dpm_enabled)
>> -			amdgpu_dpm_enable_vcn(adev, true, i);
>> -	}
>> -
>> -	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>> -		if (adev->vcn.harvest_config & (1 << i))
>> -			continue;
>> -		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>> -			r = vcn_v2_5_start_dpg_mode(adev, i, adev->vcn.indirect_sram);
>> -			continue;
>> -		}
>> +	if (adev->pm.dpm_enabled)
>> +		amdgpu_dpm_enable_vcn(adev, true, inst);
>>   
>> -		/* disable register anti-hang mechanism */
>> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS), 0,
>> -			~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>> +	if (adev->vcn.harvest_config & (1 << inst))
>> +		return 0;
>>   
>> -		/* set uvd status busy */
>> -		tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
>> -		WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
>> +	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>> +		r = vcn_v2_5_start_dpg_mode(adev, inst, adev->vcn.indirect_sram);
>> +		return r;
>>   	}
>>   
>> +	/* disable register anti-hang mechanism */
>> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS), 0,
>> +		~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>> +
>> +	/* set uvd status busy */
>> +	tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
>> +	WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
>> +
>>   	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
>>   		return 0;
>>   
>>   	/*SW clock gating */
>>   	vcn_v2_5_disable_clock_gating(adev);
>>   
>> -	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>> -		if (adev->vcn.harvest_config & (1 << i))
>> -			continue;
>> -		/* enable VCPU clock */
>> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>> -			UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>> -
>> -		/* disable master interrupt */
>> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
>> -			~UVD_MASTINT_EN__VCPU_EN_MASK);
>> -
>> -		/* setup mmUVD_LMI_CTRL */
>> -		tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
>> -		tmp &= ~0xff;
>> -		WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
>> -			UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK	|
>> -			UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>> -			UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>> -			UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>> -
>> -		/* setup mmUVD_MPC_CNTL */
>> -		tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
>> -		tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>> -		tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>> -		WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
>> -
>> -		/* setup UVD_MPC_SET_MUXA0 */
>> -		WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
>> -			((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>> -			(0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>> -			(0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>> -			(0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>> -
>> -		/* setup UVD_MPC_SET_MUXB0 */
>> -		WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
>> -			((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>> -			(0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>> -			(0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>> -			(0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>> -
>> -		/* setup mmUVD_MPC_SET_MUX */
>> -		WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
>> -			((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>> -			(0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>> -			(0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>> -	}
>> +	if (adev->vcn.harvest_config & (1 << inst))
>> +		return 0;
>> +
>> +	/* enable VCPU clock */
>> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>> +		UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>> +
>> +	/* disable master interrupt */
>> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
>> +		~UVD_MASTINT_EN__VCPU_EN_MASK);
>> +
>> +	/* setup mmUVD_LMI_CTRL */
>> +	tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
>> +	tmp &= ~0xff;
>> +	WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
>> +		UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK	|
>> +		UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>> +		UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>> +		UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>> +
>> +	/* setup mmUVD_MPC_CNTL */
>> +	tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
>> +	tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>> +	tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>> +	WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
>> +
>> +	/* setup UVD_MPC_SET_MUXA0 */
>> +	WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
>> +		((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>> +		(0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>> +		(0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>> +		(0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>> +
>> +	/* setup UVD_MPC_SET_MUXB0 */
>> +	WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
>> +		((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>> +		(0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>> +		(0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>> +		(0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>> +
>> +	/* setup mmUVD_MPC_SET_MUX */
>> +	WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
>> +		((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>> +		(0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>> +		(0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>   
>>   	vcn_v2_5_mc_resume(adev);
>>   
>> -	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>> -		volatile struct amdgpu_fw_shared *fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
>> -		if (adev->vcn.harvest_config & (1 << i))
>> -			continue;
>> -		/* VCN global tiling registers */
>> -		WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>> -			adev->gfx.config.gb_addr_config);
>> -		WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>> -			adev->gfx.config.gb_addr_config);
>> +	volatile struct amdgpu_fw_shared *fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
>> +	if (adev->vcn.harvest_config & (1 << inst))
>> +		return 0;
>> +
>> +	/* VCN global tiling registers */
>> +	WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>> +		adev->gfx.config.gb_addr_config);
>> +	WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>> +		adev->gfx.config.gb_addr_config);
>>   
>> -		/* enable LMI MC and UMC channels */
>> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
>> -			~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>> +	/* enable LMI MC and UMC channels */
>> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
>> +		~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>   
>> -		/* unblock VCPU register access */
>> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
>> -			~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>> +	/* unblock VCPU register access */
>> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
>> +		~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>   
>> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>> -			~UVD_VCPU_CNTL__BLK_RST_MASK);
>> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>> +		~UVD_VCPU_CNTL__BLK_RST_MASK);
>>   
>> -		for (k = 0; k < 10; ++k) {
>> -			uint32_t status;
>> -
>> -			for (j = 0; j < 100; ++j) {
>> -				status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
>> -				if (status & 2)
>> -					break;
>> -				if (amdgpu_emu_mode == 1)
>> -					msleep(500);
>> -				else
>> -					mdelay(10);
>> -			}
>> -			r = 0;
>> +	for (k = 0; k < 10; ++k) {
>> +		uint32_t status;
>> +
>> +		for (j = 0; j < 100; ++j) {
>> +			status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
>>   			if (status & 2)
>>   				break;
>> +			if (amdgpu_emu_mode == 1)
>> +				msleep(500);
>> +			else
>> +				mdelay(10);
>> +		}
>> +		r = 0;
>> +		if (status & 2)
>> +			break;
>>   
>> -			DRM_ERROR("VCN decode not responding, trying to reset the VCPU!!!\n");
>> -			WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>> -				UVD_VCPU_CNTL__BLK_RST_MASK,
>> -				~UVD_VCPU_CNTL__BLK_RST_MASK);
>> -			mdelay(10);
>> -			WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>> -				~UVD_VCPU_CNTL__BLK_RST_MASK);
>> +		DRM_ERROR("VCN decode not responding, trying to reset the VCPU!!!\n");
>> +		WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>> +			UVD_VCPU_CNTL__BLK_RST_MASK,
>> +			~UVD_VCPU_CNTL__BLK_RST_MASK);
>> +		mdelay(10);
>> +		WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>> +			~UVD_VCPU_CNTL__BLK_RST_MASK);
>>   
>> -			mdelay(10);
>> -			r = -1;
>> -		}
>> +		mdelay(10);
>> +		r = -1;
>> +	}
>>   
>> -		if (r) {
>> -			DRM_ERROR("VCN decode not responding, giving up!!!\n");
>> -			return r;
>> -		}
>> +	if (r) {
>> +		DRM_ERROR("VCN decode not responding, giving up!!!\n");
>> +		return r;
>> +	}
>>   
>> -		/* enable master interrupt */
>> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
>> -			UVD_MASTINT_EN__VCPU_EN_MASK,
>> -			~UVD_MASTINT_EN__VCPU_EN_MASK);
>> +	/* enable master interrupt */
>> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
>> +		UVD_MASTINT_EN__VCPU_EN_MASK,
>> +		~UVD_MASTINT_EN__VCPU_EN_MASK);
>>   
>> -		/* clear the busy bit of VCN_STATUS */
>> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
>> -			~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>> +	/* clear the busy bit of VCN_STATUS */
>> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
>> +		~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>   
>> -		WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
>> +	WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
>>   
>> -		ring = &adev->vcn.inst[i].ring_dec;
>> -		/* force RBC into idle state */
>> -		rb_bufsz = order_base_2(ring->ring_size);
>> -		tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>> -		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>> -		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>> -		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>> -		tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>> -		WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
>> +	ring = &adev->vcn.inst[inst].ring_dec;
>> +	/* force RBC into idle state */
>> +	rb_bufsz = order_base_2(ring->ring_size);
>> +	tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>> +	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>> +	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>> +	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>> +	tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>> +	WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
>>   
>> -		fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
>> -		/* program the RB_BASE for ring buffer */
>> -		WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>> -			lower_32_bits(ring->gpu_addr));
>> -		WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>> -			upper_32_bits(ring->gpu_addr));
>> +	fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
>> +	/* program the RB_BASE for ring buffer */
>> +	WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>> +		lower_32_bits(ring->gpu_addr));
>> +	WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>> +		upper_32_bits(ring->gpu_addr));
>>   
>> -		/* Initialize the ring buffer's read and write pointers */
>> -		WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
>> +	/* Initialize the ring buffer's read and write pointers */
>> +	WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
>>   
>> -		ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
>> -		WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
>> -				lower_32_bits(ring->wptr));
>> -		fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
>> +	ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
>> +	WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
>> +			lower_32_bits(ring->wptr));
>> +	fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
>>   
>> -		fw_shared->multi_queue.encode_generalpurpose_queue_mode |= FW_QUEUE_RING_RESET;
>> -		ring = &adev->vcn.inst[i].ring_enc[0];
>> -		WREG32_SOC15(VCN, i, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
>> -		WREG32_SOC15(VCN, i, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
>> -		WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
>> -		WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
>> -		WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
>> -		fw_shared->multi_queue.encode_generalpurpose_queue_mode &= ~FW_QUEUE_RING_RESET;
>> -
>> -		fw_shared->multi_queue.encode_lowlatency_queue_mode |= FW_QUEUE_RING_RESET;
>> -		ring = &adev->vcn.inst[i].ring_enc[1];
>> -		WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
>> -		WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
>> -		WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>> -		WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
>> -		WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4);
>> -		fw_shared->multi_queue.encode_lowlatency_queue_mode &= ~FW_QUEUE_RING_RESET;
>> -	}
>> +	fw_shared->multi_queue.encode_generalpurpose_queue_mode |= FW_QUEUE_RING_RESET;
>> +	ring = &adev->vcn.inst[inst].ring_enc[0];
>> +	WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
>> +	WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
>> +	WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
>> +	WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
>> +	WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
>> +	fw_shared->multi_queue.encode_generalpurpose_queue_mode &= ~FW_QUEUE_RING_RESET;
>> +
>> +	fw_shared->multi_queue.encode_lowlatency_queue_mode |= FW_QUEUE_RING_RESET;
>> +	ring = &adev->vcn.inst[inst].ring_enc[1];
>> +	WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
>> +	WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
>> +	WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>> +	WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
>> +	WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
>> +	fw_shared->multi_queue.encode_lowlatency_queue_mode &= ~FW_QUEUE_RING_RESET;
>>   
>>   	return 0;
>>   }
>> @@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
>>   	return 0;
>>   }
>>   
>> -static int vcn_v2_5_stop(struct amdgpu_device *adev)
>> +static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned int inst)
>>   {
>>   	uint32_t tmp;
>> -	int i, r = 0;
>> +	int r = 0;
>>   
>> -	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>> -		if (adev->vcn.harvest_config & (1 << i))
>> -			continue;
>> -		if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>> -			r = vcn_v2_5_stop_dpg_mode(adev, i);
>> -			continue;
>> -		}
>> +	if (adev->vcn.harvest_config & (1 << inst))
>> +		goto done;
>>   
>> -		/* wait for vcn idle */
>> -		r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS, UVD_STATUS__IDLE, 0x7);
>> -		if (r)
>> -			return r;
>> +	if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>> +		r = vcn_v2_5_stop_dpg_mode(adev, inst);
>> +		goto done;
>> +	}
>>   
>> -		tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>> -			UVD_LMI_STATUS__READ_CLEAN_MASK |
>> -			UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>> -			UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>> -		r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
>> -		if (r)
>> -			return r;
>> +	/* wait for vcn idle */
>> +	r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS, UVD_STATUS__IDLE, 0x7);
>> +	if (r)
>> +		return r;
>>   
>> -		/* block LMI UMC channel */
>> -		tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
>> -		tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>> -		WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
>> +	tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>> +		UVD_LMI_STATUS__READ_CLEAN_MASK |
>> +		UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>> +		UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>> +	r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
>> +	if (r)
>> +		return r;
>>   
>> -		tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>> -			UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>> -		r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
>> -		if (r)
>> -			return r;
>> +	/* block LMI UMC channel */
>> +	tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
>> +	tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>> +	WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
>>   
>> -		/* block VCPU register access */
>> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
>> -			UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>> -			~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>> +	tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>> +		UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>> +	r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
>> +	if (r)
>> +		return r;
>>   
>> -		/* reset VCPU */
>> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>> -			UVD_VCPU_CNTL__BLK_RST_MASK,
>> -			~UVD_VCPU_CNTL__BLK_RST_MASK);
>> +	/* block VCPU register access */
>> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
>> +		UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>> +		~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>   
>> -		/* disable VCPU clock */
>> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>> -			~(UVD_VCPU_CNTL__CLK_EN_MASK));
>> +	/* reset VCPU */
>> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>> +		UVD_VCPU_CNTL__BLK_RST_MASK,
>> +		~UVD_VCPU_CNTL__BLK_RST_MASK);
>>   
>> -		/* clear status */
>> -		WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
>> +	/* disable VCPU clock */
>> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>> +		~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>   
>> -		vcn_v2_5_enable_clock_gating(adev);
>> +	/* clear status */
>> +	WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
>>   
>> -		/* enable register anti-hang mechanism */
>> -		WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
>> -			UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>> -			~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>> -	}
>> +	vcn_v2_5_enable_clock_gating(adev);
>>   
>> -	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>> -		if (adev->pm.dpm_enabled)
>> -			amdgpu_dpm_enable_vcn(adev, false, i);
>> -	}
>> +	/* enable register anti-hang mechanism */
>> +	WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
>> +		UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>> +		~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>> +done:
>> +	if (adev->pm.dpm_enabled)
>> +		amdgpu_dpm_enable_vcn(adev, false, inst);
>>   
>>   	return 0;
>>   }
>> @@ -1838,9 +1827,9 @@ static int vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
>>   		return 0;
>>   
>>   	if (state == AMD_PG_STATE_GATE)
>> -		ret = vcn_v2_5_stop(adev);
>> +		ret = vcn_v2_5_stop(adev, inst);
>>   	else
>> -		ret = vcn_v2_5_start(adev);
>> +		ret = vcn_v2_5_start(adev, inst);
>>   
>>   	if (!ret)
>>   		adev->vcn.cur_state[inst] = state;

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-07 13:33     ` Boyuan Zhang
@ 2024-10-07 13:50       ` Lazar, Lijo
  2024-10-07 14:17         ` Alex Deucher
  0 siblings, 1 reply; 37+ messages in thread
From: Lazar, Lijo @ 2024-10-07 13:50 UTC (permalink / raw)
  To: Boyuan Zhang, amd-gfx, leo.liu, christian.koenig,
	alexander.deucher, sunil.khatri



On 10/7/2024 7:03 PM, Boyuan Zhang wrote:
> 
> On 2024-10-07 01:22, Lazar, Lijo wrote:
>>
>> On 10/5/2024 12:14 AM, boyuan.zhang@amd.com wrote:
>>> From: Boyuan Zhang <boyuan.zhang@amd.com>
>>>
>>> For vcn 2_5, add ip_block for each vcn instance during discovery stage.
>>>
>>> And only powering on/off one of the vcn instance using the
>>> instance value stored in ip_block, instead of powering on/off all
>>> vcn instances. Modify the existing functions to use the instance value
>>> in ip_block, and remove the original for loop for all vcn instances.
>>>
>>> v2: rename "i"/"j" to "inst" for instance value.
>>>
>>> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
>>> ---
>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
>>>   drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565 +++++++++---------
>>>   2 files changed, 280 insertions(+), 289 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>> index 9f9a1867da72..de1053cc2a2b 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>> @@ -2278,6 +2278,7 @@ static int
>>> amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
>>>     static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device
>>> *adev)
>>>   {
>>> +    int i;
>>>       if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
>>>           switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
>>>           case IP_VERSION(7, 0, 0):
>>> @@ -2321,7 +2322,8 @@ static int
>>> amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>>>           case IP_VERSION(2, 0, 3):
>>>               break;
>>>           case IP_VERSION(2, 5, 0):
>>> -            amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>>> +            for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
>>> +                amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>>
>> This introduces a totally confusing design now. At a higher level an IP
>> block type manages multiple instances and their power states. Now there
>> is a mix where no definition can be attributed to an IP block. Or, if
>> this were to be done uniformly for other IPs, then for some SOCs there
>> could be 16 SDMA blocks, 8 GFX blocks and so forth.
>>
>> What is the reason to do this way? Can't VCN IP block maintain the state
>> of multiple instances within itself?
>>
>> Thanks,
>> Lijo
> This is part of the fundamental design change for separating IP block
> per instance, in order to
> handle each instance separately within same IP block (e.g. separate
> power/clock management).
> 
> Part 1, Change all adev ptr handle to amdgpu_ip_block ptr in all
> callbacks (hw_init/fini, sw_init/fini,
> suspend, etc...) for all IP blocks, so that each IP knows which IP_block
> (and which instance) the
> callback is for. Most parts of this changes have been submitted by Sunil.
> 
> Part 2, Separate IP block per instance.
> 
> Part 3, Since callbacks can pass in IP_block now after Part 1 change and
> instance value can be
> obtained from each IP block in Part 2, IP can then choose to handle
> callbacks ONLY for the given
> instance of a given IP block (or still handling for all instances as
> before).
> For VCN, all callbacks will be handled only for the given one instance,
> instead of the original for-
> loop for all instance. As a result, each VCN instance can be
> start/stop/int/fini/suspend separately.
> 
> Part 4, Change all VCN helper functions to handle only the given
> instance, instead of the original
> for-loop for all instance.
> 
> Each instance can have its own states, so we think it makes more sense
> to separate them on IP
> block level to handle each of them separately.


Such a change should not be done unless all IPs follow the same design.
You didn't answer the question - what necessitates this change? What is
special about VCN that it cannot manage the states of multiple instances
within the IP block?

Thanks,
Lijo

> 
> Thanks,
> Boyuan
>>
>>>               amdgpu_device_ip_block_add(adev, &jpeg_v2_5_ip_block);
>>>               break;
>>>           case IP_VERSION(2, 6, 0):
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>> b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>> index d00df51bc400..1f8738ae360a 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>> @@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct
>>> amdgpu_ip_block *ip_block)
>>>   static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>>>   {
>>>       struct amdgpu_ring *ring;
>>> -    int i, j, r;
>>> +    int i, r;
>>>       uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
>>>       uint32_t *ptr;
>>>       struct amdgpu_device *adev = ip_block->adev;
>>> +    int inst = ip_block->instance;
>>>   -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>> -        if (adev->vcn.harvest_config & (1 << j))
>>> -            continue;
>>> -        /* VCN DEC TRAP */
>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>> -                VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>> &adev->vcn.inst[j].irq);
>>> -        if (r)
>>> -            return r;
>>> -
>>> -        /* VCN ENC TRAP */
>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>> -            r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>> -                i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>> &adev->vcn.inst[j].irq);
>>> -            if (r)
>>> -                return r;
>>> -        }
>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>> +        goto sw_init;
>>> +    /* VCN DEC TRAP */
>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>> +            VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>> &adev->vcn.inst[inst].irq);
>>> +    if (r)
>>> +        return r;
>>>   -        /* VCN POISON TRAP */
>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>> -            VCN_2_6__SRCID_UVD_POISON,
>>> &adev->vcn.inst[j].ras_poison_irq);
>>> +    /* VCN ENC TRAP */
>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>> +        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>> +            i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>> &adev->vcn.inst[inst].irq);
>>>           if (r)
>>>               return r;
>>>       }
>>>   +    /* VCN POISON TRAP */
>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>> +        VCN_2_6__SRCID_UVD_POISON,
>>> &adev->vcn.inst[inst].ras_poison_irq);
>>> +    if (r)
>>> +        return r;
>>> +sw_init:
>>>       r = amdgpu_vcn_sw_init(adev);
>>>       if (r)
>>>           return r;
>>> @@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct
>>> amdgpu_ip_block *ip_block)
>>>       if (r)
>>>           return r;
>>>   -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>> -        volatile struct amdgpu_fw_shared *fw_shared;
>>> +    volatile struct amdgpu_fw_shared *fw_shared;
>>>   -        if (adev->vcn.harvest_config & (1 << j))
>>> -            continue;
>>> -        adev->vcn.internal.context_id =
>>> mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>> -        adev->vcn.internal.ib_vmid =
>>> mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>> -        adev->vcn.internal.ib_bar_low =
>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>> -        adev->vcn.internal.ib_bar_high =
>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>> -        adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>> -        adev->vcn.internal.gp_scratch8 =
>>> mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>> -
>>> -        adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>> -        adev->vcn.inst[j].external.scratch9 = SOC15_REG_OFFSET(VCN,
>>> j, mmUVD_SCRATCH9);
>>> -        adev->vcn.internal.data0 =
>>> mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>> -        adev->vcn.inst[j].external.data0 = SOC15_REG_OFFSET(VCN, j,
>>> mmUVD_GPCOM_VCPU_DATA0);
>>> -        adev->vcn.internal.data1 =
>>> mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>> -        adev->vcn.inst[j].external.data1 = SOC15_REG_OFFSET(VCN, j,
>>> mmUVD_GPCOM_VCPU_DATA1);
>>> -        adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>> -        adev->vcn.inst[j].external.cmd = SOC15_REG_OFFSET(VCN, j,
>>> mmUVD_GPCOM_VCPU_CMD);
>>> -        adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>> -        adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(VCN, j,
>>> mmUVD_NO_OP);
>>> -
>>> -        ring = &adev->vcn.inst[j].ring_dec;
>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>> +        goto done;
>>> +    adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>> +    adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>> +    adev->vcn.internal.ib_bar_low =
>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>> +    adev->vcn.internal.ib_bar_high =
>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>> +    adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>> +    adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>> +
>>> +    adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>> +    adev->vcn.inst[inst].external.scratch9 = SOC15_REG_OFFSET(VCN,
>>> inst, mmUVD_SCRATCH9);
>>> +    adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>> +    adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN,
>>> inst, mmUVD_GPCOM_VCPU_DATA0);
>>> +    adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>> +    adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN,
>>> inst, mmUVD_GPCOM_VCPU_DATA1);
>>> +    adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>> +    adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN, inst,
>>> mmUVD_GPCOM_VCPU_CMD);
>>> +    adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>> +    adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN, inst,
>>> mmUVD_NO_OP);
>>> +
>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>> +    ring->use_doorbell = true;
>>> +
>>> +    ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 <<
>>> 1) +
>>> +            (amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
>>> +
>>> +    if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
>>> +        ring->vm_hub = AMDGPU_MMHUB1(0);
>>> +    else
>>> +        ring->vm_hub = AMDGPU_MMHUB0(0);
>>> +
>>> +    sprintf(ring->name, "vcn_dec_%d", inst);
>>> +    r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq,
>>> +                 0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>> +    if (r)
>>> +        return r;
>>> +
>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>> +        enum amdgpu_ring_priority_level hw_prio =
>>> amdgpu_vcn_get_enc_ring_prio(i);
>>> +
>>> +        ring = &adev->vcn.inst[inst].ring_enc[i];
>>>           ring->use_doorbell = true;
>>>             ring->doorbell_index =
>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>> -                (amdgpu_sriov_vf(adev) ? 2*j : 8*j);
>>> +                (amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2 + i +
>>> 8*inst));
>>>   -        if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2,
>>> 5, 0))
>>> +        if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>> +            IP_VERSION(2, 5, 0))
>>>               ring->vm_hub = AMDGPU_MMHUB1(0);
>>>           else
>>>               ring->vm_hub = AMDGPU_MMHUB0(0);
>>>   -        sprintf(ring->name, "vcn_dec_%d", j);
>>> -        r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq,
>>> -                     0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>> +        sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
>>> +        r = amdgpu_ring_init(adev, ring, 512,
>>> +                     &adev->vcn.inst[inst].irq, 0,
>>> +                     hw_prio, NULL);
>>>           if (r)
>>>               return r;
>>> -
>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>> -            enum amdgpu_ring_priority_level hw_prio =
>>> amdgpu_vcn_get_enc_ring_prio(i);
>>> -
>>> -            ring = &adev->vcn.inst[j].ring_enc[i];
>>> -            ring->use_doorbell = true;
>>> -
>>> -            ring->doorbell_index =
>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>> -                    (amdgpu_sriov_vf(adev) ? (1 + i + 2*j) : (2 + i
>>> + 8*j));
>>> -
>>> -            if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>> -                IP_VERSION(2, 5, 0))
>>> -                ring->vm_hub = AMDGPU_MMHUB1(0);
>>> -            else
>>> -                ring->vm_hub = AMDGPU_MMHUB0(0);
>>> -
>>> -            sprintf(ring->name, "vcn_enc_%d.%d", j, i);
>>> -            r = amdgpu_ring_init(adev, ring, 512,
>>> -                         &adev->vcn.inst[j].irq, 0,
>>> -                         hw_prio, NULL);
>>> -            if (r)
>>> -                return r;
>>> -        }
>>> -
>>> -        fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
>>> -        fw_shared->present_flag_0 =
>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>> -
>>> -        if (amdgpu_vcnfw_log)
>>> -            amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>       }
>>>   +    fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
>>> +    fw_shared->present_flag_0 =
>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>> +
>>> +    if (amdgpu_vcnfw_log)
>>> +        amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>> +done:
>>>       if (amdgpu_sriov_vf(adev)) {
>>>           r = amdgpu_virt_alloc_mm_table(adev);
>>>           if (r)
>>> @@ -1005,197 +1002,192 @@ static int vcn_v2_5_start_dpg_mode(struct
>>> amdgpu_device *adev, int inst_idx, boo
>>>       return 0;
>>>   }
>>>   -static int vcn_v2_5_start(struct amdgpu_device *adev)
>>> +static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned int
>>> inst)
>>>   {
>>>       struct amdgpu_ring *ring;
>>>       uint32_t rb_bufsz, tmp;
>>> -    int i, j, k, r;
>>> +    int j, k, r;
>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>> -        if (adev->pm.dpm_enabled)
>>> -            amdgpu_dpm_enable_vcn(adev, true, i);
>>> -    }
>>> -
>>> -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>> -        if (adev->vcn.harvest_config & (1 << i))
>>> -            continue;
>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>> -            r = vcn_v2_5_start_dpg_mode(adev, i,
>>> adev->vcn.indirect_sram);
>>> -            continue;
>>> -        }
>>> +    if (adev->pm.dpm_enabled)
>>> +        amdgpu_dpm_enable_vcn(adev, true, inst);
>>>   -        /* disable register anti-hang mechanism */
>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS), 0,
>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>> +        return 0;
>>>   -        /* set uvd status busy */
>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) |
>>> UVD_STATUS__UVD_BUSY;
>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>> +        r = vcn_v2_5_start_dpg_mode(adev, inst,
>>> adev->vcn.indirect_sram);
>>> +        return r;
>>>       }
>>>   +    /* disable register anti-hang mechanism */
>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS), 0,
>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>> +
>>> +    /* set uvd status busy */
>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
>>> +
>>>       if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
>>>           return 0;
>>>         /*SW clock gating */
>>>       vcn_v2_5_disable_clock_gating(adev);
>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>> -        if (adev->vcn.harvest_config & (1 << i))
>>> -            continue;
>>> -        /* enable VCPU clock */
>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>> -            UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>> -
>>> -        /* disable master interrupt */
>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>> -
>>> -        /* setup mmUVD_LMI_CTRL */
>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
>>> -        tmp &= ~0xff;
>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
>>> -            UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>> -            UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>> -            UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>> -            UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>> -
>>> -        /* setup mmUVD_MPC_CNTL */
>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
>>> -        tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>> -        tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
>>> -
>>> -        /* setup UVD_MPC_SET_MUXA0 */
>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
>>> -            ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>> -            (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>> -            (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>> -            (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>> -
>>> -        /* setup UVD_MPC_SET_MUXB0 */
>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
>>> -            ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>> -            (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>> -            (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>> -            (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>> -
>>> -        /* setup mmUVD_MPC_SET_MUX */
>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
>>> -            ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>> -            (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>> -            (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>> -    }
>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>> +        return 0;
>>> +
>>> +    /* enable VCPU clock */
>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>> +        UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>> +
>>> +    /* disable master interrupt */
>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>> +
>>> +    /* setup mmUVD_LMI_CTRL */
>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
>>> +    tmp &= ~0xff;
>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
>>> +        UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>> +        UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>> +        UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>> +        UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>> +
>>> +    /* setup mmUVD_MPC_CNTL */
>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
>>> +    tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>> +    tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
>>> +
>>> +    /* setup UVD_MPC_SET_MUXA0 */
>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
>>> +        ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>> +        (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>> +        (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>> +        (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>> +
>>> +    /* setup UVD_MPC_SET_MUXB0 */
>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
>>> +        ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>> +        (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>> +        (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>> +        (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>> +
>>> +    /* setup mmUVD_MPC_SET_MUX */
>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
>>> +        ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>> +        (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>> +        (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>         vcn_v2_5_mc_resume(adev);
>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>> -        volatile struct amdgpu_fw_shared *fw_shared =
>>> adev->vcn.inst[i].fw_shared.cpu_addr;
>>> -        if (adev->vcn.harvest_config & (1 << i))
>>> -            continue;
>>> -        /* VCN global tiling registers */
>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>> -            adev->gfx.config.gb_addr_config);
>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>> -            adev->gfx.config.gb_addr_config);
>>> +    volatile struct amdgpu_fw_shared *fw_shared =
>>> adev->vcn.inst[inst].fw_shared.cpu_addr;
>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>> +        return 0;
>>> +
>>> +    /* VCN global tiling registers */
>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>> +        adev->gfx.config.gb_addr_config);
>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>> +        adev->gfx.config.gb_addr_config);
>>>   -        /* enable LMI MC and UMC channels */
>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
>>> -            ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>> +    /* enable LMI MC and UMC channels */
>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
>>> +        ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>   -        /* unblock VCPU register access */
>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>> +    /* unblock VCPU register access */
>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>   -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>   -        for (k = 0; k < 10; ++k) {
>>> -            uint32_t status;
>>> -
>>> -            for (j = 0; j < 100; ++j) {
>>> -                status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
>>> -                if (status & 2)
>>> -                    break;
>>> -                if (amdgpu_emu_mode == 1)
>>> -                    msleep(500);
>>> -                else
>>> -                    mdelay(10);
>>> -            }
>>> -            r = 0;
>>> +    for (k = 0; k < 10; ++k) {
>>> +        uint32_t status;
>>> +
>>> +        for (j = 0; j < 100; ++j) {
>>> +            status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
>>>               if (status & 2)
>>>                   break;
>>> +            if (amdgpu_emu_mode == 1)
>>> +                msleep(500);
>>> +            else
>>> +                mdelay(10);
>>> +        }
>>> +        r = 0;
>>> +        if (status & 2)
>>> +            break;
>>>   -            DRM_ERROR("VCN decode not responding, trying to reset
>>> the VCPU!!!\n");
>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>> -                UVD_VCPU_CNTL__BLK_RST_MASK,
>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>> -            mdelay(10);
>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>> +        DRM_ERROR("VCN decode not responding, trying to reset the
>>> VCPU!!!\n");
>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>> +            UVD_VCPU_CNTL__BLK_RST_MASK,
>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>> +        mdelay(10);
>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>   -            mdelay(10);
>>> -            r = -1;
>>> -        }
>>> +        mdelay(10);
>>> +        r = -1;
>>> +    }
>>>   -        if (r) {
>>> -            DRM_ERROR("VCN decode not responding, giving up!!!\n");
>>> -            return r;
>>> -        }
>>> +    if (r) {
>>> +        DRM_ERROR("VCN decode not responding, giving up!!!\n");
>>> +        return r;
>>> +    }
>>>   -        /* enable master interrupt */
>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
>>> -            UVD_MASTINT_EN__VCPU_EN_MASK,
>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>> +    /* enable master interrupt */
>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
>>> +        UVD_MASTINT_EN__VCPU_EN_MASK,
>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>   -        /* clear the busy bit of VCN_STATUS */
>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
>>> -            ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>> +    /* clear the busy bit of VCN_STATUS */
>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
>>> +        ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>   -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
>>>   -        ring = &adev->vcn.inst[i].ring_dec;
>>> -        /* force RBC into idle state */
>>> -        rb_bufsz = order_base_2(ring->ring_size);
>>> -        tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>> +    /* force RBC into idle state */
>>> +    rb_bufsz = order_base_2(ring->ring_size);
>>> +    tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
>>>   -        fw_shared->multi_queue.decode_queue_mode |=
>>> FW_QUEUE_RING_RESET;
>>> -        /* program the RB_BASE for ring buffer */
>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>> -            lower_32_bits(ring->gpu_addr));
>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>> -            upper_32_bits(ring->gpu_addr));
>>> +    fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
>>> +    /* program the RB_BASE for ring buffer */
>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>> +        lower_32_bits(ring->gpu_addr));
>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>> +        upper_32_bits(ring->gpu_addr));
>>>   -        /* Initialize the ring buffer's read and write pointers */
>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
>>> +    /* Initialize the ring buffer's read and write pointers */
>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
>>>   -        ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
>>> -                lower_32_bits(ring->wptr));
>>> -        fw_shared->multi_queue.decode_queue_mode &=
>>> ~FW_QUEUE_RING_RESET;
>>> +    ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
>>> +            lower_32_bits(ring->wptr));
>>> +    fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
>>>   -        fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>> FW_QUEUE_RING_RESET;
>>> -        ring = &adev->vcn.inst[i].ring_enc[0];
>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI,
>>> upper_32_bits(ring->gpu_addr));
>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
>>> -        fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>> ~FW_QUEUE_RING_RESET;
>>> -
>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>> FW_QUEUE_RING_RESET;
>>> -        ring = &adev->vcn.inst[i].ring_enc[1];
>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2,
>>> lower_32_bits(ring->wptr));
>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2,
>>> lower_32_bits(ring->wptr));
>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2,
>>> upper_32_bits(ring->gpu_addr));
>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4);
>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>> ~FW_QUEUE_RING_RESET;
>>> -    }
>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>> FW_QUEUE_RING_RESET;
>>> +    ring = &adev->vcn.inst[inst].ring_enc[0];
>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI,
>>> upper_32_bits(ring->gpu_addr));
>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>> ~FW_QUEUE_RING_RESET;
>>> +
>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>> FW_QUEUE_RING_RESET;
>>> +    ring = &adev->vcn.inst[inst].ring_enc[1];
>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2,
>>> upper_32_bits(ring->gpu_addr));
>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>> ~FW_QUEUE_RING_RESET;
>>>         return 0;
>>>   }
>>> @@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct
>>> amdgpu_device *adev, int inst_idx)
>>>       return 0;
>>>   }
>>>   -static int vcn_v2_5_stop(struct amdgpu_device *adev)
>>> +static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned int inst)
>>>   {
>>>       uint32_t tmp;
>>> -    int i, r = 0;
>>> +    int r = 0;
>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>> -        if (adev->vcn.harvest_config & (1 << i))
>>> -            continue;
>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>> -            r = vcn_v2_5_stop_dpg_mode(adev, i);
>>> -            continue;
>>> -        }
>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>> +        goto done;
>>>   -        /* wait for vcn idle */
>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS,
>>> UVD_STATUS__IDLE, 0x7);
>>> -        if (r)
>>> -            return r;
>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>> +        r = vcn_v2_5_stop_dpg_mode(adev, inst);
>>> +        goto done;
>>> +    }
>>>   -        tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>> -            UVD_LMI_STATUS__READ_CLEAN_MASK |
>>> -            UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>> -            UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
>>> -        if (r)
>>> -            return r;
>>> +    /* wait for vcn idle */
>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS,
>>> UVD_STATUS__IDLE, 0x7);
>>> +    if (r)
>>> +        return r;
>>>   -        /* block LMI UMC channel */
>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
>>> -        tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
>>> +    tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>> +        UVD_LMI_STATUS__READ_CLEAN_MASK |
>>> +        UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>> +        UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
>>> +    if (r)
>>> +        return r;
>>>   -        tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>> -            UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
>>> -        if (r)
>>> -            return r;
>>> +    /* block LMI UMC channel */
>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
>>> +    tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
>>>   -        /* block VCPU register access */
>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
>>> -            UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>> +    tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>> +        UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
>>> +    if (r)
>>> +        return r;
>>>   -        /* reset VCPU */
>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>> -            UVD_VCPU_CNTL__BLK_RST_MASK,
>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>> +    /* block VCPU register access */
>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
>>> +        UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>   -        /* disable VCPU clock */
>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>> -            ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>> +    /* reset VCPU */
>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>> +        UVD_VCPU_CNTL__BLK_RST_MASK,
>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>   -        /* clear status */
>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
>>> +    /* disable VCPU clock */
>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>> +        ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>   -        vcn_v2_5_enable_clock_gating(adev);
>>> +    /* clear status */
>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
>>>   -        /* enable register anti-hang mechanism */
>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
>>> -            UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>> -    }
>>> +    vcn_v2_5_enable_clock_gating(adev);
>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>> -        if (adev->pm.dpm_enabled)
>>> -            amdgpu_dpm_enable_vcn(adev, false, i);
>>> -    }
>>> +    /* enable register anti-hang mechanism */
>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
>>> +        UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>> +done:
>>> +    if (adev->pm.dpm_enabled)
>>> +        amdgpu_dpm_enable_vcn(adev, false, inst);
>>>         return 0;
>>>   }
>>> @@ -1838,9 +1827,9 @@ static int
>>> vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
>>>           return 0;
>>>         if (state == AMD_PG_STATE_GATE)
>>> -        ret = vcn_v2_5_stop(adev);
>>> +        ret = vcn_v2_5_stop(adev, inst);
>>>       else
>>> -        ret = vcn_v2_5_start(adev);
>>> +        ret = vcn_v2_5_start(adev, inst);
>>>         if (!ret)
>>>           adev->vcn.cur_state[inst] = state;

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-07 13:50       ` Lazar, Lijo
@ 2024-10-07 14:17         ` Alex Deucher
  2024-10-07 14:29           ` Christian König
  2024-10-07 14:32           ` Lazar, Lijo
  0 siblings, 2 replies; 37+ messages in thread
From: Alex Deucher @ 2024-10-07 14:17 UTC (permalink / raw)
  To: Lazar, Lijo
  Cc: Boyuan Zhang, amd-gfx, leo.liu, christian.koenig,
	alexander.deucher, sunil.khatri

On Mon, Oct 7, 2024 at 9:58 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>
>
>
> On 10/7/2024 7:03 PM, Boyuan Zhang wrote:
> >
> > On 2024-10-07 01:22, Lazar, Lijo wrote:
> >>
> >> On 10/5/2024 12:14 AM, boyuan.zhang@amd.com wrote:
> >>> From: Boyuan Zhang <boyuan.zhang@amd.com>
> >>>
> >>> For vcn 2_5, add ip_block for each vcn instance during discovery stage.
> >>>
> >>> And only powering on/off one of the vcn instance using the
> >>> instance value stored in ip_block, instead of powering on/off all
> >>> vcn instances. Modify the existing functions to use the instance value
> >>> in ip_block, and remove the original for loop for all vcn instances.
> >>>
> >>> v2: rename "i"/"j" to "inst" for instance value.
> >>>
> >>> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
> >>> ---
> >>>   drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
> >>>   drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565 +++++++++---------
> >>>   2 files changed, 280 insertions(+), 289 deletions(-)
> >>>
> >>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
> >>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
> >>> index 9f9a1867da72..de1053cc2a2b 100644
> >>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
> >>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
> >>> @@ -2278,6 +2278,7 @@ static int
> >>> amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
> >>>     static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device
> >>> *adev)
> >>>   {
> >>> +    int i;
> >>>       if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
> >>>           switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
> >>>           case IP_VERSION(7, 0, 0):
> >>> @@ -2321,7 +2322,8 @@ static int
> >>> amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
> >>>           case IP_VERSION(2, 0, 3):
> >>>               break;
> >>>           case IP_VERSION(2, 5, 0):
> >>> -            amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
> >>> +            for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
> >>> +                amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
> >>
> >> This introduces a totally confusing design now. At a higher level an IP
> >> block type manages multiple instances and their power states. Now there
> >> is a mix where no definition can be attributed to an IP block. Or, if
> >> this were to be done uniformly for other IPs, then for some SOCs there
> >> could be 16 SDMA blocks, 8 GFX blocks and so forth.
> >>
> >> What is the reason to do this way? Can't VCN IP block maintain the state
> >> of multiple instances within itself?
> >>
> >> Thanks,
> >> Lijo
> > This is part of the fundamental design change for separating IP block
> > per instance, in order to
> > handle each instance separately within same IP block (e.g. separate
> > power/clock management).
> >
> > Part 1, Change all adev ptr handle to amdgpu_ip_block ptr in all
> > callbacks (hw_init/fini, sw_init/fini,
> > suspend, etc...) for all IP blocks, so that each IP knows which IP_block
> > (and which instance) the
> > callback is for. Most parts of this changes have been submitted by Sunil.
> >
> > Part 2, Separate IP block per instance.
> >
> > Part 3, Since callbacks can pass in IP_block now after Part 1 change and
> > instance value can be
> > obtained from each IP block in Part 2, IP can then choose to handle
> > callbacks ONLY for the given
> > instance of a given IP block (or still handling for all instances as
> > before).
> > For VCN, all callbacks will be handled only for the given one instance,
> > instead of the original for-
> > loop for all instance. As a result, each VCN instance can be
> > start/stop/int/fini/suspend separately.
> >
> > Part 4, Change all VCN helper functions to handle only the given
> > instance, instead of the original
> > for-loop for all instance.
> >
> > Each instance can have its own states, so we think it makes more sense
> > to separate them on IP
> > block level to handle each of them separately.
>
>
> Such a change should not be done unless all IPs follow the same design.
> You didn't answer the question - what necessitates this change? What is
> special about VCN that it cannot manage the states of multiple instances
> within the IP block?

We want to be able to manage the powergating independently for each
VCN instance for both power management and VCN reset.  Right now power
gating is handled at the IP level so it's not easy or clean to handle
powergating of individual IP instances.

Alex

>
> Thanks,
> Lijo
>
> >
> > Thanks,
> > Boyuan
> >>
> >>>               amdgpu_device_ip_block_add(adev, &jpeg_v2_5_ip_block);
> >>>               break;
> >>>           case IP_VERSION(2, 6, 0):
> >>> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
> >>> b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
> >>> index d00df51bc400..1f8738ae360a 100644
> >>> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
> >>> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
> >>> @@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct
> >>> amdgpu_ip_block *ip_block)
> >>>   static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
> >>>   {
> >>>       struct amdgpu_ring *ring;
> >>> -    int i, j, r;
> >>> +    int i, r;
> >>>       uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
> >>>       uint32_t *ptr;
> >>>       struct amdgpu_device *adev = ip_block->adev;
> >>> +    int inst = ip_block->instance;
> >>>   -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
> >>> -        if (adev->vcn.harvest_config & (1 << j))
> >>> -            continue;
> >>> -        /* VCN DEC TRAP */
> >>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
> >>> -                VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
> >>> &adev->vcn.inst[j].irq);
> >>> -        if (r)
> >>> -            return r;
> >>> -
> >>> -        /* VCN ENC TRAP */
> >>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> >>> -            r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
> >>> -                i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
> >>> &adev->vcn.inst[j].irq);
> >>> -            if (r)
> >>> -                return r;
> >>> -        }
> >>> +    if (adev->vcn.harvest_config & (1 << inst))
> >>> +        goto sw_init;
> >>> +    /* VCN DEC TRAP */
> >>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
> >>> +            VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
> >>> &adev->vcn.inst[inst].irq);
> >>> +    if (r)
> >>> +        return r;
> >>>   -        /* VCN POISON TRAP */
> >>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
> >>> -            VCN_2_6__SRCID_UVD_POISON,
> >>> &adev->vcn.inst[j].ras_poison_irq);
> >>> +    /* VCN ENC TRAP */
> >>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> >>> +        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
> >>> +            i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
> >>> &adev->vcn.inst[inst].irq);
> >>>           if (r)
> >>>               return r;
> >>>       }
> >>>   +    /* VCN POISON TRAP */
> >>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
> >>> +        VCN_2_6__SRCID_UVD_POISON,
> >>> &adev->vcn.inst[inst].ras_poison_irq);
> >>> +    if (r)
> >>> +        return r;
> >>> +sw_init:
> >>>       r = amdgpu_vcn_sw_init(adev);
> >>>       if (r)
> >>>           return r;
> >>> @@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct
> >>> amdgpu_ip_block *ip_block)
> >>>       if (r)
> >>>           return r;
> >>>   -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
> >>> -        volatile struct amdgpu_fw_shared *fw_shared;
> >>> +    volatile struct amdgpu_fw_shared *fw_shared;
> >>>   -        if (adev->vcn.harvest_config & (1 << j))
> >>> -            continue;
> >>> -        adev->vcn.internal.context_id =
> >>> mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
> >>> -        adev->vcn.internal.ib_vmid =
> >>> mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
> >>> -        adev->vcn.internal.ib_bar_low =
> >>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
> >>> -        adev->vcn.internal.ib_bar_high =
> >>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
> >>> -        adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
> >>> -        adev->vcn.internal.gp_scratch8 =
> >>> mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
> >>> -
> >>> -        adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
> >>> -        adev->vcn.inst[j].external.scratch9 = SOC15_REG_OFFSET(VCN,
> >>> j, mmUVD_SCRATCH9);
> >>> -        adev->vcn.internal.data0 =
> >>> mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
> >>> -        adev->vcn.inst[j].external.data0 = SOC15_REG_OFFSET(VCN, j,
> >>> mmUVD_GPCOM_VCPU_DATA0);
> >>> -        adev->vcn.internal.data1 =
> >>> mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
> >>> -        adev->vcn.inst[j].external.data1 = SOC15_REG_OFFSET(VCN, j,
> >>> mmUVD_GPCOM_VCPU_DATA1);
> >>> -        adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
> >>> -        adev->vcn.inst[j].external.cmd = SOC15_REG_OFFSET(VCN, j,
> >>> mmUVD_GPCOM_VCPU_CMD);
> >>> -        adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
> >>> -        adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(VCN, j,
> >>> mmUVD_NO_OP);
> >>> -
> >>> -        ring = &adev->vcn.inst[j].ring_dec;
> >>> +    if (adev->vcn.harvest_config & (1 << inst))
> >>> +        goto done;
> >>> +    adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
> >>> +    adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
> >>> +    adev->vcn.internal.ib_bar_low =
> >>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
> >>> +    adev->vcn.internal.ib_bar_high =
> >>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
> >>> +    adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
> >>> +    adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
> >>> +
> >>> +    adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
> >>> +    adev->vcn.inst[inst].external.scratch9 = SOC15_REG_OFFSET(VCN,
> >>> inst, mmUVD_SCRATCH9);
> >>> +    adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
> >>> +    adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN,
> >>> inst, mmUVD_GPCOM_VCPU_DATA0);
> >>> +    adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
> >>> +    adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN,
> >>> inst, mmUVD_GPCOM_VCPU_DATA1);
> >>> +    adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
> >>> +    adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN, inst,
> >>> mmUVD_GPCOM_VCPU_CMD);
> >>> +    adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
> >>> +    adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN, inst,
> >>> mmUVD_NO_OP);
> >>> +
> >>> +    ring = &adev->vcn.inst[inst].ring_dec;
> >>> +    ring->use_doorbell = true;
> >>> +
> >>> +    ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 <<
> >>> 1) +
> >>> +            (amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
> >>> +
> >>> +    if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
> >>> +        ring->vm_hub = AMDGPU_MMHUB1(0);
> >>> +    else
> >>> +        ring->vm_hub = AMDGPU_MMHUB0(0);
> >>> +
> >>> +    sprintf(ring->name, "vcn_dec_%d", inst);
> >>> +    r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq,
> >>> +                 0, AMDGPU_RING_PRIO_DEFAULT, NULL);
> >>> +    if (r)
> >>> +        return r;
> >>> +
> >>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> >>> +        enum amdgpu_ring_priority_level hw_prio =
> >>> amdgpu_vcn_get_enc_ring_prio(i);
> >>> +
> >>> +        ring = &adev->vcn.inst[inst].ring_enc[i];
> >>>           ring->use_doorbell = true;
> >>>             ring->doorbell_index =
> >>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
> >>> -                (amdgpu_sriov_vf(adev) ? 2*j : 8*j);
> >>> +                (amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2 + i +
> >>> 8*inst));
> >>>   -        if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2,
> >>> 5, 0))
> >>> +        if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
> >>> +            IP_VERSION(2, 5, 0))
> >>>               ring->vm_hub = AMDGPU_MMHUB1(0);
> >>>           else
> >>>               ring->vm_hub = AMDGPU_MMHUB0(0);
> >>>   -        sprintf(ring->name, "vcn_dec_%d", j);
> >>> -        r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq,
> >>> -                     0, AMDGPU_RING_PRIO_DEFAULT, NULL);
> >>> +        sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
> >>> +        r = amdgpu_ring_init(adev, ring, 512,
> >>> +                     &adev->vcn.inst[inst].irq, 0,
> >>> +                     hw_prio, NULL);
> >>>           if (r)
> >>>               return r;
> >>> -
> >>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> >>> -            enum amdgpu_ring_priority_level hw_prio =
> >>> amdgpu_vcn_get_enc_ring_prio(i);
> >>> -
> >>> -            ring = &adev->vcn.inst[j].ring_enc[i];
> >>> -            ring->use_doorbell = true;
> >>> -
> >>> -            ring->doorbell_index =
> >>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
> >>> -                    (amdgpu_sriov_vf(adev) ? (1 + i + 2*j) : (2 + i
> >>> + 8*j));
> >>> -
> >>> -            if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
> >>> -                IP_VERSION(2, 5, 0))
> >>> -                ring->vm_hub = AMDGPU_MMHUB1(0);
> >>> -            else
> >>> -                ring->vm_hub = AMDGPU_MMHUB0(0);
> >>> -
> >>> -            sprintf(ring->name, "vcn_enc_%d.%d", j, i);
> >>> -            r = amdgpu_ring_init(adev, ring, 512,
> >>> -                         &adev->vcn.inst[j].irq, 0,
> >>> -                         hw_prio, NULL);
> >>> -            if (r)
> >>> -                return r;
> >>> -        }
> >>> -
> >>> -        fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
> >>> -        fw_shared->present_flag_0 =
> >>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
> >>> -
> >>> -        if (amdgpu_vcnfw_log)
> >>> -            amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
> >>>       }
> >>>   +    fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
> >>> +    fw_shared->present_flag_0 =
> >>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
> >>> +
> >>> +    if (amdgpu_vcnfw_log)
> >>> +        amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
> >>> +done:
> >>>       if (amdgpu_sriov_vf(adev)) {
> >>>           r = amdgpu_virt_alloc_mm_table(adev);
> >>>           if (r)
> >>> @@ -1005,197 +1002,192 @@ static int vcn_v2_5_start_dpg_mode(struct
> >>> amdgpu_device *adev, int inst_idx, boo
> >>>       return 0;
> >>>   }
> >>>   -static int vcn_v2_5_start(struct amdgpu_device *adev)
> >>> +static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned int
> >>> inst)
> >>>   {
> >>>       struct amdgpu_ring *ring;
> >>>       uint32_t rb_bufsz, tmp;
> >>> -    int i, j, k, r;
> >>> +    int j, k, r;
> >>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> >>> -        if (adev->pm.dpm_enabled)
> >>> -            amdgpu_dpm_enable_vcn(adev, true, i);
> >>> -    }
> >>> -
> >>> -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> >>> -        if (adev->vcn.harvest_config & (1 << i))
> >>> -            continue;
> >>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> >>> -            r = vcn_v2_5_start_dpg_mode(adev, i,
> >>> adev->vcn.indirect_sram);
> >>> -            continue;
> >>> -        }
> >>> +    if (adev->pm.dpm_enabled)
> >>> +        amdgpu_dpm_enable_vcn(adev, true, inst);
> >>>   -        /* disable register anti-hang mechanism */
> >>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS), 0,
> >>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> >>> +    if (adev->vcn.harvest_config & (1 << inst))
> >>> +        return 0;
> >>>   -        /* set uvd status busy */
> >>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) |
> >>> UVD_STATUS__UVD_BUSY;
> >>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
> >>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> >>> +        r = vcn_v2_5_start_dpg_mode(adev, inst,
> >>> adev->vcn.indirect_sram);
> >>> +        return r;
> >>>       }
> >>>   +    /* disable register anti-hang mechanism */
> >>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS), 0,
> >>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> >>> +
> >>> +    /* set uvd status busy */
> >>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
> >>> +
> >>>       if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
> >>>           return 0;
> >>>         /*SW clock gating */
> >>>       vcn_v2_5_disable_clock_gating(adev);
> >>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> >>> -        if (adev->vcn.harvest_config & (1 << i))
> >>> -            continue;
> >>> -        /* enable VCPU clock */
> >>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
> >>> -            UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
> >>> -
> >>> -        /* disable master interrupt */
> >>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
> >>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
> >>> -
> >>> -        /* setup mmUVD_LMI_CTRL */
> >>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
> >>> -        tmp &= ~0xff;
> >>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
> >>> -            UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
> >>> -            UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
> >>> -            UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
> >>> -            UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
> >>> -
> >>> -        /* setup mmUVD_MPC_CNTL */
> >>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
> >>> -        tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
> >>> -        tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
> >>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
> >>> -
> >>> -        /* setup UVD_MPC_SET_MUXA0 */
> >>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
> >>> -            ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
> >>> -            (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
> >>> -            (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
> >>> -            (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
> >>> -
> >>> -        /* setup UVD_MPC_SET_MUXB0 */
> >>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
> >>> -            ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
> >>> -            (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
> >>> -            (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
> >>> -            (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
> >>> -
> >>> -        /* setup mmUVD_MPC_SET_MUX */
> >>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
> >>> -            ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
> >>> -            (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
> >>> -            (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
> >>> -    }
> >>> +    if (adev->vcn.harvest_config & (1 << inst))
> >>> +        return 0;
> >>> +
> >>> +    /* enable VCPU clock */
> >>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
> >>> +        UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
> >>> +
> >>> +    /* disable master interrupt */
> >>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
> >>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
> >>> +
> >>> +    /* setup mmUVD_LMI_CTRL */
> >>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
> >>> +    tmp &= ~0xff;
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
> >>> +        UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
> >>> +        UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
> >>> +        UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
> >>> +        UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
> >>> +
> >>> +    /* setup mmUVD_MPC_CNTL */
> >>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
> >>> +    tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
> >>> +    tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
> >>> +
> >>> +    /* setup UVD_MPC_SET_MUXA0 */
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
> >>> +        ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
> >>> +        (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
> >>> +        (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
> >>> +        (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
> >>> +
> >>> +    /* setup UVD_MPC_SET_MUXB0 */
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
> >>> +        ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
> >>> +        (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
> >>> +        (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
> >>> +        (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
> >>> +
> >>> +    /* setup mmUVD_MPC_SET_MUX */
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
> >>> +        ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
> >>> +        (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
> >>> +        (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
> >>>         vcn_v2_5_mc_resume(adev);
> >>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> >>> -        volatile struct amdgpu_fw_shared *fw_shared =
> >>> adev->vcn.inst[i].fw_shared.cpu_addr;
> >>> -        if (adev->vcn.harvest_config & (1 << i))
> >>> -            continue;
> >>> -        /* VCN global tiling registers */
> >>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
> >>> -            adev->gfx.config.gb_addr_config);
> >>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
> >>> -            adev->gfx.config.gb_addr_config);
> >>> +    volatile struct amdgpu_fw_shared *fw_shared =
> >>> adev->vcn.inst[inst].fw_shared.cpu_addr;
> >>> +    if (adev->vcn.harvest_config & (1 << inst))
> >>> +        return 0;
> >>> +
> >>> +    /* VCN global tiling registers */
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
> >>> +        adev->gfx.config.gb_addr_config);
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
> >>> +        adev->gfx.config.gb_addr_config);
> >>>   -        /* enable LMI MC and UMC channels */
> >>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
> >>> -            ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
> >>> +    /* enable LMI MC and UMC channels */
> >>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
> >>> +        ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
> >>>   -        /* unblock VCPU register access */
> >>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
> >>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
> >>> +    /* unblock VCPU register access */
> >>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
> >>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
> >>>   -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
> >>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
> >>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>>   -        for (k = 0; k < 10; ++k) {
> >>> -            uint32_t status;
> >>> -
> >>> -            for (j = 0; j < 100; ++j) {
> >>> -                status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
> >>> -                if (status & 2)
> >>> -                    break;
> >>> -                if (amdgpu_emu_mode == 1)
> >>> -                    msleep(500);
> >>> -                else
> >>> -                    mdelay(10);
> >>> -            }
> >>> -            r = 0;
> >>> +    for (k = 0; k < 10; ++k) {
> >>> +        uint32_t status;
> >>> +
> >>> +        for (j = 0; j < 100; ++j) {
> >>> +            status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
> >>>               if (status & 2)
> >>>                   break;
> >>> +            if (amdgpu_emu_mode == 1)
> >>> +                msleep(500);
> >>> +            else
> >>> +                mdelay(10);
> >>> +        }
> >>> +        r = 0;
> >>> +        if (status & 2)
> >>> +            break;
> >>>   -            DRM_ERROR("VCN decode not responding, trying to reset
> >>> the VCPU!!!\n");
> >>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
> >>> -                UVD_VCPU_CNTL__BLK_RST_MASK,
> >>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>> -            mdelay(10);
> >>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
> >>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>> +        DRM_ERROR("VCN decode not responding, trying to reset the
> >>> VCPU!!!\n");
> >>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
> >>> +            UVD_VCPU_CNTL__BLK_RST_MASK,
> >>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>> +        mdelay(10);
> >>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
> >>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>>   -            mdelay(10);
> >>> -            r = -1;
> >>> -        }
> >>> +        mdelay(10);
> >>> +        r = -1;
> >>> +    }
> >>>   -        if (r) {
> >>> -            DRM_ERROR("VCN decode not responding, giving up!!!\n");
> >>> -            return r;
> >>> -        }
> >>> +    if (r) {
> >>> +        DRM_ERROR("VCN decode not responding, giving up!!!\n");
> >>> +        return r;
> >>> +    }
> >>>   -        /* enable master interrupt */
> >>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
> >>> -            UVD_MASTINT_EN__VCPU_EN_MASK,
> >>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
> >>> +    /* enable master interrupt */
> >>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
> >>> +        UVD_MASTINT_EN__VCPU_EN_MASK,
> >>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
> >>>   -        /* clear the busy bit of VCN_STATUS */
> >>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
> >>> -            ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
> >>> +    /* clear the busy bit of VCN_STATUS */
> >>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
> >>> +        ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
> >>>   -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
> >>>   -        ring = &adev->vcn.inst[i].ring_dec;
> >>> -        /* force RBC into idle state */
> >>> -        rb_bufsz = order_base_2(ring->ring_size);
> >>> -        tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
> >>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
> >>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
> >>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
> >>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
> >>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
> >>> +    ring = &adev->vcn.inst[inst].ring_dec;
> >>> +    /* force RBC into idle state */
> >>> +    rb_bufsz = order_base_2(ring->ring_size);
> >>> +    tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
> >>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
> >>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
> >>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
> >>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
> >>>   -        fw_shared->multi_queue.decode_queue_mode |=
> >>> FW_QUEUE_RING_RESET;
> >>> -        /* program the RB_BASE for ring buffer */
> >>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
> >>> -            lower_32_bits(ring->gpu_addr));
> >>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
> >>> -            upper_32_bits(ring->gpu_addr));
> >>> +    fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
> >>> +    /* program the RB_BASE for ring buffer */
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
> >>> +        lower_32_bits(ring->gpu_addr));
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
> >>> +        upper_32_bits(ring->gpu_addr));
> >>>   -        /* Initialize the ring buffer's read and write pointers */
> >>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
> >>> +    /* Initialize the ring buffer's read and write pointers */
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
> >>>   -        ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
> >>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
> >>> -                lower_32_bits(ring->wptr));
> >>> -        fw_shared->multi_queue.decode_queue_mode &=
> >>> ~FW_QUEUE_RING_RESET;
> >>> +    ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
> >>> +            lower_32_bits(ring->wptr));
> >>> +    fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
> >>>   -        fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
> >>> FW_QUEUE_RING_RESET;
> >>> -        ring = &adev->vcn.inst[i].ring_enc[0];
> >>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
> >>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
> >>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
> >>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI,
> >>> upper_32_bits(ring->gpu_addr));
> >>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
> >>> -        fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
> >>> ~FW_QUEUE_RING_RESET;
> >>> -
> >>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode |=
> >>> FW_QUEUE_RING_RESET;
> >>> -        ring = &adev->vcn.inst[i].ring_enc[1];
> >>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2,
> >>> lower_32_bits(ring->wptr));
> >>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2,
> >>> lower_32_bits(ring->wptr));
> >>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
> >>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2,
> >>> upper_32_bits(ring->gpu_addr));
> >>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4);
> >>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode &=
> >>> ~FW_QUEUE_RING_RESET;
> >>> -    }
> >>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
> >>> FW_QUEUE_RING_RESET;
> >>> +    ring = &adev->vcn.inst[inst].ring_enc[0];
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI,
> >>> upper_32_bits(ring->gpu_addr));
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
> >>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
> >>> ~FW_QUEUE_RING_RESET;
> >>> +
> >>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode |=
> >>> FW_QUEUE_RING_RESET;
> >>> +    ring = &adev->vcn.inst[inst].ring_enc[1];
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2,
> >>> upper_32_bits(ring->gpu_addr));
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
> >>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode &=
> >>> ~FW_QUEUE_RING_RESET;
> >>>         return 0;
> >>>   }
> >>> @@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct
> >>> amdgpu_device *adev, int inst_idx)
> >>>       return 0;
> >>>   }
> >>>   -static int vcn_v2_5_stop(struct amdgpu_device *adev)
> >>> +static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned int inst)
> >>>   {
> >>>       uint32_t tmp;
> >>> -    int i, r = 0;
> >>> +    int r = 0;
> >>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> >>> -        if (adev->vcn.harvest_config & (1 << i))
> >>> -            continue;
> >>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> >>> -            r = vcn_v2_5_stop_dpg_mode(adev, i);
> >>> -            continue;
> >>> -        }
> >>> +    if (adev->vcn.harvest_config & (1 << inst))
> >>> +        goto done;
> >>>   -        /* wait for vcn idle */
> >>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS,
> >>> UVD_STATUS__IDLE, 0x7);
> >>> -        if (r)
> >>> -            return r;
> >>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> >>> +        r = vcn_v2_5_stop_dpg_mode(adev, inst);
> >>> +        goto done;
> >>> +    }
> >>>   -        tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
> >>> -            UVD_LMI_STATUS__READ_CLEAN_MASK |
> >>> -            UVD_LMI_STATUS__WRITE_CLEAN_MASK |
> >>> -            UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
> >>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
> >>> -        if (r)
> >>> -            return r;
> >>> +    /* wait for vcn idle */
> >>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS,
> >>> UVD_STATUS__IDLE, 0x7);
> >>> +    if (r)
> >>> +        return r;
> >>>   -        /* block LMI UMC channel */
> >>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
> >>> -        tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
> >>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
> >>> +    tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
> >>> +        UVD_LMI_STATUS__READ_CLEAN_MASK |
> >>> +        UVD_LMI_STATUS__WRITE_CLEAN_MASK |
> >>> +        UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
> >>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
> >>> +    if (r)
> >>> +        return r;
> >>>   -        tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
> >>> -            UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
> >>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
> >>> -        if (r)
> >>> -            return r;
> >>> +    /* block LMI UMC channel */
> >>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
> >>> +    tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
> >>>   -        /* block VCPU register access */
> >>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
> >>> -            UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
> >>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
> >>> +    tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
> >>> +        UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
> >>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
> >>> +    if (r)
> >>> +        return r;
> >>>   -        /* reset VCPU */
> >>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
> >>> -            UVD_VCPU_CNTL__BLK_RST_MASK,
> >>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>> +    /* block VCPU register access */
> >>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
> >>> +        UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
> >>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
> >>>   -        /* disable VCPU clock */
> >>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
> >>> -            ~(UVD_VCPU_CNTL__CLK_EN_MASK));
> >>> +    /* reset VCPU */
> >>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
> >>> +        UVD_VCPU_CNTL__BLK_RST_MASK,
> >>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>>   -        /* clear status */
> >>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
> >>> +    /* disable VCPU clock */
> >>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
> >>> +        ~(UVD_VCPU_CNTL__CLK_EN_MASK));
> >>>   -        vcn_v2_5_enable_clock_gating(adev);
> >>> +    /* clear status */
> >>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
> >>>   -        /* enable register anti-hang mechanism */
> >>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
> >>> -            UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
> >>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> >>> -    }
> >>> +    vcn_v2_5_enable_clock_gating(adev);
> >>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> >>> -        if (adev->pm.dpm_enabled)
> >>> -            amdgpu_dpm_enable_vcn(adev, false, i);
> >>> -    }
> >>> +    /* enable register anti-hang mechanism */
> >>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
> >>> +        UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
> >>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> >>> +done:
> >>> +    if (adev->pm.dpm_enabled)
> >>> +        amdgpu_dpm_enable_vcn(adev, false, inst);
> >>>         return 0;
> >>>   }
> >>> @@ -1838,9 +1827,9 @@ static int
> >>> vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
> >>>           return 0;
> >>>         if (state == AMD_PG_STATE_GATE)
> >>> -        ret = vcn_v2_5_stop(adev);
> >>> +        ret = vcn_v2_5_stop(adev, inst);
> >>>       else
> >>> -        ret = vcn_v2_5_start(adev);
> >>> +        ret = vcn_v2_5_start(adev, inst);
> >>>         if (!ret)
> >>>           adev->vcn.cur_state[inst] = state;

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-07 14:17         ` Alex Deucher
@ 2024-10-07 14:29           ` Christian König
  2024-10-07 14:32           ` Lazar, Lijo
  1 sibling, 0 replies; 37+ messages in thread
From: Christian König @ 2024-10-07 14:29 UTC (permalink / raw)
  To: Alex Deucher, Lazar, Lijo
  Cc: Boyuan Zhang, amd-gfx, leo.liu, alexander.deucher, sunil.khatri

Am 07.10.24 um 16:17 schrieb Alex Deucher:
> On Mon, Oct 7, 2024 at 9:58 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>> On 10/7/2024 7:03 PM, Boyuan Zhang wrote:
>>> On 2024-10-07 01:22, Lazar, Lijo wrote:
>>>> On 10/5/2024 12:14 AM, boyuan.zhang@amd.com wrote:
>>>>> From: Boyuan Zhang <boyuan.zhang@amd.com>
>>>>>
>>>>> For vcn 2_5, add ip_block for each vcn instance during discovery stage.
>>>>>
>>>>> And only powering on/off one of the vcn instance using the
>>>>> instance value stored in ip_block, instead of powering on/off all
>>>>> vcn instances. Modify the existing functions to use the instance value
>>>>> in ip_block, and remove the original for loop for all vcn instances.
>>>>>
>>>>> v2: rename "i"/"j" to "inst" for instance value.
>>>>>
>>>>> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
>>>>> ---
>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
>>>>>    drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565 +++++++++---------
>>>>>    2 files changed, 280 insertions(+), 289 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>> index 9f9a1867da72..de1053cc2a2b 100644
>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>> @@ -2278,6 +2278,7 @@ static int
>>>>> amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
>>>>>      static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device
>>>>> *adev)
>>>>>    {
>>>>> +    int i;
>>>>>        if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
>>>>>            switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
>>>>>            case IP_VERSION(7, 0, 0):
>>>>> @@ -2321,7 +2322,8 @@ static int
>>>>> amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>>>>>            case IP_VERSION(2, 0, 3):
>>>>>                break;
>>>>>            case IP_VERSION(2, 5, 0):
>>>>> -            amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>>>>> +            for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
>>>>> +                amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>>>> This introduces a totally confusing design now. At a higher level an IP
>>>> block type manages multiple instances and their power states. Now there
>>>> is a mix where no definition can be attributed to an IP block. Or, if
>>>> this were to be done uniformly for other IPs, then for some SOCs there
>>>> could be 16 SDMA blocks, 8 GFX blocks and so forth.
>>>>
>>>> What is the reason to do this way? Can't VCN IP block maintain the state
>>>> of multiple instances within itself?
>>>>
>>>> Thanks,
>>>> Lijo
>>> This is part of the fundamental design change for separating IP block
>>> per instance, in order to
>>> handle each instance separately within same IP block (e.g. separate
>>> power/clock management).
>>>
>>> Part 1, Change all adev ptr handle to amdgpu_ip_block ptr in all
>>> callbacks (hw_init/fini, sw_init/fini,
>>> suspend, etc...) for all IP blocks, so that each IP knows which IP_block
>>> (and which instance) the
>>> callback is for. Most parts of this changes have been submitted by Sunil.
>>>
>>> Part 2, Separate IP block per instance.
>>>
>>> Part 3, Since callbacks can pass in IP_block now after Part 1 change and
>>> instance value can be
>>> obtained from each IP block in Part 2, IP can then choose to handle
>>> callbacks ONLY for the given
>>> instance of a given IP block (or still handling for all instances as
>>> before).
>>> For VCN, all callbacks will be handled only for the given one instance,
>>> instead of the original for-
>>> loop for all instance. As a result, each VCN instance can be
>>> start/stop/int/fini/suspend separately.
>>>
>>> Part 4, Change all VCN helper functions to handle only the given
>>> instance, instead of the original
>>> for-loop for all instance.
>>>
>>> Each instance can have its own states, so we think it makes more sense
>>> to separate them on IP
>>> block level to handle each of them separately.
>>
>> Such a change should not be done unless all IPs follow the same design.
>> You didn't answer the question - what necessitates this change? What is
>> special about VCN that it cannot manage the states of multiple instances
>> within the IP block?
> We want to be able to manage the powergating independently for each
> VCN instance for both power management and VCN reset.  Right now power
> gating is handled at the IP level so it's not easy or clean to handle
> powergating of individual IP instances.

Longer story short the design should be applied to all IPs, but VCN is 
just the block were we current ran into problems.

So yes long term plan is to change all designs with multiple blocks into 
this per instance format IP block format.

Christian.

>
> Alex
>
>> Thanks,
>> Lijo
>>
>>> Thanks,
>>> Boyuan
>>>>>                amdgpu_device_ip_block_add(adev, &jpeg_v2_5_ip_block);
>>>>>                break;
>>>>>            case IP_VERSION(2, 6, 0):
>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>> b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>> index d00df51bc400..1f8738ae360a 100644
>>>>> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>> @@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct
>>>>> amdgpu_ip_block *ip_block)
>>>>>    static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>>>>>    {
>>>>>        struct amdgpu_ring *ring;
>>>>> -    int i, j, r;
>>>>> +    int i, r;
>>>>>        uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
>>>>>        uint32_t *ptr;
>>>>>        struct amdgpu_device *adev = ip_block->adev;
>>>>> +    int inst = ip_block->instance;
>>>>>    -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>>>> -        if (adev->vcn.harvest_config & (1 << j))
>>>>> -            continue;
>>>>> -        /* VCN DEC TRAP */
>>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>> -                VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>>>> &adev->vcn.inst[j].irq);
>>>>> -        if (r)
>>>>> -            return r;
>>>>> -
>>>>> -        /* VCN ENC TRAP */
>>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>> -            r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>> -                i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>>>> &adev->vcn.inst[j].irq);
>>>>> -            if (r)
>>>>> -                return r;
>>>>> -        }
>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>> +        goto sw_init;
>>>>> +    /* VCN DEC TRAP */
>>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>> +            VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>>>> &adev->vcn.inst[inst].irq);
>>>>> +    if (r)
>>>>> +        return r;
>>>>>    -        /* VCN POISON TRAP */
>>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>> -            VCN_2_6__SRCID_UVD_POISON,
>>>>> &adev->vcn.inst[j].ras_poison_irq);
>>>>> +    /* VCN ENC TRAP */
>>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>> +        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>> +            i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>>>> &adev->vcn.inst[inst].irq);
>>>>>            if (r)
>>>>>                return r;
>>>>>        }
>>>>>    +    /* VCN POISON TRAP */
>>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>> +        VCN_2_6__SRCID_UVD_POISON,
>>>>> &adev->vcn.inst[inst].ras_poison_irq);
>>>>> +    if (r)
>>>>> +        return r;
>>>>> +sw_init:
>>>>>        r = amdgpu_vcn_sw_init(adev);
>>>>>        if (r)
>>>>>            return r;
>>>>> @@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct
>>>>> amdgpu_ip_block *ip_block)
>>>>>        if (r)
>>>>>            return r;
>>>>>    -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>>>> -        volatile struct amdgpu_fw_shared *fw_shared;
>>>>> +    volatile struct amdgpu_fw_shared *fw_shared;
>>>>>    -        if (adev->vcn.harvest_config & (1 << j))
>>>>> -            continue;
>>>>> -        adev->vcn.internal.context_id =
>>>>> mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>>>> -        adev->vcn.internal.ib_vmid =
>>>>> mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>>>> -        adev->vcn.internal.ib_bar_low =
>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>>>> -        adev->vcn.internal.ib_bar_high =
>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>>>> -        adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>>>> -        adev->vcn.internal.gp_scratch8 =
>>>>> mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>>>> -
>>>>> -        adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>>>> -        adev->vcn.inst[j].external.scratch9 = SOC15_REG_OFFSET(VCN,
>>>>> j, mmUVD_SCRATCH9);
>>>>> -        adev->vcn.internal.data0 =
>>>>> mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>>>> -        adev->vcn.inst[j].external.data0 = SOC15_REG_OFFSET(VCN, j,
>>>>> mmUVD_GPCOM_VCPU_DATA0);
>>>>> -        adev->vcn.internal.data1 =
>>>>> mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>>>> -        adev->vcn.inst[j].external.data1 = SOC15_REG_OFFSET(VCN, j,
>>>>> mmUVD_GPCOM_VCPU_DATA1);
>>>>> -        adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>>>> -        adev->vcn.inst[j].external.cmd = SOC15_REG_OFFSET(VCN, j,
>>>>> mmUVD_GPCOM_VCPU_CMD);
>>>>> -        adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>>>> -        adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(VCN, j,
>>>>> mmUVD_NO_OP);
>>>>> -
>>>>> -        ring = &adev->vcn.inst[j].ring_dec;
>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>> +        goto done;
>>>>> +    adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>>>> +    adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>>>> +    adev->vcn.internal.ib_bar_low =
>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>>>> +    adev->vcn.internal.ib_bar_high =
>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>>>> +    adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>>>> +    adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>>>> +
>>>>> +    adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>>>> +    adev->vcn.inst[inst].external.scratch9 = SOC15_REG_OFFSET(VCN,
>>>>> inst, mmUVD_SCRATCH9);
>>>>> +    adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>>>> +    adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN,
>>>>> inst, mmUVD_GPCOM_VCPU_DATA0);
>>>>> +    adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>>>> +    adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN,
>>>>> inst, mmUVD_GPCOM_VCPU_DATA1);
>>>>> +    adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>>>> +    adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN, inst,
>>>>> mmUVD_GPCOM_VCPU_CMD);
>>>>> +    adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>>>> +    adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN, inst,
>>>>> mmUVD_NO_OP);
>>>>> +
>>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>>>> +    ring->use_doorbell = true;
>>>>> +
>>>>> +    ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 <<
>>>>> 1) +
>>>>> +            (amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
>>>>> +
>>>>> +    if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
>>>>> +        ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>> +    else
>>>>> +        ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>> +
>>>>> +    sprintf(ring->name, "vcn_dec_%d", inst);
>>>>> +    r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq,
>>>>> +                 0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>>>> +    if (r)
>>>>> +        return r;
>>>>> +
>>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>> +        enum amdgpu_ring_priority_level hw_prio =
>>>>> amdgpu_vcn_get_enc_ring_prio(i);
>>>>> +
>>>>> +        ring = &adev->vcn.inst[inst].ring_enc[i];
>>>>>            ring->use_doorbell = true;
>>>>>              ring->doorbell_index =
>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>>>> -                (amdgpu_sriov_vf(adev) ? 2*j : 8*j);
>>>>> +                (amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2 + i +
>>>>> 8*inst));
>>>>>    -        if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2,
>>>>> 5, 0))
>>>>> +        if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>> +            IP_VERSION(2, 5, 0))
>>>>>                ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>            else
>>>>>                ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>    -        sprintf(ring->name, "vcn_dec_%d", j);
>>>>> -        r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq,
>>>>> -                     0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>>>> +        sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
>>>>> +        r = amdgpu_ring_init(adev, ring, 512,
>>>>> +                     &adev->vcn.inst[inst].irq, 0,
>>>>> +                     hw_prio, NULL);
>>>>>            if (r)
>>>>>                return r;
>>>>> -
>>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>> -            enum amdgpu_ring_priority_level hw_prio =
>>>>> amdgpu_vcn_get_enc_ring_prio(i);
>>>>> -
>>>>> -            ring = &adev->vcn.inst[j].ring_enc[i];
>>>>> -            ring->use_doorbell = true;
>>>>> -
>>>>> -            ring->doorbell_index =
>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>>>> -                    (amdgpu_sriov_vf(adev) ? (1 + i + 2*j) : (2 + i
>>>>> + 8*j));
>>>>> -
>>>>> -            if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>> -                IP_VERSION(2, 5, 0))
>>>>> -                ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>> -            else
>>>>> -                ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>> -
>>>>> -            sprintf(ring->name, "vcn_enc_%d.%d", j, i);
>>>>> -            r = amdgpu_ring_init(adev, ring, 512,
>>>>> -                         &adev->vcn.inst[j].irq, 0,
>>>>> -                         hw_prio, NULL);
>>>>> -            if (r)
>>>>> -                return r;
>>>>> -        }
>>>>> -
>>>>> -        fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
>>>>> -        fw_shared->present_flag_0 =
>>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>>>> -
>>>>> -        if (amdgpu_vcnfw_log)
>>>>> -            amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>>>        }
>>>>>    +    fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
>>>>> +    fw_shared->present_flag_0 =
>>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>>>> +
>>>>> +    if (amdgpu_vcnfw_log)
>>>>> +        amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>>> +done:
>>>>>        if (amdgpu_sriov_vf(adev)) {
>>>>>            r = amdgpu_virt_alloc_mm_table(adev);
>>>>>            if (r)
>>>>> @@ -1005,197 +1002,192 @@ static int vcn_v2_5_start_dpg_mode(struct
>>>>> amdgpu_device *adev, int inst_idx, boo
>>>>>        return 0;
>>>>>    }
>>>>>    -static int vcn_v2_5_start(struct amdgpu_device *adev)
>>>>> +static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned int
>>>>> inst)
>>>>>    {
>>>>>        struct amdgpu_ring *ring;
>>>>>        uint32_t rb_bufsz, tmp;
>>>>> -    int i, j, k, r;
>>>>> +    int j, k, r;
>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>> -        if (adev->pm.dpm_enabled)
>>>>> -            amdgpu_dpm_enable_vcn(adev, true, i);
>>>>> -    }
>>>>> -
>>>>> -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>> -            continue;
>>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>> -            r = vcn_v2_5_start_dpg_mode(adev, i,
>>>>> adev->vcn.indirect_sram);
>>>>> -            continue;
>>>>> -        }
>>>>> +    if (adev->pm.dpm_enabled)
>>>>> +        amdgpu_dpm_enable_vcn(adev, true, inst);
>>>>>    -        /* disable register anti-hang mechanism */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS), 0,
>>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>> +        return 0;
>>>>>    -        /* set uvd status busy */
>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) |
>>>>> UVD_STATUS__UVD_BUSY;
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
>>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>> +        r = vcn_v2_5_start_dpg_mode(adev, inst,
>>>>> adev->vcn.indirect_sram);
>>>>> +        return r;
>>>>>        }
>>>>>    +    /* disable register anti-hang mechanism */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS), 0,
>>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>> +
>>>>> +    /* set uvd status busy */
>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
>>>>> +
>>>>>        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
>>>>>            return 0;
>>>>>          /*SW clock gating */
>>>>>        vcn_v2_5_disable_clock_gating(adev);
>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>> -            continue;
>>>>> -        /* enable VCPU clock */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>> -            UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>>>> -
>>>>> -        /* disable master interrupt */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
>>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>> -
>>>>> -        /* setup mmUVD_LMI_CTRL */
>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
>>>>> -        tmp &= ~0xff;
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
>>>>> -            UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>>>> -            UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>>>> -            UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>>>> -            UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>>>> -
>>>>> -        /* setup mmUVD_MPC_CNTL */
>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
>>>>> -        tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>>>> -        tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
>>>>> -
>>>>> -        /* setup UVD_MPC_SET_MUXA0 */
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
>>>>> -            ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>>>> -            (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>>>> -            (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>>>> -            (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>>>> -
>>>>> -        /* setup UVD_MPC_SET_MUXB0 */
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
>>>>> -            ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>>>> -            (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>>>> -            (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>>>> -            (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>>>> -
>>>>> -        /* setup mmUVD_MPC_SET_MUX */
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
>>>>> -            ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>>>> -            (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>>>> -            (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>>> -    }
>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>> +        return 0;
>>>>> +
>>>>> +    /* enable VCPU clock */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>> +        UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>>>> +
>>>>> +    /* disable master interrupt */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
>>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>> +
>>>>> +    /* setup mmUVD_LMI_CTRL */
>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
>>>>> +    tmp &= ~0xff;
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
>>>>> +        UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>>>> +        UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>>>> +        UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>>>> +        UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>>>> +
>>>>> +    /* setup mmUVD_MPC_CNTL */
>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
>>>>> +    tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>>>> +    tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
>>>>> +
>>>>> +    /* setup UVD_MPC_SET_MUXA0 */
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
>>>>> +        ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>>>> +        (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>>>> +        (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>>>> +        (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>>>> +
>>>>> +    /* setup UVD_MPC_SET_MUXB0 */
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
>>>>> +        ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>>>> +        (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>>>> +        (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>>>> +        (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>>>> +
>>>>> +    /* setup mmUVD_MPC_SET_MUX */
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
>>>>> +        ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>>>> +        (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>>>> +        (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>>>          vcn_v2_5_mc_resume(adev);
>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>> -        volatile struct amdgpu_fw_shared *fw_shared =
>>>>> adev->vcn.inst[i].fw_shared.cpu_addr;
>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>> -            continue;
>>>>> -        /* VCN global tiling registers */
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>>>> -            adev->gfx.config.gb_addr_config);
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>>>> -            adev->gfx.config.gb_addr_config);
>>>>> +    volatile struct amdgpu_fw_shared *fw_shared =
>>>>> adev->vcn.inst[inst].fw_shared.cpu_addr;
>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>> +        return 0;
>>>>> +
>>>>> +    /* VCN global tiling registers */
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>>>> +        adev->gfx.config.gb_addr_config);
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>>>> +        adev->gfx.config.gb_addr_config);
>>>>>    -        /* enable LMI MC and UMC channels */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
>>>>> -            ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>>> +    /* enable LMI MC and UMC channels */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
>>>>> +        ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>>>    -        /* unblock VCPU register access */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
>>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>> +    /* unblock VCPU register access */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
>>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>    -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>    -        for (k = 0; k < 10; ++k) {
>>>>> -            uint32_t status;
>>>>> -
>>>>> -            for (j = 0; j < 100; ++j) {
>>>>> -                status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
>>>>> -                if (status & 2)
>>>>> -                    break;
>>>>> -                if (amdgpu_emu_mode == 1)
>>>>> -                    msleep(500);
>>>>> -                else
>>>>> -                    mdelay(10);
>>>>> -            }
>>>>> -            r = 0;
>>>>> +    for (k = 0; k < 10; ++k) {
>>>>> +        uint32_t status;
>>>>> +
>>>>> +        for (j = 0; j < 100; ++j) {
>>>>> +            status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
>>>>>                if (status & 2)
>>>>>                    break;
>>>>> +            if (amdgpu_emu_mode == 1)
>>>>> +                msleep(500);
>>>>> +            else
>>>>> +                mdelay(10);
>>>>> +        }
>>>>> +        r = 0;
>>>>> +        if (status & 2)
>>>>> +            break;
>>>>>    -            DRM_ERROR("VCN decode not responding, trying to reset
>>>>> the VCPU!!!\n");
>>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>> -                UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>> -            mdelay(10);
>>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>> +        DRM_ERROR("VCN decode not responding, trying to reset the
>>>>> VCPU!!!\n");
>>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>> +            UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>> +        mdelay(10);
>>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>    -            mdelay(10);
>>>>> -            r = -1;
>>>>> -        }
>>>>> +        mdelay(10);
>>>>> +        r = -1;
>>>>> +    }
>>>>>    -        if (r) {
>>>>> -            DRM_ERROR("VCN decode not responding, giving up!!!\n");
>>>>> -            return r;
>>>>> -        }
>>>>> +    if (r) {
>>>>> +        DRM_ERROR("VCN decode not responding, giving up!!!\n");
>>>>> +        return r;
>>>>> +    }
>>>>>    -        /* enable master interrupt */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
>>>>> -            UVD_MASTINT_EN__VCPU_EN_MASK,
>>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>> +    /* enable master interrupt */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
>>>>> +        UVD_MASTINT_EN__VCPU_EN_MASK,
>>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>    -        /* clear the busy bit of VCN_STATUS */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
>>>>> -            ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>>> +    /* clear the busy bit of VCN_STATUS */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
>>>>> +        ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>>>    -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
>>>>>    -        ring = &adev->vcn.inst[i].ring_dec;
>>>>> -        /* force RBC into idle state */
>>>>> -        rb_bufsz = order_base_2(ring->ring_size);
>>>>> -        tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
>>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>>>> +    /* force RBC into idle state */
>>>>> +    rb_bufsz = order_base_2(ring->ring_size);
>>>>> +    tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
>>>>>    -        fw_shared->multi_queue.decode_queue_mode |=
>>>>> FW_QUEUE_RING_RESET;
>>>>> -        /* program the RB_BASE for ring buffer */
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>>>> -            lower_32_bits(ring->gpu_addr));
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>>>> -            upper_32_bits(ring->gpu_addr));
>>>>> +    fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
>>>>> +    /* program the RB_BASE for ring buffer */
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>>>> +        lower_32_bits(ring->gpu_addr));
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>>>> +        upper_32_bits(ring->gpu_addr));
>>>>>    -        /* Initialize the ring buffer's read and write pointers */
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
>>>>> +    /* Initialize the ring buffer's read and write pointers */
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
>>>>>    -        ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
>>>>> -                lower_32_bits(ring->wptr));
>>>>> -        fw_shared->multi_queue.decode_queue_mode &=
>>>>> ~FW_QUEUE_RING_RESET;
>>>>> +    ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
>>>>> +            lower_32_bits(ring->wptr));
>>>>> +    fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
>>>>>    -        fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>>>> FW_QUEUE_RING_RESET;
>>>>> -        ring = &adev->vcn.inst[i].ring_enc[0];
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI,
>>>>> upper_32_bits(ring->gpu_addr));
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
>>>>> -        fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>>>> ~FW_QUEUE_RING_RESET;
>>>>> -
>>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>>>> FW_QUEUE_RING_RESET;
>>>>> -        ring = &adev->vcn.inst[i].ring_enc[1];
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2,
>>>>> lower_32_bits(ring->wptr));
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2,
>>>>> lower_32_bits(ring->wptr));
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2,
>>>>> upper_32_bits(ring->gpu_addr));
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4);
>>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>>>> ~FW_QUEUE_RING_RESET;
>>>>> -    }
>>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>>>> FW_QUEUE_RING_RESET;
>>>>> +    ring = &adev->vcn.inst[inst].ring_enc[0];
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI,
>>>>> upper_32_bits(ring->gpu_addr));
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
>>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>>>> ~FW_QUEUE_RING_RESET;
>>>>> +
>>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>>>> FW_QUEUE_RING_RESET;
>>>>> +    ring = &adev->vcn.inst[inst].ring_enc[1];
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2,
>>>>> upper_32_bits(ring->gpu_addr));
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
>>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>>>> ~FW_QUEUE_RING_RESET;
>>>>>          return 0;
>>>>>    }
>>>>> @@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct
>>>>> amdgpu_device *adev, int inst_idx)
>>>>>        return 0;
>>>>>    }
>>>>>    -static int vcn_v2_5_stop(struct amdgpu_device *adev)
>>>>> +static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned int inst)
>>>>>    {
>>>>>        uint32_t tmp;
>>>>> -    int i, r = 0;
>>>>> +    int r = 0;
>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>> -            continue;
>>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>> -            r = vcn_v2_5_stop_dpg_mode(adev, i);
>>>>> -            continue;
>>>>> -        }
>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>> +        goto done;
>>>>>    -        /* wait for vcn idle */
>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS,
>>>>> UVD_STATUS__IDLE, 0x7);
>>>>> -        if (r)
>>>>> -            return r;
>>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>> +        r = vcn_v2_5_stop_dpg_mode(adev, inst);
>>>>> +        goto done;
>>>>> +    }
>>>>>    -        tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>>>> -            UVD_LMI_STATUS__READ_CLEAN_MASK |
>>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
>>>>> -        if (r)
>>>>> -            return r;
>>>>> +    /* wait for vcn idle */
>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS,
>>>>> UVD_STATUS__IDLE, 0x7);
>>>>> +    if (r)
>>>>> +        return r;
>>>>>    -        /* block LMI UMC channel */
>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
>>>>> -        tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
>>>>> +    tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>>>> +        UVD_LMI_STATUS__READ_CLEAN_MASK |
>>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
>>>>> +    if (r)
>>>>> +        return r;
>>>>>    -        tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>>>> -            UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
>>>>> -        if (r)
>>>>> -            return r;
>>>>> +    /* block LMI UMC channel */
>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
>>>>> +    tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
>>>>>    -        /* block VCPU register access */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
>>>>> -            UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>> +    tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>>>> +        UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
>>>>> +    if (r)
>>>>> +        return r;
>>>>>    -        /* reset VCPU */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>> -            UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>> +    /* block VCPU register access */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
>>>>> +        UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>    -        /* disable VCPU clock */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>> -            ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>>> +    /* reset VCPU */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>> +        UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>    -        /* clear status */
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
>>>>> +    /* disable VCPU clock */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>> +        ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>>>    -        vcn_v2_5_enable_clock_gating(adev);
>>>>> +    /* clear status */
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
>>>>>    -        /* enable register anti-hang mechanism */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
>>>>> -            UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>> -    }
>>>>> +    vcn_v2_5_enable_clock_gating(adev);
>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>> -        if (adev->pm.dpm_enabled)
>>>>> -            amdgpu_dpm_enable_vcn(adev, false, i);
>>>>> -    }
>>>>> +    /* enable register anti-hang mechanism */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
>>>>> +        UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>> +done:
>>>>> +    if (adev->pm.dpm_enabled)
>>>>> +        amdgpu_dpm_enable_vcn(adev, false, inst);
>>>>>          return 0;
>>>>>    }
>>>>> @@ -1838,9 +1827,9 @@ static int
>>>>> vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
>>>>>            return 0;
>>>>>          if (state == AMD_PG_STATE_GATE)
>>>>> -        ret = vcn_v2_5_stop(adev);
>>>>> +        ret = vcn_v2_5_stop(adev, inst);
>>>>>        else
>>>>> -        ret = vcn_v2_5_start(adev);
>>>>> +        ret = vcn_v2_5_start(adev, inst);
>>>>>          if (!ret)
>>>>>            adev->vcn.cur_state[inst] = state;


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-07 14:17         ` Alex Deucher
  2024-10-07 14:29           ` Christian König
@ 2024-10-07 14:32           ` Lazar, Lijo
  2024-10-07 15:24             ` Alex Deucher
  1 sibling, 1 reply; 37+ messages in thread
From: Lazar, Lijo @ 2024-10-07 14:32 UTC (permalink / raw)
  To: Alex Deucher
  Cc: Boyuan Zhang, amd-gfx, leo.liu, christian.koenig,
	alexander.deucher, sunil.khatri



On 10/7/2024 7:47 PM, Alex Deucher wrote:
> On Mon, Oct 7, 2024 at 9:58 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>>
>>
>>
>> On 10/7/2024 7:03 PM, Boyuan Zhang wrote:
>>>
>>> On 2024-10-07 01:22, Lazar, Lijo wrote:
>>>>
>>>> On 10/5/2024 12:14 AM, boyuan.zhang@amd.com wrote:
>>>>> From: Boyuan Zhang <boyuan.zhang@amd.com>
>>>>>
>>>>> For vcn 2_5, add ip_block for each vcn instance during discovery stage.
>>>>>
>>>>> And only powering on/off one of the vcn instance using the
>>>>> instance value stored in ip_block, instead of powering on/off all
>>>>> vcn instances. Modify the existing functions to use the instance value
>>>>> in ip_block, and remove the original for loop for all vcn instances.
>>>>>
>>>>> v2: rename "i"/"j" to "inst" for instance value.
>>>>>
>>>>> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
>>>>> ---
>>>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
>>>>>   drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565 +++++++++---------
>>>>>   2 files changed, 280 insertions(+), 289 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>> index 9f9a1867da72..de1053cc2a2b 100644
>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>> @@ -2278,6 +2278,7 @@ static int
>>>>> amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
>>>>>     static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device
>>>>> *adev)
>>>>>   {
>>>>> +    int i;
>>>>>       if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
>>>>>           switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
>>>>>           case IP_VERSION(7, 0, 0):
>>>>> @@ -2321,7 +2322,8 @@ static int
>>>>> amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>>>>>           case IP_VERSION(2, 0, 3):
>>>>>               break;
>>>>>           case IP_VERSION(2, 5, 0):
>>>>> -            amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>>>>> +            for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
>>>>> +                amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>>>>
>>>> This introduces a totally confusing design now. At a higher level an IP
>>>> block type manages multiple instances and their power states. Now there
>>>> is a mix where no definition can be attributed to an IP block. Or, if
>>>> this were to be done uniformly for other IPs, then for some SOCs there
>>>> could be 16 SDMA blocks, 8 GFX blocks and so forth.
>>>>
>>>> What is the reason to do this way? Can't VCN IP block maintain the state
>>>> of multiple instances within itself?
>>>>
>>>> Thanks,
>>>> Lijo
>>> This is part of the fundamental design change for separating IP block
>>> per instance, in order to
>>> handle each instance separately within same IP block (e.g. separate
>>> power/clock management).
>>>
>>> Part 1, Change all adev ptr handle to amdgpu_ip_block ptr in all
>>> callbacks (hw_init/fini, sw_init/fini,
>>> suspend, etc...) for all IP blocks, so that each IP knows which IP_block
>>> (and which instance) the
>>> callback is for. Most parts of this changes have been submitted by Sunil.
>>>
>>> Part 2, Separate IP block per instance.
>>>
>>> Part 3, Since callbacks can pass in IP_block now after Part 1 change and
>>> instance value can be
>>> obtained from each IP block in Part 2, IP can then choose to handle
>>> callbacks ONLY for the given
>>> instance of a given IP block (or still handling for all instances as
>>> before).
>>> For VCN, all callbacks will be handled only for the given one instance,
>>> instead of the original for-
>>> loop for all instance. As a result, each VCN instance can be
>>> start/stop/int/fini/suspend separately.
>>>
>>> Part 4, Change all VCN helper functions to handle only the given
>>> instance, instead of the original
>>> for-loop for all instance.
>>>
>>> Each instance can have its own states, so we think it makes more sense
>>> to separate them on IP
>>> block level to handle each of them separately.
>>
>>
>> Such a change should not be done unless all IPs follow the same design.
>> You didn't answer the question - what necessitates this change? What is
>> special about VCN that it cannot manage the states of multiple instances
>> within the IP block?
> 
> We want to be able to manage the powergating independently for each
> VCN instance for both power management and VCN reset.  Right now power
> gating is handled at the IP level so it's not easy or clean to handle
> powergating of individual IP instances.
> 

Still VCN block can manage the powergated instances (FWIW, it's just an
array in SMU block). Also vcn block gets to run the idle worker and
knows the rings (and corresponding VCN instances) that are idle.
Maintaining instance states in VCN block and modifying idle worker to
just idle that instance alone doesn't look like a complex change.

Moving to IP block per instance for VCN alone is not a change that helps
to define an IP block. If that needs to be done for every other IP type,
that's also a massive change.

Also, then it's no longer possible to have something static like this -
 	struct amdgpu_ip_block          ip_blocks[AMDGPU_MAX_IP_NUM];


Thanks,
Lijo

> Alex
> 
>>
>> Thanks,
>> Lijo
>>
>>>
>>> Thanks,
>>> Boyuan
>>>>
>>>>>               amdgpu_device_ip_block_add(adev, &jpeg_v2_5_ip_block);
>>>>>               break;
>>>>>           case IP_VERSION(2, 6, 0):
>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>> b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>> index d00df51bc400..1f8738ae360a 100644
>>>>> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>> @@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct
>>>>> amdgpu_ip_block *ip_block)
>>>>>   static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>>>>>   {
>>>>>       struct amdgpu_ring *ring;
>>>>> -    int i, j, r;
>>>>> +    int i, r;
>>>>>       uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
>>>>>       uint32_t *ptr;
>>>>>       struct amdgpu_device *adev = ip_block->adev;
>>>>> +    int inst = ip_block->instance;
>>>>>   -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>>>> -        if (adev->vcn.harvest_config & (1 << j))
>>>>> -            continue;
>>>>> -        /* VCN DEC TRAP */
>>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>> -                VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>>>> &adev->vcn.inst[j].irq);
>>>>> -        if (r)
>>>>> -            return r;
>>>>> -
>>>>> -        /* VCN ENC TRAP */
>>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>> -            r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>> -                i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>>>> &adev->vcn.inst[j].irq);
>>>>> -            if (r)
>>>>> -                return r;
>>>>> -        }
>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>> +        goto sw_init;
>>>>> +    /* VCN DEC TRAP */
>>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>> +            VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>>>> &adev->vcn.inst[inst].irq);
>>>>> +    if (r)
>>>>> +        return r;
>>>>>   -        /* VCN POISON TRAP */
>>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>> -            VCN_2_6__SRCID_UVD_POISON,
>>>>> &adev->vcn.inst[j].ras_poison_irq);
>>>>> +    /* VCN ENC TRAP */
>>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>> +        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>> +            i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>>>> &adev->vcn.inst[inst].irq);
>>>>>           if (r)
>>>>>               return r;
>>>>>       }
>>>>>   +    /* VCN POISON TRAP */
>>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>> +        VCN_2_6__SRCID_UVD_POISON,
>>>>> &adev->vcn.inst[inst].ras_poison_irq);
>>>>> +    if (r)
>>>>> +        return r;
>>>>> +sw_init:
>>>>>       r = amdgpu_vcn_sw_init(adev);
>>>>>       if (r)
>>>>>           return r;
>>>>> @@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct
>>>>> amdgpu_ip_block *ip_block)
>>>>>       if (r)
>>>>>           return r;
>>>>>   -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>>>> -        volatile struct amdgpu_fw_shared *fw_shared;
>>>>> +    volatile struct amdgpu_fw_shared *fw_shared;
>>>>>   -        if (adev->vcn.harvest_config & (1 << j))
>>>>> -            continue;
>>>>> -        adev->vcn.internal.context_id =
>>>>> mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>>>> -        adev->vcn.internal.ib_vmid =
>>>>> mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>>>> -        adev->vcn.internal.ib_bar_low =
>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>>>> -        adev->vcn.internal.ib_bar_high =
>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>>>> -        adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>>>> -        adev->vcn.internal.gp_scratch8 =
>>>>> mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>>>> -
>>>>> -        adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>>>> -        adev->vcn.inst[j].external.scratch9 = SOC15_REG_OFFSET(VCN,
>>>>> j, mmUVD_SCRATCH9);
>>>>> -        adev->vcn.internal.data0 =
>>>>> mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>>>> -        adev->vcn.inst[j].external.data0 = SOC15_REG_OFFSET(VCN, j,
>>>>> mmUVD_GPCOM_VCPU_DATA0);
>>>>> -        adev->vcn.internal.data1 =
>>>>> mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>>>> -        adev->vcn.inst[j].external.data1 = SOC15_REG_OFFSET(VCN, j,
>>>>> mmUVD_GPCOM_VCPU_DATA1);
>>>>> -        adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>>>> -        adev->vcn.inst[j].external.cmd = SOC15_REG_OFFSET(VCN, j,
>>>>> mmUVD_GPCOM_VCPU_CMD);
>>>>> -        adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>>>> -        adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(VCN, j,
>>>>> mmUVD_NO_OP);
>>>>> -
>>>>> -        ring = &adev->vcn.inst[j].ring_dec;
>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>> +        goto done;
>>>>> +    adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>>>> +    adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>>>> +    adev->vcn.internal.ib_bar_low =
>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>>>> +    adev->vcn.internal.ib_bar_high =
>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>>>> +    adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>>>> +    adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>>>> +
>>>>> +    adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>>>> +    adev->vcn.inst[inst].external.scratch9 = SOC15_REG_OFFSET(VCN,
>>>>> inst, mmUVD_SCRATCH9);
>>>>> +    adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>>>> +    adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN,
>>>>> inst, mmUVD_GPCOM_VCPU_DATA0);
>>>>> +    adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>>>> +    adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN,
>>>>> inst, mmUVD_GPCOM_VCPU_DATA1);
>>>>> +    adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>>>> +    adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN, inst,
>>>>> mmUVD_GPCOM_VCPU_CMD);
>>>>> +    adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>>>> +    adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN, inst,
>>>>> mmUVD_NO_OP);
>>>>> +
>>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>>>> +    ring->use_doorbell = true;
>>>>> +
>>>>> +    ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 <<
>>>>> 1) +
>>>>> +            (amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
>>>>> +
>>>>> +    if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
>>>>> +        ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>> +    else
>>>>> +        ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>> +
>>>>> +    sprintf(ring->name, "vcn_dec_%d", inst);
>>>>> +    r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq,
>>>>> +                 0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>>>> +    if (r)
>>>>> +        return r;
>>>>> +
>>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>> +        enum amdgpu_ring_priority_level hw_prio =
>>>>> amdgpu_vcn_get_enc_ring_prio(i);
>>>>> +
>>>>> +        ring = &adev->vcn.inst[inst].ring_enc[i];
>>>>>           ring->use_doorbell = true;
>>>>>             ring->doorbell_index =
>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>>>> -                (amdgpu_sriov_vf(adev) ? 2*j : 8*j);
>>>>> +                (amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2 + i +
>>>>> 8*inst));
>>>>>   -        if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2,
>>>>> 5, 0))
>>>>> +        if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>> +            IP_VERSION(2, 5, 0))
>>>>>               ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>           else
>>>>>               ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>   -        sprintf(ring->name, "vcn_dec_%d", j);
>>>>> -        r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq,
>>>>> -                     0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>>>> +        sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
>>>>> +        r = amdgpu_ring_init(adev, ring, 512,
>>>>> +                     &adev->vcn.inst[inst].irq, 0,
>>>>> +                     hw_prio, NULL);
>>>>>           if (r)
>>>>>               return r;
>>>>> -
>>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>> -            enum amdgpu_ring_priority_level hw_prio =
>>>>> amdgpu_vcn_get_enc_ring_prio(i);
>>>>> -
>>>>> -            ring = &adev->vcn.inst[j].ring_enc[i];
>>>>> -            ring->use_doorbell = true;
>>>>> -
>>>>> -            ring->doorbell_index =
>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>>>> -                    (amdgpu_sriov_vf(adev) ? (1 + i + 2*j) : (2 + i
>>>>> + 8*j));
>>>>> -
>>>>> -            if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>> -                IP_VERSION(2, 5, 0))
>>>>> -                ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>> -            else
>>>>> -                ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>> -
>>>>> -            sprintf(ring->name, "vcn_enc_%d.%d", j, i);
>>>>> -            r = amdgpu_ring_init(adev, ring, 512,
>>>>> -                         &adev->vcn.inst[j].irq, 0,
>>>>> -                         hw_prio, NULL);
>>>>> -            if (r)
>>>>> -                return r;
>>>>> -        }
>>>>> -
>>>>> -        fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
>>>>> -        fw_shared->present_flag_0 =
>>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>>>> -
>>>>> -        if (amdgpu_vcnfw_log)
>>>>> -            amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>>>       }
>>>>>   +    fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
>>>>> +    fw_shared->present_flag_0 =
>>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>>>> +
>>>>> +    if (amdgpu_vcnfw_log)
>>>>> +        amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>>> +done:
>>>>>       if (amdgpu_sriov_vf(adev)) {
>>>>>           r = amdgpu_virt_alloc_mm_table(adev);
>>>>>           if (r)
>>>>> @@ -1005,197 +1002,192 @@ static int vcn_v2_5_start_dpg_mode(struct
>>>>> amdgpu_device *adev, int inst_idx, boo
>>>>>       return 0;
>>>>>   }
>>>>>   -static int vcn_v2_5_start(struct amdgpu_device *adev)
>>>>> +static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned int
>>>>> inst)
>>>>>   {
>>>>>       struct amdgpu_ring *ring;
>>>>>       uint32_t rb_bufsz, tmp;
>>>>> -    int i, j, k, r;
>>>>> +    int j, k, r;
>>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>> -        if (adev->pm.dpm_enabled)
>>>>> -            amdgpu_dpm_enable_vcn(adev, true, i);
>>>>> -    }
>>>>> -
>>>>> -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>> -            continue;
>>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>> -            r = vcn_v2_5_start_dpg_mode(adev, i,
>>>>> adev->vcn.indirect_sram);
>>>>> -            continue;
>>>>> -        }
>>>>> +    if (adev->pm.dpm_enabled)
>>>>> +        amdgpu_dpm_enable_vcn(adev, true, inst);
>>>>>   -        /* disable register anti-hang mechanism */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS), 0,
>>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>> +        return 0;
>>>>>   -        /* set uvd status busy */
>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) |
>>>>> UVD_STATUS__UVD_BUSY;
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
>>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>> +        r = vcn_v2_5_start_dpg_mode(adev, inst,
>>>>> adev->vcn.indirect_sram);
>>>>> +        return r;
>>>>>       }
>>>>>   +    /* disable register anti-hang mechanism */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS), 0,
>>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>> +
>>>>> +    /* set uvd status busy */
>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
>>>>> +
>>>>>       if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
>>>>>           return 0;
>>>>>         /*SW clock gating */
>>>>>       vcn_v2_5_disable_clock_gating(adev);
>>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>> -            continue;
>>>>> -        /* enable VCPU clock */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>> -            UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>>>> -
>>>>> -        /* disable master interrupt */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
>>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>> -
>>>>> -        /* setup mmUVD_LMI_CTRL */
>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
>>>>> -        tmp &= ~0xff;
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
>>>>> -            UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>>>> -            UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>>>> -            UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>>>> -            UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>>>> -
>>>>> -        /* setup mmUVD_MPC_CNTL */
>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
>>>>> -        tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>>>> -        tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
>>>>> -
>>>>> -        /* setup UVD_MPC_SET_MUXA0 */
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
>>>>> -            ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>>>> -            (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>>>> -            (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>>>> -            (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>>>> -
>>>>> -        /* setup UVD_MPC_SET_MUXB0 */
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
>>>>> -            ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>>>> -            (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>>>> -            (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>>>> -            (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>>>> -
>>>>> -        /* setup mmUVD_MPC_SET_MUX */
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
>>>>> -            ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>>>> -            (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>>>> -            (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>>> -    }
>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>> +        return 0;
>>>>> +
>>>>> +    /* enable VCPU clock */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>> +        UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>>>> +
>>>>> +    /* disable master interrupt */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
>>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>> +
>>>>> +    /* setup mmUVD_LMI_CTRL */
>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
>>>>> +    tmp &= ~0xff;
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
>>>>> +        UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>>>> +        UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>>>> +        UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>>>> +        UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>>>> +
>>>>> +    /* setup mmUVD_MPC_CNTL */
>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
>>>>> +    tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>>>> +    tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
>>>>> +
>>>>> +    /* setup UVD_MPC_SET_MUXA0 */
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
>>>>> +        ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>>>> +        (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>>>> +        (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>>>> +        (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>>>> +
>>>>> +    /* setup UVD_MPC_SET_MUXB0 */
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
>>>>> +        ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>>>> +        (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>>>> +        (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>>>> +        (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>>>> +
>>>>> +    /* setup mmUVD_MPC_SET_MUX */
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
>>>>> +        ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>>>> +        (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>>>> +        (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>>>         vcn_v2_5_mc_resume(adev);
>>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>> -        volatile struct amdgpu_fw_shared *fw_shared =
>>>>> adev->vcn.inst[i].fw_shared.cpu_addr;
>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>> -            continue;
>>>>> -        /* VCN global tiling registers */
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>>>> -            adev->gfx.config.gb_addr_config);
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>>>> -            adev->gfx.config.gb_addr_config);
>>>>> +    volatile struct amdgpu_fw_shared *fw_shared =
>>>>> adev->vcn.inst[inst].fw_shared.cpu_addr;
>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>> +        return 0;
>>>>> +
>>>>> +    /* VCN global tiling registers */
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>>>> +        adev->gfx.config.gb_addr_config);
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>>>> +        adev->gfx.config.gb_addr_config);
>>>>>   -        /* enable LMI MC and UMC channels */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
>>>>> -            ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>>> +    /* enable LMI MC and UMC channels */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
>>>>> +        ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>>>   -        /* unblock VCPU register access */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
>>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>> +    /* unblock VCPU register access */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
>>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>   -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>   -        for (k = 0; k < 10; ++k) {
>>>>> -            uint32_t status;
>>>>> -
>>>>> -            for (j = 0; j < 100; ++j) {
>>>>> -                status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
>>>>> -                if (status & 2)
>>>>> -                    break;
>>>>> -                if (amdgpu_emu_mode == 1)
>>>>> -                    msleep(500);
>>>>> -                else
>>>>> -                    mdelay(10);
>>>>> -            }
>>>>> -            r = 0;
>>>>> +    for (k = 0; k < 10; ++k) {
>>>>> +        uint32_t status;
>>>>> +
>>>>> +        for (j = 0; j < 100; ++j) {
>>>>> +            status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
>>>>>               if (status & 2)
>>>>>                   break;
>>>>> +            if (amdgpu_emu_mode == 1)
>>>>> +                msleep(500);
>>>>> +            else
>>>>> +                mdelay(10);
>>>>> +        }
>>>>> +        r = 0;
>>>>> +        if (status & 2)
>>>>> +            break;
>>>>>   -            DRM_ERROR("VCN decode not responding, trying to reset
>>>>> the VCPU!!!\n");
>>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>> -                UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>> -            mdelay(10);
>>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>> +        DRM_ERROR("VCN decode not responding, trying to reset the
>>>>> VCPU!!!\n");
>>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>> +            UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>> +        mdelay(10);
>>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>   -            mdelay(10);
>>>>> -            r = -1;
>>>>> -        }
>>>>> +        mdelay(10);
>>>>> +        r = -1;
>>>>> +    }
>>>>>   -        if (r) {
>>>>> -            DRM_ERROR("VCN decode not responding, giving up!!!\n");
>>>>> -            return r;
>>>>> -        }
>>>>> +    if (r) {
>>>>> +        DRM_ERROR("VCN decode not responding, giving up!!!\n");
>>>>> +        return r;
>>>>> +    }
>>>>>   -        /* enable master interrupt */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
>>>>> -            UVD_MASTINT_EN__VCPU_EN_MASK,
>>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>> +    /* enable master interrupt */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
>>>>> +        UVD_MASTINT_EN__VCPU_EN_MASK,
>>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>   -        /* clear the busy bit of VCN_STATUS */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
>>>>> -            ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>>> +    /* clear the busy bit of VCN_STATUS */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
>>>>> +        ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>>>   -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
>>>>>   -        ring = &adev->vcn.inst[i].ring_dec;
>>>>> -        /* force RBC into idle state */
>>>>> -        rb_bufsz = order_base_2(ring->ring_size);
>>>>> -        tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
>>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>>>> +    /* force RBC into idle state */
>>>>> +    rb_bufsz = order_base_2(ring->ring_size);
>>>>> +    tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
>>>>>   -        fw_shared->multi_queue.decode_queue_mode |=
>>>>> FW_QUEUE_RING_RESET;
>>>>> -        /* program the RB_BASE for ring buffer */
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>>>> -            lower_32_bits(ring->gpu_addr));
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>>>> -            upper_32_bits(ring->gpu_addr));
>>>>> +    fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
>>>>> +    /* program the RB_BASE for ring buffer */
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>>>> +        lower_32_bits(ring->gpu_addr));
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>>>> +        upper_32_bits(ring->gpu_addr));
>>>>>   -        /* Initialize the ring buffer's read and write pointers */
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
>>>>> +    /* Initialize the ring buffer's read and write pointers */
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
>>>>>   -        ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
>>>>> -                lower_32_bits(ring->wptr));
>>>>> -        fw_shared->multi_queue.decode_queue_mode &=
>>>>> ~FW_QUEUE_RING_RESET;
>>>>> +    ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
>>>>> +            lower_32_bits(ring->wptr));
>>>>> +    fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
>>>>>   -        fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>>>> FW_QUEUE_RING_RESET;
>>>>> -        ring = &adev->vcn.inst[i].ring_enc[0];
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI,
>>>>> upper_32_bits(ring->gpu_addr));
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
>>>>> -        fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>>>> ~FW_QUEUE_RING_RESET;
>>>>> -
>>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>>>> FW_QUEUE_RING_RESET;
>>>>> -        ring = &adev->vcn.inst[i].ring_enc[1];
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2,
>>>>> lower_32_bits(ring->wptr));
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2,
>>>>> lower_32_bits(ring->wptr));
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2,
>>>>> upper_32_bits(ring->gpu_addr));
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4);
>>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>>>> ~FW_QUEUE_RING_RESET;
>>>>> -    }
>>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>>>> FW_QUEUE_RING_RESET;
>>>>> +    ring = &adev->vcn.inst[inst].ring_enc[0];
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI,
>>>>> upper_32_bits(ring->gpu_addr));
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
>>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>>>> ~FW_QUEUE_RING_RESET;
>>>>> +
>>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>>>> FW_QUEUE_RING_RESET;
>>>>> +    ring = &adev->vcn.inst[inst].ring_enc[1];
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2,
>>>>> upper_32_bits(ring->gpu_addr));
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
>>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>>>> ~FW_QUEUE_RING_RESET;
>>>>>         return 0;
>>>>>   }
>>>>> @@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct
>>>>> amdgpu_device *adev, int inst_idx)
>>>>>       return 0;
>>>>>   }
>>>>>   -static int vcn_v2_5_stop(struct amdgpu_device *adev)
>>>>> +static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned int inst)
>>>>>   {
>>>>>       uint32_t tmp;
>>>>> -    int i, r = 0;
>>>>> +    int r = 0;
>>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>> -            continue;
>>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>> -            r = vcn_v2_5_stop_dpg_mode(adev, i);
>>>>> -            continue;
>>>>> -        }
>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>> +        goto done;
>>>>>   -        /* wait for vcn idle */
>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS,
>>>>> UVD_STATUS__IDLE, 0x7);
>>>>> -        if (r)
>>>>> -            return r;
>>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>> +        r = vcn_v2_5_stop_dpg_mode(adev, inst);
>>>>> +        goto done;
>>>>> +    }
>>>>>   -        tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>>>> -            UVD_LMI_STATUS__READ_CLEAN_MASK |
>>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
>>>>> -        if (r)
>>>>> -            return r;
>>>>> +    /* wait for vcn idle */
>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS,
>>>>> UVD_STATUS__IDLE, 0x7);
>>>>> +    if (r)
>>>>> +        return r;
>>>>>   -        /* block LMI UMC channel */
>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
>>>>> -        tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
>>>>> +    tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>>>> +        UVD_LMI_STATUS__READ_CLEAN_MASK |
>>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
>>>>> +    if (r)
>>>>> +        return r;
>>>>>   -        tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>>>> -            UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
>>>>> -        if (r)
>>>>> -            return r;
>>>>> +    /* block LMI UMC channel */
>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
>>>>> +    tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
>>>>>   -        /* block VCPU register access */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
>>>>> -            UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>> +    tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>>>> +        UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
>>>>> +    if (r)
>>>>> +        return r;
>>>>>   -        /* reset VCPU */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>> -            UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>> +    /* block VCPU register access */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
>>>>> +        UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>   -        /* disable VCPU clock */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>> -            ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>>> +    /* reset VCPU */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>> +        UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>   -        /* clear status */
>>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
>>>>> +    /* disable VCPU clock */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>> +        ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>>>   -        vcn_v2_5_enable_clock_gating(adev);
>>>>> +    /* clear status */
>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
>>>>>   -        /* enable register anti-hang mechanism */
>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
>>>>> -            UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>> -    }
>>>>> +    vcn_v2_5_enable_clock_gating(adev);
>>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>> -        if (adev->pm.dpm_enabled)
>>>>> -            amdgpu_dpm_enable_vcn(adev, false, i);
>>>>> -    }
>>>>> +    /* enable register anti-hang mechanism */
>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
>>>>> +        UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>> +done:
>>>>> +    if (adev->pm.dpm_enabled)
>>>>> +        amdgpu_dpm_enable_vcn(adev, false, inst);
>>>>>         return 0;
>>>>>   }
>>>>> @@ -1838,9 +1827,9 @@ static int
>>>>> vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
>>>>>           return 0;
>>>>>         if (state == AMD_PG_STATE_GATE)
>>>>> -        ret = vcn_v2_5_stop(adev);
>>>>> +        ret = vcn_v2_5_stop(adev, inst);
>>>>>       else
>>>>> -        ret = vcn_v2_5_start(adev);
>>>>> +        ret = vcn_v2_5_start(adev, inst);
>>>>>         if (!ret)
>>>>>           adev->vcn.cur_state[inst] = state;

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-07 14:32           ` Lazar, Lijo
@ 2024-10-07 15:24             ` Alex Deucher
  2024-10-08  7:03               ` Lazar, Lijo
  0 siblings, 1 reply; 37+ messages in thread
From: Alex Deucher @ 2024-10-07 15:24 UTC (permalink / raw)
  To: Lazar, Lijo
  Cc: Boyuan Zhang, amd-gfx, leo.liu, christian.koenig,
	alexander.deucher, sunil.khatri

On Mon, Oct 7, 2024 at 10:32 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>
>
>
> On 10/7/2024 7:47 PM, Alex Deucher wrote:
> > On Mon, Oct 7, 2024 at 9:58 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
> >>
> >>
> >>
> >> On 10/7/2024 7:03 PM, Boyuan Zhang wrote:
> >>>
> >>> On 2024-10-07 01:22, Lazar, Lijo wrote:
> >>>>
> >>>> On 10/5/2024 12:14 AM, boyuan.zhang@amd.com wrote:
> >>>>> From: Boyuan Zhang <boyuan.zhang@amd.com>
> >>>>>
> >>>>> For vcn 2_5, add ip_block for each vcn instance during discovery stage.
> >>>>>
> >>>>> And only powering on/off one of the vcn instance using the
> >>>>> instance value stored in ip_block, instead of powering on/off all
> >>>>> vcn instances. Modify the existing functions to use the instance value
> >>>>> in ip_block, and remove the original for loop for all vcn instances.
> >>>>>
> >>>>> v2: rename "i"/"j" to "inst" for instance value.
> >>>>>
> >>>>> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
> >>>>> ---
> >>>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
> >>>>>   drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565 +++++++++---------
> >>>>>   2 files changed, 280 insertions(+), 289 deletions(-)
> >>>>>
> >>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
> >>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
> >>>>> index 9f9a1867da72..de1053cc2a2b 100644
> >>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
> >>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
> >>>>> @@ -2278,6 +2278,7 @@ static int
> >>>>> amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
> >>>>>     static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device
> >>>>> *adev)
> >>>>>   {
> >>>>> +    int i;
> >>>>>       if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
> >>>>>           switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
> >>>>>           case IP_VERSION(7, 0, 0):
> >>>>> @@ -2321,7 +2322,8 @@ static int
> >>>>> amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
> >>>>>           case IP_VERSION(2, 0, 3):
> >>>>>               break;
> >>>>>           case IP_VERSION(2, 5, 0):
> >>>>> -            amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
> >>>>> +            for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
> >>>>> +                amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
> >>>>
> >>>> This introduces a totally confusing design now. At a higher level an IP
> >>>> block type manages multiple instances and their power states. Now there
> >>>> is a mix where no definition can be attributed to an IP block. Or, if
> >>>> this were to be done uniformly for other IPs, then for some SOCs there
> >>>> could be 16 SDMA blocks, 8 GFX blocks and so forth.
> >>>>
> >>>> What is the reason to do this way? Can't VCN IP block maintain the state
> >>>> of multiple instances within itself?
> >>>>
> >>>> Thanks,
> >>>> Lijo
> >>> This is part of the fundamental design change for separating IP block
> >>> per instance, in order to
> >>> handle each instance separately within same IP block (e.g. separate
> >>> power/clock management).
> >>>
> >>> Part 1, Change all adev ptr handle to amdgpu_ip_block ptr in all
> >>> callbacks (hw_init/fini, sw_init/fini,
> >>> suspend, etc...) for all IP blocks, so that each IP knows which IP_block
> >>> (and which instance) the
> >>> callback is for. Most parts of this changes have been submitted by Sunil.
> >>>
> >>> Part 2, Separate IP block per instance.
> >>>
> >>> Part 3, Since callbacks can pass in IP_block now after Part 1 change and
> >>> instance value can be
> >>> obtained from each IP block in Part 2, IP can then choose to handle
> >>> callbacks ONLY for the given
> >>> instance of a given IP block (or still handling for all instances as
> >>> before).
> >>> For VCN, all callbacks will be handled only for the given one instance,
> >>> instead of the original for-
> >>> loop for all instance. As a result, each VCN instance can be
> >>> start/stop/int/fini/suspend separately.
> >>>
> >>> Part 4, Change all VCN helper functions to handle only the given
> >>> instance, instead of the original
> >>> for-loop for all instance.
> >>>
> >>> Each instance can have its own states, so we think it makes more sense
> >>> to separate them on IP
> >>> block level to handle each of them separately.
> >>
> >>
> >> Such a change should not be done unless all IPs follow the same design.
> >> You didn't answer the question - what necessitates this change? What is
> >> special about VCN that it cannot manage the states of multiple instances
> >> within the IP block?
> >
> > We want to be able to manage the powergating independently for each
> > VCN instance for both power management and VCN reset.  Right now power
> > gating is handled at the IP level so it's not easy or clean to handle
> > powergating of individual IP instances.
> >
>
> Still VCN block can manage the powergated instances (FWIW, it's just an
> array in SMU block). Also vcn block gets to run the idle worker and
> knows the rings (and corresponding VCN instances) that are idle.
> Maintaining instance states in VCN block and modifying idle worker to
> just idle that instance alone doesn't look like a complex change.


We already went down that road and it's really ugly.  We end up
duplicating a bunch of code paths for different driver flows because
set_powergating_state() and set_clockgating_state are at the IP level
and we want per instance gating.  We could add a num_instances member
at the IP block level and then convert all of the high level code that
calls the IP functions loop over the number of instances, but that
seems like just as much work and it's not quite as clean IMHO.

Alex

>
> Moving to IP block per instance for VCN alone is not a change that helps
> to define an IP block. If that needs to be done for every other IP type,
> that's also a massive change.
>
> Also, then it's no longer possible to have something static like this -
>         struct amdgpu_ip_block          ip_blocks[AMDGPU_MAX_IP_NUM];
>
>
> Thanks,
> Lijo
>
> > Alex
> >
> >>
> >> Thanks,
> >> Lijo
> >>
> >>>
> >>> Thanks,
> >>> Boyuan
> >>>>
> >>>>>               amdgpu_device_ip_block_add(adev, &jpeg_v2_5_ip_block);
> >>>>>               break;
> >>>>>           case IP_VERSION(2, 6, 0):
> >>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
> >>>>> b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
> >>>>> index d00df51bc400..1f8738ae360a 100644
> >>>>> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
> >>>>> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
> >>>>> @@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct
> >>>>> amdgpu_ip_block *ip_block)
> >>>>>   static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
> >>>>>   {
> >>>>>       struct amdgpu_ring *ring;
> >>>>> -    int i, j, r;
> >>>>> +    int i, r;
> >>>>>       uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
> >>>>>       uint32_t *ptr;
> >>>>>       struct amdgpu_device *adev = ip_block->adev;
> >>>>> +    int inst = ip_block->instance;
> >>>>>   -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
> >>>>> -        if (adev->vcn.harvest_config & (1 << j))
> >>>>> -            continue;
> >>>>> -        /* VCN DEC TRAP */
> >>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
> >>>>> -                VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
> >>>>> &adev->vcn.inst[j].irq);
> >>>>> -        if (r)
> >>>>> -            return r;
> >>>>> -
> >>>>> -        /* VCN ENC TRAP */
> >>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> >>>>> -            r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
> >>>>> -                i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
> >>>>> &adev->vcn.inst[j].irq);
> >>>>> -            if (r)
> >>>>> -                return r;
> >>>>> -        }
> >>>>> +    if (adev->vcn.harvest_config & (1 << inst))
> >>>>> +        goto sw_init;
> >>>>> +    /* VCN DEC TRAP */
> >>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
> >>>>> +            VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
> >>>>> &adev->vcn.inst[inst].irq);
> >>>>> +    if (r)
> >>>>> +        return r;
> >>>>>   -        /* VCN POISON TRAP */
> >>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
> >>>>> -            VCN_2_6__SRCID_UVD_POISON,
> >>>>> &adev->vcn.inst[j].ras_poison_irq);
> >>>>> +    /* VCN ENC TRAP */
> >>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> >>>>> +        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
> >>>>> +            i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
> >>>>> &adev->vcn.inst[inst].irq);
> >>>>>           if (r)
> >>>>>               return r;
> >>>>>       }
> >>>>>   +    /* VCN POISON TRAP */
> >>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
> >>>>> +        VCN_2_6__SRCID_UVD_POISON,
> >>>>> &adev->vcn.inst[inst].ras_poison_irq);
> >>>>> +    if (r)
> >>>>> +        return r;
> >>>>> +sw_init:
> >>>>>       r = amdgpu_vcn_sw_init(adev);
> >>>>>       if (r)
> >>>>>           return r;
> >>>>> @@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct
> >>>>> amdgpu_ip_block *ip_block)
> >>>>>       if (r)
> >>>>>           return r;
> >>>>>   -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
> >>>>> -        volatile struct amdgpu_fw_shared *fw_shared;
> >>>>> +    volatile struct amdgpu_fw_shared *fw_shared;
> >>>>>   -        if (adev->vcn.harvest_config & (1 << j))
> >>>>> -            continue;
> >>>>> -        adev->vcn.internal.context_id =
> >>>>> mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
> >>>>> -        adev->vcn.internal.ib_vmid =
> >>>>> mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
> >>>>> -        adev->vcn.internal.ib_bar_low =
> >>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
> >>>>> -        adev->vcn.internal.ib_bar_high =
> >>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
> >>>>> -        adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
> >>>>> -        adev->vcn.internal.gp_scratch8 =
> >>>>> mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
> >>>>> -
> >>>>> -        adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
> >>>>> -        adev->vcn.inst[j].external.scratch9 = SOC15_REG_OFFSET(VCN,
> >>>>> j, mmUVD_SCRATCH9);
> >>>>> -        adev->vcn.internal.data0 =
> >>>>> mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
> >>>>> -        adev->vcn.inst[j].external.data0 = SOC15_REG_OFFSET(VCN, j,
> >>>>> mmUVD_GPCOM_VCPU_DATA0);
> >>>>> -        adev->vcn.internal.data1 =
> >>>>> mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
> >>>>> -        adev->vcn.inst[j].external.data1 = SOC15_REG_OFFSET(VCN, j,
> >>>>> mmUVD_GPCOM_VCPU_DATA1);
> >>>>> -        adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
> >>>>> -        adev->vcn.inst[j].external.cmd = SOC15_REG_OFFSET(VCN, j,
> >>>>> mmUVD_GPCOM_VCPU_CMD);
> >>>>> -        adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
> >>>>> -        adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(VCN, j,
> >>>>> mmUVD_NO_OP);
> >>>>> -
> >>>>> -        ring = &adev->vcn.inst[j].ring_dec;
> >>>>> +    if (adev->vcn.harvest_config & (1 << inst))
> >>>>> +        goto done;
> >>>>> +    adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
> >>>>> +    adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
> >>>>> +    adev->vcn.internal.ib_bar_low =
> >>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
> >>>>> +    adev->vcn.internal.ib_bar_high =
> >>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
> >>>>> +    adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
> >>>>> +    adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
> >>>>> +
> >>>>> +    adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
> >>>>> +    adev->vcn.inst[inst].external.scratch9 = SOC15_REG_OFFSET(VCN,
> >>>>> inst, mmUVD_SCRATCH9);
> >>>>> +    adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
> >>>>> +    adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN,
> >>>>> inst, mmUVD_GPCOM_VCPU_DATA0);
> >>>>> +    adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
> >>>>> +    adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN,
> >>>>> inst, mmUVD_GPCOM_VCPU_DATA1);
> >>>>> +    adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
> >>>>> +    adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN, inst,
> >>>>> mmUVD_GPCOM_VCPU_CMD);
> >>>>> +    adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
> >>>>> +    adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN, inst,
> >>>>> mmUVD_NO_OP);
> >>>>> +
> >>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
> >>>>> +    ring->use_doorbell = true;
> >>>>> +
> >>>>> +    ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 <<
> >>>>> 1) +
> >>>>> +            (amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
> >>>>> +
> >>>>> +    if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
> >>>>> +        ring->vm_hub = AMDGPU_MMHUB1(0);
> >>>>> +    else
> >>>>> +        ring->vm_hub = AMDGPU_MMHUB0(0);
> >>>>> +
> >>>>> +    sprintf(ring->name, "vcn_dec_%d", inst);
> >>>>> +    r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq,
> >>>>> +                 0, AMDGPU_RING_PRIO_DEFAULT, NULL);
> >>>>> +    if (r)
> >>>>> +        return r;
> >>>>> +
> >>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> >>>>> +        enum amdgpu_ring_priority_level hw_prio =
> >>>>> amdgpu_vcn_get_enc_ring_prio(i);
> >>>>> +
> >>>>> +        ring = &adev->vcn.inst[inst].ring_enc[i];
> >>>>>           ring->use_doorbell = true;
> >>>>>             ring->doorbell_index =
> >>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
> >>>>> -                (amdgpu_sriov_vf(adev) ? 2*j : 8*j);
> >>>>> +                (amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2 + i +
> >>>>> 8*inst));
> >>>>>   -        if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2,
> >>>>> 5, 0))
> >>>>> +        if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
> >>>>> +            IP_VERSION(2, 5, 0))
> >>>>>               ring->vm_hub = AMDGPU_MMHUB1(0);
> >>>>>           else
> >>>>>               ring->vm_hub = AMDGPU_MMHUB0(0);
> >>>>>   -        sprintf(ring->name, "vcn_dec_%d", j);
> >>>>> -        r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq,
> >>>>> -                     0, AMDGPU_RING_PRIO_DEFAULT, NULL);
> >>>>> +        sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
> >>>>> +        r = amdgpu_ring_init(adev, ring, 512,
> >>>>> +                     &adev->vcn.inst[inst].irq, 0,
> >>>>> +                     hw_prio, NULL);
> >>>>>           if (r)
> >>>>>               return r;
> >>>>> -
> >>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
> >>>>> -            enum amdgpu_ring_priority_level hw_prio =
> >>>>> amdgpu_vcn_get_enc_ring_prio(i);
> >>>>> -
> >>>>> -            ring = &adev->vcn.inst[j].ring_enc[i];
> >>>>> -            ring->use_doorbell = true;
> >>>>> -
> >>>>> -            ring->doorbell_index =
> >>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
> >>>>> -                    (amdgpu_sriov_vf(adev) ? (1 + i + 2*j) : (2 + i
> >>>>> + 8*j));
> >>>>> -
> >>>>> -            if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
> >>>>> -                IP_VERSION(2, 5, 0))
> >>>>> -                ring->vm_hub = AMDGPU_MMHUB1(0);
> >>>>> -            else
> >>>>> -                ring->vm_hub = AMDGPU_MMHUB0(0);
> >>>>> -
> >>>>> -            sprintf(ring->name, "vcn_enc_%d.%d", j, i);
> >>>>> -            r = amdgpu_ring_init(adev, ring, 512,
> >>>>> -                         &adev->vcn.inst[j].irq, 0,
> >>>>> -                         hw_prio, NULL);
> >>>>> -            if (r)
> >>>>> -                return r;
> >>>>> -        }
> >>>>> -
> >>>>> -        fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
> >>>>> -        fw_shared->present_flag_0 =
> >>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
> >>>>> -
> >>>>> -        if (amdgpu_vcnfw_log)
> >>>>> -            amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
> >>>>>       }
> >>>>>   +    fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
> >>>>> +    fw_shared->present_flag_0 =
> >>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
> >>>>> +
> >>>>> +    if (amdgpu_vcnfw_log)
> >>>>> +        amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
> >>>>> +done:
> >>>>>       if (amdgpu_sriov_vf(adev)) {
> >>>>>           r = amdgpu_virt_alloc_mm_table(adev);
> >>>>>           if (r)
> >>>>> @@ -1005,197 +1002,192 @@ static int vcn_v2_5_start_dpg_mode(struct
> >>>>> amdgpu_device *adev, int inst_idx, boo
> >>>>>       return 0;
> >>>>>   }
> >>>>>   -static int vcn_v2_5_start(struct amdgpu_device *adev)
> >>>>> +static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned int
> >>>>> inst)
> >>>>>   {
> >>>>>       struct amdgpu_ring *ring;
> >>>>>       uint32_t rb_bufsz, tmp;
> >>>>> -    int i, j, k, r;
> >>>>> +    int j, k, r;
> >>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> >>>>> -        if (adev->pm.dpm_enabled)
> >>>>> -            amdgpu_dpm_enable_vcn(adev, true, i);
> >>>>> -    }
> >>>>> -
> >>>>> -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> >>>>> -        if (adev->vcn.harvest_config & (1 << i))
> >>>>> -            continue;
> >>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> >>>>> -            r = vcn_v2_5_start_dpg_mode(adev, i,
> >>>>> adev->vcn.indirect_sram);
> >>>>> -            continue;
> >>>>> -        }
> >>>>> +    if (adev->pm.dpm_enabled)
> >>>>> +        amdgpu_dpm_enable_vcn(adev, true, inst);
> >>>>>   -        /* disable register anti-hang mechanism */
> >>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS), 0,
> >>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> >>>>> +    if (adev->vcn.harvest_config & (1 << inst))
> >>>>> +        return 0;
> >>>>>   -        /* set uvd status busy */
> >>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) |
> >>>>> UVD_STATUS__UVD_BUSY;
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
> >>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> >>>>> +        r = vcn_v2_5_start_dpg_mode(adev, inst,
> >>>>> adev->vcn.indirect_sram);
> >>>>> +        return r;
> >>>>>       }
> >>>>>   +    /* disable register anti-hang mechanism */
> >>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS), 0,
> >>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> >>>>> +
> >>>>> +    /* set uvd status busy */
> >>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
> >>>>> +
> >>>>>       if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
> >>>>>           return 0;
> >>>>>         /*SW clock gating */
> >>>>>       vcn_v2_5_disable_clock_gating(adev);
> >>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> >>>>> -        if (adev->vcn.harvest_config & (1 << i))
> >>>>> -            continue;
> >>>>> -        /* enable VCPU clock */
> >>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
> >>>>> -            UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
> >>>>> -
> >>>>> -        /* disable master interrupt */
> >>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
> >>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
> >>>>> -
> >>>>> -        /* setup mmUVD_LMI_CTRL */
> >>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
> >>>>> -        tmp &= ~0xff;
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
> >>>>> -            UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
> >>>>> -            UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
> >>>>> -            UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
> >>>>> -            UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
> >>>>> -
> >>>>> -        /* setup mmUVD_MPC_CNTL */
> >>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
> >>>>> -        tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
> >>>>> -        tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
> >>>>> -
> >>>>> -        /* setup UVD_MPC_SET_MUXA0 */
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
> >>>>> -            ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
> >>>>> -            (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
> >>>>> -            (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
> >>>>> -            (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
> >>>>> -
> >>>>> -        /* setup UVD_MPC_SET_MUXB0 */
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
> >>>>> -            ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
> >>>>> -            (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
> >>>>> -            (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
> >>>>> -            (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
> >>>>> -
> >>>>> -        /* setup mmUVD_MPC_SET_MUX */
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
> >>>>> -            ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
> >>>>> -            (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
> >>>>> -            (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
> >>>>> -    }
> >>>>> +    if (adev->vcn.harvest_config & (1 << inst))
> >>>>> +        return 0;
> >>>>> +
> >>>>> +    /* enable VCPU clock */
> >>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
> >>>>> +        UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
> >>>>> +
> >>>>> +    /* disable master interrupt */
> >>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
> >>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
> >>>>> +
> >>>>> +    /* setup mmUVD_LMI_CTRL */
> >>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
> >>>>> +    tmp &= ~0xff;
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
> >>>>> +        UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
> >>>>> +        UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
> >>>>> +        UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
> >>>>> +        UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
> >>>>> +
> >>>>> +    /* setup mmUVD_MPC_CNTL */
> >>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
> >>>>> +    tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
> >>>>> +    tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
> >>>>> +
> >>>>> +    /* setup UVD_MPC_SET_MUXA0 */
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
> >>>>> +        ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
> >>>>> +        (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
> >>>>> +        (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
> >>>>> +        (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
> >>>>> +
> >>>>> +    /* setup UVD_MPC_SET_MUXB0 */
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
> >>>>> +        ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
> >>>>> +        (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
> >>>>> +        (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
> >>>>> +        (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
> >>>>> +
> >>>>> +    /* setup mmUVD_MPC_SET_MUX */
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
> >>>>> +        ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
> >>>>> +        (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
> >>>>> +        (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
> >>>>>         vcn_v2_5_mc_resume(adev);
> >>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> >>>>> -        volatile struct amdgpu_fw_shared *fw_shared =
> >>>>> adev->vcn.inst[i].fw_shared.cpu_addr;
> >>>>> -        if (adev->vcn.harvest_config & (1 << i))
> >>>>> -            continue;
> >>>>> -        /* VCN global tiling registers */
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
> >>>>> -            adev->gfx.config.gb_addr_config);
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
> >>>>> -            adev->gfx.config.gb_addr_config);
> >>>>> +    volatile struct amdgpu_fw_shared *fw_shared =
> >>>>> adev->vcn.inst[inst].fw_shared.cpu_addr;
> >>>>> +    if (adev->vcn.harvest_config & (1 << inst))
> >>>>> +        return 0;
> >>>>> +
> >>>>> +    /* VCN global tiling registers */
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
> >>>>> +        adev->gfx.config.gb_addr_config);
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
> >>>>> +        adev->gfx.config.gb_addr_config);
> >>>>>   -        /* enable LMI MC and UMC channels */
> >>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
> >>>>> -            ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
> >>>>> +    /* enable LMI MC and UMC channels */
> >>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
> >>>>> +        ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
> >>>>>   -        /* unblock VCPU register access */
> >>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
> >>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
> >>>>> +    /* unblock VCPU register access */
> >>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
> >>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
> >>>>>   -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
> >>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
> >>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>>>>   -        for (k = 0; k < 10; ++k) {
> >>>>> -            uint32_t status;
> >>>>> -
> >>>>> -            for (j = 0; j < 100; ++j) {
> >>>>> -                status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
> >>>>> -                if (status & 2)
> >>>>> -                    break;
> >>>>> -                if (amdgpu_emu_mode == 1)
> >>>>> -                    msleep(500);
> >>>>> -                else
> >>>>> -                    mdelay(10);
> >>>>> -            }
> >>>>> -            r = 0;
> >>>>> +    for (k = 0; k < 10; ++k) {
> >>>>> +        uint32_t status;
> >>>>> +
> >>>>> +        for (j = 0; j < 100; ++j) {
> >>>>> +            status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
> >>>>>               if (status & 2)
> >>>>>                   break;
> >>>>> +            if (amdgpu_emu_mode == 1)
> >>>>> +                msleep(500);
> >>>>> +            else
> >>>>> +                mdelay(10);
> >>>>> +        }
> >>>>> +        r = 0;
> >>>>> +        if (status & 2)
> >>>>> +            break;
> >>>>>   -            DRM_ERROR("VCN decode not responding, trying to reset
> >>>>> the VCPU!!!\n");
> >>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
> >>>>> -                UVD_VCPU_CNTL__BLK_RST_MASK,
> >>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>>>> -            mdelay(10);
> >>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
> >>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>>>> +        DRM_ERROR("VCN decode not responding, trying to reset the
> >>>>> VCPU!!!\n");
> >>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
> >>>>> +            UVD_VCPU_CNTL__BLK_RST_MASK,
> >>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>>>> +        mdelay(10);
> >>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
> >>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>>>>   -            mdelay(10);
> >>>>> -            r = -1;
> >>>>> -        }
> >>>>> +        mdelay(10);
> >>>>> +        r = -1;
> >>>>> +    }
> >>>>>   -        if (r) {
> >>>>> -            DRM_ERROR("VCN decode not responding, giving up!!!\n");
> >>>>> -            return r;
> >>>>> -        }
> >>>>> +    if (r) {
> >>>>> +        DRM_ERROR("VCN decode not responding, giving up!!!\n");
> >>>>> +        return r;
> >>>>> +    }
> >>>>>   -        /* enable master interrupt */
> >>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
> >>>>> -            UVD_MASTINT_EN__VCPU_EN_MASK,
> >>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
> >>>>> +    /* enable master interrupt */
> >>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
> >>>>> +        UVD_MASTINT_EN__VCPU_EN_MASK,
> >>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
> >>>>>   -        /* clear the busy bit of VCN_STATUS */
> >>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
> >>>>> -            ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
> >>>>> +    /* clear the busy bit of VCN_STATUS */
> >>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
> >>>>> +        ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
> >>>>>   -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
> >>>>>   -        ring = &adev->vcn.inst[i].ring_dec;
> >>>>> -        /* force RBC into idle state */
> >>>>> -        rb_bufsz = order_base_2(ring->ring_size);
> >>>>> -        tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
> >>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
> >>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
> >>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
> >>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
> >>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
> >>>>> +    /* force RBC into idle state */
> >>>>> +    rb_bufsz = order_base_2(ring->ring_size);
> >>>>> +    tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
> >>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
> >>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
> >>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
> >>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
> >>>>>   -        fw_shared->multi_queue.decode_queue_mode |=
> >>>>> FW_QUEUE_RING_RESET;
> >>>>> -        /* program the RB_BASE for ring buffer */
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
> >>>>> -            lower_32_bits(ring->gpu_addr));
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
> >>>>> -            upper_32_bits(ring->gpu_addr));
> >>>>> +    fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
> >>>>> +    /* program the RB_BASE for ring buffer */
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
> >>>>> +        lower_32_bits(ring->gpu_addr));
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
> >>>>> +        upper_32_bits(ring->gpu_addr));
> >>>>>   -        /* Initialize the ring buffer's read and write pointers */
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
> >>>>> +    /* Initialize the ring buffer's read and write pointers */
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
> >>>>>   -        ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
> >>>>> -                lower_32_bits(ring->wptr));
> >>>>> -        fw_shared->multi_queue.decode_queue_mode &=
> >>>>> ~FW_QUEUE_RING_RESET;
> >>>>> +    ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
> >>>>> +            lower_32_bits(ring->wptr));
> >>>>> +    fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
> >>>>>   -        fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
> >>>>> FW_QUEUE_RING_RESET;
> >>>>> -        ring = &adev->vcn.inst[i].ring_enc[0];
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI,
> >>>>> upper_32_bits(ring->gpu_addr));
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
> >>>>> -        fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
> >>>>> ~FW_QUEUE_RING_RESET;
> >>>>> -
> >>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode |=
> >>>>> FW_QUEUE_RING_RESET;
> >>>>> -        ring = &adev->vcn.inst[i].ring_enc[1];
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2,
> >>>>> lower_32_bits(ring->wptr));
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2,
> >>>>> lower_32_bits(ring->wptr));
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2,
> >>>>> upper_32_bits(ring->gpu_addr));
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4);
> >>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode &=
> >>>>> ~FW_QUEUE_RING_RESET;
> >>>>> -    }
> >>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
> >>>>> FW_QUEUE_RING_RESET;
> >>>>> +    ring = &adev->vcn.inst[inst].ring_enc[0];
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI,
> >>>>> upper_32_bits(ring->gpu_addr));
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
> >>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
> >>>>> ~FW_QUEUE_RING_RESET;
> >>>>> +
> >>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode |=
> >>>>> FW_QUEUE_RING_RESET;
> >>>>> +    ring = &adev->vcn.inst[inst].ring_enc[1];
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2,
> >>>>> upper_32_bits(ring->gpu_addr));
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
> >>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode &=
> >>>>> ~FW_QUEUE_RING_RESET;
> >>>>>         return 0;
> >>>>>   }
> >>>>> @@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct
> >>>>> amdgpu_device *adev, int inst_idx)
> >>>>>       return 0;
> >>>>>   }
> >>>>>   -static int vcn_v2_5_stop(struct amdgpu_device *adev)
> >>>>> +static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned int inst)
> >>>>>   {
> >>>>>       uint32_t tmp;
> >>>>> -    int i, r = 0;
> >>>>> +    int r = 0;
> >>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> >>>>> -        if (adev->vcn.harvest_config & (1 << i))
> >>>>> -            continue;
> >>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> >>>>> -            r = vcn_v2_5_stop_dpg_mode(adev, i);
> >>>>> -            continue;
> >>>>> -        }
> >>>>> +    if (adev->vcn.harvest_config & (1 << inst))
> >>>>> +        goto done;
> >>>>>   -        /* wait for vcn idle */
> >>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS,
> >>>>> UVD_STATUS__IDLE, 0x7);
> >>>>> -        if (r)
> >>>>> -            return r;
> >>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
> >>>>> +        r = vcn_v2_5_stop_dpg_mode(adev, inst);
> >>>>> +        goto done;
> >>>>> +    }
> >>>>>   -        tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
> >>>>> -            UVD_LMI_STATUS__READ_CLEAN_MASK |
> >>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_MASK |
> >>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
> >>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
> >>>>> -        if (r)
> >>>>> -            return r;
> >>>>> +    /* wait for vcn idle */
> >>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS,
> >>>>> UVD_STATUS__IDLE, 0x7);
> >>>>> +    if (r)
> >>>>> +        return r;
> >>>>>   -        /* block LMI UMC channel */
> >>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
> >>>>> -        tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
> >>>>> +    tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
> >>>>> +        UVD_LMI_STATUS__READ_CLEAN_MASK |
> >>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_MASK |
> >>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
> >>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
> >>>>> +    if (r)
> >>>>> +        return r;
> >>>>>   -        tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
> >>>>> -            UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
> >>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
> >>>>> -        if (r)
> >>>>> -            return r;
> >>>>> +    /* block LMI UMC channel */
> >>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
> >>>>> +    tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
> >>>>>   -        /* block VCPU register access */
> >>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
> >>>>> -            UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
> >>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
> >>>>> +    tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
> >>>>> +        UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
> >>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
> >>>>> +    if (r)
> >>>>> +        return r;
> >>>>>   -        /* reset VCPU */
> >>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
> >>>>> -            UVD_VCPU_CNTL__BLK_RST_MASK,
> >>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>>>> +    /* block VCPU register access */
> >>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
> >>>>> +        UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
> >>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
> >>>>>   -        /* disable VCPU clock */
> >>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
> >>>>> -            ~(UVD_VCPU_CNTL__CLK_EN_MASK));
> >>>>> +    /* reset VCPU */
> >>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
> >>>>> +        UVD_VCPU_CNTL__BLK_RST_MASK,
> >>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
> >>>>>   -        /* clear status */
> >>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
> >>>>> +    /* disable VCPU clock */
> >>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
> >>>>> +        ~(UVD_VCPU_CNTL__CLK_EN_MASK));
> >>>>>   -        vcn_v2_5_enable_clock_gating(adev);
> >>>>> +    /* clear status */
> >>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
> >>>>>   -        /* enable register anti-hang mechanism */
> >>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
> >>>>> -            UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
> >>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> >>>>> -    }
> >>>>> +    vcn_v2_5_enable_clock_gating(adev);
> >>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
> >>>>> -        if (adev->pm.dpm_enabled)
> >>>>> -            amdgpu_dpm_enable_vcn(adev, false, i);
> >>>>> -    }
> >>>>> +    /* enable register anti-hang mechanism */
> >>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
> >>>>> +        UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
> >>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
> >>>>> +done:
> >>>>> +    if (adev->pm.dpm_enabled)
> >>>>> +        amdgpu_dpm_enable_vcn(adev, false, inst);
> >>>>>         return 0;
> >>>>>   }
> >>>>> @@ -1838,9 +1827,9 @@ static int
> >>>>> vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
> >>>>>           return 0;
> >>>>>         if (state == AMD_PG_STATE_GATE)
> >>>>> -        ret = vcn_v2_5_stop(adev);
> >>>>> +        ret = vcn_v2_5_stop(adev, inst);
> >>>>>       else
> >>>>> -        ret = vcn_v2_5_start(adev);
> >>>>> +        ret = vcn_v2_5_start(adev, inst);
> >>>>>         if (!ret)
> >>>>>           adev->vcn.cur_state[inst] = state;

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-07 15:24             ` Alex Deucher
@ 2024-10-08  7:03               ` Lazar, Lijo
  2024-10-08 22:04                 ` Boyuan Zhang
  0 siblings, 1 reply; 37+ messages in thread
From: Lazar, Lijo @ 2024-10-08  7:03 UTC (permalink / raw)
  To: Alex Deucher
  Cc: Boyuan Zhang, amd-gfx, leo.liu, christian.koenig,
	alexander.deucher, sunil.khatri



On 10/7/2024 8:54 PM, Alex Deucher wrote:
> On Mon, Oct 7, 2024 at 10:32 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>>
>>
>>
>> On 10/7/2024 7:47 PM, Alex Deucher wrote:
>>> On Mon, Oct 7, 2024 at 9:58 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>>>>
>>>>
>>>>
>>>> On 10/7/2024 7:03 PM, Boyuan Zhang wrote:
>>>>>
>>>>> On 2024-10-07 01:22, Lazar, Lijo wrote:
>>>>>>
>>>>>> On 10/5/2024 12:14 AM, boyuan.zhang@amd.com wrote:
>>>>>>> From: Boyuan Zhang <boyuan.zhang@amd.com>
>>>>>>>
>>>>>>> For vcn 2_5, add ip_block for each vcn instance during discovery stage.
>>>>>>>
>>>>>>> And only powering on/off one of the vcn instance using the
>>>>>>> instance value stored in ip_block, instead of powering on/off all
>>>>>>> vcn instances. Modify the existing functions to use the instance value
>>>>>>> in ip_block, and remove the original for loop for all vcn instances.
>>>>>>>
>>>>>>> v2: rename "i"/"j" to "inst" for instance value.
>>>>>>>
>>>>>>> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
>>>>>>> ---
>>>>>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
>>>>>>>   drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565 +++++++++---------
>>>>>>>   2 files changed, 280 insertions(+), 289 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>> index 9f9a1867da72..de1053cc2a2b 100644
>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>> @@ -2278,6 +2278,7 @@ static int
>>>>>>> amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
>>>>>>>     static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device
>>>>>>> *adev)
>>>>>>>   {
>>>>>>> +    int i;
>>>>>>>       if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
>>>>>>>           switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
>>>>>>>           case IP_VERSION(7, 0, 0):
>>>>>>> @@ -2321,7 +2322,8 @@ static int
>>>>>>> amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>>>>>>>           case IP_VERSION(2, 0, 3):
>>>>>>>               break;
>>>>>>>           case IP_VERSION(2, 5, 0):
>>>>>>> -            amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>>>>>>> +            for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
>>>>>>> +                amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>>>>>>
>>>>>> This introduces a totally confusing design now. At a higher level an IP
>>>>>> block type manages multiple instances and their power states. Now there
>>>>>> is a mix where no definition can be attributed to an IP block. Or, if
>>>>>> this were to be done uniformly for other IPs, then for some SOCs there
>>>>>> could be 16 SDMA blocks, 8 GFX blocks and so forth.
>>>>>>
>>>>>> What is the reason to do this way? Can't VCN IP block maintain the state
>>>>>> of multiple instances within itself?
>>>>>>
>>>>>> Thanks,
>>>>>> Lijo
>>>>> This is part of the fundamental design change for separating IP block
>>>>> per instance, in order to
>>>>> handle each instance separately within same IP block (e.g. separate
>>>>> power/clock management).
>>>>>
>>>>> Part 1, Change all adev ptr handle to amdgpu_ip_block ptr in all
>>>>> callbacks (hw_init/fini, sw_init/fini,
>>>>> suspend, etc...) for all IP blocks, so that each IP knows which IP_block
>>>>> (and which instance) the
>>>>> callback is for. Most parts of this changes have been submitted by Sunil.
>>>>>
>>>>> Part 2, Separate IP block per instance.
>>>>>
>>>>> Part 3, Since callbacks can pass in IP_block now after Part 1 change and
>>>>> instance value can be
>>>>> obtained from each IP block in Part 2, IP can then choose to handle
>>>>> callbacks ONLY for the given
>>>>> instance of a given IP block (or still handling for all instances as
>>>>> before).
>>>>> For VCN, all callbacks will be handled only for the given one instance,
>>>>> instead of the original for-
>>>>> loop for all instance. As a result, each VCN instance can be
>>>>> start/stop/int/fini/suspend separately.
>>>>>
>>>>> Part 4, Change all VCN helper functions to handle only the given
>>>>> instance, instead of the original
>>>>> for-loop for all instance.
>>>>>
>>>>> Each instance can have its own states, so we think it makes more sense
>>>>> to separate them on IP
>>>>> block level to handle each of them separately.
>>>>
>>>>
>>>> Such a change should not be done unless all IPs follow the same design.
>>>> You didn't answer the question - what necessitates this change? What is
>>>> special about VCN that it cannot manage the states of multiple instances
>>>> within the IP block?
>>>
>>> We want to be able to manage the powergating independently for each
>>> VCN instance for both power management and VCN reset.  Right now power
>>> gating is handled at the IP level so it's not easy or clean to handle
>>> powergating of individual IP instances.
>>>
>>
>> Still VCN block can manage the powergated instances (FWIW, it's just an
>> array in SMU block). Also vcn block gets to run the idle worker and
>> knows the rings (and corresponding VCN instances) that are idle.
>> Maintaining instance states in VCN block and modifying idle worker to
>> just idle that instance alone doesn't look like a complex change.
> 
> 
> We already went down that road and it's really ugly.  We end up
> duplicating a bunch of code paths for different driver flows because
> set_powergating_state() and set_clockgating_state are at the IP level
> and we want per instance gating.  We could add a num_instances member
> at the IP block level and then convert all of the high level code that
> calls the IP functions loop over the number of instances, but that
> seems like just as much work and it's not quite as clean IMHO.
> 

Sorry, I'm not seeing much difference in this design. All it does is
just split instances to IP block at the same time it's going to keep an
instance parameter in IP block APIs.

	amdgpu_device_ip_set_clockgating_state(blocktype, instance);
	amdgpu_device_ip_set_powergating_state(blocktype, instance);

Also, VCN continues to maintain an array of amdgpu_vcn_inst. I think
it's easier manage this with changes to amdgpu_vcn_inst. Since it is
continued to be maintained, what about just moving the states and
idle_work inside amdgpu_vcn_inst.
	
	int inst;
	enum amd_powergating_state cur_pg_state;
	enum amd_clockgating_state state cur_cg_state;
	struct delayed_work     idle_work;

At the end of ring usage of corresponding instance, just invoke the
corresponding instance's idle work.

schedule_delayed_work(&ring->adev->vcn.inst[ring->me].idle_work,
idle_time_out);

I don't see any change in this series for other IP block APIs.

Thanks,
Lijo

> Alex
> 
>>
>> Moving to IP block per instance for VCN alone is not a change that helps
>> to define an IP block. If that needs to be done for every other IP type,
>> that's also a massive change.
>>
>> Also, then it's no longer possible to have something static like this -
>>         struct amdgpu_ip_block          ip_blocks[AMDGPU_MAX_IP_NUM];
>>
>>
>> Thanks,
>> Lijo
>>
>>> Alex
>>>
>>>>
>>>> Thanks,
>>>> Lijo
>>>>
>>>>>
>>>>> Thanks,
>>>>> Boyuan
>>>>>>
>>>>>>>               amdgpu_device_ip_block_add(adev, &jpeg_v2_5_ip_block);
>>>>>>>               break;
>>>>>>>           case IP_VERSION(2, 6, 0):
>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>> b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>> index d00df51bc400..1f8738ae360a 100644
>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>> @@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct
>>>>>>> amdgpu_ip_block *ip_block)
>>>>>>>   static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>>>>>>>   {
>>>>>>>       struct amdgpu_ring *ring;
>>>>>>> -    int i, j, r;
>>>>>>> +    int i, r;
>>>>>>>       uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
>>>>>>>       uint32_t *ptr;
>>>>>>>       struct amdgpu_device *adev = ip_block->adev;
>>>>>>> +    int inst = ip_block->instance;
>>>>>>>   -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>>>>>> -        if (adev->vcn.harvest_config & (1 << j))
>>>>>>> -            continue;
>>>>>>> -        /* VCN DEC TRAP */
>>>>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>>>> -                VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>>>>>> &adev->vcn.inst[j].irq);
>>>>>>> -        if (r)
>>>>>>> -            return r;
>>>>>>> -
>>>>>>> -        /* VCN ENC TRAP */
>>>>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>> -            r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>>>> -                i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>>>>>> &adev->vcn.inst[j].irq);
>>>>>>> -            if (r)
>>>>>>> -                return r;
>>>>>>> -        }
>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>> +        goto sw_init;
>>>>>>> +    /* VCN DEC TRAP */
>>>>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>>>> +            VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>>>>>> &adev->vcn.inst[inst].irq);
>>>>>>> +    if (r)
>>>>>>> +        return r;
>>>>>>>   -        /* VCN POISON TRAP */
>>>>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>>>> -            VCN_2_6__SRCID_UVD_POISON,
>>>>>>> &adev->vcn.inst[j].ras_poison_irq);
>>>>>>> +    /* VCN ENC TRAP */
>>>>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>> +        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>>>> +            i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>>>>>> &adev->vcn.inst[inst].irq);
>>>>>>>           if (r)
>>>>>>>               return r;
>>>>>>>       }
>>>>>>>   +    /* VCN POISON TRAP */
>>>>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>>>> +        VCN_2_6__SRCID_UVD_POISON,
>>>>>>> &adev->vcn.inst[inst].ras_poison_irq);
>>>>>>> +    if (r)
>>>>>>> +        return r;
>>>>>>> +sw_init:
>>>>>>>       r = amdgpu_vcn_sw_init(adev);
>>>>>>>       if (r)
>>>>>>>           return r;
>>>>>>> @@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct
>>>>>>> amdgpu_ip_block *ip_block)
>>>>>>>       if (r)
>>>>>>>           return r;
>>>>>>>   -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>>>>>> -        volatile struct amdgpu_fw_shared *fw_shared;
>>>>>>> +    volatile struct amdgpu_fw_shared *fw_shared;
>>>>>>>   -        if (adev->vcn.harvest_config & (1 << j))
>>>>>>> -            continue;
>>>>>>> -        adev->vcn.internal.context_id =
>>>>>>> mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>>>>>> -        adev->vcn.internal.ib_vmid =
>>>>>>> mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>>>>>> -        adev->vcn.internal.ib_bar_low =
>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>>>>>> -        adev->vcn.internal.ib_bar_high =
>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>>>>>> -        adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>>>>>> -        adev->vcn.internal.gp_scratch8 =
>>>>>>> mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>>>>>> -
>>>>>>> -        adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>>>>>> -        adev->vcn.inst[j].external.scratch9 = SOC15_REG_OFFSET(VCN,
>>>>>>> j, mmUVD_SCRATCH9);
>>>>>>> -        adev->vcn.internal.data0 =
>>>>>>> mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>>>>>> -        adev->vcn.inst[j].external.data0 = SOC15_REG_OFFSET(VCN, j,
>>>>>>> mmUVD_GPCOM_VCPU_DATA0);
>>>>>>> -        adev->vcn.internal.data1 =
>>>>>>> mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>>>>>> -        adev->vcn.inst[j].external.data1 = SOC15_REG_OFFSET(VCN, j,
>>>>>>> mmUVD_GPCOM_VCPU_DATA1);
>>>>>>> -        adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>>>>>> -        adev->vcn.inst[j].external.cmd = SOC15_REG_OFFSET(VCN, j,
>>>>>>> mmUVD_GPCOM_VCPU_CMD);
>>>>>>> -        adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>>>>>> -        adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(VCN, j,
>>>>>>> mmUVD_NO_OP);
>>>>>>> -
>>>>>>> -        ring = &adev->vcn.inst[j].ring_dec;
>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>> +        goto done;
>>>>>>> +    adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>>>>>> +    adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>>>>>> +    adev->vcn.internal.ib_bar_low =
>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>>>>>> +    adev->vcn.internal.ib_bar_high =
>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>>>>>> +    adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>>>>>> +    adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>>>>>> +
>>>>>>> +    adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>>>>>> +    adev->vcn.inst[inst].external.scratch9 = SOC15_REG_OFFSET(VCN,
>>>>>>> inst, mmUVD_SCRATCH9);
>>>>>>> +    adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>>>>>> +    adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN,
>>>>>>> inst, mmUVD_GPCOM_VCPU_DATA0);
>>>>>>> +    adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>>>>>> +    adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN,
>>>>>>> inst, mmUVD_GPCOM_VCPU_DATA1);
>>>>>>> +    adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>>>>>> +    adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN, inst,
>>>>>>> mmUVD_GPCOM_VCPU_CMD);
>>>>>>> +    adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>>>>>> +    adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN, inst,
>>>>>>> mmUVD_NO_OP);
>>>>>>> +
>>>>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>>>>>> +    ring->use_doorbell = true;
>>>>>>> +
>>>>>>> +    ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 <<
>>>>>>> 1) +
>>>>>>> +            (amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
>>>>>>> +
>>>>>>> +    if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
>>>>>>> +        ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>> +    else
>>>>>>> +        ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>> +
>>>>>>> +    sprintf(ring->name, "vcn_dec_%d", inst);
>>>>>>> +    r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq,
>>>>>>> +                 0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>>>>>> +    if (r)
>>>>>>> +        return r;
>>>>>>> +
>>>>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>> +        enum amdgpu_ring_priority_level hw_prio =
>>>>>>> amdgpu_vcn_get_enc_ring_prio(i);
>>>>>>> +
>>>>>>> +        ring = &adev->vcn.inst[inst].ring_enc[i];
>>>>>>>           ring->use_doorbell = true;
>>>>>>>             ring->doorbell_index =
>>>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>>>>>> -                (amdgpu_sriov_vf(adev) ? 2*j : 8*j);
>>>>>>> +                (amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2 + i +
>>>>>>> 8*inst));
>>>>>>>   -        if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2,
>>>>>>> 5, 0))
>>>>>>> +        if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>>>> +            IP_VERSION(2, 5, 0))
>>>>>>>               ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>>           else
>>>>>>>               ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>>   -        sprintf(ring->name, "vcn_dec_%d", j);
>>>>>>> -        r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq,
>>>>>>> -                     0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>>>>>> +        sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
>>>>>>> +        r = amdgpu_ring_init(adev, ring, 512,
>>>>>>> +                     &adev->vcn.inst[inst].irq, 0,
>>>>>>> +                     hw_prio, NULL);
>>>>>>>           if (r)
>>>>>>>               return r;
>>>>>>> -
>>>>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>> -            enum amdgpu_ring_priority_level hw_prio =
>>>>>>> amdgpu_vcn_get_enc_ring_prio(i);
>>>>>>> -
>>>>>>> -            ring = &adev->vcn.inst[j].ring_enc[i];
>>>>>>> -            ring->use_doorbell = true;
>>>>>>> -
>>>>>>> -            ring->doorbell_index =
>>>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>>>>>> -                    (amdgpu_sriov_vf(adev) ? (1 + i + 2*j) : (2 + i
>>>>>>> + 8*j));
>>>>>>> -
>>>>>>> -            if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>>>> -                IP_VERSION(2, 5, 0))
>>>>>>> -                ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>> -            else
>>>>>>> -                ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>> -
>>>>>>> -            sprintf(ring->name, "vcn_enc_%d.%d", j, i);
>>>>>>> -            r = amdgpu_ring_init(adev, ring, 512,
>>>>>>> -                         &adev->vcn.inst[j].irq, 0,
>>>>>>> -                         hw_prio, NULL);
>>>>>>> -            if (r)
>>>>>>> -                return r;
>>>>>>> -        }
>>>>>>> -
>>>>>>> -        fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
>>>>>>> -        fw_shared->present_flag_0 =
>>>>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>>>>>> -
>>>>>>> -        if (amdgpu_vcnfw_log)
>>>>>>> -            amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>>>>>       }
>>>>>>>   +    fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
>>>>>>> +    fw_shared->present_flag_0 =
>>>>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>>>>>> +
>>>>>>> +    if (amdgpu_vcnfw_log)
>>>>>>> +        amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>>>>> +done:
>>>>>>>       if (amdgpu_sriov_vf(adev)) {
>>>>>>>           r = amdgpu_virt_alloc_mm_table(adev);
>>>>>>>           if (r)
>>>>>>> @@ -1005,197 +1002,192 @@ static int vcn_v2_5_start_dpg_mode(struct
>>>>>>> amdgpu_device *adev, int inst_idx, boo
>>>>>>>       return 0;
>>>>>>>   }
>>>>>>>   -static int vcn_v2_5_start(struct amdgpu_device *adev)
>>>>>>> +static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned int
>>>>>>> inst)
>>>>>>>   {
>>>>>>>       struct amdgpu_ring *ring;
>>>>>>>       uint32_t rb_bufsz, tmp;
>>>>>>> -    int i, j, k, r;
>>>>>>> +    int j, k, r;
>>>>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>> -        if (adev->pm.dpm_enabled)
>>>>>>> -            amdgpu_dpm_enable_vcn(adev, true, i);
>>>>>>> -    }
>>>>>>> -
>>>>>>> -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>> -            continue;
>>>>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>> -            r = vcn_v2_5_start_dpg_mode(adev, i,
>>>>>>> adev->vcn.indirect_sram);
>>>>>>> -            continue;
>>>>>>> -        }
>>>>>>> +    if (adev->pm.dpm_enabled)
>>>>>>> +        amdgpu_dpm_enable_vcn(adev, true, inst);
>>>>>>>   -        /* disable register anti-hang mechanism */
>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS), 0,
>>>>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>> +        return 0;
>>>>>>>   -        /* set uvd status busy */
>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) |
>>>>>>> UVD_STATUS__UVD_BUSY;
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
>>>>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>> +        r = vcn_v2_5_start_dpg_mode(adev, inst,
>>>>>>> adev->vcn.indirect_sram);
>>>>>>> +        return r;
>>>>>>>       }
>>>>>>>   +    /* disable register anti-hang mechanism */
>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS), 0,
>>>>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>> +
>>>>>>> +    /* set uvd status busy */
>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
>>>>>>> +
>>>>>>>       if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
>>>>>>>           return 0;
>>>>>>>         /*SW clock gating */
>>>>>>>       vcn_v2_5_disable_clock_gating(adev);
>>>>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>> -            continue;
>>>>>>> -        /* enable VCPU clock */
>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>> -            UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>>>>>> -
>>>>>>> -        /* disable master interrupt */
>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
>>>>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>> -
>>>>>>> -        /* setup mmUVD_LMI_CTRL */
>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
>>>>>>> -        tmp &= ~0xff;
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
>>>>>>> -            UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>>>>>> -            UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>>>>>> -            UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>>>>>> -            UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>>>>>> -
>>>>>>> -        /* setup mmUVD_MPC_CNTL */
>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
>>>>>>> -        tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>>>>>> -        tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
>>>>>>> -
>>>>>>> -        /* setup UVD_MPC_SET_MUXA0 */
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
>>>>>>> -            ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>>>>>> -            (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>>>>>> -            (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>>>>>> -            (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>>>>>> -
>>>>>>> -        /* setup UVD_MPC_SET_MUXB0 */
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
>>>>>>> -            ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>>>>>> -            (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>>>>>> -            (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>>>>>> -            (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>>>>>> -
>>>>>>> -        /* setup mmUVD_MPC_SET_MUX */
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
>>>>>>> -            ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>>>>>> -            (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>>>>>> -            (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>>>>> -    }
>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>> +        return 0;
>>>>>>> +
>>>>>>> +    /* enable VCPU clock */
>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>> +        UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>>>>>> +
>>>>>>> +    /* disable master interrupt */
>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
>>>>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>> +
>>>>>>> +    /* setup mmUVD_LMI_CTRL */
>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
>>>>>>> +    tmp &= ~0xff;
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
>>>>>>> +        UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>>>>>> +        UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>>>>>> +        UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>>>>>> +        UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>>>>>> +
>>>>>>> +    /* setup mmUVD_MPC_CNTL */
>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
>>>>>>> +    tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>>>>>> +    tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
>>>>>>> +
>>>>>>> +    /* setup UVD_MPC_SET_MUXA0 */
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
>>>>>>> +        ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>>>>>> +        (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>>>>>> +        (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>>>>>> +        (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>>>>>> +
>>>>>>> +    /* setup UVD_MPC_SET_MUXB0 */
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
>>>>>>> +        ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>>>>>> +        (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>>>>>> +        (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>>>>>> +        (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>>>>>> +
>>>>>>> +    /* setup mmUVD_MPC_SET_MUX */
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
>>>>>>> +        ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>>>>>> +        (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>>>>>> +        (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>>>>>         vcn_v2_5_mc_resume(adev);
>>>>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>> -        volatile struct amdgpu_fw_shared *fw_shared =
>>>>>>> adev->vcn.inst[i].fw_shared.cpu_addr;
>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>> -            continue;
>>>>>>> -        /* VCN global tiling registers */
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>> -            adev->gfx.config.gb_addr_config);
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>> -            adev->gfx.config.gb_addr_config);
>>>>>>> +    volatile struct amdgpu_fw_shared *fw_shared =
>>>>>>> adev->vcn.inst[inst].fw_shared.cpu_addr;
>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>> +        return 0;
>>>>>>> +
>>>>>>> +    /* VCN global tiling registers */
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>> +        adev->gfx.config.gb_addr_config);
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>> +        adev->gfx.config.gb_addr_config);
>>>>>>>   -        /* enable LMI MC and UMC channels */
>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
>>>>>>> -            ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>>>>> +    /* enable LMI MC and UMC channels */
>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
>>>>>>> +        ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>>>>>   -        /* unblock VCPU register access */
>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
>>>>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>> +    /* unblock VCPU register access */
>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
>>>>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>   -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>   -        for (k = 0; k < 10; ++k) {
>>>>>>> -            uint32_t status;
>>>>>>> -
>>>>>>> -            for (j = 0; j < 100; ++j) {
>>>>>>> -                status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
>>>>>>> -                if (status & 2)
>>>>>>> -                    break;
>>>>>>> -                if (amdgpu_emu_mode == 1)
>>>>>>> -                    msleep(500);
>>>>>>> -                else
>>>>>>> -                    mdelay(10);
>>>>>>> -            }
>>>>>>> -            r = 0;
>>>>>>> +    for (k = 0; k < 10; ++k) {
>>>>>>> +        uint32_t status;
>>>>>>> +
>>>>>>> +        for (j = 0; j < 100; ++j) {
>>>>>>> +            status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
>>>>>>>               if (status & 2)
>>>>>>>                   break;
>>>>>>> +            if (amdgpu_emu_mode == 1)
>>>>>>> +                msleep(500);
>>>>>>> +            else
>>>>>>> +                mdelay(10);
>>>>>>> +        }
>>>>>>> +        r = 0;
>>>>>>> +        if (status & 2)
>>>>>>> +            break;
>>>>>>>   -            DRM_ERROR("VCN decode not responding, trying to reset
>>>>>>> the VCPU!!!\n");
>>>>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>> -                UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>> -            mdelay(10);
>>>>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>> +        DRM_ERROR("VCN decode not responding, trying to reset the
>>>>>>> VCPU!!!\n");
>>>>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>> +            UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>> +        mdelay(10);
>>>>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>   -            mdelay(10);
>>>>>>> -            r = -1;
>>>>>>> -        }
>>>>>>> +        mdelay(10);
>>>>>>> +        r = -1;
>>>>>>> +    }
>>>>>>>   -        if (r) {
>>>>>>> -            DRM_ERROR("VCN decode not responding, giving up!!!\n");
>>>>>>> -            return r;
>>>>>>> -        }
>>>>>>> +    if (r) {
>>>>>>> +        DRM_ERROR("VCN decode not responding, giving up!!!\n");
>>>>>>> +        return r;
>>>>>>> +    }
>>>>>>>   -        /* enable master interrupt */
>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
>>>>>>> -            UVD_MASTINT_EN__VCPU_EN_MASK,
>>>>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>> +    /* enable master interrupt */
>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
>>>>>>> +        UVD_MASTINT_EN__VCPU_EN_MASK,
>>>>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>   -        /* clear the busy bit of VCN_STATUS */
>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
>>>>>>> -            ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>>>>> +    /* clear the busy bit of VCN_STATUS */
>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
>>>>>>> +        ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>>>>>   -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
>>>>>>>   -        ring = &adev->vcn.inst[i].ring_dec;
>>>>>>> -        /* force RBC into idle state */
>>>>>>> -        rb_bufsz = order_base_2(ring->ring_size);
>>>>>>> -        tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
>>>>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>>>>>> +    /* force RBC into idle state */
>>>>>>> +    rb_bufsz = order_base_2(ring->ring_size);
>>>>>>> +    tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
>>>>>>>   -        fw_shared->multi_queue.decode_queue_mode |=
>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>> -        /* program the RB_BASE for ring buffer */
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>>>>>> -            lower_32_bits(ring->gpu_addr));
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>>>>>> -            upper_32_bits(ring->gpu_addr));
>>>>>>> +    fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
>>>>>>> +    /* program the RB_BASE for ring buffer */
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>>>>>> +        lower_32_bits(ring->gpu_addr));
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>>>>>> +        upper_32_bits(ring->gpu_addr));
>>>>>>>   -        /* Initialize the ring buffer's read and write pointers */
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
>>>>>>> +    /* Initialize the ring buffer's read and write pointers */
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
>>>>>>>   -        ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
>>>>>>> -                lower_32_bits(ring->wptr));
>>>>>>> -        fw_shared->multi_queue.decode_queue_mode &=
>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>> +    ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
>>>>>>> +            lower_32_bits(ring->wptr));
>>>>>>> +    fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
>>>>>>>   -        fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>> -        ring = &adev->vcn.inst[i].ring_enc[0];
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI,
>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
>>>>>>> -        fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>> -
>>>>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>> -        ring = &adev->vcn.inst[i].ring_enc[1];
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2,
>>>>>>> lower_32_bits(ring->wptr));
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2,
>>>>>>> lower_32_bits(ring->wptr));
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2,
>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4);
>>>>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>> -    }
>>>>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>> +    ring = &adev->vcn.inst[inst].ring_enc[0];
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI,
>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
>>>>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>> +
>>>>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>> +    ring = &adev->vcn.inst[inst].ring_enc[1];
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2,
>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
>>>>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>         return 0;
>>>>>>>   }
>>>>>>> @@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct
>>>>>>> amdgpu_device *adev, int inst_idx)
>>>>>>>       return 0;
>>>>>>>   }
>>>>>>>   -static int vcn_v2_5_stop(struct amdgpu_device *adev)
>>>>>>> +static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned int inst)
>>>>>>>   {
>>>>>>>       uint32_t tmp;
>>>>>>> -    int i, r = 0;
>>>>>>> +    int r = 0;
>>>>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>> -            continue;
>>>>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>> -            r = vcn_v2_5_stop_dpg_mode(adev, i);
>>>>>>> -            continue;
>>>>>>> -        }
>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>> +        goto done;
>>>>>>>   -        /* wait for vcn idle */
>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS,
>>>>>>> UVD_STATUS__IDLE, 0x7);
>>>>>>> -        if (r)
>>>>>>> -            return r;
>>>>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>> +        r = vcn_v2_5_stop_dpg_mode(adev, inst);
>>>>>>> +        goto done;
>>>>>>> +    }
>>>>>>>   -        tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>>>>>> -            UVD_LMI_STATUS__READ_CLEAN_MASK |
>>>>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>>>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
>>>>>>> -        if (r)
>>>>>>> -            return r;
>>>>>>> +    /* wait for vcn idle */
>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS,
>>>>>>> UVD_STATUS__IDLE, 0x7);
>>>>>>> +    if (r)
>>>>>>> +        return r;
>>>>>>>   -        /* block LMI UMC channel */
>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
>>>>>>> -        tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
>>>>>>> +    tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>>>>>> +        UVD_LMI_STATUS__READ_CLEAN_MASK |
>>>>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>>>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
>>>>>>> +    if (r)
>>>>>>> +        return r;
>>>>>>>   -        tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>>>>>> -            UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
>>>>>>> -        if (r)
>>>>>>> -            return r;
>>>>>>> +    /* block LMI UMC channel */
>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
>>>>>>> +    tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
>>>>>>>   -        /* block VCPU register access */
>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
>>>>>>> -            UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>>>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>> +    tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>>>>>> +        UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
>>>>>>> +    if (r)
>>>>>>> +        return r;
>>>>>>>   -        /* reset VCPU */
>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>> -            UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>> +    /* block VCPU register access */
>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
>>>>>>> +        UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>>>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>   -        /* disable VCPU clock */
>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>>>> -            ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>>>>> +    /* reset VCPU */
>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>> +        UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>   -        /* clear status */
>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
>>>>>>> +    /* disable VCPU clock */
>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>>>> +        ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>>>>>   -        vcn_v2_5_enable_clock_gating(adev);
>>>>>>> +    /* clear status */
>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
>>>>>>>   -        /* enable register anti-hang mechanism */
>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
>>>>>>> -            UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>>>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>> -    }
>>>>>>> +    vcn_v2_5_enable_clock_gating(adev);
>>>>>>>   -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>> -        if (adev->pm.dpm_enabled)
>>>>>>> -            amdgpu_dpm_enable_vcn(adev, false, i);
>>>>>>> -    }
>>>>>>> +    /* enable register anti-hang mechanism */
>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
>>>>>>> +        UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>>>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>> +done:
>>>>>>> +    if (adev->pm.dpm_enabled)
>>>>>>> +        amdgpu_dpm_enable_vcn(adev, false, inst);
>>>>>>>         return 0;
>>>>>>>   }
>>>>>>> @@ -1838,9 +1827,9 @@ static int
>>>>>>> vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
>>>>>>>           return 0;
>>>>>>>         if (state == AMD_PG_STATE_GATE)
>>>>>>> -        ret = vcn_v2_5_stop(adev);
>>>>>>> +        ret = vcn_v2_5_stop(adev, inst);
>>>>>>>       else
>>>>>>> -        ret = vcn_v2_5_start(adev);
>>>>>>> +        ret = vcn_v2_5_start(adev, inst);
>>>>>>>         if (!ret)
>>>>>>>           adev->vcn.cur_state[inst] = state;

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-08  7:03               ` Lazar, Lijo
@ 2024-10-08 22:04                 ` Boyuan Zhang
  2024-10-09  3:43                   ` Lazar, Lijo
  0 siblings, 1 reply; 37+ messages in thread
From: Boyuan Zhang @ 2024-10-08 22:04 UTC (permalink / raw)
  To: Lazar, Lijo, Alex Deucher
  Cc: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri


On 2024-10-08 03:03, Lazar, Lijo wrote:
>
> On 10/7/2024 8:54 PM, Alex Deucher wrote:
>> On Mon, Oct 7, 2024 at 10:32 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>>>
>>>
>>> On 10/7/2024 7:47 PM, Alex Deucher wrote:
>>>> On Mon, Oct 7, 2024 at 9:58 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>>>>>
>>>>>
>>>>> On 10/7/2024 7:03 PM, Boyuan Zhang wrote:
>>>>>> On 2024-10-07 01:22, Lazar, Lijo wrote:
>>>>>>> On 10/5/2024 12:14 AM, boyuan.zhang@amd.com wrote:
>>>>>>>> From: Boyuan Zhang <boyuan.zhang@amd.com>
>>>>>>>>
>>>>>>>> For vcn 2_5, add ip_block for each vcn instance during discovery stage.
>>>>>>>>
>>>>>>>> And only powering on/off one of the vcn instance using the
>>>>>>>> instance value stored in ip_block, instead of powering on/off all
>>>>>>>> vcn instances. Modify the existing functions to use the instance value
>>>>>>>> in ip_block, and remove the original for loop for all vcn instances.
>>>>>>>>
>>>>>>>> v2: rename "i"/"j" to "inst" for instance value.
>>>>>>>>
>>>>>>>> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
>>>>>>>> ---
>>>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
>>>>>>>>    drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565 +++++++++---------
>>>>>>>>    2 files changed, 280 insertions(+), 289 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>> index 9f9a1867da72..de1053cc2a2b 100644
>>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>> @@ -2278,6 +2278,7 @@ static int
>>>>>>>> amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
>>>>>>>>      static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device
>>>>>>>> *adev)
>>>>>>>>    {
>>>>>>>> +    int i;
>>>>>>>>        if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
>>>>>>>>            switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
>>>>>>>>            case IP_VERSION(7, 0, 0):
>>>>>>>> @@ -2321,7 +2322,8 @@ static int
>>>>>>>> amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>>>>>>>>            case IP_VERSION(2, 0, 3):
>>>>>>>>                break;
>>>>>>>>            case IP_VERSION(2, 5, 0):
>>>>>>>> -            amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>>>>>>>> +            for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
>>>>>>>> +                amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>>>>>>> This introduces a totally confusing design now. At a higher level an IP
>>>>>>> block type manages multiple instances and their power states. Now there
>>>>>>> is a mix where no definition can be attributed to an IP block. Or, if
>>>>>>> this were to be done uniformly for other IPs, then for some SOCs there
>>>>>>> could be 16 SDMA blocks, 8 GFX blocks and so forth.
>>>>>>>
>>>>>>> What is the reason to do this way? Can't VCN IP block maintain the state
>>>>>>> of multiple instances within itself?
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Lijo
>>>>>> This is part of the fundamental design change for separating IP block
>>>>>> per instance, in order to
>>>>>> handle each instance separately within same IP block (e.g. separate
>>>>>> power/clock management).
>>>>>>
>>>>>> Part 1, Change all adev ptr handle to amdgpu_ip_block ptr in all
>>>>>> callbacks (hw_init/fini, sw_init/fini,
>>>>>> suspend, etc...) for all IP blocks, so that each IP knows which IP_block
>>>>>> (and which instance) the
>>>>>> callback is for. Most parts of this changes have been submitted by Sunil.
>>>>>>
>>>>>> Part 2, Separate IP block per instance.
>>>>>>
>>>>>> Part 3, Since callbacks can pass in IP_block now after Part 1 change and
>>>>>> instance value can be
>>>>>> obtained from each IP block in Part 2, IP can then choose to handle
>>>>>> callbacks ONLY for the given
>>>>>> instance of a given IP block (or still handling for all instances as
>>>>>> before).
>>>>>> For VCN, all callbacks will be handled only for the given one instance,
>>>>>> instead of the original for-
>>>>>> loop for all instance. As a result, each VCN instance can be
>>>>>> start/stop/int/fini/suspend separately.
>>>>>>
>>>>>> Part 4, Change all VCN helper functions to handle only the given
>>>>>> instance, instead of the original
>>>>>> for-loop for all instance.
>>>>>>
>>>>>> Each instance can have its own states, so we think it makes more sense
>>>>>> to separate them on IP
>>>>>> block level to handle each of them separately.
>>>>>
>>>>> Such a change should not be done unless all IPs follow the same design.
>>>>> You didn't answer the question - what necessitates this change? What is
>>>>> special about VCN that it cannot manage the states of multiple instances
>>>>> within the IP block?
>>>> We want to be able to manage the powergating independently for each
>>>> VCN instance for both power management and VCN reset.  Right now power
>>>> gating is handled at the IP level so it's not easy or clean to handle
>>>> powergating of individual IP instances.
>>>>
>>> Still VCN block can manage the powergated instances (FWIW, it's just an
>>> array in SMU block). Also vcn block gets to run the idle worker and
>>> knows the rings (and corresponding VCN instances) that are idle.
>>> Maintaining instance states in VCN block and modifying idle worker to
>>> just idle that instance alone doesn't look like a complex change.
>>
>> We already went down that road and it's really ugly.  We end up
>> duplicating a bunch of code paths for different driver flows because
>> set_powergating_state() and set_clockgating_state are at the IP level
>> and we want per instance gating.  We could add a num_instances member
>> at the IP block level and then convert all of the high level code that
>> calls the IP functions loop over the number of instances, but that
>> seems like just as much work and it's not quite as clean IMHO.
>>
> Sorry, I'm not seeing much difference in this design. All it does is
> just split instances to IP block at the same time it's going to keep an
> instance parameter in IP block APIs.
>
> 	amdgpu_device_ip_set_clockgating_state(blocktype, instance);
> 	amdgpu_device_ip_set_powergating_state(blocktype, instance);
>
> Also, VCN continues to maintain an array of amdgpu_vcn_inst. I think
> it's easier manage this with changes to amdgpu_vcn_inst. Since it is
> continued to be maintained, what about just moving the states and
> idle_work inside amdgpu_vcn_inst.
> 	
> 	int inst;
> 	enum amd_powergating_state cur_pg_state;
> 	enum amd_clockgating_state state cur_cg_state;
> 	struct delayed_work     idle_work;
>
> At the end of ring usage of corresponding instance, just invoke the
> corresponding instance's idle work.
>
> schedule_delayed_work(&ring->adev->vcn.inst[ring->me].idle_work,
> idle_time_out);
First of all, separating idle work and state is still needed in current 
design.
Separating idle work by instance is already handled in patch 17/18.
Separating power gating state is already handled in patch 10/18.

I agree that "adding instance variable" in amdgpu_vcn_inst requires
much less effort, but as mentioned by Alex previously, we already
went down that way to use "inst" variable in amdgou_vcn_inst as you
listed above and track this instance value all the way from VCN to SMU.
However, this is a no-go based on discussions with Christian and Alex.
Since set_powergating_state() is at IP level, it will be clean to do
per instance gating at IP level. With the change of passing ip_block to
callback functions, all ip functions can now choose to handle only the
given instance, which is a clean separation between multiple instance.


>
> I don't see any change in this series for other IP block APIs.
Yes, currently we only do this per instance IP block for VCN. For long term,
the plan is to change all other IP with multiple blocks into this design.

Regards,
Boyuan


>
> Thanks,
> Lijo
>
>> Alex
>>
>>> Moving to IP block per instance for VCN alone is not a change that helps
>>> to define an IP block. If that needs to be done for every other IP type,
>>> that's also a massive change.
>>>
>>> Also, then it's no longer possible to have something static like this -
>>>          struct amdgpu_ip_block          ip_blocks[AMDGPU_MAX_IP_NUM];
>>>
>>>
>>> Thanks,
>>> Lijo
>>>
>>>> Alex
>>>>
>>>>> Thanks,
>>>>> Lijo
>>>>>
>>>>>> Thanks,
>>>>>> Boyuan
>>>>>>>>                amdgpu_device_ip_block_add(adev, &jpeg_v2_5_ip_block);
>>>>>>>>                break;
>>>>>>>>            case IP_VERSION(2, 6, 0):
>>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>> b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>> index d00df51bc400..1f8738ae360a 100644
>>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>> @@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct
>>>>>>>> amdgpu_ip_block *ip_block)
>>>>>>>>    static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>>>>>>>>    {
>>>>>>>>        struct amdgpu_ring *ring;
>>>>>>>> -    int i, j, r;
>>>>>>>> +    int i, r;
>>>>>>>>        uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
>>>>>>>>        uint32_t *ptr;
>>>>>>>>        struct amdgpu_device *adev = ip_block->adev;
>>>>>>>> +    int inst = ip_block->instance;
>>>>>>>>    -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>>>>>>> -        if (adev->vcn.harvest_config & (1 << j))
>>>>>>>> -            continue;
>>>>>>>> -        /* VCN DEC TRAP */
>>>>>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>>>>> -                VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>>>>>>> &adev->vcn.inst[j].irq);
>>>>>>>> -        if (r)
>>>>>>>> -            return r;
>>>>>>>> -
>>>>>>>> -        /* VCN ENC TRAP */
>>>>>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>> -            r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>>>>> -                i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>>>>>>> &adev->vcn.inst[j].irq);
>>>>>>>> -            if (r)
>>>>>>>> -                return r;
>>>>>>>> -        }
>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>> +        goto sw_init;
>>>>>>>> +    /* VCN DEC TRAP */
>>>>>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>>>>> +            VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>>>>>>> &adev->vcn.inst[inst].irq);
>>>>>>>> +    if (r)
>>>>>>>> +        return r;
>>>>>>>>    -        /* VCN POISON TRAP */
>>>>>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>>>>> -            VCN_2_6__SRCID_UVD_POISON,
>>>>>>>> &adev->vcn.inst[j].ras_poison_irq);
>>>>>>>> +    /* VCN ENC TRAP */
>>>>>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>> +        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>>>>> +            i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>>>>>>> &adev->vcn.inst[inst].irq);
>>>>>>>>            if (r)
>>>>>>>>                return r;
>>>>>>>>        }
>>>>>>>>    +    /* VCN POISON TRAP */
>>>>>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>>>>> +        VCN_2_6__SRCID_UVD_POISON,
>>>>>>>> &adev->vcn.inst[inst].ras_poison_irq);
>>>>>>>> +    if (r)
>>>>>>>> +        return r;
>>>>>>>> +sw_init:
>>>>>>>>        r = amdgpu_vcn_sw_init(adev);
>>>>>>>>        if (r)
>>>>>>>>            return r;
>>>>>>>> @@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct
>>>>>>>> amdgpu_ip_block *ip_block)
>>>>>>>>        if (r)
>>>>>>>>            return r;
>>>>>>>>    -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>>>>>>> -        volatile struct amdgpu_fw_shared *fw_shared;
>>>>>>>> +    volatile struct amdgpu_fw_shared *fw_shared;
>>>>>>>>    -        if (adev->vcn.harvest_config & (1 << j))
>>>>>>>> -            continue;
>>>>>>>> -        adev->vcn.internal.context_id =
>>>>>>>> mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>>>>>>> -        adev->vcn.internal.ib_vmid =
>>>>>>>> mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>>>>>>> -        adev->vcn.internal.ib_bar_low =
>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>>>>>>> -        adev->vcn.internal.ib_bar_high =
>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>>>>>>> -        adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>>>>>>> -        adev->vcn.internal.gp_scratch8 =
>>>>>>>> mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>>>>>>> -
>>>>>>>> -        adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>>>>>>> -        adev->vcn.inst[j].external.scratch9 = SOC15_REG_OFFSET(VCN,
>>>>>>>> j, mmUVD_SCRATCH9);
>>>>>>>> -        adev->vcn.internal.data0 =
>>>>>>>> mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>>>>>>> -        adev->vcn.inst[j].external.data0 = SOC15_REG_OFFSET(VCN, j,
>>>>>>>> mmUVD_GPCOM_VCPU_DATA0);
>>>>>>>> -        adev->vcn.internal.data1 =
>>>>>>>> mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>>>>>>> -        adev->vcn.inst[j].external.data1 = SOC15_REG_OFFSET(VCN, j,
>>>>>>>> mmUVD_GPCOM_VCPU_DATA1);
>>>>>>>> -        adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>>>>>>> -        adev->vcn.inst[j].external.cmd = SOC15_REG_OFFSET(VCN, j,
>>>>>>>> mmUVD_GPCOM_VCPU_CMD);
>>>>>>>> -        adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>>>>>>> -        adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(VCN, j,
>>>>>>>> mmUVD_NO_OP);
>>>>>>>> -
>>>>>>>> -        ring = &adev->vcn.inst[j].ring_dec;
>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>> +        goto done;
>>>>>>>> +    adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>>>>>>> +    adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>>>>>>> +    adev->vcn.internal.ib_bar_low =
>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>>>>>>> +    adev->vcn.internal.ib_bar_high =
>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>>>>>>> +    adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>>>>>>> +    adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>>>>>>> +
>>>>>>>> +    adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>>>>>>> +    adev->vcn.inst[inst].external.scratch9 = SOC15_REG_OFFSET(VCN,
>>>>>>>> inst, mmUVD_SCRATCH9);
>>>>>>>> +    adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>>>>>>> +    adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN,
>>>>>>>> inst, mmUVD_GPCOM_VCPU_DATA0);
>>>>>>>> +    adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>>>>>>> +    adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN,
>>>>>>>> inst, mmUVD_GPCOM_VCPU_DATA1);
>>>>>>>> +    adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>>>>>>> +    adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN, inst,
>>>>>>>> mmUVD_GPCOM_VCPU_CMD);
>>>>>>>> +    adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>>>>>>> +    adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN, inst,
>>>>>>>> mmUVD_NO_OP);
>>>>>>>> +
>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>>>>>>> +    ring->use_doorbell = true;
>>>>>>>> +
>>>>>>>> +    ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 <<
>>>>>>>> 1) +
>>>>>>>> +            (amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
>>>>>>>> +
>>>>>>>> +    if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
>>>>>>>> +        ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>>> +    else
>>>>>>>> +        ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>>> +
>>>>>>>> +    sprintf(ring->name, "vcn_dec_%d", inst);
>>>>>>>> +    r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq,
>>>>>>>> +                 0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>>>>>>> +    if (r)
>>>>>>>> +        return r;
>>>>>>>> +
>>>>>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>> +        enum amdgpu_ring_priority_level hw_prio =
>>>>>>>> amdgpu_vcn_get_enc_ring_prio(i);
>>>>>>>> +
>>>>>>>> +        ring = &adev->vcn.inst[inst].ring_enc[i];
>>>>>>>>            ring->use_doorbell = true;
>>>>>>>>              ring->doorbell_index =
>>>>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>>>>>>> -                (amdgpu_sriov_vf(adev) ? 2*j : 8*j);
>>>>>>>> +                (amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2 + i +
>>>>>>>> 8*inst));
>>>>>>>>    -        if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2,
>>>>>>>> 5, 0))
>>>>>>>> +        if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>>>>> +            IP_VERSION(2, 5, 0))
>>>>>>>>                ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>>>            else
>>>>>>>>                ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>>>    -        sprintf(ring->name, "vcn_dec_%d", j);
>>>>>>>> -        r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq,
>>>>>>>> -                     0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>>>>>>> +        sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
>>>>>>>> +        r = amdgpu_ring_init(adev, ring, 512,
>>>>>>>> +                     &adev->vcn.inst[inst].irq, 0,
>>>>>>>> +                     hw_prio, NULL);
>>>>>>>>            if (r)
>>>>>>>>                return r;
>>>>>>>> -
>>>>>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>> -            enum amdgpu_ring_priority_level hw_prio =
>>>>>>>> amdgpu_vcn_get_enc_ring_prio(i);
>>>>>>>> -
>>>>>>>> -            ring = &adev->vcn.inst[j].ring_enc[i];
>>>>>>>> -            ring->use_doorbell = true;
>>>>>>>> -
>>>>>>>> -            ring->doorbell_index =
>>>>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>>>>>>> -                    (amdgpu_sriov_vf(adev) ? (1 + i + 2*j) : (2 + i
>>>>>>>> + 8*j));
>>>>>>>> -
>>>>>>>> -            if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>>>>> -                IP_VERSION(2, 5, 0))
>>>>>>>> -                ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>>> -            else
>>>>>>>> -                ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>>> -
>>>>>>>> -            sprintf(ring->name, "vcn_enc_%d.%d", j, i);
>>>>>>>> -            r = amdgpu_ring_init(adev, ring, 512,
>>>>>>>> -                         &adev->vcn.inst[j].irq, 0,
>>>>>>>> -                         hw_prio, NULL);
>>>>>>>> -            if (r)
>>>>>>>> -                return r;
>>>>>>>> -        }
>>>>>>>> -
>>>>>>>> -        fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
>>>>>>>> -        fw_shared->present_flag_0 =
>>>>>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>>>>>>> -
>>>>>>>> -        if (amdgpu_vcnfw_log)
>>>>>>>> -            amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>>>>>>        }
>>>>>>>>    +    fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
>>>>>>>> +    fw_shared->present_flag_0 =
>>>>>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>>>>>>> +
>>>>>>>> +    if (amdgpu_vcnfw_log)
>>>>>>>> +        amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>>>>>> +done:
>>>>>>>>        if (amdgpu_sriov_vf(adev)) {
>>>>>>>>            r = amdgpu_virt_alloc_mm_table(adev);
>>>>>>>>            if (r)
>>>>>>>> @@ -1005,197 +1002,192 @@ static int vcn_v2_5_start_dpg_mode(struct
>>>>>>>> amdgpu_device *adev, int inst_idx, boo
>>>>>>>>        return 0;
>>>>>>>>    }
>>>>>>>>    -static int vcn_v2_5_start(struct amdgpu_device *adev)
>>>>>>>> +static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned int
>>>>>>>> inst)
>>>>>>>>    {
>>>>>>>>        struct amdgpu_ring *ring;
>>>>>>>>        uint32_t rb_bufsz, tmp;
>>>>>>>> -    int i, j, k, r;
>>>>>>>> +    int j, k, r;
>>>>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>> -        if (adev->pm.dpm_enabled)
>>>>>>>> -            amdgpu_dpm_enable_vcn(adev, true, i);
>>>>>>>> -    }
>>>>>>>> -
>>>>>>>> -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>> -            continue;
>>>>>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>> -            r = vcn_v2_5_start_dpg_mode(adev, i,
>>>>>>>> adev->vcn.indirect_sram);
>>>>>>>> -            continue;
>>>>>>>> -        }
>>>>>>>> +    if (adev->pm.dpm_enabled)
>>>>>>>> +        amdgpu_dpm_enable_vcn(adev, true, inst);
>>>>>>>>    -        /* disable register anti-hang mechanism */
>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS), 0,
>>>>>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>> +        return 0;
>>>>>>>>    -        /* set uvd status busy */
>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) |
>>>>>>>> UVD_STATUS__UVD_BUSY;
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
>>>>>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>> +        r = vcn_v2_5_start_dpg_mode(adev, inst,
>>>>>>>> adev->vcn.indirect_sram);
>>>>>>>> +        return r;
>>>>>>>>        }
>>>>>>>>    +    /* disable register anti-hang mechanism */
>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS), 0,
>>>>>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>> +
>>>>>>>> +    /* set uvd status busy */
>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
>>>>>>>> +
>>>>>>>>        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
>>>>>>>>            return 0;
>>>>>>>>          /*SW clock gating */
>>>>>>>>        vcn_v2_5_disable_clock_gating(adev);
>>>>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>> -            continue;
>>>>>>>> -        /* enable VCPU clock */
>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>>> -            UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>>>>>>> -
>>>>>>>> -        /* disable master interrupt */
>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
>>>>>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>> -
>>>>>>>> -        /* setup mmUVD_LMI_CTRL */
>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
>>>>>>>> -        tmp &= ~0xff;
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
>>>>>>>> -            UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>>>>>>> -            UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>>>>>>> -            UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>>>>>>> -            UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>>>>>>> -
>>>>>>>> -        /* setup mmUVD_MPC_CNTL */
>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
>>>>>>>> -        tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>>>>>>> -        tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
>>>>>>>> -
>>>>>>>> -        /* setup UVD_MPC_SET_MUXA0 */
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
>>>>>>>> -            ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>>>>>>> -            (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>>>>>>> -            (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>>>>>>> -            (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>>>>>>> -
>>>>>>>> -        /* setup UVD_MPC_SET_MUXB0 */
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
>>>>>>>> -            ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>>>>>>> -            (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>>>>>>> -            (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>>>>>>> -            (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>>>>>>> -
>>>>>>>> -        /* setup mmUVD_MPC_SET_MUX */
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
>>>>>>>> -            ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>>>>>>> -            (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>>>>>>> -            (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>>>>>> -    }
>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>> +        return 0;
>>>>>>>> +
>>>>>>>> +    /* enable VCPU clock */
>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>>> +        UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>>>>>>> +
>>>>>>>> +    /* disable master interrupt */
>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
>>>>>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>> +
>>>>>>>> +    /* setup mmUVD_LMI_CTRL */
>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
>>>>>>>> +    tmp &= ~0xff;
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
>>>>>>>> +        UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>>>>>>> +        UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>>>>>>> +        UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>>>>>>> +        UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>>>>>>> +
>>>>>>>> +    /* setup mmUVD_MPC_CNTL */
>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
>>>>>>>> +    tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>>>>>>> +    tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
>>>>>>>> +
>>>>>>>> +    /* setup UVD_MPC_SET_MUXA0 */
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
>>>>>>>> +        ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>>>>>>> +        (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>>>>>>> +        (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>>>>>>> +        (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>>>>>>> +
>>>>>>>> +    /* setup UVD_MPC_SET_MUXB0 */
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
>>>>>>>> +        ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>>>>>>> +        (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>>>>>>> +        (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>>>>>>> +        (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>>>>>>> +
>>>>>>>> +    /* setup mmUVD_MPC_SET_MUX */
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
>>>>>>>> +        ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>>>>>>> +        (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>>>>>>> +        (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>>>>>>          vcn_v2_5_mc_resume(adev);
>>>>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>> -        volatile struct amdgpu_fw_shared *fw_shared =
>>>>>>>> adev->vcn.inst[i].fw_shared.cpu_addr;
>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>> -            continue;
>>>>>>>> -        /* VCN global tiling registers */
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>> -            adev->gfx.config.gb_addr_config);
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>> -            adev->gfx.config.gb_addr_config);
>>>>>>>> +    volatile struct amdgpu_fw_shared *fw_shared =
>>>>>>>> adev->vcn.inst[inst].fw_shared.cpu_addr;
>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>> +        return 0;
>>>>>>>> +
>>>>>>>> +    /* VCN global tiling registers */
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>> +        adev->gfx.config.gb_addr_config);
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>> +        adev->gfx.config.gb_addr_config);
>>>>>>>>    -        /* enable LMI MC and UMC channels */
>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
>>>>>>>> -            ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>>>>>> +    /* enable LMI MC and UMC channels */
>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
>>>>>>>> +        ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>>>>>>    -        /* unblock VCPU register access */
>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
>>>>>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>> +    /* unblock VCPU register access */
>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
>>>>>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>>    -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>    -        for (k = 0; k < 10; ++k) {
>>>>>>>> -            uint32_t status;
>>>>>>>> -
>>>>>>>> -            for (j = 0; j < 100; ++j) {
>>>>>>>> -                status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
>>>>>>>> -                if (status & 2)
>>>>>>>> -                    break;
>>>>>>>> -                if (amdgpu_emu_mode == 1)
>>>>>>>> -                    msleep(500);
>>>>>>>> -                else
>>>>>>>> -                    mdelay(10);
>>>>>>>> -            }
>>>>>>>> -            r = 0;
>>>>>>>> +    for (k = 0; k < 10; ++k) {
>>>>>>>> +        uint32_t status;
>>>>>>>> +
>>>>>>>> +        for (j = 0; j < 100; ++j) {
>>>>>>>> +            status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
>>>>>>>>                if (status & 2)
>>>>>>>>                    break;
>>>>>>>> +            if (amdgpu_emu_mode == 1)
>>>>>>>> +                msleep(500);
>>>>>>>> +            else
>>>>>>>> +                mdelay(10);
>>>>>>>> +        }
>>>>>>>> +        r = 0;
>>>>>>>> +        if (status & 2)
>>>>>>>> +            break;
>>>>>>>>    -            DRM_ERROR("VCN decode not responding, trying to reset
>>>>>>>> the VCPU!!!\n");
>>>>>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>>> -                UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>> -            mdelay(10);
>>>>>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>> +        DRM_ERROR("VCN decode not responding, trying to reset the
>>>>>>>> VCPU!!!\n");
>>>>>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>>> +            UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>> +        mdelay(10);
>>>>>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>    -            mdelay(10);
>>>>>>>> -            r = -1;
>>>>>>>> -        }
>>>>>>>> +        mdelay(10);
>>>>>>>> +        r = -1;
>>>>>>>> +    }
>>>>>>>>    -        if (r) {
>>>>>>>> -            DRM_ERROR("VCN decode not responding, giving up!!!\n");
>>>>>>>> -            return r;
>>>>>>>> -        }
>>>>>>>> +    if (r) {
>>>>>>>> +        DRM_ERROR("VCN decode not responding, giving up!!!\n");
>>>>>>>> +        return r;
>>>>>>>> +    }
>>>>>>>>    -        /* enable master interrupt */
>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
>>>>>>>> -            UVD_MASTINT_EN__VCPU_EN_MASK,
>>>>>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>> +    /* enable master interrupt */
>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
>>>>>>>> +        UVD_MASTINT_EN__VCPU_EN_MASK,
>>>>>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>>    -        /* clear the busy bit of VCN_STATUS */
>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
>>>>>>>> -            ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>>>>>> +    /* clear the busy bit of VCN_STATUS */
>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
>>>>>>>> +        ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>>>>>>    -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
>>>>>>>>    -        ring = &adev->vcn.inst[i].ring_dec;
>>>>>>>> -        /* force RBC into idle state */
>>>>>>>> -        rb_bufsz = order_base_2(ring->ring_size);
>>>>>>>> -        tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>>>>>>> +    /* force RBC into idle state */
>>>>>>>> +    rb_bufsz = order_base_2(ring->ring_size);
>>>>>>>> +    tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
>>>>>>>>    -        fw_shared->multi_queue.decode_queue_mode |=
>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>> -        /* program the RB_BASE for ring buffer */
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>>>>>>> -            lower_32_bits(ring->gpu_addr));
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>>>>>>> -            upper_32_bits(ring->gpu_addr));
>>>>>>>> +    fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
>>>>>>>> +    /* program the RB_BASE for ring buffer */
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>>>>>>> +        lower_32_bits(ring->gpu_addr));
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>>>>>>> +        upper_32_bits(ring->gpu_addr));
>>>>>>>>    -        /* Initialize the ring buffer's read and write pointers */
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
>>>>>>>> +    /* Initialize the ring buffer's read and write pointers */
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
>>>>>>>>    -        ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
>>>>>>>> -                lower_32_bits(ring->wptr));
>>>>>>>> -        fw_shared->multi_queue.decode_queue_mode &=
>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>> +    ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
>>>>>>>> +            lower_32_bits(ring->wptr));
>>>>>>>> +    fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
>>>>>>>>    -        fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>> -        ring = &adev->vcn.inst[i].ring_enc[0];
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI,
>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
>>>>>>>> -        fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>> -
>>>>>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>> -        ring = &adev->vcn.inst[i].ring_enc[1];
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2,
>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2,
>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2,
>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4);
>>>>>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>> -    }
>>>>>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_enc[0];
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI,
>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
>>>>>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>> +
>>>>>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_enc[1];
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2,
>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
>>>>>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>          return 0;
>>>>>>>>    }
>>>>>>>> @@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct
>>>>>>>> amdgpu_device *adev, int inst_idx)
>>>>>>>>        return 0;
>>>>>>>>    }
>>>>>>>>    -static int vcn_v2_5_stop(struct amdgpu_device *adev)
>>>>>>>> +static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned int inst)
>>>>>>>>    {
>>>>>>>>        uint32_t tmp;
>>>>>>>> -    int i, r = 0;
>>>>>>>> +    int r = 0;
>>>>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>> -            continue;
>>>>>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>> -            r = vcn_v2_5_stop_dpg_mode(adev, i);
>>>>>>>> -            continue;
>>>>>>>> -        }
>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>> +        goto done;
>>>>>>>>    -        /* wait for vcn idle */
>>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS,
>>>>>>>> UVD_STATUS__IDLE, 0x7);
>>>>>>>> -        if (r)
>>>>>>>> -            return r;
>>>>>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>> +        r = vcn_v2_5_stop_dpg_mode(adev, inst);
>>>>>>>> +        goto done;
>>>>>>>> +    }
>>>>>>>>    -        tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>>>>>>> -            UVD_LMI_STATUS__READ_CLEAN_MASK |
>>>>>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>>>>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
>>>>>>>> -        if (r)
>>>>>>>> -            return r;
>>>>>>>> +    /* wait for vcn idle */
>>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS,
>>>>>>>> UVD_STATUS__IDLE, 0x7);
>>>>>>>> +    if (r)
>>>>>>>> +        return r;
>>>>>>>>    -        /* block LMI UMC channel */
>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
>>>>>>>> -        tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
>>>>>>>> +    tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>>>>>>> +        UVD_LMI_STATUS__READ_CLEAN_MASK |
>>>>>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>>>>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
>>>>>>>> +    if (r)
>>>>>>>> +        return r;
>>>>>>>>    -        tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>>>>>>> -            UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
>>>>>>>> -        if (r)
>>>>>>>> -            return r;
>>>>>>>> +    /* block LMI UMC channel */
>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
>>>>>>>> +    tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
>>>>>>>>    -        /* block VCPU register access */
>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
>>>>>>>> -            UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>>>>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>> +    tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>>>>>>> +        UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
>>>>>>>> +    if (r)
>>>>>>>> +        return r;
>>>>>>>>    -        /* reset VCPU */
>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>>> -            UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>> +    /* block VCPU register access */
>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
>>>>>>>> +        UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>>>>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>>    -        /* disable VCPU clock */
>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>>>>> -            ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>>>>>> +    /* reset VCPU */
>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>>> +        UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>    -        /* clear status */
>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
>>>>>>>> +    /* disable VCPU clock */
>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>>>>> +        ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>>>>>>    -        vcn_v2_5_enable_clock_gating(adev);
>>>>>>>> +    /* clear status */
>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
>>>>>>>>    -        /* enable register anti-hang mechanism */
>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
>>>>>>>> -            UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>>>>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>> -    }
>>>>>>>> +    vcn_v2_5_enable_clock_gating(adev);
>>>>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>> -        if (adev->pm.dpm_enabled)
>>>>>>>> -            amdgpu_dpm_enable_vcn(adev, false, i);
>>>>>>>> -    }
>>>>>>>> +    /* enable register anti-hang mechanism */
>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
>>>>>>>> +        UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>>>>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>> +done:
>>>>>>>> +    if (adev->pm.dpm_enabled)
>>>>>>>> +        amdgpu_dpm_enable_vcn(adev, false, inst);
>>>>>>>>          return 0;
>>>>>>>>    }
>>>>>>>> @@ -1838,9 +1827,9 @@ static int
>>>>>>>> vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
>>>>>>>>            return 0;
>>>>>>>>          if (state == AMD_PG_STATE_GATE)
>>>>>>>> -        ret = vcn_v2_5_stop(adev);
>>>>>>>> +        ret = vcn_v2_5_stop(adev, inst);
>>>>>>>>        else
>>>>>>>> -        ret = vcn_v2_5_start(adev);
>>>>>>>> +        ret = vcn_v2_5_start(adev, inst);
>>>>>>>>          if (!ret)
>>>>>>>>            adev->vcn.cur_state[inst] = state;

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 04/18] drm/amd/pm: add inst to set_powergating_by_smu
  2024-10-04 19:14   ` Alex Deucher
@ 2024-10-08 22:06     ` Boyuan Zhang
  0 siblings, 0 replies; 37+ messages in thread
From: Boyuan Zhang @ 2024-10-08 22:06 UTC (permalink / raw)
  To: Alex Deucher
  Cc: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri


On 2024-10-04 15:14, Alex Deucher wrote:
> On Fri, Oct 4, 2024 at 2:45 PM <boyuan.zhang@amd.com> wrote:
>> From: Boyuan Zhang <boyuan.zhang@amd.com>
>>
>> Add an instance parameter to set_powergating_by_smu() function, and
>> re-write all amd_pm functions accordingly. Then use the instance to
>> call smu_dpm_set_vcn_enable().
>>
>> v2: remove duplicated functions.
>>
>> remove for-loop in smu_dpm_set_power_gate(), and temporarily move it to
>> to amdgpu_dpm_set_powergating_by_smu(), in order to keep the exact same
>> logic as before, until further separation in next patch.
>>
>> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
>> ---
>>   drivers/gpu/drm/amd/include/kgd_pp_interface.h   |  4 +++-
>>   drivers/gpu/drm/amd/pm/amdgpu_dpm.c              | 10 ++++++++--
>>   drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c       |  4 +++-
>>   drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c |  4 +++-
>>   drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c        | 14 ++++++--------
>>   5 files changed, 23 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
>> index 2fa71f68205e..f24bc61df9a7 100644
>> --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h
>> +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
>> @@ -405,7 +405,9 @@ struct amd_pm_funcs {
>>          int (*load_firmware)(void *handle);
>>          int (*wait_for_fw_loading_complete)(void *handle);
>>          int (*set_powergating_by_smu)(void *handle,
>> -                               uint32_t block_type, bool gate);
>> +                               uint32_t block_type,
>> +                               bool gate,
>> +                               int inst);
>>          int (*set_clockgating_by_smu)(void *handle, uint32_t msg_id);
>>          int (*set_power_limit)(void *handle, uint32_t n);
>>          int (*get_power_limit)(void *handle, uint32_t *limit,
>> diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
>> index 9dc82f4d7c93..bcedbeec082f 100644
>> --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
>> +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
>> @@ -88,7 +88,6 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, uint32_t block
>>          case AMD_IP_BLOCK_TYPE_UVD:
>>          case AMD_IP_BLOCK_TYPE_VCE:
>>          case AMD_IP_BLOCK_TYPE_GFX:
>> -       case AMD_IP_BLOCK_TYPE_VCN:
>>          case AMD_IP_BLOCK_TYPE_SDMA:
>>          case AMD_IP_BLOCK_TYPE_JPEG:
>>          case AMD_IP_BLOCK_TYPE_GMC:
>> @@ -96,7 +95,14 @@ int amdgpu_dpm_set_powergating_by_smu(struct amdgpu_device *adev, uint32_t block
>>          case AMD_IP_BLOCK_TYPE_VPE:
>>                  if (pp_funcs && pp_funcs->set_powergating_by_smu)
>>                          ret = (pp_funcs->set_powergating_by_smu(
>> -                               (adev)->powerplay.pp_handle, block_type, gate));
>> +                               (adev)->powerplay.pp_handle, block_type, gate, 0));
>> +               break;
>> +       case AMD_IP_BLOCK_TYPE_VCN:
>> +               if (pp_funcs && pp_funcs->set_powergating_by_smu) {
>> +                       for (int i = 0; i < adev->vcn.num_vcn_inst; i++)
>> +                               ret = (pp_funcs->set_powergating_by_smu(
>> +                                       (adev)->powerplay.pp_handle, block_type, gate, i));
>> +               }
>>                  break;
>>          default:
>>                  break;
>> diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
>> index 2cd6cb991f29..af7da780b58b 100644
>> --- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
>> +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
>> @@ -3287,7 +3287,9 @@ static int kv_dpm_read_sensor(void *handle, int idx,
>>   }
>>
>>   static int kv_set_powergating_by_smu(void *handle,
>> -                               uint32_t block_type, bool gate)
>> +                               uint32_t block_type,
>> +                               bool gate,
>> +                               int inst)
>>   {
>>          switch (block_type) {
>>          case AMD_IP_BLOCK_TYPE_UVD:
>> diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
>> index f193c77cc141..de5ee1c5503f 100644
>> --- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
>> +++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
>> @@ -1241,7 +1241,9 @@ static void pp_dpm_powergate_sdma(void *handle, bool gate)
>>   }
>>
>>   static int pp_set_powergating_by_smu(void *handle,
>> -                               uint32_t block_type, bool gate)
>> +                               uint32_t block_type,
>> +                               bool gate,
>> +                               int inst)
>>   {
>>          int ret = 0;
>>
>> diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
>> index 786241fa8d2c..0da84e390d0d 100644
>> --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
>> +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
>> @@ -353,10 +353,10 @@ static int smu_set_mall_enable(struct smu_context *smu)
>>    */
>>   static int smu_dpm_set_power_gate(void *handle,
>>                                    uint32_t block_type,
>> -                                 bool gate)
>> +                                 bool gate,
>> +                                 int inst)
>>   {
>>          struct smu_context *smu = handle;
>> -       struct amdgpu_device *adev = smu->adev;
>>          int ret = 0;
>>
>>          if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) {
>> @@ -373,12 +373,10 @@ static int smu_dpm_set_power_gate(void *handle,
>>           */
>>          case AMD_IP_BLOCK_TYPE_UVD:
>>          case AMD_IP_BLOCK_TYPE_VCN:
>> -               for (int i = 0; i < adev->vcn.num_vcn_inst; i++) {
>> -                       ret = smu_dpm_set_vcn_enable(smu, !gate, i);
>> -                       if (ret)
>> -                               dev_err(smu->adev->dev, "Failed to power %s VCN!\n",
>> -                                       gate ? "gate" : "ungate");
>> -               }
>> +               ret = smu_dpm_set_vcn_enable(smu, !gate, inst);
>> +               if (ret)
>> +                       dev_err(smu->adev->dev, "Failed to power %s VCN!\n",
>> +                               gate ? "gate" : "ungate");
> Might want to note the instance in the error message.
>
> Alex
Fixed in new patch set just submitted. (patch 04)

Thanks
Boyuan
>
>>                  break;
>>          case AMD_IP_BLOCK_TYPE_GFX:
>>                  ret = smu_gfx_off_control(smu, gate);
>> --
>> 2.34.1
>>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 09/18] drm/amdgpu: add set_powergating_state_instance
  2024-10-04 19:40   ` Alex Deucher
@ 2024-10-08 22:07     ` Boyuan Zhang
  0 siblings, 0 replies; 37+ messages in thread
From: Boyuan Zhang @ 2024-10-08 22:07 UTC (permalink / raw)
  To: Alex Deucher
  Cc: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri


On 2024-10-04 15:40, Alex Deucher wrote:
> On Fri, Oct 4, 2024 at 2:45 PM <boyuan.zhang@amd.com> wrote:
>> From: Boyuan Zhang <boyuan.zhang@amd.com>
>>
>> Add a new function to allow setting requested powergating state for the
>> given instance. If the instance value doesn't match with the one inside
>> ip_block, then do nothing since this request is for other instances with
>> the same block type.
>>
>> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
>> ---
>>   drivers/gpu/drm/amd/amdgpu/amdgpu.h        |  4 +++
>>   drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 37 ++++++++++++++++++++++
>>   2 files changed, 41 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
>> index 3442564fe174..ae59497f3074 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
>> @@ -358,6 +358,10 @@ int amdgpu_device_ip_set_clockgating_state(void *dev,
>>   int amdgpu_device_ip_set_powergating_state(void *dev,
>>                                             enum amd_ip_block_type block_type,
>>                                             enum amd_powergating_state state);
>> +int amdgpu_device_ip_set_powergating_state_instance(void *dev,
>> +                                          enum amd_ip_block_type block_type,
>> +                                          enum amd_powergating_state state,
>> +                                          unsigned int inst);
>>   void amdgpu_device_ip_get_clockgating_state(struct amdgpu_device *adev,
>>                                              u64 *flags);
>>   int amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev,
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>> index 35a3e71a5a84..f0b6a9675405 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>> @@ -2162,6 +2162,43 @@ int amdgpu_device_ip_set_powergating_state(void *dev,
>>          return r;
>>   }
>>
>> +/**
>> + * amdgpu_device_ip_set_powergating_state_instance - set the PG state
>> + *
>> + * @dev: amdgpu_device pointer
>> + * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.)
>> + * @state: powergating state (gate or ungate)
>> + *
>> + * Sets the requested powergating state for the given instance of
>> + * the hardware IP specified.
>> + * Returns the error code from the last instance.
>> + */
>> +int amdgpu_device_ip_set_powergating_state_instance(void *dev,
>> +                                          enum amd_ip_block_type block_type,
>> +                                          enum amd_powergating_state state,
>> +                                          unsigned int inst)
>> +{
>> +       struct amdgpu_device *adev = dev;
>> +       int i, r = 0;
>> +
>> +       for (i = 0; i < adev->num_ip_blocks; i++) {
>> +               if (!adev->ip_blocks[i].status.valid)
>> +                       continue;
>> +               if (adev->ip_blocks[i].version->type != block_type)
>> +                       continue;
>> +               if (adev->ip_blocks[i].instance != inst)
>> +                       continue;
>> +               if (!adev->ip_blocks[i].version->funcs->set_powergating_state)
>> +                       continue;
>> +               r = adev->ip_blocks[i].version->funcs->set_powergating_state(
>> +                       (void *)&adev->ip_blocks[i], state);
>> +               if (r)
>> +                       DRM_ERROR("set_powergating_state of IP block <%s> failed %d\n",
>> +                                 adev->ip_blocks[i].version->funcs->name, r);
>> +       }
>> +       return r;
>> +}
>> +
> I think it would also be cleaner to update
> amdgpu_device_ip_set_powergating_state() to take the instance as a new
> parameter.  Same for amdgpu_device_ip_set_clockgating_state().
>
> Alex
Removed duplicated function, and add instance parameter to existing
function in new patch set (patch 19/32)

Thanks,
Boyuan


>
>>   /**
>>    * amdgpu_device_ip_get_clockgating_state - get the CG state
>>    *
>> --
>> 2.34.1
>>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-04 19:52   ` Alex Deucher
@ 2024-10-08 22:10     ` Boyuan Zhang
  0 siblings, 0 replies; 37+ messages in thread
From: Boyuan Zhang @ 2024-10-08 22:10 UTC (permalink / raw)
  To: Alex Deucher
  Cc: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri


On 2024-10-04 15:52, Alex Deucher wrote:
> On Fri, Oct 4, 2024 at 2:53 PM <boyuan.zhang@amd.com> wrote:
>> From: Boyuan Zhang <boyuan.zhang@amd.com>
>>
>> For vcn 2_5, add ip_block for each vcn instance during discovery stage.
>>
>> And only powering on/off one of the vcn instance using the
>> instance value stored in ip_block, instead of powering on/off all
>> vcn instances. Modify the existing functions to use the instance value
>> in ip_block, and remove the original for loop for all vcn instances.
>>
>> v2: rename "i"/"j" to "inst" for instance value.
>>
>> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
>> ---
>>   drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
>>   drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565 +++++++++---------
>>   2 files changed, 280 insertions(+), 289 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>> index 9f9a1867da72..de1053cc2a2b 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>> @@ -2278,6 +2278,7 @@ static int amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
>>
>>   static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>>   {
>> +       int i;
> new line between stack and code.

Fixed.

>
>>          if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
>>                  switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
>>                  case IP_VERSION(7, 0, 0):
>> @@ -2321,7 +2322,8 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>>                  case IP_VERSION(2, 0, 3):
>>                          break;
>>                  case IP_VERSION(2, 5, 0):
>> -                       amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>> +                       for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
>> +                               amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>>                          amdgpu_device_ip_block_add(adev, &jpeg_v2_5_ip_block);
>>                          break;
>>                  case IP_VERSION(2, 6, 0):
>> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>> index d00df51bc400..1f8738ae360a 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>> @@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct amdgpu_ip_block *ip_block)
>>   static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>>   {
>>          struct amdgpu_ring *ring;
>> -       int i, j, r;
>> +       int i, r;
>>          uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
>>          uint32_t *ptr;
>>          struct amdgpu_device *adev = ip_block->adev;
>> +       int inst = ip_block->instance;
>>
>> -       for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>> -               if (adev->vcn.harvest_config & (1 << j))
>> -                       continue;
>> -               /* VCN DEC TRAP */
>> -               r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>> -                               VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->vcn.inst[j].irq);
>> -               if (r)
>> -                       return r;
>> -
>> -               /* VCN ENC TRAP */
>> -               for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>> -                       r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>> -                               i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[j].irq);
>> -                       if (r)
>> -                               return r;
>> -               }
>> +       if (adev->vcn.harvest_config & (1 << inst))
>> +               goto sw_init;
>> +       /* VCN DEC TRAP */
>> +       r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>> +                       VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->vcn.inst[inst].irq);
>> +       if (r)
>> +               return r;
>>
>> -               /* VCN POISON TRAP */
>> -               r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>> -                       VCN_2_6__SRCID_UVD_POISON, &adev->vcn.inst[j].ras_poison_irq);
>> +       /* VCN ENC TRAP */
>> +       for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>> +               r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>> +                       i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.inst[inst].irq);
>>                  if (r)
>>                          return r;
>>          }
>>
>> +       /* VCN POISON TRAP */
>> +       r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>> +               VCN_2_6__SRCID_UVD_POISON, &adev->vcn.inst[inst].ras_poison_irq);
>> +       if (r)
>> +               return r;
>> +sw_init:
>>          r = amdgpu_vcn_sw_init(adev);
> I think the amdgpu_vcn_* helpers will need to be updated to handle
> instances as well.  Otherwise we'll end up leaking a bunch of memory
> when these gets called for each instance.  While you are at it, we
> should move all of the per instance state from struct amdgpu_vcn to
> struct amdgpu_vcn_inst.
>
> Alex
- All amdgpu_vcn helpers are now handled the given instance.
See new patch set (patch 20/32 to 26/32)

- All per instance variable are now moved to amdgpu_vcn_inst
See new patch set (patch 10/32)

Thanks
Boyuan
>
>>          if (r)
>>                  return r;
>> @@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>>          if (r)
>>                  return r;
>>
>> -       for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>> -               volatile struct amdgpu_fw_shared *fw_shared;
>> +       volatile struct amdgpu_fw_shared *fw_shared;
>>
>> -               if (adev->vcn.harvest_config & (1 << j))
>> -                       continue;
>> -               adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>> -               adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>> -               adev->vcn.internal.ib_bar_low = mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>> -               adev->vcn.internal.ib_bar_high = mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>> -               adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>> -               adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>> -
>> -               adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>> -               adev->vcn.inst[j].external.scratch9 = SOC15_REG_OFFSET(VCN, j, mmUVD_SCRATCH9);
>> -               adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>> -               adev->vcn.inst[j].external.data0 = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_DATA0);
>> -               adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>> -               adev->vcn.inst[j].external.data1 = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_DATA1);
>> -               adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>> -               adev->vcn.inst[j].external.cmd = SOC15_REG_OFFSET(VCN, j, mmUVD_GPCOM_VCPU_CMD);
>> -               adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>> -               adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(VCN, j, mmUVD_NO_OP);
>> -
>> -               ring = &adev->vcn.inst[j].ring_dec;
>> +       if (adev->vcn.harvest_config & (1 << inst))
>> +               goto done;
>> +       adev->vcn.internal.context_id = mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>> +       adev->vcn.internal.ib_vmid = mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>> +       adev->vcn.internal.ib_bar_low = mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>> +       adev->vcn.internal.ib_bar_high = mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>> +       adev->vcn.internal.ib_size = mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>> +       adev->vcn.internal.gp_scratch8 = mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>> +
>> +       adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>> +       adev->vcn.inst[inst].external.scratch9 = SOC15_REG_OFFSET(VCN, inst, mmUVD_SCRATCH9);
>> +       adev->vcn.internal.data0 = mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>> +       adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_DATA0);
>> +       adev->vcn.internal.data1 = mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>> +       adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_DATA1);
>> +       adev->vcn.internal.cmd = mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>> +       adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN, inst, mmUVD_GPCOM_VCPU_CMD);
>> +       adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>> +       adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN, inst, mmUVD_NO_OP);
>> +
>> +       ring = &adev->vcn.inst[inst].ring_dec;
>> +       ring->use_doorbell = true;
>> +
>> +       ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>> +                       (amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
>> +
>> +       if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
>> +               ring->vm_hub = AMDGPU_MMHUB1(0);
>> +       else
>> +               ring->vm_hub = AMDGPU_MMHUB0(0);
>> +
>> +       sprintf(ring->name, "vcn_dec_%d", inst);
>> +       r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[inst].irq,
>> +                                0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>> +       if (r)
>> +               return r;
>> +
>> +       for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>> +               enum amdgpu_ring_priority_level hw_prio = amdgpu_vcn_get_enc_ring_prio(i);
>> +
>> +               ring = &adev->vcn.inst[inst].ring_enc[i];
>>                  ring->use_doorbell = true;
>>
>>                  ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>> -                               (amdgpu_sriov_vf(adev) ? 2*j : 8*j);
>> +                               (amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2 + i + 8*inst));
>>
>> -               if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2, 5, 0))
>> +               if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>> +                       IP_VERSION(2, 5, 0))
>>                          ring->vm_hub = AMDGPU_MMHUB1(0);
>>                  else
>>                          ring->vm_hub = AMDGPU_MMHUB0(0);
>>
>> -               sprintf(ring->name, "vcn_dec_%d", j);
>> -               r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.inst[j].irq,
>> -                                    0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>> +               sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
>> +               r = amdgpu_ring_init(adev, ring, 512,
>> +                                        &adev->vcn.inst[inst].irq, 0,
>> +                                        hw_prio, NULL);
>>                  if (r)
>>                          return r;
>> -
>> -               for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>> -                       enum amdgpu_ring_priority_level hw_prio = amdgpu_vcn_get_enc_ring_prio(i);
>> -
>> -                       ring = &adev->vcn.inst[j].ring_enc[i];
>> -                       ring->use_doorbell = true;
>> -
>> -                       ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>> -                                       (amdgpu_sriov_vf(adev) ? (1 + i + 2*j) : (2 + i + 8*j));
>> -
>> -                       if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>> -                           IP_VERSION(2, 5, 0))
>> -                               ring->vm_hub = AMDGPU_MMHUB1(0);
>> -                       else
>> -                               ring->vm_hub = AMDGPU_MMHUB0(0);
>> -
>> -                       sprintf(ring->name, "vcn_enc_%d.%d", j, i);
>> -                       r = amdgpu_ring_init(adev, ring, 512,
>> -                                            &adev->vcn.inst[j].irq, 0,
>> -                                            hw_prio, NULL);
>> -                       if (r)
>> -                               return r;
>> -               }
>> -
>> -               fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
>> -               fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>> -
>> -               if (amdgpu_vcnfw_log)
>> -                       amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>          }
>>
>> +       fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
>> +       fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>> +
>> +       if (amdgpu_vcnfw_log)
>> +               amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>> +done:
>>          if (amdgpu_sriov_vf(adev)) {
>>                  r = amdgpu_virt_alloc_mm_table(adev);
>>                  if (r)
>> @@ -1005,197 +1002,192 @@ static int vcn_v2_5_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, boo
>>          return 0;
>>   }
>>
>> -static int vcn_v2_5_start(struct amdgpu_device *adev)
>> +static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned int inst)
>>   {
>>          struct amdgpu_ring *ring;
>>          uint32_t rb_bufsz, tmp;
>> -       int i, j, k, r;
>> +       int j, k, r;
>>
>> -       for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>> -               if (adev->pm.dpm_enabled)
>> -                       amdgpu_dpm_enable_vcn(adev, true, i);
>> -       }
>> -
>> -       for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>> -               if (adev->vcn.harvest_config & (1 << i))
>> -                       continue;
>> -               if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>> -                       r = vcn_v2_5_start_dpg_mode(adev, i, adev->vcn.indirect_sram);
>> -                       continue;
>> -               }
>> +       if (adev->pm.dpm_enabled)
>> +               amdgpu_dpm_enable_vcn(adev, true, inst);
>>
>> -               /* disable register anti-hang mechanism */
>> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS), 0,
>> -                       ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>> +       if (adev->vcn.harvest_config & (1 << inst))
>> +               return 0;
>>
>> -               /* set uvd status busy */
>> -               tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
>> -               WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
>> +       if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>> +               r = vcn_v2_5_start_dpg_mode(adev, inst, adev->vcn.indirect_sram);
>> +               return r;
>>          }
>>
>> +       /* disable register anti-hang mechanism */
>> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS), 0,
>> +               ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>> +
>> +       /* set uvd status busy */
>> +       tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) | UVD_STATUS__UVD_BUSY;
>> +       WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
>> +
>>          if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
>>                  return 0;
>>
>>          /*SW clock gating */
>>          vcn_v2_5_disable_clock_gating(adev);
>>
>> -       for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>> -               if (adev->vcn.harvest_config & (1 << i))
>> -                       continue;
>> -               /* enable VCPU clock */
>> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>> -                       UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>> -
>> -               /* disable master interrupt */
>> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
>> -                       ~UVD_MASTINT_EN__VCPU_EN_MASK);
>> -
>> -               /* setup mmUVD_LMI_CTRL */
>> -               tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
>> -               tmp &= ~0xff;
>> -               WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
>> -                       UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK |
>> -                       UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>> -                       UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>> -                       UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>> -
>> -               /* setup mmUVD_MPC_CNTL */
>> -               tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
>> -               tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>> -               tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>> -               WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
>> -
>> -               /* setup UVD_MPC_SET_MUXA0 */
>> -               WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
>> -                       ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>> -                       (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>> -                       (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>> -                       (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>> -
>> -               /* setup UVD_MPC_SET_MUXB0 */
>> -               WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
>> -                       ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>> -                       (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>> -                       (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>> -                       (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>> -
>> -               /* setup mmUVD_MPC_SET_MUX */
>> -               WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
>> -                       ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>> -                       (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>> -                       (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>> -       }
>> +       if (adev->vcn.harvest_config & (1 << inst))
>> +               return 0;
>> +
>> +       /* enable VCPU clock */
>> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>> +               UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>> +
>> +       /* disable master interrupt */
>> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
>> +               ~UVD_MASTINT_EN__VCPU_EN_MASK);
>> +
>> +       /* setup mmUVD_LMI_CTRL */
>> +       tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
>> +       tmp &= ~0xff;
>> +       WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
>> +               UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK |
>> +               UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>> +               UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>> +               UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>> +
>> +       /* setup mmUVD_MPC_CNTL */
>> +       tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
>> +       tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>> +       tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>> +       WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
>> +
>> +       /* setup UVD_MPC_SET_MUXA0 */
>> +       WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
>> +               ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>> +               (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>> +               (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>> +               (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>> +
>> +       /* setup UVD_MPC_SET_MUXB0 */
>> +       WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
>> +               ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>> +               (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>> +               (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>> +               (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>> +
>> +       /* setup mmUVD_MPC_SET_MUX */
>> +       WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
>> +               ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>> +               (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>> +               (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>
>>          vcn_v2_5_mc_resume(adev);
>>
>> -       for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>> -               volatile struct amdgpu_fw_shared *fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr;
>> -               if (adev->vcn.harvest_config & (1 << i))
>> -                       continue;
>> -               /* VCN global tiling registers */
>> -               WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>> -                       adev->gfx.config.gb_addr_config);
>> -               WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>> -                       adev->gfx.config.gb_addr_config);
>> +       volatile struct amdgpu_fw_shared *fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
>> +       if (adev->vcn.harvest_config & (1 << inst))
>> +               return 0;
>> +
>> +       /* VCN global tiling registers */
>> +       WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>> +               adev->gfx.config.gb_addr_config);
>> +       WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>> +               adev->gfx.config.gb_addr_config);
>>
>> -               /* enable LMI MC and UMC channels */
>> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
>> -                       ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>> +       /* enable LMI MC and UMC channels */
>> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
>> +               ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>
>> -               /* unblock VCPU register access */
>> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
>> -                       ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>> +       /* unblock VCPU register access */
>> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
>> +               ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>
>> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>> -                       ~UVD_VCPU_CNTL__BLK_RST_MASK);
>> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>> +               ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>
>> -               for (k = 0; k < 10; ++k) {
>> -                       uint32_t status;
>> -
>> -                       for (j = 0; j < 100; ++j) {
>> -                               status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
>> -                               if (status & 2)
>> -                                       break;
>> -                               if (amdgpu_emu_mode == 1)
>> -                                       msleep(500);
>> -                               else
>> -                                       mdelay(10);
>> -                       }
>> -                       r = 0;
>> +       for (k = 0; k < 10; ++k) {
>> +               uint32_t status;
>> +
>> +               for (j = 0; j < 100; ++j) {
>> +                       status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
>>                          if (status & 2)
>>                                  break;
>> +                       if (amdgpu_emu_mode == 1)
>> +                               msleep(500);
>> +                       else
>> +                               mdelay(10);
>> +               }
>> +               r = 0;
>> +               if (status & 2)
>> +                       break;
>>
>> -                       DRM_ERROR("VCN decode not responding, trying to reset the VCPU!!!\n");
>> -                       WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>> -                               UVD_VCPU_CNTL__BLK_RST_MASK,
>> -                               ~UVD_VCPU_CNTL__BLK_RST_MASK);
>> -                       mdelay(10);
>> -                       WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>> -                               ~UVD_VCPU_CNTL__BLK_RST_MASK);
>> +               DRM_ERROR("VCN decode not responding, trying to reset the VCPU!!!\n");
>> +               WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>> +                       UVD_VCPU_CNTL__BLK_RST_MASK,
>> +                       ~UVD_VCPU_CNTL__BLK_RST_MASK);
>> +               mdelay(10);
>> +               WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>> +                       ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>
>> -                       mdelay(10);
>> -                       r = -1;
>> -               }
>> +               mdelay(10);
>> +               r = -1;
>> +       }
>>
>> -               if (r) {
>> -                       DRM_ERROR("VCN decode not responding, giving up!!!\n");
>> -                       return r;
>> -               }
>> +       if (r) {
>> +               DRM_ERROR("VCN decode not responding, giving up!!!\n");
>> +               return r;
>> +       }
>>
>> -               /* enable master interrupt */
>> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
>> -                       UVD_MASTINT_EN__VCPU_EN_MASK,
>> -                       ~UVD_MASTINT_EN__VCPU_EN_MASK);
>> +       /* enable master interrupt */
>> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
>> +               UVD_MASTINT_EN__VCPU_EN_MASK,
>> +               ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>
>> -               /* clear the busy bit of VCN_STATUS */
>> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
>> -                       ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>> +       /* clear the busy bit of VCN_STATUS */
>> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
>> +               ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>
>> -               WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
>> +       WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
>>
>> -               ring = &adev->vcn.inst[i].ring_dec;
>> -               /* force RBC into idle state */
>> -               rb_bufsz = order_base_2(ring->ring_size);
>> -               tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>> -               tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>> -               tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>> -               tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>> -               tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>> -               WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
>> +       ring = &adev->vcn.inst[inst].ring_dec;
>> +       /* force RBC into idle state */
>> +       rb_bufsz = order_base_2(ring->ring_size);
>> +       tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>> +       tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>> +       tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>> +       tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>> +       tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>> +       WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
>>
>> -               fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
>> -               /* program the RB_BASE for ring buffer */
>> -               WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>> -                       lower_32_bits(ring->gpu_addr));
>> -               WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>> -                       upper_32_bits(ring->gpu_addr));
>> +       fw_shared->multi_queue.decode_queue_mode |= FW_QUEUE_RING_RESET;
>> +       /* program the RB_BASE for ring buffer */
>> +       WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>> +               lower_32_bits(ring->gpu_addr));
>> +       WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>> +               upper_32_bits(ring->gpu_addr));
>>
>> -               /* Initialize the ring buffer's read and write pointers */
>> -               WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
>> +       /* Initialize the ring buffer's read and write pointers */
>> +       WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
>>
>> -               ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
>> -               WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
>> -                               lower_32_bits(ring->wptr));
>> -               fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
>> +       ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
>> +       WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
>> +                       lower_32_bits(ring->wptr));
>> +       fw_shared->multi_queue.decode_queue_mode &= ~FW_QUEUE_RING_RESET;
>>
>> -               fw_shared->multi_queue.encode_generalpurpose_queue_mode |= FW_QUEUE_RING_RESET;
>> -               ring = &adev->vcn.inst[i].ring_enc[0];
>> -               WREG32_SOC15(VCN, i, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
>> -               WREG32_SOC15(VCN, i, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
>> -               WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
>> -               WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
>> -               WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
>> -               fw_shared->multi_queue.encode_generalpurpose_queue_mode &= ~FW_QUEUE_RING_RESET;
>> -
>> -               fw_shared->multi_queue.encode_lowlatency_queue_mode |= FW_QUEUE_RING_RESET;
>> -               ring = &adev->vcn.inst[i].ring_enc[1];
>> -               WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
>> -               WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
>> -               WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>> -               WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
>> -               WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4);
>> -               fw_shared->multi_queue.encode_lowlatency_queue_mode &= ~FW_QUEUE_RING_RESET;
>> -       }
>> +       fw_shared->multi_queue.encode_generalpurpose_queue_mode |= FW_QUEUE_RING_RESET;
>> +       ring = &adev->vcn.inst[inst].ring_enc[0];
>> +       WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
>> +       WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
>> +       WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
>> +       WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
>> +       WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
>> +       fw_shared->multi_queue.encode_generalpurpose_queue_mode &= ~FW_QUEUE_RING_RESET;
>> +
>> +       fw_shared->multi_queue.encode_lowlatency_queue_mode |= FW_QUEUE_RING_RESET;
>> +       ring = &adev->vcn.inst[inst].ring_enc[1];
>> +       WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
>> +       WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
>> +       WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>> +       WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
>> +       WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
>> +       fw_shared->multi_queue.encode_lowlatency_queue_mode &= ~FW_QUEUE_RING_RESET;
>>
>>          return 0;
>>   }
>> @@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
>>          return 0;
>>   }
>>
>> -static int vcn_v2_5_stop(struct amdgpu_device *adev)
>> +static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned int inst)
>>   {
>>          uint32_t tmp;
>> -       int i, r = 0;
>> +       int r = 0;
>>
>> -       for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>> -               if (adev->vcn.harvest_config & (1 << i))
>> -                       continue;
>> -               if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>> -                       r = vcn_v2_5_stop_dpg_mode(adev, i);
>> -                       continue;
>> -               }
>> +       if (adev->vcn.harvest_config & (1 << inst))
>> +               goto done;
>>
>> -               /* wait for vcn idle */
>> -               r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS, UVD_STATUS__IDLE, 0x7);
>> -               if (r)
>> -                       return r;
>> +       if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>> +               r = vcn_v2_5_stop_dpg_mode(adev, inst);
>> +               goto done;
>> +       }
>>
>> -               tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>> -                       UVD_LMI_STATUS__READ_CLEAN_MASK |
>> -                       UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>> -                       UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>> -               r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
>> -               if (r)
>> -                       return r;
>> +       /* wait for vcn idle */
>> +       r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS, UVD_STATUS__IDLE, 0x7);
>> +       if (r)
>> +               return r;
>>
>> -               /* block LMI UMC channel */
>> -               tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
>> -               tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>> -               WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
>> +       tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>> +               UVD_LMI_STATUS__READ_CLEAN_MASK |
>> +               UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>> +               UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>> +       r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
>> +       if (r)
>> +               return r;
>>
>> -               tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>> -                       UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>> -               r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp, tmp);
>> -               if (r)
>> -                       return r;
>> +       /* block LMI UMC channel */
>> +       tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
>> +       tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>> +       WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
>>
>> -               /* block VCPU register access */
>> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
>> -                       UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>> -                       ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>> +       tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>> +               UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>> +       r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp, tmp);
>> +       if (r)
>> +               return r;
>>
>> -               /* reset VCPU */
>> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>> -                       UVD_VCPU_CNTL__BLK_RST_MASK,
>> -                       ~UVD_VCPU_CNTL__BLK_RST_MASK);
>> +       /* block VCPU register access */
>> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
>> +               UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>> +               ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>
>> -               /* disable VCPU clock */
>> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>> -                       ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>> +       /* reset VCPU */
>> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>> +               UVD_VCPU_CNTL__BLK_RST_MASK,
>> +               ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>
>> -               /* clear status */
>> -               WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
>> +       /* disable VCPU clock */
>> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>> +               ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>
>> -               vcn_v2_5_enable_clock_gating(adev);
>> +       /* clear status */
>> +       WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
>>
>> -               /* enable register anti-hang mechanism */
>> -               WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
>> -                       UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>> -                       ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>> -       }
>> +       vcn_v2_5_enable_clock_gating(adev);
>>
>> -       for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>> -               if (adev->pm.dpm_enabled)
>> -                       amdgpu_dpm_enable_vcn(adev, false, i);
>> -       }
>> +       /* enable register anti-hang mechanism */
>> +       WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
>> +               UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>> +               ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>> +done:
>> +       if (adev->pm.dpm_enabled)
>> +               amdgpu_dpm_enable_vcn(adev, false, inst);
>>
>>          return 0;
>>   }
>> @@ -1838,9 +1827,9 @@ static int vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
>>                  return 0;
>>
>>          if (state == AMD_PG_STATE_GATE)
>> -               ret = vcn_v2_5_stop(adev);
>> +               ret = vcn_v2_5_stop(adev, inst);
>>          else
>> -               ret = vcn_v2_5_start(adev);
>> +               ret = vcn_v2_5_start(adev, inst);
>>
>>          if (!ret)
>>                  adev->vcn.cur_state[inst] = state;
>> --
>> 2.34.1
>>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-08 22:04                 ` Boyuan Zhang
@ 2024-10-09  3:43                   ` Lazar, Lijo
  2024-10-09 13:36                     ` Boyuan Zhang
  0 siblings, 1 reply; 37+ messages in thread
From: Lazar, Lijo @ 2024-10-09  3:43 UTC (permalink / raw)
  To: Boyuan Zhang, Alex Deucher
  Cc: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri



On 10/9/2024 3:34 AM, Boyuan Zhang wrote:
> 
> On 2024-10-08 03:03, Lazar, Lijo wrote:
>>
>> On 10/7/2024 8:54 PM, Alex Deucher wrote:
>>> On Mon, Oct 7, 2024 at 10:32 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>>>>
>>>>
>>>> On 10/7/2024 7:47 PM, Alex Deucher wrote:
>>>>> On Mon, Oct 7, 2024 at 9:58 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>>>>>>
>>>>>>
>>>>>> On 10/7/2024 7:03 PM, Boyuan Zhang wrote:
>>>>>>> On 2024-10-07 01:22, Lazar, Lijo wrote:
>>>>>>>> On 10/5/2024 12:14 AM, boyuan.zhang@amd.com wrote:
>>>>>>>>> From: Boyuan Zhang <boyuan.zhang@amd.com>
>>>>>>>>>
>>>>>>>>> For vcn 2_5, add ip_block for each vcn instance during
>>>>>>>>> discovery stage.
>>>>>>>>>
>>>>>>>>> And only powering on/off one of the vcn instance using the
>>>>>>>>> instance value stored in ip_block, instead of powering on/off all
>>>>>>>>> vcn instances. Modify the existing functions to use the
>>>>>>>>> instance value
>>>>>>>>> in ip_block, and remove the original for loop for all vcn
>>>>>>>>> instances.
>>>>>>>>>
>>>>>>>>> v2: rename "i"/"j" to "inst" for instance value.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
>>>>>>>>> ---
>>>>>>>>>    drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
>>>>>>>>>    drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565
>>>>>>>>> +++++++++---------
>>>>>>>>>    2 files changed, 280 insertions(+), 289 deletions(-)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>>> index 9f9a1867da72..de1053cc2a2b 100644
>>>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>>> @@ -2278,6 +2278,7 @@ static int
>>>>>>>>> amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
>>>>>>>>>      static int amdgpu_discovery_set_mm_ip_blocks(struct
>>>>>>>>> amdgpu_device
>>>>>>>>> *adev)
>>>>>>>>>    {
>>>>>>>>> +    int i;
>>>>>>>>>        if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
>>>>>>>>>            switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
>>>>>>>>>            case IP_VERSION(7, 0, 0):
>>>>>>>>> @@ -2321,7 +2322,8 @@ static int
>>>>>>>>> amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>>>>>>>>>            case IP_VERSION(2, 0, 3):
>>>>>>>>>                break;
>>>>>>>>>            case IP_VERSION(2, 5, 0):
>>>>>>>>> -            amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>>>>>>>>> +            for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
>>>>>>>>> +                amdgpu_device_ip_block_add(adev,
>>>>>>>>> &vcn_v2_5_ip_block);
>>>>>>>> This introduces a totally confusing design now. At a higher
>>>>>>>> level an IP
>>>>>>>> block type manages multiple instances and their power states.
>>>>>>>> Now there
>>>>>>>> is a mix where no definition can be attributed to an IP block.
>>>>>>>> Or, if
>>>>>>>> this were to be done uniformly for other IPs, then for some SOCs
>>>>>>>> there
>>>>>>>> could be 16 SDMA blocks, 8 GFX blocks and so forth.
>>>>>>>>
>>>>>>>> What is the reason to do this way? Can't VCN IP block maintain
>>>>>>>> the state
>>>>>>>> of multiple instances within itself?
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Lijo
>>>>>>> This is part of the fundamental design change for separating IP
>>>>>>> block
>>>>>>> per instance, in order to
>>>>>>> handle each instance separately within same IP block (e.g. separate
>>>>>>> power/clock management).
>>>>>>>
>>>>>>> Part 1, Change all adev ptr handle to amdgpu_ip_block ptr in all
>>>>>>> callbacks (hw_init/fini, sw_init/fini,
>>>>>>> suspend, etc...) for all IP blocks, so that each IP knows which
>>>>>>> IP_block
>>>>>>> (and which instance) the
>>>>>>> callback is for. Most parts of this changes have been submitted
>>>>>>> by Sunil.
>>>>>>>
>>>>>>> Part 2, Separate IP block per instance.
>>>>>>>
>>>>>>> Part 3, Since callbacks can pass in IP_block now after Part 1
>>>>>>> change and
>>>>>>> instance value can be
>>>>>>> obtained from each IP block in Part 2, IP can then choose to handle
>>>>>>> callbacks ONLY for the given
>>>>>>> instance of a given IP block (or still handling for all instances as
>>>>>>> before).
>>>>>>> For VCN, all callbacks will be handled only for the given one
>>>>>>> instance,
>>>>>>> instead of the original for-
>>>>>>> loop for all instance. As a result, each VCN instance can be
>>>>>>> start/stop/int/fini/suspend separately.
>>>>>>>
>>>>>>> Part 4, Change all VCN helper functions to handle only the given
>>>>>>> instance, instead of the original
>>>>>>> for-loop for all instance.
>>>>>>>
>>>>>>> Each instance can have its own states, so we think it makes more
>>>>>>> sense
>>>>>>> to separate them on IP
>>>>>>> block level to handle each of them separately.
>>>>>>
>>>>>> Such a change should not be done unless all IPs follow the same
>>>>>> design.
>>>>>> You didn't answer the question - what necessitates this change?
>>>>>> What is
>>>>>> special about VCN that it cannot manage the states of multiple
>>>>>> instances
>>>>>> within the IP block?
>>>>> We want to be able to manage the powergating independently for each
>>>>> VCN instance for both power management and VCN reset.  Right now power
>>>>> gating is handled at the IP level so it's not easy or clean to handle
>>>>> powergating of individual IP instances.
>>>>>
>>>> Still VCN block can manage the powergated instances (FWIW, it's just an
>>>> array in SMU block). Also vcn block gets to run the idle worker and
>>>> knows the rings (and corresponding VCN instances) that are idle.
>>>> Maintaining instance states in VCN block and modifying idle worker to
>>>> just idle that instance alone doesn't look like a complex change.
>>>
>>> We already went down that road and it's really ugly.  We end up
>>> duplicating a bunch of code paths for different driver flows because
>>> set_powergating_state() and set_clockgating_state are at the IP level
>>> and we want per instance gating.  We could add a num_instances member
>>> at the IP block level and then convert all of the high level code that
>>> calls the IP functions loop over the number of instances, but that
>>> seems like just as much work and it's not quite as clean IMHO.
>>>
>> Sorry, I'm not seeing much difference in this design. All it does is
>> just split instances to IP block at the same time it's going to keep an
>> instance parameter in IP block APIs.
>>
>>     amdgpu_device_ip_set_clockgating_state(blocktype, instance);
>>     amdgpu_device_ip_set_powergating_state(blocktype, instance);
>>
>> Also, VCN continues to maintain an array of amdgpu_vcn_inst. I think
>> it's easier manage this with changes to amdgpu_vcn_inst. Since it is
>> continued to be maintained, what about just moving the states and
>> idle_work inside amdgpu_vcn_inst.
>>     
>>     int inst;
>>     enum amd_powergating_state cur_pg_state;
>>     enum amd_clockgating_state state cur_cg_state;
>>     struct delayed_work     idle_work;
>>
>> At the end of ring usage of corresponding instance, just invoke the
>> corresponding instance's idle work.
>>
>> schedule_delayed_work(&ring->adev->vcn.inst[ring->me].idle_work,
>> idle_time_out);
> First of all, separating idle work and state is still needed in current
> design.
> Separating idle work by instance is already handled in patch 17/18.
> Separating power gating state is already handled in patch 10/18.
> 
> I agree that "adding instance variable" in amdgpu_vcn_inst requires
> much less effort, but as mentioned by Alex previously, we already
> went down that way to use "inst" variable in amdgou_vcn_inst as you
> listed above and track this instance value all the way from VCN to SMU.
> However, this is a no-go based on discussions with Christian and Alex.
> Since set_powergating_state() is at IP level, it will be clean to do
> per instance gating at IP level. With the change of passing ip_block to
> callback functions, all ip functions can now choose to handle only the
> given instance, which is a clean separation between multiple instance.
> 

I don't agree.

There is no clean separation here. What I see here is a mix where ip
block still remains a dummy.

	ipblock->inst => calls vcn.vcn_inst[i] that maintains the final state.

If the design is based only on ip block, you wouldn't have required to
maintain another vcn_inst. Everything would have been handled by
maintaining state in ip block itself.
> 
>>
>> I don't see any change in this series for other IP block APIs.
> Yes, currently we only do this per instance IP block for VCN. For long
> term,
> the plan is to change all other IP with multiple blocks into this design.
> 

This path itself is not a viable solution. We will have cases where a
group of ip blocks of the same type need to be handled together. At that
point you will need another central controller for ip blocks belonging
to a type. That will evenutally lead to another superblock being created.

Thanks,
Lijo

> Regards,
> Boyuan
> 
> 
>>
>> Thanks,
>> Lijo
>>
>>> Alex
>>>
>>>> Moving to IP block per instance for VCN alone is not a change that
>>>> helps
>>>> to define an IP block. If that needs to be done for every other IP
>>>> type,
>>>> that's also a massive change.
>>>>
>>>> Also, then it's no longer possible to have something static like this -
>>>>          struct amdgpu_ip_block          ip_blocks[AMDGPU_MAX_IP_NUM];
>>>>
>>>>
>>>> Thanks,
>>>> Lijo
>>>>
>>>>> Alex
>>>>>
>>>>>> Thanks,
>>>>>> Lijo
>>>>>>
>>>>>>> Thanks,
>>>>>>> Boyuan
>>>>>>>>>                amdgpu_device_ip_block_add(adev,
>>>>>>>>> &jpeg_v2_5_ip_block);
>>>>>>>>>                break;
>>>>>>>>>            case IP_VERSION(2, 6, 0):
>>>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>>> b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>>> index d00df51bc400..1f8738ae360a 100644
>>>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>>> @@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct
>>>>>>>>> amdgpu_ip_block *ip_block)
>>>>>>>>>    static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>>>>>>>>>    {
>>>>>>>>>        struct amdgpu_ring *ring;
>>>>>>>>> -    int i, j, r;
>>>>>>>>> +    int i, r;
>>>>>>>>>        uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
>>>>>>>>>        uint32_t *ptr;
>>>>>>>>>        struct amdgpu_device *adev = ip_block->adev;
>>>>>>>>> +    int inst = ip_block->instance;
>>>>>>>>>    -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << j))
>>>>>>>>> -            continue;
>>>>>>>>> -        /* VCN DEC TRAP */
>>>>>>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>>>>>> -                VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>>>>>>>> &adev->vcn.inst[j].irq);
>>>>>>>>> -        if (r)
>>>>>>>>> -            return r;
>>>>>>>>> -
>>>>>>>>> -        /* VCN ENC TRAP */
>>>>>>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>>> -            r = amdgpu_irq_add_id(adev,
>>>>>>>>> amdgpu_ih_clientid_vcns[j],
>>>>>>>>> -                i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>>>>>>>> &adev->vcn.inst[j].irq);
>>>>>>>>> -            if (r)
>>>>>>>>> -                return r;
>>>>>>>>> -        }
>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>> +        goto sw_init;
>>>>>>>>> +    /* VCN DEC TRAP */
>>>>>>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>>>>>> +            VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>>>>>>>> &adev->vcn.inst[inst].irq);
>>>>>>>>> +    if (r)
>>>>>>>>> +        return r;
>>>>>>>>>    -        /* VCN POISON TRAP */
>>>>>>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>>>>>> -            VCN_2_6__SRCID_UVD_POISON,
>>>>>>>>> &adev->vcn.inst[j].ras_poison_irq);
>>>>>>>>> +    /* VCN ENC TRAP */
>>>>>>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>>> +        r = amdgpu_irq_add_id(adev,
>>>>>>>>> amdgpu_ih_clientid_vcns[inst],
>>>>>>>>> +            i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>>>>>>>> &adev->vcn.inst[inst].irq);
>>>>>>>>>            if (r)
>>>>>>>>>                return r;
>>>>>>>>>        }
>>>>>>>>>    +    /* VCN POISON TRAP */
>>>>>>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>>>>>> +        VCN_2_6__SRCID_UVD_POISON,
>>>>>>>>> &adev->vcn.inst[inst].ras_poison_irq);
>>>>>>>>> +    if (r)
>>>>>>>>> +        return r;
>>>>>>>>> +sw_init:
>>>>>>>>>        r = amdgpu_vcn_sw_init(adev);
>>>>>>>>>        if (r)
>>>>>>>>>            return r;
>>>>>>>>> @@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct
>>>>>>>>> amdgpu_ip_block *ip_block)
>>>>>>>>>        if (r)
>>>>>>>>>            return r;
>>>>>>>>>    -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>>>>>>>> -        volatile struct amdgpu_fw_shared *fw_shared;
>>>>>>>>> +    volatile struct amdgpu_fw_shared *fw_shared;
>>>>>>>>>    -        if (adev->vcn.harvest_config & (1 << j))
>>>>>>>>> -            continue;
>>>>>>>>> -        adev->vcn.internal.context_id =
>>>>>>>>> mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>>>>>>>> -        adev->vcn.internal.ib_vmid =
>>>>>>>>> mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>>>>>>>> -        adev->vcn.internal.ib_bar_low =
>>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>>>>>>>> -        adev->vcn.internal.ib_bar_high =
>>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>>>>>>>> -        adev->vcn.internal.ib_size =
>>>>>>>>> mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>>>>>>>> -        adev->vcn.internal.gp_scratch8 =
>>>>>>>>> mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>>>>>>>> -
>>>>>>>>> -        adev->vcn.internal.scratch9 =
>>>>>>>>> mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>>>>>>>> -        adev->vcn.inst[j].external.scratch9 =
>>>>>>>>> SOC15_REG_OFFSET(VCN,
>>>>>>>>> j, mmUVD_SCRATCH9);
>>>>>>>>> -        adev->vcn.internal.data0 =
>>>>>>>>> mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>>>>>>>> -        adev->vcn.inst[j].external.data0 =
>>>>>>>>> SOC15_REG_OFFSET(VCN, j,
>>>>>>>>> mmUVD_GPCOM_VCPU_DATA0);
>>>>>>>>> -        adev->vcn.internal.data1 =
>>>>>>>>> mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>>>>>>>> -        adev->vcn.inst[j].external.data1 =
>>>>>>>>> SOC15_REG_OFFSET(VCN, j,
>>>>>>>>> mmUVD_GPCOM_VCPU_DATA1);
>>>>>>>>> -        adev->vcn.internal.cmd =
>>>>>>>>> mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>>>>>>>> -        adev->vcn.inst[j].external.cmd = SOC15_REG_OFFSET(VCN, j,
>>>>>>>>> mmUVD_GPCOM_VCPU_CMD);
>>>>>>>>> -        adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>>>>>>>> -        adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(VCN, j,
>>>>>>>>> mmUVD_NO_OP);
>>>>>>>>> -
>>>>>>>>> -        ring = &adev->vcn.inst[j].ring_dec;
>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>> +        goto done;
>>>>>>>>> +    adev->vcn.internal.context_id =
>>>>>>>>> mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>>>>>>>> +    adev->vcn.internal.ib_vmid =
>>>>>>>>> mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>>>>>>>> +    adev->vcn.internal.ib_bar_low =
>>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>>>>>>>> +    adev->vcn.internal.ib_bar_high =
>>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>>>>>>>> +    adev->vcn.internal.ib_size =
>>>>>>>>> mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>>>>>>>> +    adev->vcn.internal.gp_scratch8 =
>>>>>>>>> mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>>>>>>>> +
>>>>>>>>> +    adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>>>>>>>> +    adev->vcn.inst[inst].external.scratch9 =
>>>>>>>>> SOC15_REG_OFFSET(VCN,
>>>>>>>>> inst, mmUVD_SCRATCH9);
>>>>>>>>> +    adev->vcn.internal.data0 =
>>>>>>>>> mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>>>>>>>> +    adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN,
>>>>>>>>> inst, mmUVD_GPCOM_VCPU_DATA0);
>>>>>>>>> +    adev->vcn.internal.data1 =
>>>>>>>>> mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>>>>>>>> +    adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN,
>>>>>>>>> inst, mmUVD_GPCOM_VCPU_DATA1);
>>>>>>>>> +    adev->vcn.internal.cmd =
>>>>>>>>> mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>>>>>>>> +    adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN,
>>>>>>>>> inst,
>>>>>>>>> mmUVD_GPCOM_VCPU_CMD);
>>>>>>>>> +    adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>>>>>>>> +    adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN,
>>>>>>>>> inst,
>>>>>>>>> mmUVD_NO_OP);
>>>>>>>>> +
>>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>>>>>>>> +    ring->use_doorbell = true;
>>>>>>>>> +
>>>>>>>>> +    ring->doorbell_index =
>>>>>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 <<
>>>>>>>>> 1) +
>>>>>>>>> +            (amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
>>>>>>>>> +
>>>>>>>>> +    if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2,
>>>>>>>>> 5, 0))
>>>>>>>>> +        ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>>>> +    else
>>>>>>>>> +        ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>>>> +
>>>>>>>>> +    sprintf(ring->name, "vcn_dec_%d", inst);
>>>>>>>>> +    r = amdgpu_ring_init(adev, ring, 512,
>>>>>>>>> &adev->vcn.inst[inst].irq,
>>>>>>>>> +                 0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>>>>>>>> +    if (r)
>>>>>>>>> +        return r;
>>>>>>>>> +
>>>>>>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>>> +        enum amdgpu_ring_priority_level hw_prio =
>>>>>>>>> amdgpu_vcn_get_enc_ring_prio(i);
>>>>>>>>> +
>>>>>>>>> +        ring = &adev->vcn.inst[inst].ring_enc[i];
>>>>>>>>>            ring->use_doorbell = true;
>>>>>>>>>              ring->doorbell_index =
>>>>>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>>>>>>>> -                (amdgpu_sriov_vf(adev) ? 2*j : 8*j);
>>>>>>>>> +                (amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2
>>>>>>>>> + i +
>>>>>>>>> 8*inst));
>>>>>>>>>    -        if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>>>>>> IP_VERSION(2,
>>>>>>>>> 5, 0))
>>>>>>>>> +        if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>>>>>> +            IP_VERSION(2, 5, 0))
>>>>>>>>>                ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>>>>            else
>>>>>>>>>                ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>>>>    -        sprintf(ring->name, "vcn_dec_%d", j);
>>>>>>>>> -        r = amdgpu_ring_init(adev, ring, 512,
>>>>>>>>> &adev->vcn.inst[j].irq,
>>>>>>>>> -                     0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>>>>>>>> +        sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
>>>>>>>>> +        r = amdgpu_ring_init(adev, ring, 512,
>>>>>>>>> +                     &adev->vcn.inst[inst].irq, 0,
>>>>>>>>> +                     hw_prio, NULL);
>>>>>>>>>            if (r)
>>>>>>>>>                return r;
>>>>>>>>> -
>>>>>>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>>> -            enum amdgpu_ring_priority_level hw_prio =
>>>>>>>>> amdgpu_vcn_get_enc_ring_prio(i);
>>>>>>>>> -
>>>>>>>>> -            ring = &adev->vcn.inst[j].ring_enc[i];
>>>>>>>>> -            ring->use_doorbell = true;
>>>>>>>>> -
>>>>>>>>> -            ring->doorbell_index =
>>>>>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>>>>>>>> -                    (amdgpu_sriov_vf(adev) ? (1 + i + 2*j) :
>>>>>>>>> (2 + i
>>>>>>>>> + 8*j));
>>>>>>>>> -
>>>>>>>>> -            if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>>>>>> -                IP_VERSION(2, 5, 0))
>>>>>>>>> -                ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>>>> -            else
>>>>>>>>> -                ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>>>> -
>>>>>>>>> -            sprintf(ring->name, "vcn_enc_%d.%d", j, i);
>>>>>>>>> -            r = amdgpu_ring_init(adev, ring, 512,
>>>>>>>>> -                         &adev->vcn.inst[j].irq, 0,
>>>>>>>>> -                         hw_prio, NULL);
>>>>>>>>> -            if (r)
>>>>>>>>> -                return r;
>>>>>>>>> -        }
>>>>>>>>> -
>>>>>>>>> -        fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
>>>>>>>>> -        fw_shared->present_flag_0 =
>>>>>>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>>>>>>>> -
>>>>>>>>> -        if (amdgpu_vcnfw_log)
>>>>>>>>> -            amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>>>>>>>        }
>>>>>>>>>    +    fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
>>>>>>>>> +    fw_shared->present_flag_0 =
>>>>>>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>>>>>>>> +
>>>>>>>>> +    if (amdgpu_vcnfw_log)
>>>>>>>>> +        amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>>>>>>> +done:
>>>>>>>>>        if (amdgpu_sriov_vf(adev)) {
>>>>>>>>>            r = amdgpu_virt_alloc_mm_table(adev);
>>>>>>>>>            if (r)
>>>>>>>>> @@ -1005,197 +1002,192 @@ static int
>>>>>>>>> vcn_v2_5_start_dpg_mode(struct
>>>>>>>>> amdgpu_device *adev, int inst_idx, boo
>>>>>>>>>        return 0;
>>>>>>>>>    }
>>>>>>>>>    -static int vcn_v2_5_start(struct amdgpu_device *adev)
>>>>>>>>> +static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned
>>>>>>>>> int
>>>>>>>>> inst)
>>>>>>>>>    {
>>>>>>>>>        struct amdgpu_ring *ring;
>>>>>>>>>        uint32_t rb_bufsz, tmp;
>>>>>>>>> -    int i, j, k, r;
>>>>>>>>> +    int j, k, r;
>>>>>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>> -        if (adev->pm.dpm_enabled)
>>>>>>>>> -            amdgpu_dpm_enable_vcn(adev, true, i);
>>>>>>>>> -    }
>>>>>>>>> -
>>>>>>>>> -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>>> -            continue;
>>>>>>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>>> -            r = vcn_v2_5_start_dpg_mode(adev, i,
>>>>>>>>> adev->vcn.indirect_sram);
>>>>>>>>> -            continue;
>>>>>>>>> -        }
>>>>>>>>> +    if (adev->pm.dpm_enabled)
>>>>>>>>> +        amdgpu_dpm_enable_vcn(adev, true, inst);
>>>>>>>>>    -        /* disable register anti-hang mechanism */
>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS), 0,
>>>>>>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>> +        return 0;
>>>>>>>>>    -        /* set uvd status busy */
>>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) |
>>>>>>>>> UVD_STATUS__UVD_BUSY;
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
>>>>>>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>>> +        r = vcn_v2_5_start_dpg_mode(adev, inst,
>>>>>>>>> adev->vcn.indirect_sram);
>>>>>>>>> +        return r;
>>>>>>>>>        }
>>>>>>>>>    +    /* disable register anti-hang mechanism */
>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS), 0,
>>>>>>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>>> +
>>>>>>>>> +    /* set uvd status busy */
>>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) |
>>>>>>>>> UVD_STATUS__UVD_BUSY;
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
>>>>>>>>> +
>>>>>>>>>        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
>>>>>>>>>            return 0;
>>>>>>>>>          /*SW clock gating */
>>>>>>>>>        vcn_v2_5_disable_clock_gating(adev);
>>>>>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>>> -            continue;
>>>>>>>>> -        /* enable VCPU clock */
>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>>>> -            UVD_VCPU_CNTL__CLK_EN_MASK,
>>>>>>>>> ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>>>>>>>> -
>>>>>>>>> -        /* disable master interrupt */
>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
>>>>>>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>>> -
>>>>>>>>> -        /* setup mmUVD_LMI_CTRL */
>>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
>>>>>>>>> -        tmp &= ~0xff;
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
>>>>>>>>> -            UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>>>>>>>> -            UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>>>>>>>> -            UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>>>>>>>> -            UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>>>>>>>> -
>>>>>>>>> -        /* setup mmUVD_MPC_CNTL */
>>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
>>>>>>>>> -        tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>>>>>>>> -        tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
>>>>>>>>> -
>>>>>>>>> -        /* setup UVD_MPC_SET_MUXA0 */
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
>>>>>>>>> -            ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>>>>>>>> -            (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>>>>>>>> -            (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>>>>>>>> -            (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>>>>>>>> -
>>>>>>>>> -        /* setup UVD_MPC_SET_MUXB0 */
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
>>>>>>>>> -            ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>>>>>>>> -            (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>>>>>>>> -            (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>>>>>>>> -            (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>>>>>>>> -
>>>>>>>>> -        /* setup mmUVD_MPC_SET_MUX */
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
>>>>>>>>> -            ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>>>>>>>> -            (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>>>>>>>> -            (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>>>>>>> -    }
>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>> +        return 0;
>>>>>>>>> +
>>>>>>>>> +    /* enable VCPU clock */
>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>>>> +        UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>>>>>>>> +
>>>>>>>>> +    /* disable master interrupt */
>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
>>>>>>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>>> +
>>>>>>>>> +    /* setup mmUVD_LMI_CTRL */
>>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
>>>>>>>>> +    tmp &= ~0xff;
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
>>>>>>>>> +        UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>>>>>>>> +        UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>>>>>>>> +        UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>>>>>>>> +        UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>>>>>>>> +
>>>>>>>>> +    /* setup mmUVD_MPC_CNTL */
>>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
>>>>>>>>> +    tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>>>>>>>> +    tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
>>>>>>>>> +
>>>>>>>>> +    /* setup UVD_MPC_SET_MUXA0 */
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
>>>>>>>>> +        ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>>>>>>>> +        (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>>>>>>>> +        (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>>>>>>>> +        (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>>>>>>>> +
>>>>>>>>> +    /* setup UVD_MPC_SET_MUXB0 */
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
>>>>>>>>> +        ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>>>>>>>> +        (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>>>>>>>> +        (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>>>>>>>> +        (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>>>>>>>> +
>>>>>>>>> +    /* setup mmUVD_MPC_SET_MUX */
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
>>>>>>>>> +        ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>>>>>>>> +        (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>>>>>>>> +        (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>>>>>>>          vcn_v2_5_mc_resume(adev);
>>>>>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>> -        volatile struct amdgpu_fw_shared *fw_shared =
>>>>>>>>> adev->vcn.inst[i].fw_shared.cpu_addr;
>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>>> -            continue;
>>>>>>>>> -        /* VCN global tiling registers */
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>>> -            adev->gfx.config.gb_addr_config);
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>>> -            adev->gfx.config.gb_addr_config);
>>>>>>>>> +    volatile struct amdgpu_fw_shared *fw_shared =
>>>>>>>>> adev->vcn.inst[inst].fw_shared.cpu_addr;
>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>> +        return 0;
>>>>>>>>> +
>>>>>>>>> +    /* VCN global tiling registers */
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>>> +        adev->gfx.config.gb_addr_config);
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>>> +        adev->gfx.config.gb_addr_config);
>>>>>>>>>    -        /* enable LMI MC and UMC channels */
>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
>>>>>>>>> -            ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>>>>>>> +    /* enable LMI MC and UMC channels */
>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
>>>>>>>>> +        ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>>>>>>>    -        /* unblock VCPU register access */
>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
>>>>>>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>>> +    /* unblock VCPU register access */
>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
>>>>>>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>>>    -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>>>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>>>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>    -        for (k = 0; k < 10; ++k) {
>>>>>>>>> -            uint32_t status;
>>>>>>>>> -
>>>>>>>>> -            for (j = 0; j < 100; ++j) {
>>>>>>>>> -                status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
>>>>>>>>> -                if (status & 2)
>>>>>>>>> -                    break;
>>>>>>>>> -                if (amdgpu_emu_mode == 1)
>>>>>>>>> -                    msleep(500);
>>>>>>>>> -                else
>>>>>>>>> -                    mdelay(10);
>>>>>>>>> -            }
>>>>>>>>> -            r = 0;
>>>>>>>>> +    for (k = 0; k < 10; ++k) {
>>>>>>>>> +        uint32_t status;
>>>>>>>>> +
>>>>>>>>> +        for (j = 0; j < 100; ++j) {
>>>>>>>>> +            status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
>>>>>>>>>                if (status & 2)
>>>>>>>>>                    break;
>>>>>>>>> +            if (amdgpu_emu_mode == 1)
>>>>>>>>> +                msleep(500);
>>>>>>>>> +            else
>>>>>>>>> +                mdelay(10);
>>>>>>>>> +        }
>>>>>>>>> +        r = 0;
>>>>>>>>> +        if (status & 2)
>>>>>>>>> +            break;
>>>>>>>>>    -            DRM_ERROR("VCN decode not responding, trying to
>>>>>>>>> reset
>>>>>>>>> the VCPU!!!\n");
>>>>>>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>>>> -                UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>> -            mdelay(10);
>>>>>>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i,
>>>>>>>>> mmUVD_VCPU_CNTL), 0,
>>>>>>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>> +        DRM_ERROR("VCN decode not responding, trying to reset the
>>>>>>>>> VCPU!!!\n");
>>>>>>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>>>> +            UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>> +        mdelay(10);
>>>>>>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>>>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>    -            mdelay(10);
>>>>>>>>> -            r = -1;
>>>>>>>>> -        }
>>>>>>>>> +        mdelay(10);
>>>>>>>>> +        r = -1;
>>>>>>>>> +    }
>>>>>>>>>    -        if (r) {
>>>>>>>>> -            DRM_ERROR("VCN decode not responding, giving
>>>>>>>>> up!!!\n");
>>>>>>>>> -            return r;
>>>>>>>>> -        }
>>>>>>>>> +    if (r) {
>>>>>>>>> +        DRM_ERROR("VCN decode not responding, giving up!!!\n");
>>>>>>>>> +        return r;
>>>>>>>>> +    }
>>>>>>>>>    -        /* enable master interrupt */
>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
>>>>>>>>> -            UVD_MASTINT_EN__VCPU_EN_MASK,
>>>>>>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>>> +    /* enable master interrupt */
>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
>>>>>>>>> +        UVD_MASTINT_EN__VCPU_EN_MASK,
>>>>>>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>>>    -        /* clear the busy bit of VCN_STATUS */
>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
>>>>>>>>> -            ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>>>>>>> +    /* clear the busy bit of VCN_STATUS */
>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
>>>>>>>>> +        ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>>>>>>>    -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
>>>>>>>>>    -        ring = &adev->vcn.inst[i].ring_dec;
>>>>>>>>> -        /* force RBC into idle state */
>>>>>>>>> -        rb_bufsz = order_base_2(ring->ring_size);
>>>>>>>>> -        tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ,
>>>>>>>>> rb_bufsz);
>>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH,
>>>>>>>>> 1);
>>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL,
>>>>>>>>> RB_NO_UPDATE, 1);
>>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL,
>>>>>>>>> RB_RPTR_WR_EN, 1);
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
>>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>>>>>>>> +    /* force RBC into idle state */
>>>>>>>>> +    rb_bufsz = order_base_2(ring->ring_size);
>>>>>>>>> +    tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
>>>>>>>>>    -        fw_shared->multi_queue.decode_queue_mode |=
>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>> -        /* program the RB_BASE for ring buffer */
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>>>>>>>> -            lower_32_bits(ring->gpu_addr));
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>>>>>>>> -            upper_32_bits(ring->gpu_addr));
>>>>>>>>> +    fw_shared->multi_queue.decode_queue_mode |=
>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>> +    /* program the RB_BASE for ring buffer */
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>>>>>>>> +        lower_32_bits(ring->gpu_addr));
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>>>>>>>> +        upper_32_bits(ring->gpu_addr));
>>>>>>>>>    -        /* Initialize the ring buffer's read and write
>>>>>>>>> pointers */
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
>>>>>>>>> +    /* Initialize the ring buffer's read and write pointers */
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
>>>>>>>>>    -        ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
>>>>>>>>> -                lower_32_bits(ring->wptr));
>>>>>>>>> -        fw_shared->multi_queue.decode_queue_mode &=
>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>> +    ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
>>>>>>>>> +            lower_32_bits(ring->wptr));
>>>>>>>>> +    fw_shared->multi_queue.decode_queue_mode &=
>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>>    -       
>>>>>>>>> fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>> -        ring = &adev->vcn.inst[i].ring_enc[0];
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR,
>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR,
>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI,
>>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
>>>>>>>>> -       
>>>>>>>>> fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>> -
>>>>>>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>> -        ring = &adev->vcn.inst[i].ring_enc[1];
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2,
>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2,
>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2,
>>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size /
>>>>>>>>> 4);
>>>>>>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>> -    }
>>>>>>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_enc[0];
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR,
>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR,
>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI,
>>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
>>>>>>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>> +
>>>>>>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_enc[1];
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2,
>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2,
>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2,
>>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
>>>>>>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>>          return 0;
>>>>>>>>>    }
>>>>>>>>> @@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct
>>>>>>>>> amdgpu_device *adev, int inst_idx)
>>>>>>>>>        return 0;
>>>>>>>>>    }
>>>>>>>>>    -static int vcn_v2_5_stop(struct amdgpu_device *adev)
>>>>>>>>> +static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned
>>>>>>>>> int inst)
>>>>>>>>>    {
>>>>>>>>>        uint32_t tmp;
>>>>>>>>> -    int i, r = 0;
>>>>>>>>> +    int r = 0;
>>>>>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>>> -            continue;
>>>>>>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>>> -            r = vcn_v2_5_stop_dpg_mode(adev, i);
>>>>>>>>> -            continue;
>>>>>>>>> -        }
>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>> +        goto done;
>>>>>>>>>    -        /* wait for vcn idle */
>>>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS,
>>>>>>>>> UVD_STATUS__IDLE, 0x7);
>>>>>>>>> -        if (r)
>>>>>>>>> -            return r;
>>>>>>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>>> +        r = vcn_v2_5_stop_dpg_mode(adev, inst);
>>>>>>>>> +        goto done;
>>>>>>>>> +    }
>>>>>>>>>    -        tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>>>>>>>> -            UVD_LMI_STATUS__READ_CLEAN_MASK |
>>>>>>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>>>>>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp,
>>>>>>>>> tmp);
>>>>>>>>> -        if (r)
>>>>>>>>> -            return r;
>>>>>>>>> +    /* wait for vcn idle */
>>>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS,
>>>>>>>>> UVD_STATUS__IDLE, 0x7);
>>>>>>>>> +    if (r)
>>>>>>>>> +        return r;
>>>>>>>>>    -        /* block LMI UMC channel */
>>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
>>>>>>>>> -        tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
>>>>>>>>> +    tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>>>>>>>> +        UVD_LMI_STATUS__READ_CLEAN_MASK |
>>>>>>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>>>>>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp,
>>>>>>>>> tmp);
>>>>>>>>> +    if (r)
>>>>>>>>> +        return r;
>>>>>>>>>    -        tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>>>>>>>> -            UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp,
>>>>>>>>> tmp);
>>>>>>>>> -        if (r)
>>>>>>>>> -            return r;
>>>>>>>>> +    /* block LMI UMC channel */
>>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
>>>>>>>>> +    tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
>>>>>>>>>    -        /* block VCPU register access */
>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
>>>>>>>>> -            UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>>>>>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>>> +    tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>>>>>>>> +        UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp,
>>>>>>>>> tmp);
>>>>>>>>> +    if (r)
>>>>>>>>> +        return r;
>>>>>>>>>    -        /* reset VCPU */
>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>>>> -            UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>> +    /* block VCPU register access */
>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
>>>>>>>>> +        UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>>>>>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>>>    -        /* disable VCPU clock */
>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>>>>>> -            ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>>>>>>> +    /* reset VCPU */
>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>>>> +        UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>    -        /* clear status */
>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
>>>>>>>>> +    /* disable VCPU clock */
>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>>>>>> +        ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>>>>>>>    -        vcn_v2_5_enable_clock_gating(adev);
>>>>>>>>> +    /* clear status */
>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
>>>>>>>>>    -        /* enable register anti-hang mechanism */
>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
>>>>>>>>> -            UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>>>>>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>>> -    }
>>>>>>>>> +    vcn_v2_5_enable_clock_gating(adev);
>>>>>>>>>    -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>> -        if (adev->pm.dpm_enabled)
>>>>>>>>> -            amdgpu_dpm_enable_vcn(adev, false, i);
>>>>>>>>> -    }
>>>>>>>>> +    /* enable register anti-hang mechanism */
>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
>>>>>>>>> +        UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>>>>>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>>> +done:
>>>>>>>>> +    if (adev->pm.dpm_enabled)
>>>>>>>>> +        amdgpu_dpm_enable_vcn(adev, false, inst);
>>>>>>>>>          return 0;
>>>>>>>>>    }
>>>>>>>>> @@ -1838,9 +1827,9 @@ static int
>>>>>>>>> vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
>>>>>>>>>            return 0;
>>>>>>>>>          if (state == AMD_PG_STATE_GATE)
>>>>>>>>> -        ret = vcn_v2_5_stop(adev);
>>>>>>>>> +        ret = vcn_v2_5_stop(adev, inst);
>>>>>>>>>        else
>>>>>>>>> -        ret = vcn_v2_5_start(adev);
>>>>>>>>> +        ret = vcn_v2_5_start(adev, inst);
>>>>>>>>>          if (!ret)
>>>>>>>>>            adev->vcn.cur_state[inst] = state;

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-09  3:43                   ` Lazar, Lijo
@ 2024-10-09 13:36                     ` Boyuan Zhang
  2024-10-09 14:07                       ` Lazar, Lijo
  0 siblings, 1 reply; 37+ messages in thread
From: Boyuan Zhang @ 2024-10-09 13:36 UTC (permalink / raw)
  To: Lazar, Lijo, Alex Deucher
  Cc: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri


On 2024-10-08 23:43, Lazar, Lijo wrote:
>
> On 10/9/2024 3:34 AM, Boyuan Zhang wrote:
>> On 2024-10-08 03:03, Lazar, Lijo wrote:
>>> On 10/7/2024 8:54 PM, Alex Deucher wrote:
>>>> On Mon, Oct 7, 2024 at 10:32 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>>>>>
>>>>> On 10/7/2024 7:47 PM, Alex Deucher wrote:
>>>>>> On Mon, Oct 7, 2024 at 9:58 AM Lazar, Lijo <lijo.lazar@amd.com> wrote:
>>>>>>>
>>>>>>> On 10/7/2024 7:03 PM, Boyuan Zhang wrote:
>>>>>>>> On 2024-10-07 01:22, Lazar, Lijo wrote:
>>>>>>>>> On 10/5/2024 12:14 AM, boyuan.zhang@amd.com wrote:
>>>>>>>>>> From: Boyuan Zhang <boyuan.zhang@amd.com>
>>>>>>>>>>
>>>>>>>>>> For vcn 2_5, add ip_block for each vcn instance during
>>>>>>>>>> discovery stage.
>>>>>>>>>>
>>>>>>>>>> And only powering on/off one of the vcn instance using the
>>>>>>>>>> instance value stored in ip_block, instead of powering on/off all
>>>>>>>>>> vcn instances. Modify the existing functions to use the
>>>>>>>>>> instance value
>>>>>>>>>> in ip_block, and remove the original for loop for all vcn
>>>>>>>>>> instances.
>>>>>>>>>>
>>>>>>>>>> v2: rename "i"/"j" to "inst" for instance value.
>>>>>>>>>>
>>>>>>>>>> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
>>>>>>>>>> ---
>>>>>>>>>>     drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
>>>>>>>>>>     drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565
>>>>>>>>>> +++++++++---------
>>>>>>>>>>     2 files changed, 280 insertions(+), 289 deletions(-)
>>>>>>>>>>
>>>>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>>>> index 9f9a1867da72..de1053cc2a2b 100644
>>>>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>>>> @@ -2278,6 +2278,7 @@ static int
>>>>>>>>>> amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
>>>>>>>>>>       static int amdgpu_discovery_set_mm_ip_blocks(struct
>>>>>>>>>> amdgpu_device
>>>>>>>>>> *adev)
>>>>>>>>>>     {
>>>>>>>>>> +    int i;
>>>>>>>>>>         if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
>>>>>>>>>>             switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
>>>>>>>>>>             case IP_VERSION(7, 0, 0):
>>>>>>>>>> @@ -2321,7 +2322,8 @@ static int
>>>>>>>>>> amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>>>>>>>>>>             case IP_VERSION(2, 0, 3):
>>>>>>>>>>                 break;
>>>>>>>>>>             case IP_VERSION(2, 5, 0):
>>>>>>>>>> -            amdgpu_device_ip_block_add(adev, &vcn_v2_5_ip_block);
>>>>>>>>>> +            for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
>>>>>>>>>> +                amdgpu_device_ip_block_add(adev,
>>>>>>>>>> &vcn_v2_5_ip_block);
>>>>>>>>> This introduces a totally confusing design now. At a higher
>>>>>>>>> level an IP
>>>>>>>>> block type manages multiple instances and their power states.
>>>>>>>>> Now there
>>>>>>>>> is a mix where no definition can be attributed to an IP block.
>>>>>>>>> Or, if
>>>>>>>>> this were to be done uniformly for other IPs, then for some SOCs
>>>>>>>>> there
>>>>>>>>> could be 16 SDMA blocks, 8 GFX blocks and so forth.
>>>>>>>>>
>>>>>>>>> What is the reason to do this way? Can't VCN IP block maintain
>>>>>>>>> the state
>>>>>>>>> of multiple instances within itself?
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Lijo
>>>>>>>> This is part of the fundamental design change for separating IP
>>>>>>>> block
>>>>>>>> per instance, in order to
>>>>>>>> handle each instance separately within same IP block (e.g. separate
>>>>>>>> power/clock management).
>>>>>>>>
>>>>>>>> Part 1, Change all adev ptr handle to amdgpu_ip_block ptr in all
>>>>>>>> callbacks (hw_init/fini, sw_init/fini,
>>>>>>>> suspend, etc...) for all IP blocks, so that each IP knows which
>>>>>>>> IP_block
>>>>>>>> (and which instance) the
>>>>>>>> callback is for. Most parts of this changes have been submitted
>>>>>>>> by Sunil.
>>>>>>>>
>>>>>>>> Part 2, Separate IP block per instance.
>>>>>>>>
>>>>>>>> Part 3, Since callbacks can pass in IP_block now after Part 1
>>>>>>>> change and
>>>>>>>> instance value can be
>>>>>>>> obtained from each IP block in Part 2, IP can then choose to handle
>>>>>>>> callbacks ONLY for the given
>>>>>>>> instance of a given IP block (or still handling for all instances as
>>>>>>>> before).
>>>>>>>> For VCN, all callbacks will be handled only for the given one
>>>>>>>> instance,
>>>>>>>> instead of the original for-
>>>>>>>> loop for all instance. As a result, each VCN instance can be
>>>>>>>> start/stop/int/fini/suspend separately.
>>>>>>>>
>>>>>>>> Part 4, Change all VCN helper functions to handle only the given
>>>>>>>> instance, instead of the original
>>>>>>>> for-loop for all instance.
>>>>>>>>
>>>>>>>> Each instance can have its own states, so we think it makes more
>>>>>>>> sense
>>>>>>>> to separate them on IP
>>>>>>>> block level to handle each of them separately.
>>>>>>> Such a change should not be done unless all IPs follow the same
>>>>>>> design.
>>>>>>> You didn't answer the question - what necessitates this change?
>>>>>>> What is
>>>>>>> special about VCN that it cannot manage the states of multiple
>>>>>>> instances
>>>>>>> within the IP block?
>>>>>> We want to be able to manage the powergating independently for each
>>>>>> VCN instance for both power management and VCN reset.  Right now power
>>>>>> gating is handled at the IP level so it's not easy or clean to handle
>>>>>> powergating of individual IP instances.
>>>>>>
>>>>> Still VCN block can manage the powergated instances (FWIW, it's just an
>>>>> array in SMU block). Also vcn block gets to run the idle worker and
>>>>> knows the rings (and corresponding VCN instances) that are idle.
>>>>> Maintaining instance states in VCN block and modifying idle worker to
>>>>> just idle that instance alone doesn't look like a complex change.
>>>> We already went down that road and it's really ugly.  We end up
>>>> duplicating a bunch of code paths for different driver flows because
>>>> set_powergating_state() and set_clockgating_state are at the IP level
>>>> and we want per instance gating.  We could add a num_instances member
>>>> at the IP block level and then convert all of the high level code that
>>>> calls the IP functions loop over the number of instances, but that
>>>> seems like just as much work and it's not quite as clean IMHO.
>>>>
>>> Sorry, I'm not seeing much difference in this design. All it does is
>>> just split instances to IP block at the same time it's going to keep an
>>> instance parameter in IP block APIs.
>>>
>>>      amdgpu_device_ip_set_clockgating_state(blocktype, instance);
>>>      amdgpu_device_ip_set_powergating_state(blocktype, instance);
>>>
>>> Also, VCN continues to maintain an array of amdgpu_vcn_inst. I think
>>> it's easier manage this with changes to amdgpu_vcn_inst. Since it is
>>> continued to be maintained, what about just moving the states and
>>> idle_work inside amdgpu_vcn_inst.
>>>      
>>>      int inst;
>>>      enum amd_powergating_state cur_pg_state;
>>>      enum amd_clockgating_state state cur_cg_state;
>>>      struct delayed_work     idle_work;
>>>
>>> At the end of ring usage of corresponding instance, just invoke the
>>> corresponding instance's idle work.
>>>
>>> schedule_delayed_work(&ring->adev->vcn.inst[ring->me].idle_work,
>>> idle_time_out);
>> First of all, separating idle work and state is still needed in current
>> design.
>> Separating idle work by instance is already handled in patch 17/18.
>> Separating power gating state is already handled in patch 10/18.
>>
>> I agree that "adding instance variable" in amdgpu_vcn_inst requires
>> much less effort, but as mentioned by Alex previously, we already
>> went down that way to use "inst" variable in amdgou_vcn_inst as you
>> listed above and track this instance value all the way from VCN to SMU.
>> However, this is a no-go based on discussions with Christian and Alex.
>> Since set_powergating_state() is at IP level, it will be clean to do
>> per instance gating at IP level. With the change of passing ip_block to
>> callback functions, all ip functions can now choose to handle only the
>> given instance, which is a clean separation between multiple instance.
>>
> I don't agree.
>
> There is no clean separation here. What I see here is a mix where ip
> block still remains a dummy.
>
> 	ipblock->inst => calls vcn.vcn_inst[i] that maintains the final state.
>
> If the design is based only on ip block, you wouldn't have required to
> maintain another vcn_inst. Everything would have been handled by
> maintaining state in ip block itself.
The change is to separate IP blocks, not amdgpu_device. Different
IP blocks still share the same adev. vcn_inst is handled within adev.
>>> I don't see any change in this series for other IP block APIs.
>> Yes, currently we only do this per instance IP block for VCN. For long
>> term,
>> the plan is to change all other IP with multiple blocks into this design.
>>
> This path itself is not a viable solution. We will have cases where a
> group of ip blocks of the same type need to be handled together. At that
> point you will need another central controller for ip blocks belonging
> to a type. That will evenutally lead to another superblock being created.
Handling each IP block at IP level is the purpose of this change.
With similar changes as VCN, other IP types can still choose to
handle a group of IP blocks with same type, there is no need to
create a superblock.

Thanks,
Boyuan
>
> Thanks,
> Lijo
>
>> Regards,
>> Boyuan
>>
>>
>>> Thanks,
>>> Lijo
>>>
>>>> Alex
>>>>
>>>>> Moving to IP block per instance for VCN alone is not a change that
>>>>> helps
>>>>> to define an IP block. If that needs to be done for every other IP
>>>>> type,
>>>>> that's also a massive change.
>>>>>
>>>>> Also, then it's no longer possible to have something static like this -
>>>>>           struct amdgpu_ip_block          ip_blocks[AMDGPU_MAX_IP_NUM];
>>>>>
>>>>>
>>>>> Thanks,
>>>>> Lijo
>>>>>
>>>>>> Alex
>>>>>>
>>>>>>> Thanks,
>>>>>>> Lijo
>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Boyuan
>>>>>>>>>>                 amdgpu_device_ip_block_add(adev,
>>>>>>>>>> &jpeg_v2_5_ip_block);
>>>>>>>>>>                 break;
>>>>>>>>>>             case IP_VERSION(2, 6, 0):
>>>>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>>>> b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>>>> index d00df51bc400..1f8738ae360a 100644
>>>>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>>>> @@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct
>>>>>>>>>> amdgpu_ip_block *ip_block)
>>>>>>>>>>     static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block)
>>>>>>>>>>     {
>>>>>>>>>>         struct amdgpu_ring *ring;
>>>>>>>>>> -    int i, j, r;
>>>>>>>>>> +    int i, r;
>>>>>>>>>>         uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
>>>>>>>>>>         uint32_t *ptr;
>>>>>>>>>>         struct amdgpu_device *adev = ip_block->adev;
>>>>>>>>>> +    int inst = ip_block->instance;
>>>>>>>>>>     -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << j))
>>>>>>>>>> -            continue;
>>>>>>>>>> -        /* VCN DEC TRAP */
>>>>>>>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>>>>>>> -                VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>>>>>>>>> &adev->vcn.inst[j].irq);
>>>>>>>>>> -        if (r)
>>>>>>>>>> -            return r;
>>>>>>>>>> -
>>>>>>>>>> -        /* VCN ENC TRAP */
>>>>>>>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>>>> -            r = amdgpu_irq_add_id(adev,
>>>>>>>>>> amdgpu_ih_clientid_vcns[j],
>>>>>>>>>> -                i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>>>>>>>>> &adev->vcn.inst[j].irq);
>>>>>>>>>> -            if (r)
>>>>>>>>>> -                return r;
>>>>>>>>>> -        }
>>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>>> +        goto sw_init;
>>>>>>>>>> +    /* VCN DEC TRAP */
>>>>>>>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>>>>>>> +            VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>>>>>>>>> &adev->vcn.inst[inst].irq);
>>>>>>>>>> +    if (r)
>>>>>>>>>> +        return r;
>>>>>>>>>>     -        /* VCN POISON TRAP */
>>>>>>>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>>>>>>> -            VCN_2_6__SRCID_UVD_POISON,
>>>>>>>>>> &adev->vcn.inst[j].ras_poison_irq);
>>>>>>>>>> +    /* VCN ENC TRAP */
>>>>>>>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>>>> +        r = amdgpu_irq_add_id(adev,
>>>>>>>>>> amdgpu_ih_clientid_vcns[inst],
>>>>>>>>>> +            i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>>>>>>>>> &adev->vcn.inst[inst].irq);
>>>>>>>>>>             if (r)
>>>>>>>>>>                 return r;
>>>>>>>>>>         }
>>>>>>>>>>     +    /* VCN POISON TRAP */
>>>>>>>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>>>>>>> +        VCN_2_6__SRCID_UVD_POISON,
>>>>>>>>>> &adev->vcn.inst[inst].ras_poison_irq);
>>>>>>>>>> +    if (r)
>>>>>>>>>> +        return r;
>>>>>>>>>> +sw_init:
>>>>>>>>>>         r = amdgpu_vcn_sw_init(adev);
>>>>>>>>>>         if (r)
>>>>>>>>>>             return r;
>>>>>>>>>> @@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct
>>>>>>>>>> amdgpu_ip_block *ip_block)
>>>>>>>>>>         if (r)
>>>>>>>>>>             return r;
>>>>>>>>>>     -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>>>>>>>>> -        volatile struct amdgpu_fw_shared *fw_shared;
>>>>>>>>>> +    volatile struct amdgpu_fw_shared *fw_shared;
>>>>>>>>>>     -        if (adev->vcn.harvest_config & (1 << j))
>>>>>>>>>> -            continue;
>>>>>>>>>> -        adev->vcn.internal.context_id =
>>>>>>>>>> mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>>>>>>>>> -        adev->vcn.internal.ib_vmid =
>>>>>>>>>> mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>>>>>>>>> -        adev->vcn.internal.ib_bar_low =
>>>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>>>>>>>>> -        adev->vcn.internal.ib_bar_high =
>>>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>>>>>>>>> -        adev->vcn.internal.ib_size =
>>>>>>>>>> mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>>>>>>>>> -        adev->vcn.internal.gp_scratch8 =
>>>>>>>>>> mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>>>>>>>>> -
>>>>>>>>>> -        adev->vcn.internal.scratch9 =
>>>>>>>>>> mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>>>>>>>>> -        adev->vcn.inst[j].external.scratch9 =
>>>>>>>>>> SOC15_REG_OFFSET(VCN,
>>>>>>>>>> j, mmUVD_SCRATCH9);
>>>>>>>>>> -        adev->vcn.internal.data0 =
>>>>>>>>>> mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>>>>>>>>> -        adev->vcn.inst[j].external.data0 =
>>>>>>>>>> SOC15_REG_OFFSET(VCN, j,
>>>>>>>>>> mmUVD_GPCOM_VCPU_DATA0);
>>>>>>>>>> -        adev->vcn.internal.data1 =
>>>>>>>>>> mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>>>>>>>>> -        adev->vcn.inst[j].external.data1 =
>>>>>>>>>> SOC15_REG_OFFSET(VCN, j,
>>>>>>>>>> mmUVD_GPCOM_VCPU_DATA1);
>>>>>>>>>> -        adev->vcn.internal.cmd =
>>>>>>>>>> mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>>>>>>>>> -        adev->vcn.inst[j].external.cmd = SOC15_REG_OFFSET(VCN, j,
>>>>>>>>>> mmUVD_GPCOM_VCPU_CMD);
>>>>>>>>>> -        adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>>>>>>>>> -        adev->vcn.inst[j].external.nop = SOC15_REG_OFFSET(VCN, j,
>>>>>>>>>> mmUVD_NO_OP);
>>>>>>>>>> -
>>>>>>>>>> -        ring = &adev->vcn.inst[j].ring_dec;
>>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>>> +        goto done;
>>>>>>>>>> +    adev->vcn.internal.context_id =
>>>>>>>>>> mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>>>>>>>>> +    adev->vcn.internal.ib_vmid =
>>>>>>>>>> mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>>>>>>>>> +    adev->vcn.internal.ib_bar_low =
>>>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>>>>>>>>> +    adev->vcn.internal.ib_bar_high =
>>>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>>>>>>>>> +    adev->vcn.internal.ib_size =
>>>>>>>>>> mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>>>>>>>>> +    adev->vcn.internal.gp_scratch8 =
>>>>>>>>>> mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>>>>>>>>> +
>>>>>>>>>> +    adev->vcn.internal.scratch9 = mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>>>>>>>>> +    adev->vcn.inst[inst].external.scratch9 =
>>>>>>>>>> SOC15_REG_OFFSET(VCN,
>>>>>>>>>> inst, mmUVD_SCRATCH9);
>>>>>>>>>> +    adev->vcn.internal.data0 =
>>>>>>>>>> mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>>>>>>>>> +    adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN,
>>>>>>>>>> inst, mmUVD_GPCOM_VCPU_DATA0);
>>>>>>>>>> +    adev->vcn.internal.data1 =
>>>>>>>>>> mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>>>>>>>>> +    adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN,
>>>>>>>>>> inst, mmUVD_GPCOM_VCPU_DATA1);
>>>>>>>>>> +    adev->vcn.internal.cmd =
>>>>>>>>>> mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>>>>>>>>> +    adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN,
>>>>>>>>>> inst,
>>>>>>>>>> mmUVD_GPCOM_VCPU_CMD);
>>>>>>>>>> +    adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>>>>>>>>> +    adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN,
>>>>>>>>>> inst,
>>>>>>>>>> mmUVD_NO_OP);
>>>>>>>>>> +
>>>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>>>>>>>>> +    ring->use_doorbell = true;
>>>>>>>>>> +
>>>>>>>>>> +    ring->doorbell_index =
>>>>>>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 <<
>>>>>>>>>> 1) +
>>>>>>>>>> +            (amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
>>>>>>>>>> +
>>>>>>>>>> +    if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2,
>>>>>>>>>> 5, 0))
>>>>>>>>>> +        ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>>>>> +    else
>>>>>>>>>> +        ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>>>>> +
>>>>>>>>>> +    sprintf(ring->name, "vcn_dec_%d", inst);
>>>>>>>>>> +    r = amdgpu_ring_init(adev, ring, 512,
>>>>>>>>>> &adev->vcn.inst[inst].irq,
>>>>>>>>>> +                 0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>>>>>>>>> +    if (r)
>>>>>>>>>> +        return r;
>>>>>>>>>> +
>>>>>>>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>>>> +        enum amdgpu_ring_priority_level hw_prio =
>>>>>>>>>> amdgpu_vcn_get_enc_ring_prio(i);
>>>>>>>>>> +
>>>>>>>>>> +        ring = &adev->vcn.inst[inst].ring_enc[i];
>>>>>>>>>>             ring->use_doorbell = true;
>>>>>>>>>>               ring->doorbell_index =
>>>>>>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>>>>>>>>> -                (amdgpu_sriov_vf(adev) ? 2*j : 8*j);
>>>>>>>>>> +                (amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2
>>>>>>>>>> + i +
>>>>>>>>>> 8*inst));
>>>>>>>>>>     -        if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>>>>>>> IP_VERSION(2,
>>>>>>>>>> 5, 0))
>>>>>>>>>> +        if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>>>>>>> +            IP_VERSION(2, 5, 0))
>>>>>>>>>>                 ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>>>>>             else
>>>>>>>>>>                 ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>>>>>     -        sprintf(ring->name, "vcn_dec_%d", j);
>>>>>>>>>> -        r = amdgpu_ring_init(adev, ring, 512,
>>>>>>>>>> &adev->vcn.inst[j].irq,
>>>>>>>>>> -                     0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>>>>>>>>> +        sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
>>>>>>>>>> +        r = amdgpu_ring_init(adev, ring, 512,
>>>>>>>>>> +                     &adev->vcn.inst[inst].irq, 0,
>>>>>>>>>> +                     hw_prio, NULL);
>>>>>>>>>>             if (r)
>>>>>>>>>>                 return r;
>>>>>>>>>> -
>>>>>>>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>>>> -            enum amdgpu_ring_priority_level hw_prio =
>>>>>>>>>> amdgpu_vcn_get_enc_ring_prio(i);
>>>>>>>>>> -
>>>>>>>>>> -            ring = &adev->vcn.inst[j].ring_enc[i];
>>>>>>>>>> -            ring->use_doorbell = true;
>>>>>>>>>> -
>>>>>>>>>> -            ring->doorbell_index =
>>>>>>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>>>>>>>>> -                    (amdgpu_sriov_vf(adev) ? (1 + i + 2*j) :
>>>>>>>>>> (2 + i
>>>>>>>>>> + 8*j));
>>>>>>>>>> -
>>>>>>>>>> -            if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>>>>>>> -                IP_VERSION(2, 5, 0))
>>>>>>>>>> -                ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>>>>> -            else
>>>>>>>>>> -                ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>>>>> -
>>>>>>>>>> -            sprintf(ring->name, "vcn_enc_%d.%d", j, i);
>>>>>>>>>> -            r = amdgpu_ring_init(adev, ring, 512,
>>>>>>>>>> -                         &adev->vcn.inst[j].irq, 0,
>>>>>>>>>> -                         hw_prio, NULL);
>>>>>>>>>> -            if (r)
>>>>>>>>>> -                return r;
>>>>>>>>>> -        }
>>>>>>>>>> -
>>>>>>>>>> -        fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
>>>>>>>>>> -        fw_shared->present_flag_0 =
>>>>>>>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>>>>>>>>> -
>>>>>>>>>> -        if (amdgpu_vcnfw_log)
>>>>>>>>>> -            amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>>>>>>>>         }
>>>>>>>>>>     +    fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
>>>>>>>>>> +    fw_shared->present_flag_0 =
>>>>>>>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>>>>>>>>> +
>>>>>>>>>> +    if (amdgpu_vcnfw_log)
>>>>>>>>>> +        amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>>>>>>>> +done:
>>>>>>>>>>         if (amdgpu_sriov_vf(adev)) {
>>>>>>>>>>             r = amdgpu_virt_alloc_mm_table(adev);
>>>>>>>>>>             if (r)
>>>>>>>>>> @@ -1005,197 +1002,192 @@ static int
>>>>>>>>>> vcn_v2_5_start_dpg_mode(struct
>>>>>>>>>> amdgpu_device *adev, int inst_idx, boo
>>>>>>>>>>         return 0;
>>>>>>>>>>     }
>>>>>>>>>>     -static int vcn_v2_5_start(struct amdgpu_device *adev)
>>>>>>>>>> +static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned
>>>>>>>>>> int
>>>>>>>>>> inst)
>>>>>>>>>>     {
>>>>>>>>>>         struct amdgpu_ring *ring;
>>>>>>>>>>         uint32_t rb_bufsz, tmp;
>>>>>>>>>> -    int i, j, k, r;
>>>>>>>>>> +    int j, k, r;
>>>>>>>>>>     -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>>> -        if (adev->pm.dpm_enabled)
>>>>>>>>>> -            amdgpu_dpm_enable_vcn(adev, true, i);
>>>>>>>>>> -    }
>>>>>>>>>> -
>>>>>>>>>> -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>>>> -            continue;
>>>>>>>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>>>> -            r = vcn_v2_5_start_dpg_mode(adev, i,
>>>>>>>>>> adev->vcn.indirect_sram);
>>>>>>>>>> -            continue;
>>>>>>>>>> -        }
>>>>>>>>>> +    if (adev->pm.dpm_enabled)
>>>>>>>>>> +        amdgpu_dpm_enable_vcn(adev, true, inst);
>>>>>>>>>>     -        /* disable register anti-hang mechanism */
>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS), 0,
>>>>>>>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>>> +        return 0;
>>>>>>>>>>     -        /* set uvd status busy */
>>>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) |
>>>>>>>>>> UVD_STATUS__UVD_BUSY;
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
>>>>>>>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>>>> +        r = vcn_v2_5_start_dpg_mode(adev, inst,
>>>>>>>>>> adev->vcn.indirect_sram);
>>>>>>>>>> +        return r;
>>>>>>>>>>         }
>>>>>>>>>>     +    /* disable register anti-hang mechanism */
>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS), 0,
>>>>>>>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>>>> +
>>>>>>>>>> +    /* set uvd status busy */
>>>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) |
>>>>>>>>>> UVD_STATUS__UVD_BUSY;
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
>>>>>>>>>> +
>>>>>>>>>>         if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
>>>>>>>>>>             return 0;
>>>>>>>>>>           /*SW clock gating */
>>>>>>>>>>         vcn_v2_5_disable_clock_gating(adev);
>>>>>>>>>>     -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>>>> -            continue;
>>>>>>>>>> -        /* enable VCPU clock */
>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>>>>> -            UVD_VCPU_CNTL__CLK_EN_MASK,
>>>>>>>>>> ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>>>>>>>>> -
>>>>>>>>>> -        /* disable master interrupt */
>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
>>>>>>>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>>>> -
>>>>>>>>>> -        /* setup mmUVD_LMI_CTRL */
>>>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
>>>>>>>>>> -        tmp &= ~0xff;
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
>>>>>>>>>> -            UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>>>>>>>>> -            UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>>>>>>>>> -            UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>>>>>>>>> -            UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>>>>>>>>> -
>>>>>>>>>> -        /* setup mmUVD_MPC_CNTL */
>>>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
>>>>>>>>>> -        tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>>>>>>>>> -        tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
>>>>>>>>>> -
>>>>>>>>>> -        /* setup UVD_MPC_SET_MUXA0 */
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
>>>>>>>>>> -            ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>>>>>>>>> -            (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>>>>>>>>> -            (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>>>>>>>>> -            (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>>>>>>>>> -
>>>>>>>>>> -        /* setup UVD_MPC_SET_MUXB0 */
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
>>>>>>>>>> -            ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>>>>>>>>> -            (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>>>>>>>>> -            (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>>>>>>>>> -            (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>>>>>>>>> -
>>>>>>>>>> -        /* setup mmUVD_MPC_SET_MUX */
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
>>>>>>>>>> -            ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>>>>>>>>> -            (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>>>>>>>>> -            (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>>>>>>>> -    }
>>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>>> +        return 0;
>>>>>>>>>> +
>>>>>>>>>> +    /* enable VCPU clock */
>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>>>>> +        UVD_VCPU_CNTL__CLK_EN_MASK, ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>>>>>>>>> +
>>>>>>>>>> +    /* disable master interrupt */
>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
>>>>>>>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>>>> +
>>>>>>>>>> +    /* setup mmUVD_LMI_CTRL */
>>>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
>>>>>>>>>> +    tmp &= ~0xff;
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
>>>>>>>>>> +        UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>>>>>>>>> +        UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>>>>>>>>> +        UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>>>>>>>>> +        UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>>>>>>>>> +
>>>>>>>>>> +    /* setup mmUVD_MPC_CNTL */
>>>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
>>>>>>>>>> +    tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>>>>>>>>> +    tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
>>>>>>>>>> +
>>>>>>>>>> +    /* setup UVD_MPC_SET_MUXA0 */
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
>>>>>>>>>> +        ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>>>>>>>>> +        (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>>>>>>>>> +        (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>>>>>>>>> +        (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>>>>>>>>> +
>>>>>>>>>> +    /* setup UVD_MPC_SET_MUXB0 */
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
>>>>>>>>>> +        ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>>>>>>>>> +        (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>>>>>>>>> +        (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>>>>>>>>> +        (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>>>>>>>>> +
>>>>>>>>>> +    /* setup mmUVD_MPC_SET_MUX */
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
>>>>>>>>>> +        ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>>>>>>>>> +        (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>>>>>>>>> +        (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>>>>>>>>           vcn_v2_5_mc_resume(adev);
>>>>>>>>>>     -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>>> -        volatile struct amdgpu_fw_shared *fw_shared =
>>>>>>>>>> adev->vcn.inst[i].fw_shared.cpu_addr;
>>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>>>> -            continue;
>>>>>>>>>> -        /* VCN global tiling registers */
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>>>> -            adev->gfx.config.gb_addr_config);
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>>>> -            adev->gfx.config.gb_addr_config);
>>>>>>>>>> +    volatile struct amdgpu_fw_shared *fw_shared =
>>>>>>>>>> adev->vcn.inst[inst].fw_shared.cpu_addr;
>>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>>> +        return 0;
>>>>>>>>>> +
>>>>>>>>>> +    /* VCN global tiling registers */
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>>>> +        adev->gfx.config.gb_addr_config);
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>>>> +        adev->gfx.config.gb_addr_config);
>>>>>>>>>>     -        /* enable LMI MC and UMC channels */
>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
>>>>>>>>>> -            ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>>>>>>>> +    /* enable LMI MC and UMC channels */
>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
>>>>>>>>>> +        ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>>>>>>>>     -        /* unblock VCPU register access */
>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL), 0,
>>>>>>>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>>>> +    /* unblock VCPU register access */
>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
>>>>>>>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>>>>     -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>>>>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>>>>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>>     -        for (k = 0; k < 10; ++k) {
>>>>>>>>>> -            uint32_t status;
>>>>>>>>>> -
>>>>>>>>>> -            for (j = 0; j < 100; ++j) {
>>>>>>>>>> -                status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
>>>>>>>>>> -                if (status & 2)
>>>>>>>>>> -                    break;
>>>>>>>>>> -                if (amdgpu_emu_mode == 1)
>>>>>>>>>> -                    msleep(500);
>>>>>>>>>> -                else
>>>>>>>>>> -                    mdelay(10);
>>>>>>>>>> -            }
>>>>>>>>>> -            r = 0;
>>>>>>>>>> +    for (k = 0; k < 10; ++k) {
>>>>>>>>>> +        uint32_t status;
>>>>>>>>>> +
>>>>>>>>>> +        for (j = 0; j < 100; ++j) {
>>>>>>>>>> +            status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
>>>>>>>>>>                 if (status & 2)
>>>>>>>>>>                     break;
>>>>>>>>>> +            if (amdgpu_emu_mode == 1)
>>>>>>>>>> +                msleep(500);
>>>>>>>>>> +            else
>>>>>>>>>> +                mdelay(10);
>>>>>>>>>> +        }
>>>>>>>>>> +        r = 0;
>>>>>>>>>> +        if (status & 2)
>>>>>>>>>> +            break;
>>>>>>>>>>     -            DRM_ERROR("VCN decode not responding, trying to
>>>>>>>>>> reset
>>>>>>>>>> the VCPU!!!\n");
>>>>>>>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>>>>> -                UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>> -            mdelay(10);
>>>>>>>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i,
>>>>>>>>>> mmUVD_VCPU_CNTL), 0,
>>>>>>>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>> +        DRM_ERROR("VCN decode not responding, trying to reset the
>>>>>>>>>> VCPU!!!\n");
>>>>>>>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>>>>> +            UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>> +        mdelay(10);
>>>>>>>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>>>>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>>     -            mdelay(10);
>>>>>>>>>> -            r = -1;
>>>>>>>>>> -        }
>>>>>>>>>> +        mdelay(10);
>>>>>>>>>> +        r = -1;
>>>>>>>>>> +    }
>>>>>>>>>>     -        if (r) {
>>>>>>>>>> -            DRM_ERROR("VCN decode not responding, giving
>>>>>>>>>> up!!!\n");
>>>>>>>>>> -            return r;
>>>>>>>>>> -        }
>>>>>>>>>> +    if (r) {
>>>>>>>>>> +        DRM_ERROR("VCN decode not responding, giving up!!!\n");
>>>>>>>>>> +        return r;
>>>>>>>>>> +    }
>>>>>>>>>>     -        /* enable master interrupt */
>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
>>>>>>>>>> -            UVD_MASTINT_EN__VCPU_EN_MASK,
>>>>>>>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>>>> +    /* enable master interrupt */
>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
>>>>>>>>>> +        UVD_MASTINT_EN__VCPU_EN_MASK,
>>>>>>>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>>>>     -        /* clear the busy bit of VCN_STATUS */
>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
>>>>>>>>>> -            ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>>>>>>>> +    /* clear the busy bit of VCN_STATUS */
>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
>>>>>>>>>> +        ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>>>>>>>>     -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
>>>>>>>>>>     -        ring = &adev->vcn.inst[i].ring_dec;
>>>>>>>>>> -        /* force RBC into idle state */
>>>>>>>>>> -        rb_bufsz = order_base_2(ring->ring_size);
>>>>>>>>>> -        tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ,
>>>>>>>>>> rb_bufsz);
>>>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH,
>>>>>>>>>> 1);
>>>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL,
>>>>>>>>>> RB_NO_UPDATE, 1);
>>>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL,
>>>>>>>>>> RB_RPTR_WR_EN, 1);
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
>>>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>>>>>>>>> +    /* force RBC into idle state */
>>>>>>>>>> +    rb_bufsz = order_base_2(ring->ring_size);
>>>>>>>>>> +    tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz);
>>>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>>>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>>>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1);
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
>>>>>>>>>>     -        fw_shared->multi_queue.decode_queue_mode |=
>>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>>> -        /* program the RB_BASE for ring buffer */
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>>>>>>>>> -            lower_32_bits(ring->gpu_addr));
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>>>>>>>>> -            upper_32_bits(ring->gpu_addr));
>>>>>>>>>> +    fw_shared->multi_queue.decode_queue_mode |=
>>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>>> +    /* program the RB_BASE for ring buffer */
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>>>>>>>>> +        lower_32_bits(ring->gpu_addr));
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>>>>>>>>> +        upper_32_bits(ring->gpu_addr));
>>>>>>>>>>     -        /* Initialize the ring buffer's read and write
>>>>>>>>>> pointers */
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
>>>>>>>>>> +    /* Initialize the ring buffer's read and write pointers */
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
>>>>>>>>>>     -        ring->wptr = RREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR);
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
>>>>>>>>>> -                lower_32_bits(ring->wptr));
>>>>>>>>>> -        fw_shared->multi_queue.decode_queue_mode &=
>>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>>> +    ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
>>>>>>>>>> +            lower_32_bits(ring->wptr));
>>>>>>>>>> +    fw_shared->multi_queue.decode_queue_mode &=
>>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>>>     -
>>>>>>>>>> fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>>> -        ring = &adev->vcn.inst[i].ring_enc[0];
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR,
>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR,
>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI,
>>>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size / 4);
>>>>>>>>>> -
>>>>>>>>>> fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>>> -
>>>>>>>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>>> -        ring = &adev->vcn.inst[i].ring_enc[1];
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2,
>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2,
>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2,
>>>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size /
>>>>>>>>>> 4);
>>>>>>>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>>> -    }
>>>>>>>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_enc[0];
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR,
>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR,
>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI,
>>>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size / 4);
>>>>>>>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>>> +
>>>>>>>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_enc[1];
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2,
>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2,
>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2,
>>>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size / 4);
>>>>>>>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>>>           return 0;
>>>>>>>>>>     }
>>>>>>>>>> @@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct
>>>>>>>>>> amdgpu_device *adev, int inst_idx)
>>>>>>>>>>         return 0;
>>>>>>>>>>     }
>>>>>>>>>>     -static int vcn_v2_5_stop(struct amdgpu_device *adev)
>>>>>>>>>> +static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned
>>>>>>>>>> int inst)
>>>>>>>>>>     {
>>>>>>>>>>         uint32_t tmp;
>>>>>>>>>> -    int i, r = 0;
>>>>>>>>>> +    int r = 0;
>>>>>>>>>>     -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>>>> -            continue;
>>>>>>>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>>>> -            r = vcn_v2_5_stop_dpg_mode(adev, i);
>>>>>>>>>> -            continue;
>>>>>>>>>> -        }
>>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>>> +        goto done;
>>>>>>>>>>     -        /* wait for vcn idle */
>>>>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS,
>>>>>>>>>> UVD_STATUS__IDLE, 0x7);
>>>>>>>>>> -        if (r)
>>>>>>>>>> -            return r;
>>>>>>>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>>>> +        r = vcn_v2_5_stop_dpg_mode(adev, inst);
>>>>>>>>>> +        goto done;
>>>>>>>>>> +    }
>>>>>>>>>>     -        tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>>>>>>>>> -            UVD_LMI_STATUS__READ_CLEAN_MASK |
>>>>>>>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>>>>>>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>>>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp,
>>>>>>>>>> tmp);
>>>>>>>>>> -        if (r)
>>>>>>>>>> -            return r;
>>>>>>>>>> +    /* wait for vcn idle */
>>>>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS,
>>>>>>>>>> UVD_STATUS__IDLE, 0x7);
>>>>>>>>>> +    if (r)
>>>>>>>>>> +        return r;
>>>>>>>>>>     -        /* block LMI UMC channel */
>>>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
>>>>>>>>>> -        tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
>>>>>>>>>> +    tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>>>>>>>>> +        UVD_LMI_STATUS__READ_CLEAN_MASK |
>>>>>>>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>>>>>>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>>>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp,
>>>>>>>>>> tmp);
>>>>>>>>>> +    if (r)
>>>>>>>>>> +        return r;
>>>>>>>>>>     -        tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>>>>>>>>> -            UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>>>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp,
>>>>>>>>>> tmp);
>>>>>>>>>> -        if (r)
>>>>>>>>>> -            return r;
>>>>>>>>>> +    /* block LMI UMC channel */
>>>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
>>>>>>>>>> +    tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
>>>>>>>>>>     -        /* block VCPU register access */
>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
>>>>>>>>>> -            UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>>>>>>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>>>> +    tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>>>>>>>>> +        UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>>>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp,
>>>>>>>>>> tmp);
>>>>>>>>>> +    if (r)
>>>>>>>>>> +        return r;
>>>>>>>>>>     -        /* reset VCPU */
>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>>>>> -            UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>> +    /* block VCPU register access */
>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
>>>>>>>>>> +        UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>>>>>>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>>>>     -        /* disable VCPU clock */
>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>>>>>>> -            ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>>>>>>>> +    /* reset VCPU */
>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>>>>> +        UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>>     -        /* clear status */
>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
>>>>>>>>>> +    /* disable VCPU clock */
>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>>>>>>> +        ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>>>>>>>>     -        vcn_v2_5_enable_clock_gating(adev);
>>>>>>>>>> +    /* clear status */
>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
>>>>>>>>>>     -        /* enable register anti-hang mechanism */
>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
>>>>>>>>>> -            UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>>>>>>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>>>> -    }
>>>>>>>>>> +    vcn_v2_5_enable_clock_gating(adev);
>>>>>>>>>>     -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>>> -        if (adev->pm.dpm_enabled)
>>>>>>>>>> -            amdgpu_dpm_enable_vcn(adev, false, i);
>>>>>>>>>> -    }
>>>>>>>>>> +    /* enable register anti-hang mechanism */
>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
>>>>>>>>>> +        UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>>>>>>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>>>> +done:
>>>>>>>>>> +    if (adev->pm.dpm_enabled)
>>>>>>>>>> +        amdgpu_dpm_enable_vcn(adev, false, inst);
>>>>>>>>>>           return 0;
>>>>>>>>>>     }
>>>>>>>>>> @@ -1838,9 +1827,9 @@ static int
>>>>>>>>>> vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
>>>>>>>>>>             return 0;
>>>>>>>>>>           if (state == AMD_PG_STATE_GATE)
>>>>>>>>>> -        ret = vcn_v2_5_stop(adev);
>>>>>>>>>> +        ret = vcn_v2_5_stop(adev, inst);
>>>>>>>>>>         else
>>>>>>>>>> -        ret = vcn_v2_5_start(adev);
>>>>>>>>>> +        ret = vcn_v2_5_start(adev, inst);
>>>>>>>>>>           if (!ret)
>>>>>>>>>>             adev->vcn.cur_state[inst] = state;

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 11/18] drm/amdgpu: power vcn 2_5 by instance
  2024-10-09 13:36                     ` Boyuan Zhang
@ 2024-10-09 14:07                       ` Lazar, Lijo
  0 siblings, 0 replies; 37+ messages in thread
From: Lazar, Lijo @ 2024-10-09 14:07 UTC (permalink / raw)
  To: Boyuan Zhang, Alex Deucher
  Cc: amd-gfx, leo.liu, christian.koenig, alexander.deucher,
	sunil.khatri



On 10/9/2024 7:06 PM, Boyuan Zhang wrote:
> 
> On 2024-10-08 23:43, Lazar, Lijo wrote:
>>
>> On 10/9/2024 3:34 AM, Boyuan Zhang wrote:
>>> On 2024-10-08 03:03, Lazar, Lijo wrote:
>>>> On 10/7/2024 8:54 PM, Alex Deucher wrote:
>>>>> On Mon, Oct 7, 2024 at 10:32 AM Lazar, Lijo <lijo.lazar@amd.com>
>>>>> wrote:
>>>>>>
>>>>>> On 10/7/2024 7:47 PM, Alex Deucher wrote:
>>>>>>> On Mon, Oct 7, 2024 at 9:58 AM Lazar, Lijo <lijo.lazar@amd.com>
>>>>>>> wrote:
>>>>>>>>
>>>>>>>> On 10/7/2024 7:03 PM, Boyuan Zhang wrote:
>>>>>>>>> On 2024-10-07 01:22, Lazar, Lijo wrote:
>>>>>>>>>> On 10/5/2024 12:14 AM, boyuan.zhang@amd.com wrote:
>>>>>>>>>>> From: Boyuan Zhang <boyuan.zhang@amd.com>
>>>>>>>>>>>
>>>>>>>>>>> For vcn 2_5, add ip_block for each vcn instance during
>>>>>>>>>>> discovery stage.
>>>>>>>>>>>
>>>>>>>>>>> And only powering on/off one of the vcn instance using the
>>>>>>>>>>> instance value stored in ip_block, instead of powering on/off
>>>>>>>>>>> all
>>>>>>>>>>> vcn instances. Modify the existing functions to use the
>>>>>>>>>>> instance value
>>>>>>>>>>> in ip_block, and remove the original for loop for all vcn
>>>>>>>>>>> instances.
>>>>>>>>>>>
>>>>>>>>>>> v2: rename "i"/"j" to "inst" for instance value.
>>>>>>>>>>>
>>>>>>>>>>> Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com>
>>>>>>>>>>> ---
>>>>>>>>>>>     drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c |   4 +-
>>>>>>>>>>>     drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c         | 565
>>>>>>>>>>> +++++++++---------
>>>>>>>>>>>     2 files changed, 280 insertions(+), 289 deletions(-)
>>>>>>>>>>>
>>>>>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>>>>> index 9f9a1867da72..de1053cc2a2b 100644
>>>>>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
>>>>>>>>>>> @@ -2278,6 +2278,7 @@ static int
>>>>>>>>>>> amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
>>>>>>>>>>>       static int amdgpu_discovery_set_mm_ip_blocks(struct
>>>>>>>>>>> amdgpu_device
>>>>>>>>>>> *adev)
>>>>>>>>>>>     {
>>>>>>>>>>> +    int i;
>>>>>>>>>>>         if (amdgpu_ip_version(adev, VCE_HWIP, 0)) {
>>>>>>>>>>>             switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) {
>>>>>>>>>>>             case IP_VERSION(7, 0, 0):
>>>>>>>>>>> @@ -2321,7 +2322,8 @@ static int
>>>>>>>>>>> amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
>>>>>>>>>>>             case IP_VERSION(2, 0, 3):
>>>>>>>>>>>                 break;
>>>>>>>>>>>             case IP_VERSION(2, 5, 0):
>>>>>>>>>>> -            amdgpu_device_ip_block_add(adev,
>>>>>>>>>>> &vcn_v2_5_ip_block);
>>>>>>>>>>> +            for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
>>>>>>>>>>> +                amdgpu_device_ip_block_add(adev,
>>>>>>>>>>> &vcn_v2_5_ip_block);
>>>>>>>>>> This introduces a totally confusing design now. At a higher
>>>>>>>>>> level an IP
>>>>>>>>>> block type manages multiple instances and their power states.
>>>>>>>>>> Now there
>>>>>>>>>> is a mix where no definition can be attributed to an IP block.
>>>>>>>>>> Or, if
>>>>>>>>>> this were to be done uniformly for other IPs, then for some SOCs
>>>>>>>>>> there
>>>>>>>>>> could be 16 SDMA blocks, 8 GFX blocks and so forth.
>>>>>>>>>>
>>>>>>>>>> What is the reason to do this way? Can't VCN IP block maintain
>>>>>>>>>> the state
>>>>>>>>>> of multiple instances within itself?
>>>>>>>>>>
>>>>>>>>>> Thanks,
>>>>>>>>>> Lijo
>>>>>>>>> This is part of the fundamental design change for separating IP
>>>>>>>>> block
>>>>>>>>> per instance, in order to
>>>>>>>>> handle each instance separately within same IP block (e.g.
>>>>>>>>> separate
>>>>>>>>> power/clock management).
>>>>>>>>>
>>>>>>>>> Part 1, Change all adev ptr handle to amdgpu_ip_block ptr in all
>>>>>>>>> callbacks (hw_init/fini, sw_init/fini,
>>>>>>>>> suspend, etc...) for all IP blocks, so that each IP knows which
>>>>>>>>> IP_block
>>>>>>>>> (and which instance) the
>>>>>>>>> callback is for. Most parts of this changes have been submitted
>>>>>>>>> by Sunil.
>>>>>>>>>
>>>>>>>>> Part 2, Separate IP block per instance.
>>>>>>>>>
>>>>>>>>> Part 3, Since callbacks can pass in IP_block now after Part 1
>>>>>>>>> change and
>>>>>>>>> instance value can be
>>>>>>>>> obtained from each IP block in Part 2, IP can then choose to
>>>>>>>>> handle
>>>>>>>>> callbacks ONLY for the given
>>>>>>>>> instance of a given IP block (or still handling for all
>>>>>>>>> instances as
>>>>>>>>> before).
>>>>>>>>> For VCN, all callbacks will be handled only for the given one
>>>>>>>>> instance,
>>>>>>>>> instead of the original for-
>>>>>>>>> loop for all instance. As a result, each VCN instance can be
>>>>>>>>> start/stop/int/fini/suspend separately.
>>>>>>>>>
>>>>>>>>> Part 4, Change all VCN helper functions to handle only the given
>>>>>>>>> instance, instead of the original
>>>>>>>>> for-loop for all instance.
>>>>>>>>>
>>>>>>>>> Each instance can have its own states, so we think it makes more
>>>>>>>>> sense
>>>>>>>>> to separate them on IP
>>>>>>>>> block level to handle each of them separately.
>>>>>>>> Such a change should not be done unless all IPs follow the same
>>>>>>>> design.
>>>>>>>> You didn't answer the question - what necessitates this change?
>>>>>>>> What is
>>>>>>>> special about VCN that it cannot manage the states of multiple
>>>>>>>> instances
>>>>>>>> within the IP block?
>>>>>>> We want to be able to manage the powergating independently for each
>>>>>>> VCN instance for both power management and VCN reset.  Right now
>>>>>>> power
>>>>>>> gating is handled at the IP level so it's not easy or clean to
>>>>>>> handle
>>>>>>> powergating of individual IP instances.
>>>>>>>
>>>>>> Still VCN block can manage the powergated instances (FWIW, it's
>>>>>> just an
>>>>>> array in SMU block). Also vcn block gets to run the idle worker and
>>>>>> knows the rings (and corresponding VCN instances) that are idle.
>>>>>> Maintaining instance states in VCN block and modifying idle worker to
>>>>>> just idle that instance alone doesn't look like a complex change.
>>>>> We already went down that road and it's really ugly.  We end up
>>>>> duplicating a bunch of code paths for different driver flows because
>>>>> set_powergating_state() and set_clockgating_state are at the IP level
>>>>> and we want per instance gating.  We could add a num_instances member
>>>>> at the IP block level and then convert all of the high level code that
>>>>> calls the IP functions loop over the number of instances, but that
>>>>> seems like just as much work and it's not quite as clean IMHO.
>>>>>
>>>> Sorry, I'm not seeing much difference in this design. All it does is
>>>> just split instances to IP block at the same time it's going to keep an
>>>> instance parameter in IP block APIs.
>>>>
>>>>      amdgpu_device_ip_set_clockgating_state(blocktype, instance);
>>>>      amdgpu_device_ip_set_powergating_state(blocktype, instance);
>>>>
>>>> Also, VCN continues to maintain an array of amdgpu_vcn_inst. I think
>>>> it's easier manage this with changes to amdgpu_vcn_inst. Since it is
>>>> continued to be maintained, what about just moving the states and
>>>> idle_work inside amdgpu_vcn_inst.
>>>>           int inst;
>>>>      enum amd_powergating_state cur_pg_state;
>>>>      enum amd_clockgating_state state cur_cg_state;
>>>>      struct delayed_work     idle_work;
>>>>
>>>> At the end of ring usage of corresponding instance, just invoke the
>>>> corresponding instance's idle work.
>>>>
>>>> schedule_delayed_work(&ring->adev->vcn.inst[ring->me].idle_work,
>>>> idle_time_out);
>>> First of all, separating idle work and state is still needed in current
>>> design.
>>> Separating idle work by instance is already handled in patch 17/18.
>>> Separating power gating state is already handled in patch 10/18.
>>>
>>> I agree that "adding instance variable" in amdgpu_vcn_inst requires
>>> much less effort, but as mentioned by Alex previously, we already
>>> went down that way to use "inst" variable in amdgou_vcn_inst as you
>>> listed above and track this instance value all the way from VCN to SMU.
>>> However, this is a no-go based on discussions with Christian and Alex.
>>> Since set_powergating_state() is at IP level, it will be clean to do
>>> per instance gating at IP level. With the change of passing ip_block to
>>> callback functions, all ip functions can now choose to handle only the
>>> given instance, which is a clean separation between multiple instance.
>>>
>> I don't agree.
>>
>> There is no clean separation here. What I see here is a mix where ip
>> block still remains a dummy.
>>
>>     ipblock->inst => calls vcn.vcn_inst[i] that maintains the final
>> state.
>>
>> If the design is based only on ip block, you wouldn't have required to
>> maintain another vcn_inst. Everything would have been handled by
>> maintaining state in ip block itself.
> The change is to separate IP blocks, not amdgpu_device. Different
> IP blocks still share the same adev. vcn_inst is handled within adev.

That is the basic flaw in this design. All that is done is to take out
the for loop, instance state etc. are all maintained in vcn_inst.
Another thing is - there is no need to check for harvested instance if
ip block is per instance basis. You simply don't need to add a block for
harvested instance. Those are a few things done hastily in this series.

Basically, if someone wants to look this as an example code to develop a
per instance based IP block, this is not the right candidate.

Regardless, of that I think this is not required. All that is required
is to maintain the state of IP instance, and this is not the only way.
If vcn_inst is continued to be maintained, all that is done here can be
achieved using that itself.

>>>> I don't see any change in this series for other IP block APIs.
>>> Yes, currently we only do this per instance IP block for VCN. For long
>>> term,
>>> the plan is to change all other IP with multiple blocks into this
>>> design.
>>>
>> This path itself is not a viable solution. We will have cases where a
>> group of ip blocks of the same type need to be handled together. At that
>> point you will need another central controller for ip blocks belonging
>> to a type. That will evenutally lead to another superblock being created.
> Handling each IP block at IP level is the purpose of this change.
> With similar changes as VCN, other IP types can still choose to
> handle a group of IP blocks with same type, there is no need to
> create a superblock.
> 

This is based on your assumption that each IP block instance is
independent. As a hypothetical example, you may expect a case where
ucodes should be loaded to all IP block instances (let's say through
backdoor mechanism) before any one of the instances can be used because
there could be a handshake between Fw instances running. When you run
hw_init at a per-instance/per block basis, that breaks. You could run
into other situations where there could be some handshake between
instances of the same type. IP block currently can act as that super
block managing multiple instances.

Thanks,
Lijo

> Thanks,
> Boyuan
>>
>> Thanks,
>> Lijo
>>
>>> Regards,
>>> Boyuan
>>>
>>>
>>>> Thanks,
>>>> Lijo
>>>>
>>>>> Alex
>>>>>
>>>>>> Moving to IP block per instance for VCN alone is not a change that
>>>>>> helps
>>>>>> to define an IP block. If that needs to be done for every other IP
>>>>>> type,
>>>>>> that's also a massive change.
>>>>>>
>>>>>> Also, then it's no longer possible to have something static like
>>>>>> this -
>>>>>>           struct amdgpu_ip_block         
>>>>>> ip_blocks[AMDGPU_MAX_IP_NUM];
>>>>>>
>>>>>>
>>>>>> Thanks,
>>>>>> Lijo
>>>>>>
>>>>>>> Alex
>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Lijo
>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Boyuan
>>>>>>>>>>>                 amdgpu_device_ip_block_add(adev,
>>>>>>>>>>> &jpeg_v2_5_ip_block);
>>>>>>>>>>>                 break;
>>>>>>>>>>>             case IP_VERSION(2, 6, 0):
>>>>>>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>>>>> b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>>>>> index d00df51bc400..1f8738ae360a 100644
>>>>>>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
>>>>>>>>>>> @@ -158,35 +158,34 @@ static int vcn_v2_5_early_init(struct
>>>>>>>>>>> amdgpu_ip_block *ip_block)
>>>>>>>>>>>     static int vcn_v2_5_sw_init(struct amdgpu_ip_block
>>>>>>>>>>> *ip_block)
>>>>>>>>>>>     {
>>>>>>>>>>>         struct amdgpu_ring *ring;
>>>>>>>>>>> -    int i, j, r;
>>>>>>>>>>> +    int i, r;
>>>>>>>>>>>         uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5);
>>>>>>>>>>>         uint32_t *ptr;
>>>>>>>>>>>         struct amdgpu_device *adev = ip_block->adev;
>>>>>>>>>>> +    int inst = ip_block->instance;
>>>>>>>>>>>     -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << j))
>>>>>>>>>>> -            continue;
>>>>>>>>>>> -        /* VCN DEC TRAP */
>>>>>>>>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>>>>>>>> -                VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>>>>>>>>>> &adev->vcn.inst[j].irq);
>>>>>>>>>>> -        if (r)
>>>>>>>>>>> -            return r;
>>>>>>>>>>> -
>>>>>>>>>>> -        /* VCN ENC TRAP */
>>>>>>>>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>>>>> -            r = amdgpu_irq_add_id(adev,
>>>>>>>>>>> amdgpu_ih_clientid_vcns[j],
>>>>>>>>>>> -                i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>>>>>>>>>> &adev->vcn.inst[j].irq);
>>>>>>>>>>> -            if (r)
>>>>>>>>>>> -                return r;
>>>>>>>>>>> -        }
>>>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>>>> +        goto sw_init;
>>>>>>>>>>> +    /* VCN DEC TRAP */
>>>>>>>>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>>>>>>>> +            VCN_2_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT,
>>>>>>>>>>> &adev->vcn.inst[inst].irq);
>>>>>>>>>>> +    if (r)
>>>>>>>>>>> +        return r;
>>>>>>>>>>>     -        /* VCN POISON TRAP */
>>>>>>>>>>> -        r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
>>>>>>>>>>> -            VCN_2_6__SRCID_UVD_POISON,
>>>>>>>>>>> &adev->vcn.inst[j].ras_poison_irq);
>>>>>>>>>>> +    /* VCN ENC TRAP */
>>>>>>>>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>>>>> +        r = amdgpu_irq_add_id(adev,
>>>>>>>>>>> amdgpu_ih_clientid_vcns[inst],
>>>>>>>>>>> +            i + VCN_2_0__SRCID__UVD_ENC_GENERAL_PURPOSE,
>>>>>>>>>>> &adev->vcn.inst[inst].irq);
>>>>>>>>>>>             if (r)
>>>>>>>>>>>                 return r;
>>>>>>>>>>>         }
>>>>>>>>>>>     +    /* VCN POISON TRAP */
>>>>>>>>>>> +    r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[inst],
>>>>>>>>>>> +        VCN_2_6__SRCID_UVD_POISON,
>>>>>>>>>>> &adev->vcn.inst[inst].ras_poison_irq);
>>>>>>>>>>> +    if (r)
>>>>>>>>>>> +        return r;
>>>>>>>>>>> +sw_init:
>>>>>>>>>>>         r = amdgpu_vcn_sw_init(adev);
>>>>>>>>>>>         if (r)
>>>>>>>>>>>             return r;
>>>>>>>>>>> @@ -197,76 +196,74 @@ static int vcn_v2_5_sw_init(struct
>>>>>>>>>>> amdgpu_ip_block *ip_block)
>>>>>>>>>>>         if (r)
>>>>>>>>>>>             return r;
>>>>>>>>>>>     -    for (j = 0; j < adev->vcn.num_vcn_inst; j++) {
>>>>>>>>>>> -        volatile struct amdgpu_fw_shared *fw_shared;
>>>>>>>>>>> +    volatile struct amdgpu_fw_shared *fw_shared;
>>>>>>>>>>>     -        if (adev->vcn.harvest_config & (1 << j))
>>>>>>>>>>> -            continue;
>>>>>>>>>>> -        adev->vcn.internal.context_id =
>>>>>>>>>>> mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>>>>>>>>>> -        adev->vcn.internal.ib_vmid =
>>>>>>>>>>> mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>>>>>>>>>> -        adev->vcn.internal.ib_bar_low =
>>>>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>>>>>>>>>> -        adev->vcn.internal.ib_bar_high =
>>>>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>>>>>>>>>> -        adev->vcn.internal.ib_size =
>>>>>>>>>>> mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>>>>>>>>>> -        adev->vcn.internal.gp_scratch8 =
>>>>>>>>>>> mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>>>>>>>>>> -
>>>>>>>>>>> -        adev->vcn.internal.scratch9 =
>>>>>>>>>>> mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>>>>>>>>>> -        adev->vcn.inst[j].external.scratch9 =
>>>>>>>>>>> SOC15_REG_OFFSET(VCN,
>>>>>>>>>>> j, mmUVD_SCRATCH9);
>>>>>>>>>>> -        adev->vcn.internal.data0 =
>>>>>>>>>>> mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>>>>>>>>>> -        adev->vcn.inst[j].external.data0 =
>>>>>>>>>>> SOC15_REG_OFFSET(VCN, j,
>>>>>>>>>>> mmUVD_GPCOM_VCPU_DATA0);
>>>>>>>>>>> -        adev->vcn.internal.data1 =
>>>>>>>>>>> mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>>>>>>>>>> -        adev->vcn.inst[j].external.data1 =
>>>>>>>>>>> SOC15_REG_OFFSET(VCN, j,
>>>>>>>>>>> mmUVD_GPCOM_VCPU_DATA1);
>>>>>>>>>>> -        adev->vcn.internal.cmd =
>>>>>>>>>>> mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>>>>>>>>>> -        adev->vcn.inst[j].external.cmd =
>>>>>>>>>>> SOC15_REG_OFFSET(VCN, j,
>>>>>>>>>>> mmUVD_GPCOM_VCPU_CMD);
>>>>>>>>>>> -        adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>>>>>>>>>> -        adev->vcn.inst[j].external.nop =
>>>>>>>>>>> SOC15_REG_OFFSET(VCN, j,
>>>>>>>>>>> mmUVD_NO_OP);
>>>>>>>>>>> -
>>>>>>>>>>> -        ring = &adev->vcn.inst[j].ring_dec;
>>>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>>>> +        goto done;
>>>>>>>>>>> +    adev->vcn.internal.context_id =
>>>>>>>>>>> mmUVD_CONTEXT_ID_INTERNAL_OFFSET;
>>>>>>>>>>> +    adev->vcn.internal.ib_vmid =
>>>>>>>>>>> mmUVD_LMI_RBC_IB_VMID_INTERNAL_OFFSET;
>>>>>>>>>>> +    adev->vcn.internal.ib_bar_low =
>>>>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_LOW_INTERNAL_OFFSET;
>>>>>>>>>>> +    adev->vcn.internal.ib_bar_high =
>>>>>>>>>>> mmUVD_LMI_RBC_IB_64BIT_BAR_HIGH_INTERNAL_OFFSET;
>>>>>>>>>>> +    adev->vcn.internal.ib_size =
>>>>>>>>>>> mmUVD_RBC_IB_SIZE_INTERNAL_OFFSET;
>>>>>>>>>>> +    adev->vcn.internal.gp_scratch8 =
>>>>>>>>>>> mmUVD_GP_SCRATCH8_INTERNAL_OFFSET;
>>>>>>>>>>> +
>>>>>>>>>>> +    adev->vcn.internal.scratch9 =
>>>>>>>>>>> mmUVD_SCRATCH9_INTERNAL_OFFSET;
>>>>>>>>>>> +    adev->vcn.inst[inst].external.scratch9 =
>>>>>>>>>>> SOC15_REG_OFFSET(VCN,
>>>>>>>>>>> inst, mmUVD_SCRATCH9);
>>>>>>>>>>> +    adev->vcn.internal.data0 =
>>>>>>>>>>> mmUVD_GPCOM_VCPU_DATA0_INTERNAL_OFFSET;
>>>>>>>>>>> +    adev->vcn.inst[inst].external.data0 = SOC15_REG_OFFSET(VCN,
>>>>>>>>>>> inst, mmUVD_GPCOM_VCPU_DATA0);
>>>>>>>>>>> +    adev->vcn.internal.data1 =
>>>>>>>>>>> mmUVD_GPCOM_VCPU_DATA1_INTERNAL_OFFSET;
>>>>>>>>>>> +    adev->vcn.inst[inst].external.data1 = SOC15_REG_OFFSET(VCN,
>>>>>>>>>>> inst, mmUVD_GPCOM_VCPU_DATA1);
>>>>>>>>>>> +    adev->vcn.internal.cmd =
>>>>>>>>>>> mmUVD_GPCOM_VCPU_CMD_INTERNAL_OFFSET;
>>>>>>>>>>> +    adev->vcn.inst[inst].external.cmd = SOC15_REG_OFFSET(VCN,
>>>>>>>>>>> inst,
>>>>>>>>>>> mmUVD_GPCOM_VCPU_CMD);
>>>>>>>>>>> +    adev->vcn.internal.nop = mmUVD_NO_OP_INTERNAL_OFFSET;
>>>>>>>>>>> +    adev->vcn.inst[inst].external.nop = SOC15_REG_OFFSET(VCN,
>>>>>>>>>>> inst,
>>>>>>>>>>> mmUVD_NO_OP);
>>>>>>>>>>> +
>>>>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>>>>>>>>>> +    ring->use_doorbell = true;
>>>>>>>>>>> +
>>>>>>>>>>> +    ring->doorbell_index =
>>>>>>>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 <<
>>>>>>>>>>> 1) +
>>>>>>>>>>> +            (amdgpu_sriov_vf(adev) ? 2*inst : 8*inst);
>>>>>>>>>>> +
>>>>>>>>>>> +    if (amdgpu_ip_version(adev, UVD_HWIP, 0) == IP_VERSION(2,
>>>>>>>>>>> 5, 0))
>>>>>>>>>>> +        ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>>>>>> +    else
>>>>>>>>>>> +        ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>>>>>> +
>>>>>>>>>>> +    sprintf(ring->name, "vcn_dec_%d", inst);
>>>>>>>>>>> +    r = amdgpu_ring_init(adev, ring, 512,
>>>>>>>>>>> &adev->vcn.inst[inst].irq,
>>>>>>>>>>> +                 0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>>>>>>>>>> +    if (r)
>>>>>>>>>>> +        return r;
>>>>>>>>>>> +
>>>>>>>>>>> +    for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>>>>> +        enum amdgpu_ring_priority_level hw_prio =
>>>>>>>>>>> amdgpu_vcn_get_enc_ring_prio(i);
>>>>>>>>>>> +
>>>>>>>>>>> +        ring = &adev->vcn.inst[inst].ring_enc[i];
>>>>>>>>>>>             ring->use_doorbell = true;
>>>>>>>>>>>               ring->doorbell_index =
>>>>>>>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>>>>>>>>>> -                (amdgpu_sriov_vf(adev) ? 2*j : 8*j);
>>>>>>>>>>> +                (amdgpu_sriov_vf(adev) ? (1 + i + 2*inst) : (2
>>>>>>>>>>> + i +
>>>>>>>>>>> 8*inst));
>>>>>>>>>>>     -        if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>>>>>>>> IP_VERSION(2,
>>>>>>>>>>> 5, 0))
>>>>>>>>>>> +        if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>>>>>>>> +            IP_VERSION(2, 5, 0))
>>>>>>>>>>>                 ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>>>>>>             else
>>>>>>>>>>>                 ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>>>>>>     -        sprintf(ring->name, "vcn_dec_%d", j);
>>>>>>>>>>> -        r = amdgpu_ring_init(adev, ring, 512,
>>>>>>>>>>> &adev->vcn.inst[j].irq,
>>>>>>>>>>> -                     0, AMDGPU_RING_PRIO_DEFAULT, NULL);
>>>>>>>>>>> +        sprintf(ring->name, "vcn_enc_%d.%d", inst, i);
>>>>>>>>>>> +        r = amdgpu_ring_init(adev, ring, 512,
>>>>>>>>>>> +                     &adev->vcn.inst[inst].irq, 0,
>>>>>>>>>>> +                     hw_prio, NULL);
>>>>>>>>>>>             if (r)
>>>>>>>>>>>                 return r;
>>>>>>>>>>> -
>>>>>>>>>>> -        for (i = 0; i < adev->vcn.num_enc_rings; ++i) {
>>>>>>>>>>> -            enum amdgpu_ring_priority_level hw_prio =
>>>>>>>>>>> amdgpu_vcn_get_enc_ring_prio(i);
>>>>>>>>>>> -
>>>>>>>>>>> -            ring = &adev->vcn.inst[j].ring_enc[i];
>>>>>>>>>>> -            ring->use_doorbell = true;
>>>>>>>>>>> -
>>>>>>>>>>> -            ring->doorbell_index =
>>>>>>>>>>> (adev->doorbell_index.vcn.vcn_ring0_1 << 1) +
>>>>>>>>>>> -                    (amdgpu_sriov_vf(adev) ? (1 + i + 2*j) :
>>>>>>>>>>> (2 + i
>>>>>>>>>>> + 8*j));
>>>>>>>>>>> -
>>>>>>>>>>> -            if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==
>>>>>>>>>>> -                IP_VERSION(2, 5, 0))
>>>>>>>>>>> -                ring->vm_hub = AMDGPU_MMHUB1(0);
>>>>>>>>>>> -            else
>>>>>>>>>>> -                ring->vm_hub = AMDGPU_MMHUB0(0);
>>>>>>>>>>> -
>>>>>>>>>>> -            sprintf(ring->name, "vcn_enc_%d.%d", j, i);
>>>>>>>>>>> -            r = amdgpu_ring_init(adev, ring, 512,
>>>>>>>>>>> -                         &adev->vcn.inst[j].irq, 0,
>>>>>>>>>>> -                         hw_prio, NULL);
>>>>>>>>>>> -            if (r)
>>>>>>>>>>> -                return r;
>>>>>>>>>>> -        }
>>>>>>>>>>> -
>>>>>>>>>>> -        fw_shared = adev->vcn.inst[j].fw_shared.cpu_addr;
>>>>>>>>>>> -        fw_shared->present_flag_0 =
>>>>>>>>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>>>>>>>>>> -
>>>>>>>>>>> -        if (amdgpu_vcnfw_log)
>>>>>>>>>>> -            amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>>>>>>>>>         }
>>>>>>>>>>>     +    fw_shared = adev->vcn.inst[inst].fw_shared.cpu_addr;
>>>>>>>>>>> +    fw_shared->present_flag_0 =
>>>>>>>>>>> cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG);
>>>>>>>>>>> +
>>>>>>>>>>> +    if (amdgpu_vcnfw_log)
>>>>>>>>>>> +        amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
>>>>>>>>>>> +done:
>>>>>>>>>>>         if (amdgpu_sriov_vf(adev)) {
>>>>>>>>>>>             r = amdgpu_virt_alloc_mm_table(adev);
>>>>>>>>>>>             if (r)
>>>>>>>>>>> @@ -1005,197 +1002,192 @@ static int
>>>>>>>>>>> vcn_v2_5_start_dpg_mode(struct
>>>>>>>>>>> amdgpu_device *adev, int inst_idx, boo
>>>>>>>>>>>         return 0;
>>>>>>>>>>>     }
>>>>>>>>>>>     -static int vcn_v2_5_start(struct amdgpu_device *adev)
>>>>>>>>>>> +static int vcn_v2_5_start(struct amdgpu_device *adev, unsigned
>>>>>>>>>>> int
>>>>>>>>>>> inst)
>>>>>>>>>>>     {
>>>>>>>>>>>         struct amdgpu_ring *ring;
>>>>>>>>>>>         uint32_t rb_bufsz, tmp;
>>>>>>>>>>> -    int i, j, k, r;
>>>>>>>>>>> +    int j, k, r;
>>>>>>>>>>>     -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>>>> -        if (adev->pm.dpm_enabled)
>>>>>>>>>>> -            amdgpu_dpm_enable_vcn(adev, true, i);
>>>>>>>>>>> -    }
>>>>>>>>>>> -
>>>>>>>>>>> -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>>>>> -            continue;
>>>>>>>>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>>>>> -            r = vcn_v2_5_start_dpg_mode(adev, i,
>>>>>>>>>>> adev->vcn.indirect_sram);
>>>>>>>>>>> -            continue;
>>>>>>>>>>> -        }
>>>>>>>>>>> +    if (adev->pm.dpm_enabled)
>>>>>>>>>>> +        amdgpu_dpm_enable_vcn(adev, true, inst);
>>>>>>>>>>>     -        /* disable register anti-hang mechanism */
>>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i,
>>>>>>>>>>> mmUVD_POWER_STATUS), 0,
>>>>>>>>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>>>> +        return 0;
>>>>>>>>>>>     -        /* set uvd status busy */
>>>>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_STATUS) |
>>>>>>>>>>> UVD_STATUS__UVD_BUSY;
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, tmp);
>>>>>>>>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>>>>> +        r = vcn_v2_5_start_dpg_mode(adev, inst,
>>>>>>>>>>> adev->vcn.indirect_sram);
>>>>>>>>>>> +        return r;
>>>>>>>>>>>         }
>>>>>>>>>>>     +    /* disable register anti-hang mechanism */
>>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst,
>>>>>>>>>>> mmUVD_POWER_STATUS), 0,
>>>>>>>>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>>>>> +
>>>>>>>>>>> +    /* set uvd status busy */
>>>>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_STATUS) |
>>>>>>>>>>> UVD_STATUS__UVD_BUSY;
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, tmp);
>>>>>>>>>>> +
>>>>>>>>>>>         if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG)
>>>>>>>>>>>             return 0;
>>>>>>>>>>>           /*SW clock gating */
>>>>>>>>>>>         vcn_v2_5_disable_clock_gating(adev);
>>>>>>>>>>>     -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>>>>> -            continue;
>>>>>>>>>>> -        /* enable VCPU clock */
>>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>>>>>> -            UVD_VCPU_CNTL__CLK_EN_MASK,
>>>>>>>>>>> ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>>>>>>>>>> -
>>>>>>>>>>> -        /* disable master interrupt */
>>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN), 0,
>>>>>>>>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>>>>> -
>>>>>>>>>>> -        /* setup mmUVD_LMI_CTRL */
>>>>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL);
>>>>>>>>>>> -        tmp &= ~0xff;
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL, tmp | 0x8|
>>>>>>>>>>> -            UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>>>>>>>>>> -            UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>>>>>>>>>> -            UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>>>>>>>>>> -            UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>>>>>>>>>> -
>>>>>>>>>>> -        /* setup mmUVD_MPC_CNTL */
>>>>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_MPC_CNTL);
>>>>>>>>>>> -        tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>>>>>>>>>> -        tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_CNTL, tmp);
>>>>>>>>>>> -
>>>>>>>>>>> -        /* setup UVD_MPC_SET_MUXA0 */
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXA0,
>>>>>>>>>>> -            ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>>>>>>>>>> -            (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>>>>>>>>>> -            (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>>>>>>>>>> -            (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>>>>>>>>>> -
>>>>>>>>>>> -        /* setup UVD_MPC_SET_MUXB0 */
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUXB0,
>>>>>>>>>>> -            ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>>>>>>>>>> -            (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>>>>>>>>>> -            (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>>>>>>>>>> -            (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>>>>>>>>>> -
>>>>>>>>>>> -        /* setup mmUVD_MPC_SET_MUX */
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_MPC_SET_MUX,
>>>>>>>>>>> -            ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>>>>>>>>>> -            (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>>>>>>>>>> -            (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>>>>>>>>> -    }
>>>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>>>> +        return 0;
>>>>>>>>>>> +
>>>>>>>>>>> +    /* enable VCPU clock */
>>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>>>>>> +        UVD_VCPU_CNTL__CLK_EN_MASK,
>>>>>>>>>>> ~UVD_VCPU_CNTL__CLK_EN_MASK);
>>>>>>>>>>> +
>>>>>>>>>>> +    /* disable master interrupt */
>>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN), 0,
>>>>>>>>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>>>>> +
>>>>>>>>>>> +    /* setup mmUVD_LMI_CTRL */
>>>>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL);
>>>>>>>>>>> +    tmp &= ~0xff;
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL, tmp | 0x8|
>>>>>>>>>>> +        UVD_LMI_CTRL__WRITE_CLEAN_TIMER_EN_MASK    |
>>>>>>>>>>> +        UVD_LMI_CTRL__MASK_MC_URGENT_MASK |
>>>>>>>>>>> +        UVD_LMI_CTRL__DATA_COHERENCY_EN_MASK |
>>>>>>>>>>> +        UVD_LMI_CTRL__VCPU_DATA_COHERENCY_EN_MASK);
>>>>>>>>>>> +
>>>>>>>>>>> +    /* setup mmUVD_MPC_CNTL */
>>>>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL);
>>>>>>>>>>> +    tmp &= ~UVD_MPC_CNTL__REPLACEMENT_MODE_MASK;
>>>>>>>>>>> +    tmp |= 0x2 << UVD_MPC_CNTL__REPLACEMENT_MODE__SHIFT;
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_CNTL, tmp);
>>>>>>>>>>> +
>>>>>>>>>>> +    /* setup UVD_MPC_SET_MUXA0 */
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXA0,
>>>>>>>>>>> +        ((0x1 << UVD_MPC_SET_MUXA0__VARA_1__SHIFT) |
>>>>>>>>>>> +        (0x2 << UVD_MPC_SET_MUXA0__VARA_2__SHIFT) |
>>>>>>>>>>> +        (0x3 << UVD_MPC_SET_MUXA0__VARA_3__SHIFT) |
>>>>>>>>>>> +        (0x4 << UVD_MPC_SET_MUXA0__VARA_4__SHIFT)));
>>>>>>>>>>> +
>>>>>>>>>>> +    /* setup UVD_MPC_SET_MUXB0 */
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUXB0,
>>>>>>>>>>> +        ((0x1 << UVD_MPC_SET_MUXB0__VARB_1__SHIFT) |
>>>>>>>>>>> +        (0x2 << UVD_MPC_SET_MUXB0__VARB_2__SHIFT) |
>>>>>>>>>>> +        (0x3 << UVD_MPC_SET_MUXB0__VARB_3__SHIFT) |
>>>>>>>>>>> +        (0x4 << UVD_MPC_SET_MUXB0__VARB_4__SHIFT)));
>>>>>>>>>>> +
>>>>>>>>>>> +    /* setup mmUVD_MPC_SET_MUX */
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_MPC_SET_MUX,
>>>>>>>>>>> +        ((0x0 << UVD_MPC_SET_MUX__SET_0__SHIFT) |
>>>>>>>>>>> +        (0x1 << UVD_MPC_SET_MUX__SET_1__SHIFT) |
>>>>>>>>>>> +        (0x2 << UVD_MPC_SET_MUX__SET_2__SHIFT)));
>>>>>>>>>>>           vcn_v2_5_mc_resume(adev);
>>>>>>>>>>>     -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>>>> -        volatile struct amdgpu_fw_shared *fw_shared =
>>>>>>>>>>> adev->vcn.inst[i].fw_shared.cpu_addr;
>>>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>>>>> -            continue;
>>>>>>>>>>> -        /* VCN global tiling registers */
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>>>>> -            adev->gfx.config.gb_addr_config);
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>>>>> -            adev->gfx.config.gb_addr_config);
>>>>>>>>>>> +    volatile struct amdgpu_fw_shared *fw_shared =
>>>>>>>>>>> adev->vcn.inst[inst].fw_shared.cpu_addr;
>>>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>>>> +        return 0;
>>>>>>>>>>> +
>>>>>>>>>>> +    /* VCN global tiling registers */
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>>>>> +        adev->gfx.config.gb_addr_config);
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_GFX8_ADDR_CONFIG,
>>>>>>>>>>> +        adev->gfx.config.gb_addr_config);
>>>>>>>>>>>     -        /* enable LMI MC and UMC channels */
>>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_LMI_CTRL2), 0,
>>>>>>>>>>> -            ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>>>>>>>>> +    /* enable LMI MC and UMC channels */
>>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_LMI_CTRL2), 0,
>>>>>>>>>>> +        ~UVD_LMI_CTRL2__STALL_ARB_UMC_MASK);
>>>>>>>>>>>     -        /* unblock VCPU register access */
>>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i,
>>>>>>>>>>> mmUVD_RB_ARB_CTRL), 0,
>>>>>>>>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>>>>> +    /* unblock VCPU register access */
>>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL), 0,
>>>>>>>>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>>>>>     -        WREG32_P(SOC15_REG_OFFSET(VCN, i,
>>>>>>>>>>> mmUVD_VCPU_CNTL), 0,
>>>>>>>>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>>>>>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>>>     -        for (k = 0; k < 10; ++k) {
>>>>>>>>>>> -            uint32_t status;
>>>>>>>>>>> -
>>>>>>>>>>> -            for (j = 0; j < 100; ++j) {
>>>>>>>>>>> -                status = RREG32_SOC15(VCN, i, mmUVD_STATUS);
>>>>>>>>>>> -                if (status & 2)
>>>>>>>>>>> -                    break;
>>>>>>>>>>> -                if (amdgpu_emu_mode == 1)
>>>>>>>>>>> -                    msleep(500);
>>>>>>>>>>> -                else
>>>>>>>>>>> -                    mdelay(10);
>>>>>>>>>>> -            }
>>>>>>>>>>> -            r = 0;
>>>>>>>>>>> +    for (k = 0; k < 10; ++k) {
>>>>>>>>>>> +        uint32_t status;
>>>>>>>>>>> +
>>>>>>>>>>> +        for (j = 0; j < 100; ++j) {
>>>>>>>>>>> +            status = RREG32_SOC15(VCN, inst, mmUVD_STATUS);
>>>>>>>>>>>                 if (status & 2)
>>>>>>>>>>>                     break;
>>>>>>>>>>> +            if (amdgpu_emu_mode == 1)
>>>>>>>>>>> +                msleep(500);
>>>>>>>>>>> +            else
>>>>>>>>>>> +        ��       mdelay(10);
>>>>>>>>>>> +        }
>>>>>>>>>>> +        r = 0;
>>>>>>>>>>> +        if (status & 2)
>>>>>>>>>>> +            break;
>>>>>>>>>>>     -            DRM_ERROR("VCN decode not responding, trying to
>>>>>>>>>>> reset
>>>>>>>>>>> the VCPU!!!\n");
>>>>>>>>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>>>>>> -                UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>>> -            mdelay(10);
>>>>>>>>>>> -            WREG32_P(SOC15_REG_OFFSET(VCN, i,
>>>>>>>>>>> mmUVD_VCPU_CNTL), 0,
>>>>>>>>>>> -                ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>>> +        DRM_ERROR("VCN decode not responding, trying to
>>>>>>>>>>> reset the
>>>>>>>>>>> VCPU!!!\n");
>>>>>>>>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>>>>>> +            UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>>> +        mdelay(10);
>>>>>>>>>>> +        WREG32_P(SOC15_REG_OFFSET(VCN, inst,
>>>>>>>>>>> mmUVD_VCPU_CNTL), 0,
>>>>>>>>>>> +            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>>>     -            mdelay(10);
>>>>>>>>>>> -            r = -1;
>>>>>>>>>>> -        }
>>>>>>>>>>> +        mdelay(10);
>>>>>>>>>>> +        r = -1;
>>>>>>>>>>> +    }
>>>>>>>>>>>     -        if (r) {
>>>>>>>>>>> -            DRM_ERROR("VCN decode not responding, giving
>>>>>>>>>>> up!!!\n");
>>>>>>>>>>> -            return r;
>>>>>>>>>>> -        }
>>>>>>>>>>> +    if (r) {
>>>>>>>>>>> +        DRM_ERROR("VCN decode not responding, giving up!!!\n");
>>>>>>>>>>> +        return r;
>>>>>>>>>>> +    }
>>>>>>>>>>>     -        /* enable master interrupt */
>>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_MASTINT_EN),
>>>>>>>>>>> -            UVD_MASTINT_EN__VCPU_EN_MASK,
>>>>>>>>>>> -            ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>>>>> +    /* enable master interrupt */
>>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_MASTINT_EN),
>>>>>>>>>>> +        UVD_MASTINT_EN__VCPU_EN_MASK,
>>>>>>>>>>> +        ~UVD_MASTINT_EN__VCPU_EN_MASK);
>>>>>>>>>>>     -        /* clear the busy bit of VCN_STATUS */
>>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS), 0,
>>>>>>>>>>> -            ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>>>>>>>>> +    /* clear the busy bit of VCN_STATUS */
>>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_STATUS), 0,
>>>>>>>>>>> +        ~(2 << UVD_STATUS__VCPU_REPORT__SHIFT));
>>>>>>>>>>>     -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_VMID, 0);
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_VMID, 0);
>>>>>>>>>>>     -        ring = &adev->vcn.inst[i].ring_dec;
>>>>>>>>>>> -        /* force RBC into idle state */
>>>>>>>>>>> -        rb_bufsz = order_base_2(ring->ring_size);
>>>>>>>>>>> -        tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ,
>>>>>>>>>>> rb_bufsz);
>>>>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>>>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH,
>>>>>>>>>>> 1);
>>>>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL,
>>>>>>>>>>> RB_NO_UPDATE, 1);
>>>>>>>>>>> -        tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL,
>>>>>>>>>>> RB_RPTR_WR_EN, 1);
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_CNTL, tmp);
>>>>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_dec;
>>>>>>>>>>> +    /* force RBC into idle state */
>>>>>>>>>>> +    rb_bufsz = order_base_2(ring->ring_size);
>>>>>>>>>>> +    tmp = REG_SET_FIELD(0, UVD_RBC_RB_CNTL, RB_BUFSZ,
>>>>>>>>>>> rb_bufsz);
>>>>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1);
>>>>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1);
>>>>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1);
>>>>>>>>>>> +    tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN,
>>>>>>>>>>> 1);
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_CNTL, tmp);
>>>>>>>>>>>     -        fw_shared->multi_queue.decode_queue_mode |=
>>>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>>>> -        /* program the RB_BASE for ring buffer */
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>>>>>>>>>> -            lower_32_bits(ring->gpu_addr));
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>>>>>>>>>> -            upper_32_bits(ring->gpu_addr));
>>>>>>>>>>> +    fw_shared->multi_queue.decode_queue_mode |=
>>>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>>>> +    /* program the RB_BASE for ring buffer */
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_LOW,
>>>>>>>>>>> +        lower_32_bits(ring->gpu_addr));
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH,
>>>>>>>>>>> +        upper_32_bits(ring->gpu_addr));
>>>>>>>>>>>     -        /* Initialize the ring buffer's read and write
>>>>>>>>>>> pointers */
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_RPTR, 0);
>>>>>>>>>>> +    /* Initialize the ring buffer's read and write pointers */
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR, 0);
>>>>>>>>>>>     -        ring->wptr = RREG32_SOC15(VCN, i,
>>>>>>>>>>> mmUVD_RBC_RB_RPTR);
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RBC_RB_WPTR,
>>>>>>>>>>> -                lower_32_bits(ring->wptr));
>>>>>>>>>>> -        fw_shared->multi_queue.decode_queue_mode &=
>>>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>>>> +    ring->wptr = RREG32_SOC15(VCN, inst, mmUVD_RBC_RB_RPTR);
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RBC_RB_WPTR,
>>>>>>>>>>> +            lower_32_bits(ring->wptr));
>>>>>>>>>>> +    fw_shared->multi_queue.decode_queue_mode &=
>>>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>>>>     -
>>>>>>>>>>> fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>>>> -        ring = &adev->vcn.inst[i].ring_enc[0];
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR,
>>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR,
>>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI,
>>>>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE, ring->ring_size
>>>>>>>>>>> / 4);
>>>>>>>>>>> -
>>>>>>>>>>> fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>>>> -
>>>>>>>>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>>>> -        ring = &adev->vcn.inst[i].ring_enc[1];
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_RPTR2,
>>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_WPTR2,
>>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_LO2,
>>>>>>>>>>> ring->gpu_addr);
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_BASE_HI2,
>>>>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size /
>>>>>>>>>>> 4);
>>>>>>>>>>> -        fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>>>> -    }
>>>>>>>>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode |=
>>>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_enc[0];
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR,
>>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR,
>>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO, ring->gpu_addr);
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI,
>>>>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE, ring->ring_size /
>>>>>>>>>>> 4);
>>>>>>>>>>> +    fw_shared->multi_queue.encode_generalpurpose_queue_mode &=
>>>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>>>> +
>>>>>>>>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode |=
>>>>>>>>>>> FW_QUEUE_RING_RESET;
>>>>>>>>>>> +    ring = &adev->vcn.inst[inst].ring_enc[1];
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_RPTR2,
>>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_WPTR2,
>>>>>>>>>>> lower_32_bits(ring->wptr));
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_LO2, ring->gpu_addr);
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_BASE_HI2,
>>>>>>>>>>> upper_32_bits(ring->gpu_addr));
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_RB_SIZE2, ring->ring_size
>>>>>>>>>>> / 4);
>>>>>>>>>>> +    fw_shared->multi_queue.encode_lowlatency_queue_mode &=
>>>>>>>>>>> ~FW_QUEUE_RING_RESET;
>>>>>>>>>>>           return 0;
>>>>>>>>>>>     }
>>>>>>>>>>> @@ -1424,72 +1416,69 @@ static int vcn_v2_5_stop_dpg_mode(struct
>>>>>>>>>>> amdgpu_device *adev, int inst_idx)
>>>>>>>>>>>         return 0;
>>>>>>>>>>>     }
>>>>>>>>>>>     -static int vcn_v2_5_stop(struct amdgpu_device *adev)
>>>>>>>>>>> +static int vcn_v2_5_stop(struct amdgpu_device *adev, unsigned
>>>>>>>>>>> int inst)
>>>>>>>>>>>     {
>>>>>>>>>>>         uint32_t tmp;
>>>>>>>>>>> -    int i, r = 0;
>>>>>>>>>>> +    int r = 0;
>>>>>>>>>>>     -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>>>> -        if (adev->vcn.harvest_config & (1 << i))
>>>>>>>>>>> -            continue;
>>>>>>>>>>> -        if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>>>>> -            r = vcn_v2_5_stop_dpg_mode(adev, i);
>>>>>>>>>>> -            continue;
>>>>>>>>>>> -        }
>>>>>>>>>>> +    if (adev->vcn.harvest_config & (1 << inst))
>>>>>>>>>>> +        goto done;
>>>>>>>>>>>     -        /* wait for vcn idle */
>>>>>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_STATUS,
>>>>>>>>>>> UVD_STATUS__IDLE, 0x7);
>>>>>>>>>>> -        if (r)
>>>>>>>>>>> -            return r;
>>>>>>>>>>> +    if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) {
>>>>>>>>>>> +        r = vcn_v2_5_stop_dpg_mode(adev, inst);
>>>>>>>>>>> +        goto done;
>>>>>>>>>>> +    }
>>>>>>>>>>>     -        tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>>>>>>>>>> -            UVD_LMI_STATUS__READ_CLEAN_MASK |
>>>>>>>>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>>>>>>>>>> -            UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>>>>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp,
>>>>>>>>>>> tmp);
>>>>>>>>>>> -        if (r)
>>>>>>>>>>> -            return r;
>>>>>>>>>>> +    /* wait for vcn idle */
>>>>>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_STATUS,
>>>>>>>>>>> UVD_STATUS__IDLE, 0x7);
>>>>>>>>>>> +    if (r)
>>>>>>>>>>> +        return r;
>>>>>>>>>>>     -        /* block LMI UMC channel */
>>>>>>>>>>> -        tmp = RREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2);
>>>>>>>>>>> -        tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_LMI_CTRL2, tmp);
>>>>>>>>>>> +    tmp = UVD_LMI_STATUS__VCPU_LMI_WRITE_CLEAN_MASK |
>>>>>>>>>>> +        UVD_LMI_STATUS__READ_CLEAN_MASK |
>>>>>>>>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_MASK |
>>>>>>>>>>> +        UVD_LMI_STATUS__WRITE_CLEAN_RAW_MASK;
>>>>>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp,
>>>>>>>>>>> tmp);
>>>>>>>>>>> +    if (r)
>>>>>>>>>>> +        return r;
>>>>>>>>>>>     -        tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>>>>>>>>>> -            UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>>>>>>>>>> -        r = SOC15_WAIT_ON_RREG(VCN, i, mmUVD_LMI_STATUS, tmp,
>>>>>>>>>>> tmp);
>>>>>>>>>>> -        if (r)
>>>>>>>>>>> -            return r;
>>>>>>>>>>> +    /* block LMI UMC channel */
>>>>>>>>>>> +    tmp = RREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2);
>>>>>>>>>>> +    tmp |= UVD_LMI_CTRL2__STALL_ARB_UMC_MASK;
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_LMI_CTRL2, tmp);
>>>>>>>>>>>     -        /* block VCPU register access */
>>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_RB_ARB_CTRL),
>>>>>>>>>>> -            UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>>>>>>>>>> -            ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>>>>> +    tmp = UVD_LMI_STATUS__UMC_READ_CLEAN_RAW_MASK|
>>>>>>>>>>> +        UVD_LMI_STATUS__UMC_WRITE_CLEAN_RAW_MASK;
>>>>>>>>>>> +    r = SOC15_WAIT_ON_RREG(VCN, inst, mmUVD_LMI_STATUS, tmp,
>>>>>>>>>>> tmp);
>>>>>>>>>>> +    if (r)
>>>>>>>>>>> +        return r;
>>>>>>>>>>>     -        /* reset VCPU */
>>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL),
>>>>>>>>>>> -            UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>>>>> -            ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>>> +    /* block VCPU register access */
>>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_RB_ARB_CTRL),
>>>>>>>>>>> +        UVD_RB_ARB_CTRL__VCPU_DIS_MASK,
>>>>>>>>>>> +        ~UVD_RB_ARB_CTRL__VCPU_DIS_MASK);
>>>>>>>>>>>     -        /* disable VCPU clock */
>>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_VCPU_CNTL), 0,
>>>>>>>>>>> -            ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>>>>>>>>> +    /* reset VCPU */
>>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL),
>>>>>>>>>>> +        UVD_VCPU_CNTL__BLK_RST_MASK,
>>>>>>>>>>> +        ~UVD_VCPU_CNTL__BLK_RST_MASK);
>>>>>>>>>>>     -        /* clear status */
>>>>>>>>>>> -        WREG32_SOC15(VCN, i, mmUVD_STATUS, 0);
>>>>>>>>>>> +    /* disable VCPU clock */
>>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_VCPU_CNTL), 0,
>>>>>>>>>>> +        ~(UVD_VCPU_CNTL__CLK_EN_MASK));
>>>>>>>>>>>     -        vcn_v2_5_enable_clock_gating(adev);
>>>>>>>>>>> +    /* clear status */
>>>>>>>>>>> +    WREG32_SOC15(VCN, inst, mmUVD_STATUS, 0);
>>>>>>>>>>>     -        /* enable register anti-hang mechanism */
>>>>>>>>>>> -        WREG32_P(SOC15_REG_OFFSET(VCN, i, mmUVD_POWER_STATUS),
>>>>>>>>>>> -            UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>>>>>>>>>> -            ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>>>>> -    }
>>>>>>>>>>> +    vcn_v2_5_enable_clock_gating(adev);
>>>>>>>>>>>     -    for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
>>>>>>>>>>> -        if (adev->pm.dpm_enabled)
>>>>>>>>>>> -            amdgpu_dpm_enable_vcn(adev, false, i);
>>>>>>>>>>> -    }
>>>>>>>>>>> +    /* enable register anti-hang mechanism */
>>>>>>>>>>> +    WREG32_P(SOC15_REG_OFFSET(VCN, inst, mmUVD_POWER_STATUS),
>>>>>>>>>>> +        UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
>>>>>>>>>>> +        ~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
>>>>>>>>>>> +done:
>>>>>>>>>>> +    if (adev->pm.dpm_enabled)
>>>>>>>>>>> +        amdgpu_dpm_enable_vcn(adev, false, inst);
>>>>>>>>>>>           return 0;
>>>>>>>>>>>     }
>>>>>>>>>>> @@ -1838,9 +1827,9 @@ static int
>>>>>>>>>>> vcn_v2_5_set_powergating_state(struct amdgpu_ip_block *ip_block,
>>>>>>>>>>>             return 0;
>>>>>>>>>>>           if (state == AMD_PG_STATE_GATE)
>>>>>>>>>>> -        ret = vcn_v2_5_stop(adev);
>>>>>>>>>>> +        ret = vcn_v2_5_stop(adev, inst);
>>>>>>>>>>>         else
>>>>>>>>>>> -        ret = vcn_v2_5_start(adev);
>>>>>>>>>>> +        ret = vcn_v2_5_start(adev, inst);
>>>>>>>>>>>           if (!ret)
>>>>>>>>>>>             adev->vcn.cur_state[inst] = state;

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2024-10-09 14:07 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-04 18:44 [PATCH 00/18] Separating vcn power management by instance boyuan.zhang
2024-10-04 18:44 ` [PATCH 01/18] drm/amd/pm: add inst to dpm_set_vcn_enable boyuan.zhang
2024-10-04 18:44 ` [PATCH 02/18] drm/amd/pm: power up or down vcn by instance boyuan.zhang
2024-10-04 18:44 ` [PATCH 03/18] drm/amd/pm: add inst to smu_dpm_set_vcn_enable boyuan.zhang
2024-10-04 18:44 ` [PATCH 04/18] drm/amd/pm: add inst to set_powergating_by_smu boyuan.zhang
2024-10-04 19:14   ` Alex Deucher
2024-10-08 22:06     ` Boyuan Zhang
2024-10-04 18:44 ` [PATCH 05/18] drm/amd/pm: add inst to amdgpu_dpm_set_powergating_by_smu boyuan.zhang
2024-10-04 18:44 ` [PATCH 06/18] add inst to amdgpu_dpm_enable_vcn boyuan.zhang
2024-10-04 18:44 ` [PATCH 07/18] drm/amdgpu: pass ip_block in set_powergating_state boyuan.zhang
2024-10-04 18:44 ` [PATCH 08/18] drm/amdgpu: track instances of the same IP block boyuan.zhang
2024-10-04 18:44 ` [PATCH 09/18] drm/amdgpu: add set_powergating_state_instance boyuan.zhang
2024-10-04 19:40   ` Alex Deucher
2024-10-08 22:07     ` Boyuan Zhang
2024-10-04 18:44 ` [PATCH 10/18] drm/amdgpu/vcn: separate gating state by instance boyuan.zhang
2024-10-04 18:44 ` [PATCH 11/18] drm/amdgpu: power vcn 2_5 " boyuan.zhang
2024-10-04 19:52   ` Alex Deucher
2024-10-08 22:10     ` Boyuan Zhang
2024-10-07  5:22   ` Lazar, Lijo
2024-10-07 13:33     ` Boyuan Zhang
2024-10-07 13:50       ` Lazar, Lijo
2024-10-07 14:17         ` Alex Deucher
2024-10-07 14:29           ` Christian König
2024-10-07 14:32           ` Lazar, Lijo
2024-10-07 15:24             ` Alex Deucher
2024-10-08  7:03               ` Lazar, Lijo
2024-10-08 22:04                 ` Boyuan Zhang
2024-10-09  3:43                   ` Lazar, Lijo
2024-10-09 13:36                     ` Boyuan Zhang
2024-10-09 14:07                       ` Lazar, Lijo
2024-10-04 18:44 ` [PATCH 12/18] drm/amdgpu: power vcn 3_0 " boyuan.zhang
2024-10-04 18:44 ` [PATCH 13/18] drm/amdgpu: power vcn 4_0 " boyuan.zhang
2024-10-04 18:44 ` [PATCH 14/18] drm/amdgpu: power vcn 4_0_3 " boyuan.zhang
2024-10-04 18:44 ` [PATCH 15/18] drm/amdgpu: power vcn 4_0_5 " boyuan.zhang
2024-10-04 18:44 ` [PATCH 16/18] drm/amdgpu: power vcn 5_0_0 " boyuan.zhang
2024-10-04 18:44 ` [PATCH 17/18] drm/amdgpu/vcn: separate idle work " boyuan.zhang
2024-10-04 18:44 ` [PATCH 18/18] drm/amdgpu: set powergating state by vcn instance boyuan.zhang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.