]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amdgpu: add doorbell range function for nbio v6_3_2
authorLikun Gao <Likun.Gao@amd.com>
Thu, 13 Mar 2025 06:36:35 +0000 (14:36 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 24 Apr 2026 14:57:02 +0000 (10:57 -0400)
Add doorbell range and ih control related function for
NBIO version 6.3.2.

v2: squash in doorbell range fixes
v3: squash in xcd doorbell fix

Signed-off-by: Likun Gao <Likun.Gao@amd.com>
Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/nbio_v6_3_2.c
drivers/gpu/drm/amd/amdgpu/soc_v1_0.c

index c21e5d2fe83979f9d657ac901d33d0f666210298..5e8f466f23ad37c2533d9279470f584c5135fff4 100644 (file)
@@ -71,6 +71,13 @@ static void nbio_v6_3_2_mc_access_enable(struct amdgpu_device *adev,
                WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_FB_EN, 0);
 }
 
+static void nbio_v6_3_2_init_registers(struct amdgpu_device *adev)
+{
+       WREG32_SOC15(NBIO, 0, regXCD_DOORBELL_FENCE_1,
+               (0xff & ~(adev->gfx.xcc_mask)) <<
+               XCD_DOORBELL_FENCE_1__XCD_0_DOORBELL_DISABLE__SHIFT);
+}
+
 static u32 nbio_v6_3_2_get_memsize(struct amdgpu_device *adev)
 {
        return RREG32_SOC15(NBIO, 0, regRCC_DEV0_EPF0_RCC_CONFIG_MEMSIZE);
@@ -114,6 +121,194 @@ static void nbio_v6_3_2_enable_doorbell_interrupt(struct amdgpu_device *adev,
                              DOORBELL_INTERRUPT_DISABLE, enable ? 0 : 1);
 }
 
+static void nbio_v6_3_2_ih_control(struct amdgpu_device *adev)
+{
+       u32 interrupt_cntl;
+
+       /* setup interrupt control */
+       WREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL2, adev->dummy_page_addr >> 8);
+
+       interrupt_cntl = RREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL);
+       /*
+        * BIF_BX0_INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=0 - dummy read disabled with msi, enabled without msi
+        * BIF_BX0_INTERRUPT_CNTL__IH_DUMMY_RD_OVERRIDE_MASK=1 - dummy read controlled by IH_DUMMY_RD_EN
+        */
+       interrupt_cntl = REG_SET_FIELD(interrupt_cntl, BIF_BX0_INTERRUPT_CNTL,
+                                      IH_DUMMY_RD_OVERRIDE, 0);
+
+       /* BIF_BX0_INTERRUPT_CNTL__IH_REQ_NONSNOOP_EN_MASK=1 if ring is in non-cacheable memory, e.g., vram */
+       interrupt_cntl = REG_SET_FIELD(interrupt_cntl, BIF_BX0_INTERRUPT_CNTL,
+                                      IH_REQ_NONSNOOP_EN, 0);
+
+       WREG32_SOC15(NBIO, 0, regBIF_BX0_INTERRUPT_CNTL, interrupt_cntl);
+}
+
+static void nbio_v6_3_2_ih_doorbell_range(struct amdgpu_device *adev,
+                                         bool use_doorbell, int doorbell_index)
+{
+       u32 ih_doorbell_range = 0;
+       u32 ih_doorbell_range1 = 0;
+
+       if (use_doorbell) {
+               ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range,
+                                                 GDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL,
+                                                 S2A_DOORBELL_PORT1_ENABLE,
+                                                 0x1);
+               ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range,
+                                                 GDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL,
+                                                 S2A_DOORBELL_PORT1_AWID,
+                                                 0x0);
+               ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range,
+                                                 GDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL,
+                                                 S2A_DOORBELL_PORT1_RANGE_OFFSET,
+                                                 doorbell_index);
+               ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range,
+                                                 GDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL,
+                                                 S2A_DOORBELL_PORT1_RANGE_SIZE,
+                                                 8);
+               ih_doorbell_range = REG_SET_FIELD(ih_doorbell_range,
+                                                 GDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL,
+                                                 S2A_DOORBELL_PORT1_AWADDR_31_28_VALUE,
+                                                 0x0);
+               ih_doorbell_range1 = REG_SET_FIELD(ih_doorbell_range1,
+                                                  GDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL1,
+                                                  S2A_DOORBELL_PORT1_TARGET_PORT_TYPE,
+                                                  0x3);
+               ih_doorbell_range1 = REG_SET_FIELD(ih_doorbell_range1,
+                                                  GDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL1,
+                                                  S2A_DOORBELL_PORT1_TARGET_DIEID,
+                                                  0x0);
+               ih_doorbell_range1 = REG_SET_FIELD(ih_doorbell_range1,
+                                                  GDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL1,
+                                                  S2A_DOORBELL_PORT1_TARGET_PORT_ID,
+                                                  0x0);
+       }
+
+       WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL, ih_doorbell_range);
+       WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_1_CTRL1, ih_doorbell_range1);
+}
+
+static void nbio_v6_3_2_gc_doorbell_init(struct amdgpu_device *adev)
+{
+       WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_0_CTRL, 0x30000007);
+       WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_0_CTRL1, 0x3);
+}
+
+static void nbio_v6_3_2_sdma_doorbell_range(struct amdgpu_device *adev,
+                                           int instance, bool use_doorbell,
+                                           int doorbell_index,
+                                           int doorbell_size)
+{
+       if (instance == 0) {
+               u32 doorbell_range = 0;
+               u32 doorbell_range1 = 0;
+
+               if (use_doorbell) {
+                       doorbell_range = REG_SET_FIELD(doorbell_range,
+                                                      GDC_S2A0_S2A_DOORBELL_ENTRY_6_CTRL,
+                                                      S2A_DOORBELL_PORT6_ENABLE,
+                                                      0x1);
+                       doorbell_range = REG_SET_FIELD(doorbell_range,
+                                                      GDC_S2A0_S2A_DOORBELL_ENTRY_6_CTRL,
+                                                      S2A_DOORBELL_PORT6_AWID,
+                                                      0xe);
+                       doorbell_range = REG_SET_FIELD(doorbell_range,
+                                                      GDC_S2A0_S2A_DOORBELL_ENTRY_6_CTRL,
+                                                      S2A_DOORBELL_PORT6_RANGE_OFFSET,
+                                                      doorbell_index);
+                       doorbell_range = REG_SET_FIELD(doorbell_range,
+                                                      GDC_S2A0_S2A_DOORBELL_ENTRY_6_CTRL,
+                                                      S2A_DOORBELL_PORT6_RANGE_SIZE,
+                                                      doorbell_size);
+                       doorbell_range = REG_SET_FIELD(doorbell_range,
+                                                      GDC_S2A0_S2A_DOORBELL_ENTRY_6_CTRL,
+                                                      S2A_DOORBELL_PORT6_AWADDR_31_28_VALUE,
+                                                      0xe);
+                       doorbell_range1 = REG_SET_FIELD(doorbell_range1,
+                                                       GDC_S2A0_S2A_DOORBELL_ENTRY_6_CTRL1,
+                                                       S2A_DOORBELL_PORT6_TARGET_PORT_TYPE,
+                                                       0x3);
+                       doorbell_range1 = REG_SET_FIELD(doorbell_range1,
+                                                       GDC_S2A0_S2A_DOORBELL_ENTRY_6_CTRL1,
+                                                       S2A_DOORBELL_PORT6_TARGET_DIEID,
+                                                       0x0);
+                       doorbell_range1 = REG_SET_FIELD(doorbell_range1,
+                                                       GDC_S2A0_S2A_DOORBELL_ENTRY_6_CTRL1,
+                                                       S2A_DOORBELL_PORT6_TARGET_PORT_ID,
+                                                       0x0);
+               }
+
+               WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_6_CTRL, doorbell_range);
+               WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_6_CTRL1, doorbell_range1);
+       }
+}
+
+static void nbio_v6_3_2_vcn_doorbell_range(struct amdgpu_device *adev,
+                                          bool use_doorbell, int doorbell_index,
+                                          int instance)
+{
+       u32 doorbell_range = 0;
+       u32 doorbell_range1 = 0;
+
+       if (use_doorbell) {
+               doorbell_range = REG_SET_FIELD(doorbell_range,
+                                              GDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL,
+                                              S2A_DOORBELL_PORT2_ENABLE,
+                                              0x1);
+               doorbell_range = REG_SET_FIELD(doorbell_range,
+                                              GDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL,
+                                              S2A_DOORBELL_PORT2_AWID,
+                                              (instance % adev->vcn.num_inst_per_aid) ? 0x7 : 0x4);
+               doorbell_range = REG_SET_FIELD(doorbell_range,
+                                              GDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL,
+                                              S2A_DOORBELL_PORT2_RANGE_OFFSET,
+                                              doorbell_index);
+               doorbell_range = REG_SET_FIELD(doorbell_range,
+                                              GDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL,
+                                              S2A_DOORBELL_PORT2_RANGE_SIZE,
+                                              8);
+               doorbell_range = REG_SET_FIELD(doorbell_range,
+                                              GDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL,
+                                              S2A_DOORBELL_PORT2_AWADDR_31_28_VALUE,
+                                              (instance % adev->vcn.num_inst_per_aid) ? 0x7 : 0x4);
+               doorbell_range1 = REG_SET_FIELD(doorbell_range1,
+                                               GDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL1,
+                                               S2A_DOORBELL_PORT2_TARGET_PORT_TYPE,
+                                               0x3);
+               doorbell_range1 = REG_SET_FIELD(doorbell_range1,
+                                               GDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL1,
+                                               S2A_DOORBELL_PORT2_TARGET_DIEID,
+                                               (instance / adev->vcn.num_inst_per_aid) ? 0x3 : 0x0);
+               doorbell_range1 = REG_SET_FIELD(doorbell_range1,
+                                               GDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL1,
+                                               S2A_DOORBELL_PORT2_TARGET_PORT_ID,
+                                               0x0);
+       }
+
+       switch (instance) {
+       case 0:
+               WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL, doorbell_range);
+               WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_2_CTRL1, doorbell_range1);
+               break;
+       case 1:
+               WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_3_CTRL, doorbell_range);
+               WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_3_CTRL1, doorbell_range1);
+               break;
+       case 2:
+               WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_4_CTRL, doorbell_range);
+               WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_4_CTRL1, doorbell_range1);
+               break;
+       case 3:
+               WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL, doorbell_range);
+               WREG32_SOC15(NBIO, 0, regGDC_S2A0_S2A_DOORBELL_ENTRY_5_CTRL1, doorbell_range1);
+               break;
+       default:
+               dev_err(adev->dev,
+                       "amdgpu: invalid vcn instance set when program doorbell range\n");
+               break;
+       }
+}
+
 static int nbio_v6_3_2_get_compute_partition_mode(struct amdgpu_device *adev)
 {
        u32 tmp, px;
@@ -165,4 +360,10 @@ const struct amdgpu_nbio_funcs nbio_v6_3_2_funcs = {
        .get_compute_partition_mode = nbio_v6_3_2_get_compute_partition_mode,
        .get_memory_partition_mode = nbio_v6_3_2_get_memory_partition_mode,
        .is_nps_switch_requested = nbio_v6_3_2_is_nps_switch_requested,
+       .ih_control = nbio_v6_3_2_ih_control,
+       .ih_doorbell_range = nbio_v6_3_2_ih_doorbell_range,
+       .gc_doorbell_init = nbio_v6_3_2_gc_doorbell_init,
+       .sdma_doorbell_range = nbio_v6_3_2_sdma_doorbell_range,
+       .vcn_doorbell_range = nbio_v6_3_2_vcn_doorbell_range,
+       .init_registers = nbio_v6_3_2_init_registers,
 };
index 709b1669b07bcbf48f9ae43251a7310713b7bddd..d06953c237ed945842f747c60734d8b23e008a81 100644 (file)
@@ -330,6 +330,8 @@ static int soc_v1_0_common_early_init(struct amdgpu_ip_block *ip_block)
                return -EINVAL;
        }
 
+       adev->nbio.funcs->init_registers(adev);
+
        return 0;
 }