Commit 7bbdbe40 authored by Hersen Wu's avatar Hersen Wu Committed by Alex Deucher

drm/amdgpu/powerplay: add renoir funcs to support dc

there are two paths for renoir dc access smu.
one dc access smu directly using bios smc
interface: set disply, dprefclk, etc.
another goes through pplib for get dpm clock
table and set watermmark.
Signed-off-by: default avatarHersen Wu <hersenxs.wu@amd.com>
Reviewed-by: default avatarKevin Wang <kevin1.wang@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 5bcc9240
...@@ -589,8 +589,7 @@ void pp_rv_set_wm_ranges(struct pp_smu *pp, ...@@ -589,8 +589,7 @@ void pp_rv_set_wm_ranges(struct pp_smu *pp,
if (pp_funcs && pp_funcs->set_watermarks_for_clocks_ranges) if (pp_funcs && pp_funcs->set_watermarks_for_clocks_ranges)
pp_funcs->set_watermarks_for_clocks_ranges(pp_handle, pp_funcs->set_watermarks_for_clocks_ranges(pp_handle,
&wm_with_clock_ranges); &wm_with_clock_ranges);
else if (adev->smu.funcs && else
adev->smu.funcs->set_watermarks_for_clock_ranges)
smu_set_watermarks_for_clock_ranges(&adev->smu, smu_set_watermarks_for_clock_ranges(&adev->smu,
&wm_with_clock_ranges); &wm_with_clock_ranges);
} }
...@@ -665,7 +664,6 @@ enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp, ...@@ -665,7 +664,6 @@ enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp,
{ {
const struct dc_context *ctx = pp->dm; const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context; struct amdgpu_device *adev = ctx->driver_context;
struct smu_context *smu = &adev->smu;
struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges; struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges;
struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks = struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks =
wm_with_clock_ranges.wm_dmif_clocks_ranges; wm_with_clock_ranges.wm_dmif_clocks_ranges;
...@@ -708,15 +706,7 @@ enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp, ...@@ -708,15 +706,7 @@ enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp,
ranges->writer_wm_sets[i].min_drain_clk_mhz * 1000; ranges->writer_wm_sets[i].min_drain_clk_mhz * 1000;
} }
if (!smu->funcs) smu_set_watermarks_for_clock_ranges(&adev->smu, &wm_with_clock_ranges);
return PP_SMU_RESULT_UNSUPPORTED;
/* 0: successful or smu.funcs->set_watermarks_for_clock_ranges = NULL;
* 1: fail
*/
if (smu_set_watermarks_for_clock_ranges(&adev->smu,
&wm_with_clock_ranges))
return PP_SMU_RESULT_UNSUPPORTED;
return PP_SMU_RESULT_OK; return PP_SMU_RESULT_OK;
} }
......
...@@ -1813,6 +1813,41 @@ int smu_set_df_cstate(struct smu_context *smu, ...@@ -1813,6 +1813,41 @@ int smu_set_df_cstate(struct smu_context *smu,
return ret; return ret;
} }
int smu_write_watermarks_table(struct smu_context *smu)
{
int ret = 0;
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *table = NULL;
table = &smu_table->tables[SMU_TABLE_WATERMARKS];
if (!table->cpu_addr)
return -EINVAL;
ret = smu_update_table(smu, SMU_TABLE_WATERMARKS, 0, table->cpu_addr,
true);
return ret;
}
int smu_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[SMU_TABLE_WATERMARKS];
void *table = watermarks->cpu_addr;
if (!smu->disable_watermark &&
smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) &&
smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
smu_set_watermarks_table(smu, table, clock_ranges);
smu->watermarks_bitmap |= WATERMARKS_EXIST;
smu->watermarks_bitmap &= ~WATERMARKS_LOADED;
}
return ret;
}
const struct amd_ip_funcs smu_ip_funcs = { const struct amd_ip_funcs smu_ip_funcs = {
.name = "smu", .name = "smu",
.early_init = smu_early_init, .early_init = smu_early_init,
......
...@@ -470,6 +470,7 @@ struct pptable_funcs { ...@@ -470,6 +470,7 @@ struct pptable_funcs {
uint32_t dpm_level, uint32_t *freq); uint32_t dpm_level, uint32_t *freq);
int (*set_df_cstate)(struct smu_context *smu, enum pp_df_cstate state); int (*set_df_cstate)(struct smu_context *smu, enum pp_df_cstate state);
int (*update_pcie_parameters)(struct smu_context *smu, uint32_t pcie_gen_cap, uint32_t pcie_width_cap); int (*update_pcie_parameters)(struct smu_context *smu, uint32_t pcie_gen_cap, uint32_t pcie_width_cap);
int (*get_dpm_clock_table)(struct smu_context *smu, struct dpm_clocks *clock_table);
}; };
struct smu_funcs struct smu_funcs
...@@ -495,7 +496,6 @@ struct smu_funcs ...@@ -495,7 +496,6 @@ struct smu_funcs
int (*set_min_dcef_deep_sleep)(struct smu_context *smu); int (*set_min_dcef_deep_sleep)(struct smu_context *smu);
int (*set_tool_table_location)(struct smu_context *smu); int (*set_tool_table_location)(struct smu_context *smu);
int (*notify_memory_pool_location)(struct smu_context *smu); int (*notify_memory_pool_location)(struct smu_context *smu);
int (*write_watermarks_table)(struct smu_context *smu);
int (*set_last_dcef_min_deep_sleep_clk)(struct smu_context *smu); int (*set_last_dcef_min_deep_sleep_clk)(struct smu_context *smu);
int (*system_features_control)(struct smu_context *smu, bool en); int (*system_features_control)(struct smu_context *smu, bool en);
int (*send_smc_msg)(struct smu_context *smu, uint16_t msg); int (*send_smc_msg)(struct smu_context *smu, uint16_t msg);
...@@ -533,8 +533,6 @@ struct smu_funcs ...@@ -533,8 +533,6 @@ struct smu_funcs
int (*get_current_shallow_sleep_clocks)(struct smu_context *smu, int (*get_current_shallow_sleep_clocks)(struct smu_context *smu,
struct smu_clock_info *clocks); struct smu_clock_info *clocks);
int (*notify_smu_enable_pwe)(struct smu_context *smu); 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);
int (*conv_power_profile_to_pplib_workload)(int power_profile); int (*conv_power_profile_to_pplib_workload)(int power_profile);
uint32_t (*get_fan_control_mode)(struct smu_context *smu); uint32_t (*get_fan_control_mode)(struct smu_context *smu);
int (*set_fan_control_mode)(struct smu_context *smu, uint32_t mode); int (*set_fan_control_mode)(struct smu_context *smu, uint32_t mode);
...@@ -599,9 +597,6 @@ struct smu_funcs ...@@ -599,9 +597,6 @@ struct smu_funcs
((smu)->funcs->notify_memory_pool_location ? (smu)->funcs->notify_memory_pool_location((smu)) : 0) ((smu)->funcs->notify_memory_pool_location ? (smu)->funcs->notify_memory_pool_location((smu)) : 0)
#define smu_gfx_off_control(smu, enable) \ #define smu_gfx_off_control(smu, enable) \
((smu)->funcs->gfx_off_control ? (smu)->funcs->gfx_off_control((smu), (enable)) : 0) ((smu)->funcs->gfx_off_control ? (smu)->funcs->gfx_off_control((smu), (enable)) : 0)
#define smu_write_watermarks_table(smu) \
((smu)->funcs->write_watermarks_table ? (smu)->funcs->write_watermarks_table((smu)) : 0)
#define smu_set_last_dcef_min_deep_sleep_clk(smu) \ #define smu_set_last_dcef_min_deep_sleep_clk(smu) \
((smu)->funcs->set_last_dcef_min_deep_sleep_clk ? (smu)->funcs->set_last_dcef_min_deep_sleep_clk((smu)) : 0) ((smu)->funcs->set_last_dcef_min_deep_sleep_clk ? (smu)->funcs->set_last_dcef_min_deep_sleep_clk((smu)) : 0)
#define smu_system_features_control(smu, en) \ #define smu_system_features_control(smu, en) \
...@@ -741,8 +736,6 @@ struct smu_funcs ...@@ -741,8 +736,6 @@ struct smu_funcs
((smu)->funcs->get_current_shallow_sleep_clocks ? (smu)->funcs->get_current_shallow_sleep_clocks((smu), (clocks)) : 0) ((smu)->funcs->get_current_shallow_sleep_clocks ? (smu)->funcs->get_current_shallow_sleep_clocks((smu), (clocks)) : 0)
#define smu_notify_smu_enable_pwe(smu) \ #define smu_notify_smu_enable_pwe(smu) \
((smu)->funcs->notify_smu_enable_pwe ? (smu)->funcs->notify_smu_enable_pwe((smu)) : 0) ((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)
#define smu_dpm_set_uvd_enable(smu, enable) \ #define smu_dpm_set_uvd_enable(smu, enable) \
((smu)->ppt_funcs->dpm_set_uvd_enable ? (smu)->ppt_funcs->dpm_set_uvd_enable((smu), (enable)) : 0) ((smu)->ppt_funcs->dpm_set_uvd_enable ? (smu)->ppt_funcs->dpm_set_uvd_enable((smu), (enable)) : 0)
#define smu_dpm_set_vce_enable(smu, enable) \ #define smu_dpm_set_vce_enable(smu, enable) \
...@@ -781,9 +774,10 @@ struct smu_funcs ...@@ -781,9 +774,10 @@ struct smu_funcs
((smu)->ppt_funcs->dump_pptable ? (smu)->ppt_funcs->dump_pptable((smu)) : 0) ((smu)->ppt_funcs->dump_pptable ? (smu)->ppt_funcs->dump_pptable((smu)) : 0)
#define smu_get_dpm_clk_limited(smu, clk_type, dpm_level, freq) \ #define smu_get_dpm_clk_limited(smu, clk_type, dpm_level, freq) \
((smu)->ppt_funcs->get_dpm_clk_limited ? (smu)->ppt_funcs->get_dpm_clk_limited((smu), (clk_type), (dpm_level), (freq)) : -EINVAL) ((smu)->ppt_funcs->get_dpm_clk_limited ? (smu)->ppt_funcs->get_dpm_clk_limited((smu), (clk_type), (dpm_level), (freq)) : -EINVAL)
#define smu_set_soft_freq_limited_range(smu, clk_type, min, max) \ #define smu_set_soft_freq_limited_range(smu, clk_type, min, max) \
((smu)->funcs->set_soft_freq_limited_range ? (smu)->funcs->set_soft_freq_limited_range((smu), (clk_type), (min), (max)) : -EINVAL) ((smu)->funcs->set_soft_freq_limited_range ? (smu)->funcs->set_soft_freq_limited_range((smu), (clk_type), (min), (max)) : -EINVAL)
#define smu_get_dpm_clock_table(smu, clock_table) \
((smu)->ppt_funcs->get_dpm_clock_table ? (smu)->ppt_funcs->get_dpm_clock_table((smu), (clock_table)) : -EINVAL)
#define smu_override_pcie_parameters(smu) \ #define smu_override_pcie_parameters(smu) \
((smu)->funcs->override_pcie_parameters ? (smu)->funcs->override_pcie_parameters((smu)) : 0) ((smu)->funcs->override_pcie_parameters ? (smu)->funcs->override_pcie_parameters((smu)) : 0)
...@@ -823,6 +817,10 @@ int smu_sys_get_pp_table(struct smu_context *smu, void **table); ...@@ -823,6 +817,10 @@ int smu_sys_get_pp_table(struct smu_context *smu, void **table);
int smu_sys_set_pp_table(struct smu_context *smu, void *buf, size_t size); int smu_sys_set_pp_table(struct smu_context *smu, void *buf, size_t size);
int smu_get_power_num_states(struct smu_context *smu, struct pp_states_info *state_info); int smu_get_power_num_states(struct smu_context *smu, struct pp_states_info *state_info);
enum amd_pm_state_type smu_get_current_power_state(struct smu_context *smu); enum amd_pm_state_type smu_get_current_power_state(struct smu_context *smu);
int smu_write_watermarks_table(struct smu_context *smu);
int smu_set_watermarks_for_clock_ranges(
struct smu_context *smu,
struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges);
/* smu to display interface */ /* smu to display interface */
extern int smu_display_configuration_change(struct smu_context *smu, const extern int smu_display_configuration_change(struct smu_context *smu, const
......
...@@ -416,6 +416,40 @@ static int renoir_get_profiling_clk_mask(struct smu_context *smu, ...@@ -416,6 +416,40 @@ static int renoir_get_profiling_clk_mask(struct smu_context *smu,
return 0; return 0;
} }
/**
* This interface get dpm clock table for dc
*/
static int renoir_get_dpm_clock_table(struct smu_context *smu, struct dpm_clocks *clock_table)
{
DpmClocks_t *table = smu->smu_table.clocks_table;
int i;
if (!clock_table || !table)
return -EINVAL;
for (i = 0; i < PP_SMU_NUM_DCFCLK_DPM_LEVELS; i++) {
clock_table->DcfClocks[i].Freq = table->DcfClocks[i].Freq;
clock_table->DcfClocks[i].Vol = table->DcfClocks[i].Vol;
}
for (i = 0; i < PP_SMU_NUM_SOCCLK_DPM_LEVELS; i++) {
clock_table->SocClocks[i].Freq = table->SocClocks[i].Freq;
clock_table->SocClocks[i].Vol = table->SocClocks[i].Vol;
}
for (i = 0; i < PP_SMU_NUM_FCLK_DPM_LEVELS; i++) {
clock_table->FClocks[i].Freq = table->FClocks[i].Freq;
clock_table->FClocks[i].Vol = table->FClocks[i].Vol;
}
for (i = 0; i< PP_SMU_NUM_MEMCLK_DPM_LEVELS; i++) {
clock_table->MemClocks[i].Freq = table->MemClocks[i].Freq;
clock_table->MemClocks[i].Vol = table->MemClocks[i].Vol;
}
return 0;
}
static int renoir_force_clk_levels(struct smu_context *smu, static int renoir_force_clk_levels(struct smu_context *smu,
enum smu_clk_type clk_type, uint32_t mask) enum smu_clk_type clk_type, uint32_t mask)
{ {
...@@ -546,6 +580,66 @@ static int renoir_set_performance_level(struct smu_context *smu, enum amd_dpm_fo ...@@ -546,6 +580,66 @@ static int renoir_set_performance_level(struct smu_context *smu, enum amd_dpm_fo
return ret; return ret;
} }
/* save watermark settings into pplib smu structure,
* also pass data to smu controller
*/
static int renoir_set_watermarks_table(
struct smu_context *smu,
void *watermarks,
struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges)
{
int i;
int ret = 0;
Watermarks_t *table = watermarks;
if (!table || !clock_ranges)
return -EINVAL;
if (clock_ranges->num_wm_dmif_sets > 4 ||
clock_ranges->num_wm_mcif_sets > 4)
return -EINVAL;
/* save into smu->smu_table.tables[SMU_TABLE_WATERMARKS]->cpu_addr*/
for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) {
table->WatermarkRow[WM_DCFCLK][i].MinClock =
cpu_to_le16((uint16_t)
(clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz));
table->WatermarkRow[WM_DCFCLK][i].MaxClock =
cpu_to_le16((uint16_t)
(clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz));
table->WatermarkRow[WM_DCFCLK][i].MinMclk =
cpu_to_le16((uint16_t)
(clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz));
table->WatermarkRow[WM_DCFCLK][i].MaxMclk =
cpu_to_le16((uint16_t)
(clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz));
table->WatermarkRow[WM_DCFCLK][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[WM_SOCCLK][i].MinClock =
cpu_to_le16((uint16_t)
(clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz));
table->WatermarkRow[WM_SOCCLK][i].MaxClock =
cpu_to_le16((uint16_t)
(clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz));
table->WatermarkRow[WM_SOCCLK][i].MinMclk =
cpu_to_le16((uint16_t)
(clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz));
table->WatermarkRow[WM_SOCCLK][i].MaxMclk =
cpu_to_le16((uint16_t)
(clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz));
table->WatermarkRow[WM_SOCCLK][i].WmSetting = (uint8_t)
clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
}
/* pass data to smu controller */
ret = smu_write_watermarks_table(smu);
return ret;
}
static const struct pptable_funcs renoir_ppt_funcs = { static const struct pptable_funcs renoir_ppt_funcs = {
.get_smu_msg_index = renoir_get_smu_msg_index, .get_smu_msg_index = renoir_get_smu_msg_index,
.get_smu_table_index = renoir_get_smu_table_index, .get_smu_table_index = renoir_get_smu_table_index,
...@@ -562,6 +656,8 @@ static const struct pptable_funcs renoir_ppt_funcs = { ...@@ -562,6 +656,8 @@ static const struct pptable_funcs renoir_ppt_funcs = {
.force_clk_levels = renoir_force_clk_levels, .force_clk_levels = renoir_force_clk_levels,
.set_power_profile_mode = renoir_set_power_profile_mode, .set_power_profile_mode = renoir_set_power_profile_mode,
.set_performance_level = renoir_set_performance_level, .set_performance_level = renoir_set_performance_level,
.get_dpm_clock_table = renoir_get_dpm_clock_table,
.set_watermarks_table = renoir_set_watermarks_table,
}; };
void renoir_set_ppt_funcs(struct smu_context *smu) void renoir_set_ppt_funcs(struct smu_context *smu)
......
...@@ -771,23 +771,6 @@ static int smu_v11_0_write_pptable(struct smu_context *smu) ...@@ -771,23 +771,6 @@ static int smu_v11_0_write_pptable(struct smu_context *smu)
return ret; return ret;
} }
static int smu_v11_0_write_watermarks_table(struct smu_context *smu)
{
int ret = 0;
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *table = NULL;
table = &smu_table->tables[SMU_TABLE_WATERMARKS];
if (!table->cpu_addr)
return -EINVAL;
ret = smu_update_table(smu, SMU_TABLE_WATERMARKS, 0, table->cpu_addr,
true);
return ret;
}
static int smu_v11_0_set_deep_sleep_dcefclk(struct smu_context *smu, uint32_t clk) static int smu_v11_0_set_deep_sleep_dcefclk(struct smu_context *smu, uint32_t clk)
{ {
int ret; int ret;
...@@ -1337,26 +1320,6 @@ smu_v11_0_display_clock_voltage_request(struct smu_context *smu, ...@@ -1337,26 +1320,6 @@ smu_v11_0_display_clock_voltage_request(struct smu_context *smu,
return ret; return ret;
} }
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[SMU_TABLE_WATERMARKS];
void *table = watermarks->cpu_addr;
if (!smu->disable_watermark &&
smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) &&
smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
smu_set_watermarks_table(smu, table, clock_ranges);
smu->watermarks_bitmap |= WATERMARKS_EXIST;
smu->watermarks_bitmap &= ~WATERMARKS_LOADED;
}
return ret;
}
static int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable) static int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable)
{ {
int ret = 0; int ret = 0;
...@@ -1855,7 +1818,6 @@ static const struct smu_funcs smu_v11_0_funcs = { ...@@ -1855,7 +1818,6 @@ static const struct smu_funcs smu_v11_0_funcs = {
.parse_pptable = smu_v11_0_parse_pptable, .parse_pptable = smu_v11_0_parse_pptable,
.populate_smc_tables = smu_v11_0_populate_smc_pptable, .populate_smc_tables = smu_v11_0_populate_smc_pptable,
.write_pptable = smu_v11_0_write_pptable, .write_pptable = smu_v11_0_write_pptable,
.write_watermarks_table = smu_v11_0_write_watermarks_table,
.set_min_dcef_deep_sleep = smu_v11_0_set_min_dcef_deep_sleep, .set_min_dcef_deep_sleep = smu_v11_0_set_min_dcef_deep_sleep,
.set_tool_table_location = smu_v11_0_set_tool_table_location, .set_tool_table_location = smu_v11_0_set_tool_table_location,
.init_display_count = smu_v11_0_init_display_count, .init_display_count = smu_v11_0_init_display_count,
...@@ -1871,7 +1833,6 @@ static const struct smu_funcs smu_v11_0_funcs = { ...@@ -1871,7 +1833,6 @@ static const struct smu_funcs smu_v11_0_funcs = {
.read_sensor = smu_v11_0_read_sensor, .read_sensor = smu_v11_0_read_sensor,
.set_deep_sleep_dcefclk = smu_v11_0_set_deep_sleep_dcefclk, .set_deep_sleep_dcefclk = smu_v11_0_set_deep_sleep_dcefclk,
.display_clock_voltage_request = smu_v11_0_display_clock_voltage_request, .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request,
.set_watermarks_for_clock_ranges = smu_v11_0_set_watermarks_for_clock_ranges,
.get_fan_control_mode = smu_v11_0_get_fan_control_mode, .get_fan_control_mode = smu_v11_0_get_fan_control_mode,
.set_fan_control_mode = smu_v11_0_set_fan_control_mode, .set_fan_control_mode = smu_v11_0_set_fan_control_mode,
.set_fan_speed_percent = smu_v11_0_set_fan_speed_percent, .set_fan_speed_percent = smu_v11_0_set_fan_speed_percent,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment