162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AMD Platform Management Framework Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2022, Advanced Micro Devices, Inc.
662306a36Sopenharmony_ci * All Rights Reserved.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/string_choices.h>
1262306a36Sopenharmony_ci#include <linux/workqueue.h>
1362306a36Sopenharmony_ci#include "pmf.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic struct cnqf_config config_store;
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#ifdef CONFIG_AMD_PMF_DEBUG
1862306a36Sopenharmony_cistatic const char *state_as_str_cnqf(unsigned int state)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	switch (state) {
2162306a36Sopenharmony_ci	case APMF_CNQF_TURBO:
2262306a36Sopenharmony_ci		return "turbo";
2362306a36Sopenharmony_ci	case APMF_CNQF_PERFORMANCE:
2462306a36Sopenharmony_ci		return "performance";
2562306a36Sopenharmony_ci	case APMF_CNQF_BALANCE:
2662306a36Sopenharmony_ci		return "balance";
2762306a36Sopenharmony_ci	case APMF_CNQF_QUIET:
2862306a36Sopenharmony_ci		return "quiet";
2962306a36Sopenharmony_ci	default:
3062306a36Sopenharmony_ci		return "Unknown CnQF State";
3162306a36Sopenharmony_ci	}
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic void amd_pmf_cnqf_dump_defaults(struct apmf_dyn_slider_output *data, int idx)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	int i;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	pr_debug("Dynamic Slider %s Defaults - BEGIN\n", idx ? "DC" : "AC");
3962306a36Sopenharmony_ci	pr_debug("size: %u\n", data->size);
4062306a36Sopenharmony_ci	pr_debug("flags: 0x%x\n", data->flags);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	/* Time constants */
4362306a36Sopenharmony_ci	pr_debug("t_perf_to_turbo: %u ms\n", data->t_perf_to_turbo);
4462306a36Sopenharmony_ci	pr_debug("t_balanced_to_perf: %u ms\n", data->t_balanced_to_perf);
4562306a36Sopenharmony_ci	pr_debug("t_quiet_to_balanced: %u ms\n", data->t_quiet_to_balanced);
4662306a36Sopenharmony_ci	pr_debug("t_balanced_to_quiet: %u ms\n", data->t_balanced_to_quiet);
4762306a36Sopenharmony_ci	pr_debug("t_perf_to_balanced: %u ms\n", data->t_perf_to_balanced);
4862306a36Sopenharmony_ci	pr_debug("t_turbo_to_perf: %u ms\n", data->t_turbo_to_perf);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	for (i = 0 ; i < CNQF_MODE_MAX ; i++) {
5162306a36Sopenharmony_ci		pr_debug("pfloor_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].pfloor);
5262306a36Sopenharmony_ci		pr_debug("fppt_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].fppt);
5362306a36Sopenharmony_ci		pr_debug("sppt_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].sppt);
5462306a36Sopenharmony_ci		pr_debug("sppt_apuonly_%s: %u mW\n",
5562306a36Sopenharmony_ci			 state_as_str_cnqf(i), data->ps[i].sppt_apu_only);
5662306a36Sopenharmony_ci		pr_debug("spl_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].spl);
5762306a36Sopenharmony_ci		pr_debug("stt_minlimit_%s: %u mW\n",
5862306a36Sopenharmony_ci			 state_as_str_cnqf(i), data->ps[i].stt_min_limit);
5962306a36Sopenharmony_ci		pr_debug("stt_skintemp_apu_%s: %u C\n", state_as_str_cnqf(i),
6062306a36Sopenharmony_ci			 data->ps[i].stt_skintemp[STT_TEMP_APU]);
6162306a36Sopenharmony_ci		pr_debug("stt_skintemp_hs2_%s: %u C\n", state_as_str_cnqf(i),
6262306a36Sopenharmony_ci			 data->ps[i].stt_skintemp[STT_TEMP_HS2]);
6362306a36Sopenharmony_ci		pr_debug("fan_id_%s: %u\n", state_as_str_cnqf(i), data->ps[i].fan_id);
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	pr_debug("Dynamic Slider %s Defaults - END\n", idx ? "DC" : "AC");
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci#else
6962306a36Sopenharmony_cistatic void amd_pmf_cnqf_dump_defaults(struct apmf_dyn_slider_output *data, int idx) {}
7062306a36Sopenharmony_ci#endif
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic int amd_pmf_set_cnqf(struct amd_pmf_dev *dev, int src, int idx,
7362306a36Sopenharmony_ci			    struct cnqf_config *table)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct power_table_control *pc;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	pc = &config_store.mode_set[src][idx].power_control;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	amd_pmf_send_cmd(dev, SET_SPL, false, pc->spl, NULL);
8062306a36Sopenharmony_ci	amd_pmf_send_cmd(dev, SET_FPPT, false, pc->fppt, NULL);
8162306a36Sopenharmony_ci	amd_pmf_send_cmd(dev, SET_SPPT, false, pc->sppt, NULL);
8262306a36Sopenharmony_ci	amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pc->sppt_apu_only, NULL);
8362306a36Sopenharmony_ci	amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pc->stt_min, NULL);
8462306a36Sopenharmony_ci	amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, pc->stt_skin_temp[STT_TEMP_APU],
8562306a36Sopenharmony_ci			 NULL);
8662306a36Sopenharmony_ci	amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, pc->stt_skin_temp[STT_TEMP_HS2],
8762306a36Sopenharmony_ci			 NULL);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX))
9062306a36Sopenharmony_ci		apmf_update_fan_idx(dev,
9162306a36Sopenharmony_ci				    config_store.mode_set[src][idx].fan_control.manual,
9262306a36Sopenharmony_ci				    config_store.mode_set[src][idx].fan_control.fan_id);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	return 0;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic void amd_pmf_update_power_threshold(int src)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct cnqf_mode_settings *ts;
10062306a36Sopenharmony_ci	struct cnqf_tran_params *tp;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_QUIET];
10362306a36Sopenharmony_ci	ts = &config_store.mode_set[src][CNQF_MODE_BALANCE];
10462306a36Sopenharmony_ci	tp->power_threshold = ts->power_floor;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_TURBO];
10762306a36Sopenharmony_ci	ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE];
10862306a36Sopenharmony_ci	tp->power_threshold = ts->power_floor;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE];
11162306a36Sopenharmony_ci	ts = &config_store.mode_set[src][CNQF_MODE_BALANCE];
11262306a36Sopenharmony_ci	tp->power_threshold = ts->power_floor;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE];
11562306a36Sopenharmony_ci	ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE];
11662306a36Sopenharmony_ci	tp->power_threshold = ts->power_floor;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE];
11962306a36Sopenharmony_ci	ts = &config_store.mode_set[src][CNQF_MODE_QUIET];
12062306a36Sopenharmony_ci	tp->power_threshold = ts->power_floor;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE];
12362306a36Sopenharmony_ci	ts = &config_store.mode_set[src][CNQF_MODE_TURBO];
12462306a36Sopenharmony_ci	tp->power_threshold = ts->power_floor;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic const char *state_as_str(unsigned int state)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	switch (state) {
13062306a36Sopenharmony_ci	case CNQF_MODE_QUIET:
13162306a36Sopenharmony_ci		return "QUIET";
13262306a36Sopenharmony_ci	case CNQF_MODE_BALANCE:
13362306a36Sopenharmony_ci		return "BALANCED";
13462306a36Sopenharmony_ci	case CNQF_MODE_TURBO:
13562306a36Sopenharmony_ci		return "TURBO";
13662306a36Sopenharmony_ci	case CNQF_MODE_PERFORMANCE:
13762306a36Sopenharmony_ci		return "PERFORMANCE";
13862306a36Sopenharmony_ci	default:
13962306a36Sopenharmony_ci		return "Unknown CnQF mode";
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic int amd_pmf_cnqf_get_power_source(struct amd_pmf_dev *dev)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) &&
14662306a36Sopenharmony_ci	    is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC))
14762306a36Sopenharmony_ci		return amd_pmf_get_power_source();
14862306a36Sopenharmony_ci	else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC))
14962306a36Sopenharmony_ci		return POWER_SOURCE_DC;
15062306a36Sopenharmony_ci	else
15162306a36Sopenharmony_ci		return POWER_SOURCE_AC;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ciint amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_lapsed_ms)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	struct cnqf_tran_params *tp;
15762306a36Sopenharmony_ci	int src, i, j;
15862306a36Sopenharmony_ci	u32 avg_power = 0;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	src = amd_pmf_cnqf_get_power_source(dev);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	if (is_pprof_balanced(dev)) {
16362306a36Sopenharmony_ci		amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL);
16462306a36Sopenharmony_ci	} else {
16562306a36Sopenharmony_ci		/*
16662306a36Sopenharmony_ci		 * Return from here if the platform_profile is not balanced
16762306a36Sopenharmony_ci		 * so that preference is given to user mode selection, rather
16862306a36Sopenharmony_ci		 * than enforcing CnQF to run all the time (if enabled)
16962306a36Sopenharmony_ci		 */
17062306a36Sopenharmony_ci		return -EINVAL;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	for (i = 0; i < CNQF_TRANSITION_MAX; i++) {
17462306a36Sopenharmony_ci		config_store.trans_param[src][i].timer += time_lapsed_ms;
17562306a36Sopenharmony_ci		config_store.trans_param[src][i].total_power += socket_power;
17662306a36Sopenharmony_ci		config_store.trans_param[src][i].count++;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci		tp = &config_store.trans_param[src][i];
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci#ifdef CONFIG_AMD_PMF_DEBUG
18162306a36Sopenharmony_ci		dev_dbg(dev->dev, "avg_power: %u mW total_power: %u mW count: %u timer: %u ms\n",
18262306a36Sopenharmony_ci			avg_power, config_store.trans_param[src][i].total_power,
18362306a36Sopenharmony_ci			config_store.trans_param[src][i].count,
18462306a36Sopenharmony_ci			config_store.trans_param[src][i].timer);
18562306a36Sopenharmony_ci#endif
18662306a36Sopenharmony_ci		if (tp->timer >= tp->time_constant && tp->count) {
18762306a36Sopenharmony_ci			avg_power = tp->total_power / tp->count;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci			/* Reset the indices */
19062306a36Sopenharmony_ci			tp->timer = 0;
19162306a36Sopenharmony_ci			tp->total_power = 0;
19262306a36Sopenharmony_ci			tp->count = 0;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci			if ((tp->shifting_up && avg_power >= tp->power_threshold) ||
19562306a36Sopenharmony_ci			    (!tp->shifting_up && avg_power <= tp->power_threshold)) {
19662306a36Sopenharmony_ci				tp->priority = true;
19762306a36Sopenharmony_ci			} else {
19862306a36Sopenharmony_ci				tp->priority = false;
19962306a36Sopenharmony_ci			}
20062306a36Sopenharmony_ci		}
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	dev_dbg(dev->dev, "[CNQF] Avg power: %u mW socket power: %u mW mode:%s\n",
20462306a36Sopenharmony_ci		avg_power, socket_power, state_as_str(config_store.current_mode));
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci#ifdef CONFIG_AMD_PMF_DEBUG
20762306a36Sopenharmony_ci	dev_dbg(dev->dev, "[CNQF] priority1: %u priority2: %u priority3: %u\n",
20862306a36Sopenharmony_ci		config_store.trans_param[src][0].priority,
20962306a36Sopenharmony_ci		config_store.trans_param[src][1].priority,
21062306a36Sopenharmony_ci		config_store.trans_param[src][2].priority);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	dev_dbg(dev->dev, "[CNQF] priority4: %u priority5: %u priority6: %u\n",
21362306a36Sopenharmony_ci		config_store.trans_param[src][3].priority,
21462306a36Sopenharmony_ci		config_store.trans_param[src][4].priority,
21562306a36Sopenharmony_ci		config_store.trans_param[src][5].priority);
21662306a36Sopenharmony_ci#endif
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	for (j = 0; j < CNQF_TRANSITION_MAX; j++) {
21962306a36Sopenharmony_ci		/* apply the highest priority */
22062306a36Sopenharmony_ci		if (config_store.trans_param[src][j].priority) {
22162306a36Sopenharmony_ci			if (config_store.current_mode !=
22262306a36Sopenharmony_ci			    config_store.trans_param[src][j].target_mode) {
22362306a36Sopenharmony_ci				config_store.current_mode =
22462306a36Sopenharmony_ci						config_store.trans_param[src][j].target_mode;
22562306a36Sopenharmony_ci				dev_dbg(dev->dev, "Moving to Mode :%s\n",
22662306a36Sopenharmony_ci					state_as_str(config_store.current_mode));
22762306a36Sopenharmony_ci				amd_pmf_set_cnqf(dev, src,
22862306a36Sopenharmony_ci						 config_store.current_mode, NULL);
22962306a36Sopenharmony_ci			}
23062306a36Sopenharmony_ci			break;
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci	return 0;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic void amd_pmf_update_trans_data(int idx, struct apmf_dyn_slider_output *out)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	struct cnqf_tran_params *tp;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_QUIET];
24162306a36Sopenharmony_ci	tp->time_constant = out->t_balanced_to_quiet;
24262306a36Sopenharmony_ci	tp->target_mode = CNQF_MODE_QUIET;
24362306a36Sopenharmony_ci	tp->shifting_up = false;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE];
24662306a36Sopenharmony_ci	tp->time_constant = out->t_balanced_to_perf;
24762306a36Sopenharmony_ci	tp->target_mode = CNQF_MODE_PERFORMANCE;
24862306a36Sopenharmony_ci	tp->shifting_up = true;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE];
25162306a36Sopenharmony_ci	tp->time_constant = out->t_quiet_to_balanced;
25262306a36Sopenharmony_ci	tp->target_mode = CNQF_MODE_BALANCE;
25362306a36Sopenharmony_ci	tp->shifting_up = true;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE];
25662306a36Sopenharmony_ci	tp->time_constant = out->t_perf_to_balanced;
25762306a36Sopenharmony_ci	tp->target_mode = CNQF_MODE_BALANCE;
25862306a36Sopenharmony_ci	tp->shifting_up = false;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE];
26162306a36Sopenharmony_ci	tp->time_constant = out->t_turbo_to_perf;
26262306a36Sopenharmony_ci	tp->target_mode = CNQF_MODE_PERFORMANCE;
26362306a36Sopenharmony_ci	tp->shifting_up = false;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_TURBO];
26662306a36Sopenharmony_ci	tp->time_constant = out->t_perf_to_turbo;
26762306a36Sopenharmony_ci	tp->target_mode = CNQF_MODE_TURBO;
26862306a36Sopenharmony_ci	tp->shifting_up = true;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic void amd_pmf_update_mode_set(int idx, struct apmf_dyn_slider_output *out)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct cnqf_mode_settings *ms;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* Quiet Mode */
27662306a36Sopenharmony_ci	ms = &config_store.mode_set[idx][CNQF_MODE_QUIET];
27762306a36Sopenharmony_ci	ms->power_floor = out->ps[APMF_CNQF_QUIET].pfloor;
27862306a36Sopenharmony_ci	ms->power_control.fppt = out->ps[APMF_CNQF_QUIET].fppt;
27962306a36Sopenharmony_ci	ms->power_control.sppt = out->ps[APMF_CNQF_QUIET].sppt;
28062306a36Sopenharmony_ci	ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_QUIET].sppt_apu_only;
28162306a36Sopenharmony_ci	ms->power_control.spl = out->ps[APMF_CNQF_QUIET].spl;
28262306a36Sopenharmony_ci	ms->power_control.stt_min = out->ps[APMF_CNQF_QUIET].stt_min_limit;
28362306a36Sopenharmony_ci	ms->power_control.stt_skin_temp[STT_TEMP_APU] =
28462306a36Sopenharmony_ci		out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_APU];
28562306a36Sopenharmony_ci	ms->power_control.stt_skin_temp[STT_TEMP_HS2] =
28662306a36Sopenharmony_ci		out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_HS2];
28762306a36Sopenharmony_ci	ms->fan_control.fan_id = out->ps[APMF_CNQF_QUIET].fan_id;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	/* Balance Mode */
29062306a36Sopenharmony_ci	ms = &config_store.mode_set[idx][CNQF_MODE_BALANCE];
29162306a36Sopenharmony_ci	ms->power_floor = out->ps[APMF_CNQF_BALANCE].pfloor;
29262306a36Sopenharmony_ci	ms->power_control.fppt = out->ps[APMF_CNQF_BALANCE].fppt;
29362306a36Sopenharmony_ci	ms->power_control.sppt = out->ps[APMF_CNQF_BALANCE].sppt;
29462306a36Sopenharmony_ci	ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_BALANCE].sppt_apu_only;
29562306a36Sopenharmony_ci	ms->power_control.spl = out->ps[APMF_CNQF_BALANCE].spl;
29662306a36Sopenharmony_ci	ms->power_control.stt_min = out->ps[APMF_CNQF_BALANCE].stt_min_limit;
29762306a36Sopenharmony_ci	ms->power_control.stt_skin_temp[STT_TEMP_APU] =
29862306a36Sopenharmony_ci		out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_APU];
29962306a36Sopenharmony_ci	ms->power_control.stt_skin_temp[STT_TEMP_HS2] =
30062306a36Sopenharmony_ci		out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_HS2];
30162306a36Sopenharmony_ci	ms->fan_control.fan_id = out->ps[APMF_CNQF_BALANCE].fan_id;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	/* Performance Mode */
30462306a36Sopenharmony_ci	ms = &config_store.mode_set[idx][CNQF_MODE_PERFORMANCE];
30562306a36Sopenharmony_ci	ms->power_floor = out->ps[APMF_CNQF_PERFORMANCE].pfloor;
30662306a36Sopenharmony_ci	ms->power_control.fppt = out->ps[APMF_CNQF_PERFORMANCE].fppt;
30762306a36Sopenharmony_ci	ms->power_control.sppt = out->ps[APMF_CNQF_PERFORMANCE].sppt;
30862306a36Sopenharmony_ci	ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_PERFORMANCE].sppt_apu_only;
30962306a36Sopenharmony_ci	ms->power_control.spl = out->ps[APMF_CNQF_PERFORMANCE].spl;
31062306a36Sopenharmony_ci	ms->power_control.stt_min = out->ps[APMF_CNQF_PERFORMANCE].stt_min_limit;
31162306a36Sopenharmony_ci	ms->power_control.stt_skin_temp[STT_TEMP_APU] =
31262306a36Sopenharmony_ci		out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_APU];
31362306a36Sopenharmony_ci	ms->power_control.stt_skin_temp[STT_TEMP_HS2] =
31462306a36Sopenharmony_ci		out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_HS2];
31562306a36Sopenharmony_ci	ms->fan_control.fan_id = out->ps[APMF_CNQF_PERFORMANCE].fan_id;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/* Turbo Mode */
31862306a36Sopenharmony_ci	ms = &config_store.mode_set[idx][CNQF_MODE_TURBO];
31962306a36Sopenharmony_ci	ms->power_floor = out->ps[APMF_CNQF_TURBO].pfloor;
32062306a36Sopenharmony_ci	ms->power_control.fppt = out->ps[APMF_CNQF_TURBO].fppt;
32162306a36Sopenharmony_ci	ms->power_control.sppt = out->ps[APMF_CNQF_TURBO].sppt;
32262306a36Sopenharmony_ci	ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_TURBO].sppt_apu_only;
32362306a36Sopenharmony_ci	ms->power_control.spl = out->ps[APMF_CNQF_TURBO].spl;
32462306a36Sopenharmony_ci	ms->power_control.stt_min = out->ps[APMF_CNQF_TURBO].stt_min_limit;
32562306a36Sopenharmony_ci	ms->power_control.stt_skin_temp[STT_TEMP_APU] =
32662306a36Sopenharmony_ci		out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_APU];
32762306a36Sopenharmony_ci	ms->power_control.stt_skin_temp[STT_TEMP_HS2] =
32862306a36Sopenharmony_ci		out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_HS2];
32962306a36Sopenharmony_ci	ms->fan_control.fan_id = out->ps[APMF_CNQF_TURBO].fan_id;
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic int amd_pmf_check_flags(struct amd_pmf_dev *dev)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	struct apmf_dyn_slider_output out = {};
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC))
33762306a36Sopenharmony_ci		apmf_get_dyn_slider_def_ac(dev, &out);
33862306a36Sopenharmony_ci	else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC))
33962306a36Sopenharmony_ci		apmf_get_dyn_slider_def_dc(dev, &out);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	return out.flags;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic int amd_pmf_load_defaults_cnqf(struct amd_pmf_dev *dev)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct apmf_dyn_slider_output out;
34762306a36Sopenharmony_ci	int i, j, ret;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	for (i = 0; i < POWER_SOURCE_MAX; i++) {
35062306a36Sopenharmony_ci		if (!is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC + i))
35162306a36Sopenharmony_ci			continue;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci		if (i == POWER_SOURCE_AC)
35462306a36Sopenharmony_ci			ret = apmf_get_dyn_slider_def_ac(dev, &out);
35562306a36Sopenharmony_ci		else
35662306a36Sopenharmony_ci			ret = apmf_get_dyn_slider_def_dc(dev, &out);
35762306a36Sopenharmony_ci		if (ret) {
35862306a36Sopenharmony_ci			dev_err(dev->dev, "APMF apmf_get_dyn_slider_def_dc failed :%d\n", ret);
35962306a36Sopenharmony_ci			return ret;
36062306a36Sopenharmony_ci		}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci		amd_pmf_cnqf_dump_defaults(&out, i);
36362306a36Sopenharmony_ci		amd_pmf_update_mode_set(i, &out);
36462306a36Sopenharmony_ci		amd_pmf_update_trans_data(i, &out);
36562306a36Sopenharmony_ci		amd_pmf_update_power_threshold(i);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		for (j = 0; j < CNQF_MODE_MAX; j++) {
36862306a36Sopenharmony_ci			if (config_store.mode_set[i][j].fan_control.fan_id == FAN_INDEX_AUTO)
36962306a36Sopenharmony_ci				config_store.mode_set[i][j].fan_control.manual = false;
37062306a36Sopenharmony_ci			else
37162306a36Sopenharmony_ci				config_store.mode_set[i][j].fan_control.manual = true;
37262306a36Sopenharmony_ci		}
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/* set to initial default values */
37662306a36Sopenharmony_ci	config_store.current_mode = CNQF_MODE_BALANCE;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	return 0;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic ssize_t cnqf_enable_store(struct device *dev,
38262306a36Sopenharmony_ci				 struct device_attribute *attr,
38362306a36Sopenharmony_ci				 const char *buf, size_t count)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
38662306a36Sopenharmony_ci	int result, src;
38762306a36Sopenharmony_ci	bool input;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	result = kstrtobool(buf, &input);
39062306a36Sopenharmony_ci	if (result)
39162306a36Sopenharmony_ci		return result;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	src = amd_pmf_cnqf_get_power_source(pdev);
39462306a36Sopenharmony_ci	pdev->cnqf_enabled = input;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (pdev->cnqf_enabled && is_pprof_balanced(pdev)) {
39762306a36Sopenharmony_ci		amd_pmf_set_cnqf(pdev, src, config_store.current_mode, NULL);
39862306a36Sopenharmony_ci	} else {
39962306a36Sopenharmony_ci		if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
40062306a36Sopenharmony_ci			amd_pmf_set_sps_power_limits(pdev);
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	dev_dbg(pdev->dev, "Received CnQF %s\n", str_on_off(input));
40462306a36Sopenharmony_ci	return count;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic ssize_t cnqf_enable_show(struct device *dev,
40862306a36Sopenharmony_ci				struct device_attribute *attr,
40962306a36Sopenharmony_ci				char *buf)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", str_on_off(pdev->cnqf_enabled));
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic DEVICE_ATTR_RW(cnqf_enable);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic umode_t cnqf_feature_is_visible(struct kobject *kobj,
41962306a36Sopenharmony_ci				       struct attribute *attr, int n)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
42262306a36Sopenharmony_ci	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return pdev->cnqf_supported ? attr->mode : 0;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic struct attribute *cnqf_feature_attrs[] = {
42862306a36Sopenharmony_ci	&dev_attr_cnqf_enable.attr,
42962306a36Sopenharmony_ci	NULL
43062306a36Sopenharmony_ci};
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ciconst struct attribute_group cnqf_feature_attribute_group = {
43362306a36Sopenharmony_ci	.is_visible = cnqf_feature_is_visible,
43462306a36Sopenharmony_ci	.attrs = cnqf_feature_attrs,
43562306a36Sopenharmony_ci};
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_civoid amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	cancel_delayed_work_sync(&dev->work_buffer);
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ciint amd_pmf_init_cnqf(struct amd_pmf_dev *dev)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	int ret, src;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	/*
44762306a36Sopenharmony_ci	 * Note the caller of this function has already checked that both
44862306a36Sopenharmony_ci	 * APMF_FUNC_DYN_SLIDER_AC and APMF_FUNC_DYN_SLIDER_DC are supported.
44962306a36Sopenharmony_ci	 */
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	ret = amd_pmf_load_defaults_cnqf(dev);
45262306a36Sopenharmony_ci	if (ret < 0)
45362306a36Sopenharmony_ci		return ret;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	amd_pmf_init_metrics_table(dev);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	dev->cnqf_supported = true;
45862306a36Sopenharmony_ci	dev->cnqf_enabled = amd_pmf_check_flags(dev);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	/* update the thermal for CnQF */
46162306a36Sopenharmony_ci	if (dev->cnqf_enabled && is_pprof_balanced(dev)) {
46262306a36Sopenharmony_ci		src = amd_pmf_cnqf_get_power_source(dev);
46362306a36Sopenharmony_ci		amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL);
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	return 0;
46762306a36Sopenharmony_ci}
468