drm/amd/powerplay: implement interface to set watermarks for clock ranges
authorHuang Rui <ray.huang@amd.com>
Thu, 17 Jan 2019 07:25:37 +0000 (15:25 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 19 Mar 2019 20:03:59 +0000 (15:03 -0500)
This patch implements inteferface to set watermarks table for clock ranges on
smu 11. It fills watermark table before it is written to SMC.

Signed-off-by: Huang Rui <ray.huang@amd.com>
Reviewed-by: Kevin Wang <Kevin1.Wang@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
drivers/gpu/drm/amd/powerplay/smu_v11_0.c

index 93830d7..634569e 100644 (file)
@@ -548,9 +548,6 @@ void pp_rv_set_wm_ranges(struct pp_smu *pp,
        wm_with_clock_ranges.num_wm_dmif_sets = ranges->num_reader_wm_sets;
        wm_with_clock_ranges.num_wm_mcif_sets = ranges->num_writer_wm_sets;
 
-       if (!pp_funcs || !pp_funcs->set_watermarks_for_clocks_ranges)
-               return;
-
        for (i = 0; i < wm_with_clock_ranges.num_wm_dmif_sets; i++) {
                if (ranges->reader_wm_sets[i].wm_inst > 3)
                        wm_dce_clocks[i].wm_set_id = WM_SET_A;
@@ -583,7 +580,13 @@ void pp_rv_set_wm_ranges(struct pp_smu *pp,
                                ranges->writer_wm_sets[i].min_drain_clk_mhz * 1000;
        }
 
-       pp_funcs->set_watermarks_for_clocks_ranges(pp_handle, &wm_with_clock_ranges);
+       if (pp_funcs && pp_funcs->set_watermarks_for_clocks_ranges)
+               pp_funcs->set_watermarks_for_clocks_ranges(pp_handle,
+                                                          &wm_with_clock_ranges);
+       else if (adev->smu.funcs &&
+                adev->smu.funcs->set_watermarks_for_clock_ranges)
+               smu_set_watermarks_for_clock_ranges(&adev->smu,
+                                                   &wm_with_clock_ranges);
 }
 
 void pp_rv_set_pme_wa_enable(struct pp_smu *pp)
index 9e60f56..e6915ef 100644 (file)
@@ -329,6 +329,7 @@ static int smu_sw_init(void *handle)
        bitmap_zero(smu->smu_feature.supported, SMU_FEATURE_MAX);
        bitmap_zero(smu->smu_feature.enabled, SMU_FEATURE_MAX);
        bitmap_zero(smu->smu_feature.allowed, SMU_FEATURE_MAX);
+       smu->watermarks_bitmap = 0;
 
        ret = smu_init_microcode(smu);
        if (ret) {
index 53bdc1c..97d44a6 100644 (file)
@@ -235,6 +235,11 @@ struct smu_context
        uint32_t default_power_limit;
 
        bool support_power_containment;
+       bool disable_watermark;
+
+#define WATERMARKS_EXIST       (1 << 0)
+#define WATERMARKS_LOADED      (1 << 1)
+       uint32_t watermarks_bitmap;
 };
 
 struct pptable_funcs {
@@ -320,6 +325,8 @@ struct smu_funcs
        int (*get_current_shallow_sleep_clocks)(struct smu_context *smu,
                                                struct smu_clock_info *clocks);
        int (*notify_smu_enable_pwe)(struct smu_context *smu);
+       int (*set_watermarks_for_clock_ranges)(struct smu_context *smu,
+                                              struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges);
 };
 
 #define smu_init_microcode(smu) \
@@ -439,6 +446,8 @@ struct smu_funcs
        ((smu)->funcs->get_current_shallow_sleep_clocks ? (smu)->funcs->get_current_shallow_sleep_clocks((smu), (clocks)) : 0)
 #define smu_notify_smu_enable_pwe(smu) \
        ((smu)->funcs->notify_smu_enable_pwe ? (smu)->funcs->notify_smu_enable_pwe((smu)) : 0)
+#define smu_set_watermarks_for_clock_ranges(smu, clock_ranges) \
+       ((smu)->funcs->set_watermarks_for_clock_ranges ? (smu)->funcs->set_watermarks_for_clock_ranges((smu), (clock_ranges)) : 0)
 
 
 extern int smu_get_atom_data_table(struct smu_context *smu, uint32_t table,
index 04d949e..e455ed4 100644 (file)
@@ -1167,6 +1167,85 @@ failed:
        return ret;
 }
 
+static int smu_v11_0_set_watermarks_table(struct smu_context *smu,
+                                         Watermarks_t *table, struct
+                                         dm_pp_wm_sets_with_clock_ranges_soc15
+                                         *clock_ranges)
+{
+       int i;
+
+       if (!table || !clock_ranges)
+               return -EINVAL;
+
+       if (clock_ranges->num_wm_dmif_sets > 4 ||
+           clock_ranges->num_wm_mcif_sets > 4)
+                return -EINVAL;
+
+        for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) {
+               table->WatermarkRow[1][i].MinClock =
+                       cpu_to_le16((uint16_t)
+                       (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz /
+                       1000));
+               table->WatermarkRow[1][i].MaxClock =
+                       cpu_to_le16((uint16_t)
+                       (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz /
+                       1000));
+               table->WatermarkRow[1][i].MinUclk =
+                       cpu_to_le16((uint16_t)
+                       (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz /
+                       1000));
+               table->WatermarkRow[1][i].MaxUclk =
+                       cpu_to_le16((uint16_t)
+                       (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz /
+                       1000));
+               table->WatermarkRow[1][i].WmSetting = (uint8_t)
+                               clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id;
+        }
+
+       for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) {
+               table->WatermarkRow[0][i].MinClock =
+                       cpu_to_le16((uint16_t)
+                       (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz /
+                       1000));
+               table->WatermarkRow[0][i].MaxClock =
+                       cpu_to_le16((uint16_t)
+                       (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz /
+                       1000));
+               table->WatermarkRow[0][i].MinUclk =
+                       cpu_to_le16((uint16_t)
+                       (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz /
+                       1000));
+               table->WatermarkRow[0][i].MaxUclk =
+                       cpu_to_le16((uint16_t)
+                       (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz /
+                       1000));
+               table->WatermarkRow[0][i].WmSetting = (uint8_t)
+                               clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
+        }
+
+       return 0;
+}
+
+static int
+smu_v11_0_set_watermarks_for_clock_ranges(struct smu_context *smu, struct
+                                         dm_pp_wm_sets_with_clock_ranges_soc15
+                                         *clock_ranges)
+{
+       int ret = 0;
+       struct smu_table *watermarks = &smu->smu_table.tables[TABLE_WATERMARKS];
+       Watermarks_t *table = watermarks->cpu_addr;
+
+       if (!smu->disable_watermark &&
+           smu_feature_is_enabled(smu, FEATURE_DPM_DCEFCLK_BIT) &&
+           smu_feature_is_enabled(smu, FEATURE_DPM_SOCCLK_BIT)) {
+               smu_v11_0_set_watermarks_table(smu, table, clock_ranges);
+               smu->watermarks_bitmap |= WATERMARKS_EXIST;
+               smu->watermarks_bitmap &= ~WATERMARKS_LOADED;
+       }
+
+       return ret;
+}
+
 static const struct smu_funcs smu_v11_0_funcs = {
        .init_microcode = smu_v11_0_init_microcode,
        .load_microcode = smu_v11_0_load_microcode,
@@ -1202,6 +1281,7 @@ static const struct smu_funcs smu_v11_0_funcs = {
        .read_sensor = smu_v11_0_read_sensor,
        .set_deep_sleep_dcefclk = smu_v11_0_set_deep_sleep_dcefclk,
        .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request,
+       .set_watermarks_for_clock_ranges = smu_v11_0_set_watermarks_for_clock_ranges,
 };
 
 void smu_v11_0_set_smu_funcs(struct smu_context *smu)