Merge remote-tracking branch 'drm/drm-next'
[linux] / drivers / gpu / drm / amd / amdgpu / soc15.c
index 9b63997..99ebcf2 100644 (file)
 #include "hdp/hdp_4_0_sh_mask.h"
 #include "smuio/smuio_9_0_offset.h"
 #include "smuio/smuio_9_0_sh_mask.h"
+#include "nbio/nbio_7_0_default.h"
+#include "nbio/nbio_7_0_sh_mask.h"
+#include "nbio/nbio_7_0_smn.h"
+#include "mp/mp_9_0_offset.h"
 
 #include "soc15.h"
 #include "soc15_common.h"
@@ -385,14 +389,13 @@ void soc15_program_register_sequence(struct amdgpu_device *adev,
 
 }
 
-
-static int soc15_asic_reset(struct amdgpu_device *adev)
+static int soc15_asic_mode1_reset(struct amdgpu_device *adev)
 {
        u32 i;
 
        amdgpu_atombios_scratch_regs_engine_hung(adev, true);
 
-       dev_info(adev->dev, "GPU reset\n");
+       dev_info(adev->dev, "GPU mode1 reset\n");
 
        /* disable BM */
        pci_clear_master(adev->pdev);
@@ -417,6 +420,63 @@ static int soc15_asic_reset(struct amdgpu_device *adev)
        return 0;
 }
 
+static int soc15_asic_get_baco_capability(struct amdgpu_device *adev, bool *cap)
+{
+       void *pp_handle = adev->powerplay.pp_handle;
+       const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+
+       if (!pp_funcs || !pp_funcs->get_asic_baco_capability) {
+               *cap = false;
+               return -ENOENT;
+       }
+
+       return pp_funcs->get_asic_baco_capability(pp_handle, cap);
+}
+
+static int soc15_asic_baco_reset(struct amdgpu_device *adev)
+{
+       void *pp_handle = adev->powerplay.pp_handle;
+       const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+
+       if (!pp_funcs ||!pp_funcs->get_asic_baco_state ||!pp_funcs->set_asic_baco_state)
+               return -ENOENT;
+
+       /* enter BACO state */
+       if (pp_funcs->set_asic_baco_state(pp_handle, 1))
+               return -EIO;
+
+       /* exit BACO state */
+       if (pp_funcs->set_asic_baco_state(pp_handle, 0))
+               return -EIO;
+
+       dev_info(adev->dev, "GPU BACO reset\n");
+
+       return 0;
+}
+
+static int soc15_asic_reset(struct amdgpu_device *adev)
+{
+       int ret;
+       bool baco_reset;
+
+       switch (adev->asic_type) {
+       case CHIP_VEGA10:
+       case CHIP_VEGA20:
+               soc15_asic_get_baco_capability(adev, &baco_reset);
+               break;
+       default:
+               baco_reset = false;
+               break;
+       }
+
+       if (baco_reset)
+               ret = soc15_asic_baco_reset(adev);
+       else
+               ret = soc15_asic_mode1_reset(adev);
+
+       return ret;
+}
+
 /*static int soc15_set_uvd_clock(struct amdgpu_device *adev, u32 clock,
                        u32 cntl_reg, u32 status_reg)
 {
@@ -535,10 +595,12 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)
                amdgpu_device_ip_block_add(adev, &vega10_common_ip_block);
                amdgpu_device_ip_block_add(adev, &gmc_v9_0_ip_block);
                amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block);
-               if (adev->asic_type == CHIP_VEGA20)
-                       amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block);
-               else
-                       amdgpu_device_ip_block_add(adev, &psp_v3_1_ip_block);
+               if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP)) {
+                       if (adev->asic_type == CHIP_VEGA20)
+                               amdgpu_device_ip_block_add(adev, &psp_v11_0_ip_block);
+                       else
+                               amdgpu_device_ip_block_add(adev, &psp_v3_1_ip_block);
+               }
                amdgpu_device_ip_block_add(adev, &gfx_v9_0_ip_block);
                amdgpu_device_ip_block_add(adev, &sdma_v4_0_ip_block);
                if (!amdgpu_sriov_vf(adev))
@@ -560,7 +622,8 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)
                amdgpu_device_ip_block_add(adev, &vega10_common_ip_block);
                amdgpu_device_ip_block_add(adev, &gmc_v9_0_ip_block);
                amdgpu_device_ip_block_add(adev, &vega10_ih_ip_block);
-               amdgpu_device_ip_block_add(adev, &psp_v10_0_ip_block);
+               if (likely(adev->firmware.load_type == AMDGPU_FW_LOAD_PSP))
+                       amdgpu_device_ip_block_add(adev, &psp_v10_0_ip_block);
                amdgpu_device_ip_block_add(adev, &gfx_v9_0_ip_block);
                amdgpu_device_ip_block_add(adev, &sdma_v4_0_ip_block);
                amdgpu_device_ip_block_add(adev, &pp_smu_ip_block);
@@ -601,6 +664,68 @@ static bool soc15_need_full_reset(struct amdgpu_device *adev)
        /* change this when we implement soft reset */
        return true;
 }
+static void soc15_get_pcie_usage(struct amdgpu_device *adev, uint64_t *count0,
+                                uint64_t *count1)
+{
+       uint32_t perfctr = 0;
+       uint64_t cnt0_of, cnt1_of;
+       int tmp;
+
+       /* This reports 0 on APUs, so return to avoid writing/reading registers
+        * that may or may not be different from their GPU counterparts
+        */
+        if (adev->flags & AMD_IS_APU)
+                return;
+
+       /* Set the 2 events that we wish to watch, defined above */
+       /* Reg 40 is # received msgs, Reg 104 is # of posted requests sent */
+       perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK, EVENT0_SEL, 40);
+       perfctr = REG_SET_FIELD(perfctr, PCIE_PERF_CNTL_TXCLK, EVENT1_SEL, 104);
+
+       /* Write to enable desired perf counters */
+       WREG32_PCIE(smnPCIE_PERF_CNTL_TXCLK, perfctr);
+       /* Zero out and enable the perf counters
+        * Write 0x5:
+        * Bit 0 = Start all counters(1)
+        * Bit 2 = Global counter reset enable(1)
+        */
+       WREG32_PCIE(smnPCIE_PERF_COUNT_CNTL, 0x00000005);
+
+       msleep(1000);
+
+       /* Load the shadow and disable the perf counters
+        * Write 0x2:
+        * Bit 0 = Stop counters(0)
+        * Bit 1 = Load the shadow counters(1)
+        */
+       WREG32_PCIE(smnPCIE_PERF_COUNT_CNTL, 0x00000002);
+
+       /* Read register values to get any >32bit overflow */
+       tmp = RREG32_PCIE(smnPCIE_PERF_CNTL_TXCLK);
+       cnt0_of = REG_GET_FIELD(tmp, PCIE_PERF_CNTL_TXCLK, COUNTER0_UPPER);
+       cnt1_of = REG_GET_FIELD(tmp, PCIE_PERF_CNTL_TXCLK, COUNTER1_UPPER);
+
+       /* Get the values and add the overflow */
+       *count0 = RREG32_PCIE(smnPCIE_PERF_COUNT0_TXCLK) | (cnt0_of << 32);
+       *count1 = RREG32_PCIE(smnPCIE_PERF_COUNT1_TXCLK) | (cnt1_of << 32);
+}
+
+static bool soc15_need_reset_on_init(struct amdgpu_device *adev)
+{
+       u32 sol_reg;
+
+       if (adev->flags & AMD_IS_APU)
+               return false;
+
+       /* Check sOS sign of life register to confirm sys driver and sOS
+        * are already been loaded.
+        */
+       sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81);
+       if (sol_reg)
+               return true;
+
+       return false;
+}
 
 static const struct amdgpu_asic_funcs soc15_asic_funcs =
 {
@@ -617,6 +742,8 @@ static const struct amdgpu_asic_funcs soc15_asic_funcs =
        .invalidate_hdp = &soc15_invalidate_hdp,
        .need_full_reset = &soc15_need_full_reset,
        .init_doorbell_index = &vega10_doorbell_index_init,
+       .get_pcie_usage = &soc15_get_pcie_usage,
+       .need_reset_on_init = &soc15_need_reset_on_init,
 };
 
 static const struct amdgpu_asic_funcs vega20_asic_funcs =
@@ -634,6 +761,8 @@ static const struct amdgpu_asic_funcs vega20_asic_funcs =
        .invalidate_hdp = &soc15_invalidate_hdp,
        .need_full_reset = &soc15_need_full_reset,
        .init_doorbell_index = &vega20_doorbell_index_init,
+       .get_pcie_usage = &soc15_get_pcie_usage,
+       .need_reset_on_init = &soc15_need_reset_on_init,
 };
 
 static int soc15_common_early_init(void *handle)
@@ -842,6 +971,22 @@ static int soc15_common_sw_fini(void *handle)
        return 0;
 }
 
+static void soc15_doorbell_range_init(struct amdgpu_device *adev)
+{
+       int i;
+       struct amdgpu_ring *ring;
+
+       for (i = 0; i < adev->sdma.num_instances; i++) {
+               ring = &adev->sdma.instance[i].ring;
+               adev->nbio_funcs->sdma_doorbell_range(adev, i,
+                       ring->use_doorbell, ring->doorbell_index,
+                       adev->doorbell_index.sdma_doorbell_range);
+       }
+
+       adev->nbio_funcs->ih_doorbell_range(adev, adev->irq.ih.use_doorbell,
+                                               adev->irq.ih.doorbell_index);
+}
+
 static int soc15_common_hw_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -854,6 +999,12 @@ static int soc15_common_hw_init(void *handle)
        adev->nbio_funcs->init_registers(adev);
        /* enable the doorbell aperture */
        soc15_enable_doorbell_aperture(adev, true);
+       /* HW doorbell routing policy: doorbell writing not
+        * in SDMA/IH/MM/ACV range will be routed to CP. So
+        * we need to init SDMA/IH/MM/ACV doorbell range prior
+        * to CP ip block init and ring test.
+        */
+       soc15_doorbell_range_init(adev);
 
        return 0;
 }