162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AMD Platform Management Framework (PMF) 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 "pmf.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic struct amd_pmf_static_slider_granular config_store;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#ifdef CONFIG_AMD_PMF_DEBUG
1662306a36Sopenharmony_cistatic const char *slider_as_str(unsigned int state)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	switch (state) {
1962306a36Sopenharmony_ci	case POWER_MODE_PERFORMANCE:
2062306a36Sopenharmony_ci		return "PERFORMANCE";
2162306a36Sopenharmony_ci	case POWER_MODE_BALANCED_POWER:
2262306a36Sopenharmony_ci		return "BALANCED_POWER";
2362306a36Sopenharmony_ci	case POWER_MODE_POWER_SAVER:
2462306a36Sopenharmony_ci		return "POWER_SAVER";
2562306a36Sopenharmony_ci	default:
2662306a36Sopenharmony_ci		return "Unknown Slider State";
2762306a36Sopenharmony_ci	}
2862306a36Sopenharmony_ci}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic const char *source_as_str(unsigned int state)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	switch (state) {
3362306a36Sopenharmony_ci	case POWER_SOURCE_AC:
3462306a36Sopenharmony_ci		return "AC";
3562306a36Sopenharmony_ci	case POWER_SOURCE_DC:
3662306a36Sopenharmony_ci		return "DC";
3762306a36Sopenharmony_ci	default:
3862306a36Sopenharmony_ci		return "Unknown Power State";
3962306a36Sopenharmony_ci	}
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic void amd_pmf_dump_sps_defaults(struct amd_pmf_static_slider_granular *data)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	int i, j;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	pr_debug("Static Slider Data - BEGIN\n");
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	for (i = 0; i < POWER_SOURCE_MAX; i++) {
4962306a36Sopenharmony_ci		for (j = 0; j < POWER_MODE_MAX; j++) {
5062306a36Sopenharmony_ci			pr_debug("--- Source:%s Mode:%s ---\n", source_as_str(i), slider_as_str(j));
5162306a36Sopenharmony_ci			pr_debug("SPL: %u mW\n", data->prop[i][j].spl);
5262306a36Sopenharmony_ci			pr_debug("SPPT: %u mW\n", data->prop[i][j].sppt);
5362306a36Sopenharmony_ci			pr_debug("SPPT_ApuOnly: %u mW\n", data->prop[i][j].sppt_apu_only);
5462306a36Sopenharmony_ci			pr_debug("FPPT: %u mW\n", data->prop[i][j].fppt);
5562306a36Sopenharmony_ci			pr_debug("STTMinLimit: %u mW\n", data->prop[i][j].stt_min);
5662306a36Sopenharmony_ci			pr_debug("STT_SkinTempLimit_APU: %u C\n",
5762306a36Sopenharmony_ci				 data->prop[i][j].stt_skin_temp[STT_TEMP_APU]);
5862306a36Sopenharmony_ci			pr_debug("STT_SkinTempLimit_HS2: %u C\n",
5962306a36Sopenharmony_ci				 data->prop[i][j].stt_skin_temp[STT_TEMP_HS2]);
6062306a36Sopenharmony_ci		}
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	pr_debug("Static Slider Data - END\n");
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci#else
6662306a36Sopenharmony_cistatic void amd_pmf_dump_sps_defaults(struct amd_pmf_static_slider_granular *data) {}
6762306a36Sopenharmony_ci#endif
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic void amd_pmf_load_defaults_sps(struct amd_pmf_dev *dev)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	struct apmf_static_slider_granular_output output;
7262306a36Sopenharmony_ci	int i, j, idx = 0;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	memset(&config_store, 0, sizeof(config_store));
7562306a36Sopenharmony_ci	apmf_get_static_slider_granular(dev, &output);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	for (i = 0; i < POWER_SOURCE_MAX; i++) {
7862306a36Sopenharmony_ci		for (j = 0; j < POWER_MODE_MAX; j++) {
7962306a36Sopenharmony_ci			config_store.prop[i][j].spl = output.prop[idx].spl;
8062306a36Sopenharmony_ci			config_store.prop[i][j].sppt = output.prop[idx].sppt;
8162306a36Sopenharmony_ci			config_store.prop[i][j].sppt_apu_only =
8262306a36Sopenharmony_ci						output.prop[idx].sppt_apu_only;
8362306a36Sopenharmony_ci			config_store.prop[i][j].fppt = output.prop[idx].fppt;
8462306a36Sopenharmony_ci			config_store.prop[i][j].stt_min = output.prop[idx].stt_min;
8562306a36Sopenharmony_ci			config_store.prop[i][j].stt_skin_temp[STT_TEMP_APU] =
8662306a36Sopenharmony_ci					output.prop[idx].stt_skin_temp[STT_TEMP_APU];
8762306a36Sopenharmony_ci			config_store.prop[i][j].stt_skin_temp[STT_TEMP_HS2] =
8862306a36Sopenharmony_ci					output.prop[idx].stt_skin_temp[STT_TEMP_HS2];
8962306a36Sopenharmony_ci			config_store.prop[i][j].fan_id = output.prop[idx].fan_id;
9062306a36Sopenharmony_ci			idx++;
9162306a36Sopenharmony_ci		}
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci	amd_pmf_dump_sps_defaults(&config_store);
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_civoid amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx,
9762306a36Sopenharmony_ci			   struct amd_pmf_static_slider_granular *table)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	int src = amd_pmf_get_power_source();
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (op == SLIDER_OP_SET) {
10262306a36Sopenharmony_ci		amd_pmf_send_cmd(dev, SET_SPL, false, config_store.prop[src][idx].spl, NULL);
10362306a36Sopenharmony_ci		amd_pmf_send_cmd(dev, SET_FPPT, false, config_store.prop[src][idx].fppt, NULL);
10462306a36Sopenharmony_ci		amd_pmf_send_cmd(dev, SET_SPPT, false, config_store.prop[src][idx].sppt, NULL);
10562306a36Sopenharmony_ci		amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false,
10662306a36Sopenharmony_ci				 config_store.prop[src][idx].sppt_apu_only, NULL);
10762306a36Sopenharmony_ci		amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false,
10862306a36Sopenharmony_ci				 config_store.prop[src][idx].stt_min, NULL);
10962306a36Sopenharmony_ci		amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
11062306a36Sopenharmony_ci				 config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU], NULL);
11162306a36Sopenharmony_ci		amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
11262306a36Sopenharmony_ci				 config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2], NULL);
11362306a36Sopenharmony_ci	} else if (op == SLIDER_OP_GET) {
11462306a36Sopenharmony_ci		amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl);
11562306a36Sopenharmony_ci		amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt);
11662306a36Sopenharmony_ci		amd_pmf_send_cmd(dev, GET_SPPT, true, ARG_NONE, &table->prop[src][idx].sppt);
11762306a36Sopenharmony_ci		amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, true, ARG_NONE,
11862306a36Sopenharmony_ci				 &table->prop[src][idx].sppt_apu_only);
11962306a36Sopenharmony_ci		amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, true, ARG_NONE,
12062306a36Sopenharmony_ci				 &table->prop[src][idx].stt_min);
12162306a36Sopenharmony_ci		amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, true, ARG_NONE,
12262306a36Sopenharmony_ci				 (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_APU]);
12362306a36Sopenharmony_ci		amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, true, ARG_NONE,
12462306a36Sopenharmony_ci				 (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_HS2]);
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ciint amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	int mode;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	mode = amd_pmf_get_pprof_modes(pmf);
13362306a36Sopenharmony_ci	if (mode < 0)
13462306a36Sopenharmony_ci		return mode;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return 0;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cibool is_pprof_balanced(struct amd_pmf_dev *pmf)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	return (pmf->current_profile == PLATFORM_PROFILE_BALANCED) ? true : false;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic int amd_pmf_profile_get(struct platform_profile_handler *pprof,
14762306a36Sopenharmony_ci			       enum platform_profile_option *profile)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	*profile = pmf->current_profile;
15262306a36Sopenharmony_ci	return 0;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ciint amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	int mode;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	switch (pmf->current_profile) {
16062306a36Sopenharmony_ci	case PLATFORM_PROFILE_PERFORMANCE:
16162306a36Sopenharmony_ci		mode = POWER_MODE_PERFORMANCE;
16262306a36Sopenharmony_ci		break;
16362306a36Sopenharmony_ci	case PLATFORM_PROFILE_BALANCED:
16462306a36Sopenharmony_ci		mode = POWER_MODE_BALANCED_POWER;
16562306a36Sopenharmony_ci		break;
16662306a36Sopenharmony_ci	case PLATFORM_PROFILE_LOW_POWER:
16762306a36Sopenharmony_ci		mode = POWER_MODE_POWER_SAVER;
16862306a36Sopenharmony_ci		break;
16962306a36Sopenharmony_ci	default:
17062306a36Sopenharmony_ci		dev_err(pmf->dev, "Unknown Platform Profile.\n");
17162306a36Sopenharmony_ci		return -EOPNOTSUPP;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	return mode;
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ciint amd_pmf_power_slider_update_event(struct amd_pmf_dev *dev)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	u8 flag = 0;
18062306a36Sopenharmony_ci	int mode;
18162306a36Sopenharmony_ci	int src;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	mode = amd_pmf_get_pprof_modes(dev);
18462306a36Sopenharmony_ci	if (mode < 0)
18562306a36Sopenharmony_ci		return mode;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	src = amd_pmf_get_power_source();
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	if (src == POWER_SOURCE_AC) {
19062306a36Sopenharmony_ci		switch (mode) {
19162306a36Sopenharmony_ci		case POWER_MODE_PERFORMANCE:
19262306a36Sopenharmony_ci			flag |= BIT(AC_BEST_PERF);
19362306a36Sopenharmony_ci			break;
19462306a36Sopenharmony_ci		case POWER_MODE_BALANCED_POWER:
19562306a36Sopenharmony_ci			flag |= BIT(AC_BETTER_PERF);
19662306a36Sopenharmony_ci			break;
19762306a36Sopenharmony_ci		case POWER_MODE_POWER_SAVER:
19862306a36Sopenharmony_ci			flag |= BIT(AC_BETTER_BATTERY);
19962306a36Sopenharmony_ci			break;
20062306a36Sopenharmony_ci		default:
20162306a36Sopenharmony_ci			dev_err(dev->dev, "unsupported platform profile\n");
20262306a36Sopenharmony_ci			return -EOPNOTSUPP;
20362306a36Sopenharmony_ci		}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	} else if (src == POWER_SOURCE_DC) {
20662306a36Sopenharmony_ci		switch (mode) {
20762306a36Sopenharmony_ci		case POWER_MODE_PERFORMANCE:
20862306a36Sopenharmony_ci			flag |= BIT(DC_BEST_PERF);
20962306a36Sopenharmony_ci			break;
21062306a36Sopenharmony_ci		case POWER_MODE_BALANCED_POWER:
21162306a36Sopenharmony_ci			flag |= BIT(DC_BETTER_PERF);
21262306a36Sopenharmony_ci			break;
21362306a36Sopenharmony_ci		case POWER_MODE_POWER_SAVER:
21462306a36Sopenharmony_ci			flag |= BIT(DC_BATTERY_SAVER);
21562306a36Sopenharmony_ci			break;
21662306a36Sopenharmony_ci		default:
21762306a36Sopenharmony_ci			dev_err(dev->dev, "unsupported platform profile\n");
21862306a36Sopenharmony_ci			return -EOPNOTSUPP;
21962306a36Sopenharmony_ci		}
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	apmf_os_power_slider_update(dev, flag);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	return 0;
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic int amd_pmf_profile_set(struct platform_profile_handler *pprof,
22862306a36Sopenharmony_ci			       enum platform_profile_option profile)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof);
23162306a36Sopenharmony_ci	int ret = 0;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	pmf->current_profile = profile;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	/* Notify EC about the slider position change */
23662306a36Sopenharmony_ci	if (is_apmf_func_supported(pmf, APMF_FUNC_OS_POWER_SLIDER_UPDATE)) {
23762306a36Sopenharmony_ci		ret = amd_pmf_power_slider_update_event(pmf);
23862306a36Sopenharmony_ci		if (ret)
23962306a36Sopenharmony_ci			return ret;
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	if (is_apmf_func_supported(pmf, APMF_FUNC_STATIC_SLIDER_GRANULAR)) {
24362306a36Sopenharmony_ci		ret = amd_pmf_set_sps_power_limits(pmf);
24462306a36Sopenharmony_ci		if (ret)
24562306a36Sopenharmony_ci			return ret;
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	return 0;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ciint amd_pmf_init_sps(struct amd_pmf_dev *dev)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	int err;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	dev->current_profile = PLATFORM_PROFILE_BALANCED;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) {
25862306a36Sopenharmony_ci		amd_pmf_load_defaults_sps(dev);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci		/* update SPS balanced power mode thermals */
26162306a36Sopenharmony_ci		amd_pmf_set_sps_power_limits(dev);
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	dev->pprof.profile_get = amd_pmf_profile_get;
26562306a36Sopenharmony_ci	dev->pprof.profile_set = amd_pmf_profile_set;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	/* Setup supported modes */
26862306a36Sopenharmony_ci	set_bit(PLATFORM_PROFILE_LOW_POWER, dev->pprof.choices);
26962306a36Sopenharmony_ci	set_bit(PLATFORM_PROFILE_BALANCED, dev->pprof.choices);
27062306a36Sopenharmony_ci	set_bit(PLATFORM_PROFILE_PERFORMANCE, dev->pprof.choices);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* Create platform_profile structure and register */
27362306a36Sopenharmony_ci	err = platform_profile_register(&dev->pprof);
27462306a36Sopenharmony_ci	if (err)
27562306a36Sopenharmony_ci		dev_err(dev->dev, "Failed to register SPS support, this is most likely an SBIOS bug: %d\n",
27662306a36Sopenharmony_ci			err);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return err;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_civoid amd_pmf_deinit_sps(struct amd_pmf_dev *dev)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	platform_profile_remove();
28462306a36Sopenharmony_ci}
285