Commit d5a4dfc3 authored by Hans de Goede's avatar Hans de Goede

Merge branch 'platform-drivers-x86-amd-pmf' into pdx86-base

parents 568035b0 ea522b80
...@@ -1022,6 +1022,12 @@ L: platform-driver-x86@vger.kernel.org ...@@ -1022,6 +1022,12 @@ L: platform-driver-x86@vger.kernel.org
S: Maintained S: Maintained
F: drivers/platform/x86/amd/pmc.c F: drivers/platform/x86/amd/pmc.c
AMD PMF DRIVER
M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/amd/pmf/
AMD HSMP DRIVER AMD HSMP DRIVER
M: Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com> M: Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com>
R: Carlos Bilbao <carlos.bilbao@amd.com> R: Carlos Bilbao <carlos.bilbao@amd.com>
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
# AMD x86 Platform Specific Drivers # AMD x86 Platform Specific Drivers
# #
source "drivers/platform/x86/amd/pmf/Kconfig"
config AMD_PMC config AMD_PMC
tristate "AMD SoC PMC driver" tristate "AMD SoC PMC driver"
depends on ACPI && PCI && RTC_CLASS depends on ACPI && PCI && RTC_CLASS
......
...@@ -8,3 +8,4 @@ amd-pmc-y := pmc.o ...@@ -8,3 +8,4 @@ amd-pmc-y := pmc.o
obj-$(CONFIG_AMD_PMC) += amd-pmc.o obj-$(CONFIG_AMD_PMC) += amd-pmc.o
amd_hsmp-y := hsmp.o amd_hsmp-y := hsmp.o
obj-$(CONFIG_AMD_HSMP) += amd_hsmp.o obj-$(CONFIG_AMD_HSMP) += amd_hsmp.o
obj-$(CONFIG_AMD_PMF) += pmf/
# SPDX-License-Identifier: GPL-2.0-only
#
# AMD PMF Driver
#
config AMD_PMF
tristate "AMD Platform Management Framework"
depends on ACPI && PCI
select ACPI_PLATFORM_PROFILE
help
This driver provides support for the AMD Platform Management Framework.
The goal is to enhance end user experience by making AMD PCs smarter,
quiter, power efficient by adapting to user behavior and environment.
To compile this driver as a module, choose M here: the module will
be called amd_pmf.
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for linux/drivers/platform/x86/amd/pmf
# AMD Platform Management Framework
#
obj-$(CONFIG_AMD_PMF) += amd-pmf.o
amd-pmf-objs := core.o acpi.o sps.o \
auto-mode.o
// SPDX-License-Identifier: GPL-2.0
/*
* AMD Platform Management Framework Driver
*
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
*/
#include <linux/acpi.h>
#include "pmf.h"
#define APMF_CQL_NOTIFICATION 2
#define APMF_AMT_NOTIFICATION 3
static union acpi_object *apmf_if_call(struct amd_pmf_dev *pdev, int fn, struct acpi_buffer *param)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_handle ahandle = ACPI_HANDLE(pdev->dev);
struct acpi_object_list apmf_if_arg_list;
union acpi_object apmf_if_args[2];
acpi_status status;
apmf_if_arg_list.count = 2;
apmf_if_arg_list.pointer = &apmf_if_args[0];
apmf_if_args[0].type = ACPI_TYPE_INTEGER;
apmf_if_args[0].integer.value = fn;
if (param) {
apmf_if_args[1].type = ACPI_TYPE_BUFFER;
apmf_if_args[1].buffer.length = param->length;
apmf_if_args[1].buffer.pointer = param->pointer;
} else {
apmf_if_args[1].type = ACPI_TYPE_INTEGER;
apmf_if_args[1].integer.value = 0;
}
status = acpi_evaluate_object(ahandle, "APMF", &apmf_if_arg_list, &buffer);
if (ACPI_FAILURE(status)) {
dev_err(pdev->dev, "APMF method:%d call failed\n", fn);
kfree(buffer.pointer);
return NULL;
}
return buffer.pointer;
}
static int apmf_if_call_store_buffer(struct amd_pmf_dev *pdev, int fn, void *dest, size_t out_sz)
{
union acpi_object *info;
size_t size;
int err = 0;
info = apmf_if_call(pdev, fn, NULL);
if (!info)
return -EIO;
if (info->type != ACPI_TYPE_BUFFER) {
dev_err(pdev->dev, "object is not a buffer\n");
err = -EINVAL;
goto out;
}
if (info->buffer.length < 2) {
dev_err(pdev->dev, "buffer too small\n");
err = -EINVAL;
goto out;
}
size = *(u16 *)info->buffer.pointer;
if (info->buffer.length < size) {
dev_err(pdev->dev, "buffer smaller then headersize %u < %zu\n",
info->buffer.length, size);
err = -EINVAL;
goto out;
}
if (size < out_sz) {
dev_err(pdev->dev, "buffer too small %zu\n", size);
err = -EINVAL;
goto out;
}
memcpy(dest, info->buffer.pointer, out_sz);
out:
kfree(info);
return err;
}
int is_apmf_func_supported(struct amd_pmf_dev *pdev, unsigned long index)
{
/* If bit-n is set, that indicates function n+1 is supported */
return !!(pdev->supported_func & BIT(index - 1));
}
int apmf_get_static_slider_granular(struct amd_pmf_dev *pdev,
struct apmf_static_slider_granular_output *data)
{
if (!is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
return -EINVAL;
return apmf_if_call_store_buffer(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR,
data, sizeof(*data));
}
static void apmf_sbios_heartbeat_notify(struct work_struct *work)
{
struct amd_pmf_dev *dev = container_of(work, struct amd_pmf_dev, heart_beat.work);
union acpi_object *info;
dev_dbg(dev->dev, "Sending heartbeat to SBIOS\n");
info = apmf_if_call(dev, APMF_FUNC_SBIOS_HEARTBEAT, NULL);
if (!info)
goto out;
schedule_delayed_work(&dev->heart_beat, msecs_to_jiffies(dev->hb_interval * 1000));
out:
kfree(info);
}
int apmf_update_fan_idx(struct amd_pmf_dev *pdev, bool manual, u32 idx)
{
union acpi_object *info;
struct apmf_fan_idx args;
struct acpi_buffer params;
int err = 0;
args.size = sizeof(args);
args.fan_ctl_mode = manual;
args.fan_ctl_idx = idx;
params.length = sizeof(args);
params.pointer = (void *)&args;
info = apmf_if_call(pdev, APMF_FUNC_SET_FAN_IDX, &params);
if (!info) {
err = -EIO;
goto out;
}
out:
kfree(info);
return err;
}
int apmf_get_auto_mode_def(struct amd_pmf_dev *pdev, struct apmf_auto_mode *data)
{
return apmf_if_call_store_buffer(pdev, APMF_FUNC_AUTO_MODE, data, sizeof(*data));
}
int apmf_get_sbios_requests(struct amd_pmf_dev *pdev, struct apmf_sbios_req *req)
{
return apmf_if_call_store_buffer(pdev, APMF_FUNC_SBIOS_REQUESTS,
req, sizeof(*req));
}
static void apmf_event_handler(acpi_handle handle, u32 event, void *data)
{
struct amd_pmf_dev *pmf_dev = data;
struct apmf_sbios_req req;
int ret;
mutex_lock(&pmf_dev->update_mutex);
ret = apmf_get_sbios_requests(pmf_dev, &req);
if (ret) {
dev_err(pmf_dev->dev, "Failed to get SBIOS requests:%d\n", ret);
goto out;
}
if (req.pending_req & BIT(APMF_AMT_NOTIFICATION)) {
dev_dbg(pmf_dev->dev, "AMT is supported and notifications %s\n",
req.amt_event ? "Enabled" : "Disabled");
pmf_dev->amt_enabled = !!req.amt_event;
if (pmf_dev->amt_enabled)
amd_pmf_handle_amt(pmf_dev);
else
amd_pmf_reset_amt(pmf_dev);
}
if (req.pending_req & BIT(APMF_CQL_NOTIFICATION)) {
dev_dbg(pmf_dev->dev, "CQL is supported and notifications %s\n",
req.cql_event ? "Enabled" : "Disabled");
/* update the target mode information */
if (pmf_dev->amt_enabled)
amd_pmf_update_2_cql(pmf_dev, req.cql_event);
}
out:
mutex_unlock(&pmf_dev->update_mutex);
}
static int apmf_if_verify_interface(struct amd_pmf_dev *pdev)
{
struct apmf_verify_interface output;
int err;
err = apmf_if_call_store_buffer(pdev, APMF_FUNC_VERIFY_INTERFACE, &output, sizeof(output));
if (err)
return err;
pdev->supported_func = output.supported_functions;
dev_dbg(pdev->dev, "supported functions:0x%x notifications:0x%x\n",
output.supported_functions, output.notification_mask);
return 0;
}
static int apmf_get_system_params(struct amd_pmf_dev *dev)
{
struct apmf_system_params params;
int err;
if (!is_apmf_func_supported(dev, APMF_FUNC_GET_SYS_PARAMS))
return -EINVAL;
err = apmf_if_call_store_buffer(dev, APMF_FUNC_GET_SYS_PARAMS, &params, sizeof(params));
if (err)
return err;
dev_dbg(dev->dev, "system params mask:0x%x flags:0x%x cmd_code:0x%x heartbeat:%d\n",
params.valid_mask,
params.flags,
params.command_code,
params.heartbeat_int);
params.flags = params.flags & params.valid_mask;
dev->hb_interval = params.heartbeat_int;
return 0;
}
void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev)
{
acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev);
if (pmf_dev->hb_interval)
cancel_delayed_work_sync(&pmf_dev->heart_beat);
if (is_apmf_func_supported(pmf_dev, APMF_FUNC_AUTO_MODE) &&
is_apmf_func_supported(pmf_dev, APMF_FUNC_SBIOS_REQUESTS))
acpi_remove_notify_handler(ahandle, ACPI_ALL_NOTIFY, apmf_event_handler);
}
int apmf_acpi_init(struct amd_pmf_dev *pmf_dev)
{
acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev);
acpi_status status;
int ret;
ret = apmf_if_verify_interface(pmf_dev);
if (ret) {
dev_err(pmf_dev->dev, "APMF verify interface failed :%d\n", ret);
goto out;
}
ret = apmf_get_system_params(pmf_dev);
if (ret) {
dev_err(pmf_dev->dev, "APMF apmf_get_system_params failed :%d\n", ret);
goto out;
}
if (pmf_dev->hb_interval) {
/* send heartbeats only if the interval is not zero */
INIT_DELAYED_WORK(&pmf_dev->heart_beat, apmf_sbios_heartbeat_notify);
schedule_delayed_work(&pmf_dev->heart_beat, 0);
}
/* Install the APMF Notify handler */
if (is_apmf_func_supported(pmf_dev, APMF_FUNC_AUTO_MODE) &&
is_apmf_func_supported(pmf_dev, APMF_FUNC_SBIOS_REQUESTS)) {
status = acpi_install_notify_handler(ahandle,
ACPI_ALL_NOTIFY,
apmf_event_handler, pmf_dev);
if (ACPI_FAILURE(status)) {
dev_err(pmf_dev->dev, "failed to install notify handler\n");
return -ENODEV;
}
/* Call the handler once manually to catch up with possibly missed notifies. */
apmf_event_handler(ahandle, 0, pmf_dev);
}
out:
return ret;
}
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* AMD Platform Management Framework Driver
*
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
*/
#ifndef PMF_H
#define PMF_H
#include <linux/acpi.h>
#include <linux/platform_profile.h>
/* APMF Functions */
#define APMF_FUNC_VERIFY_INTERFACE 0
#define APMF_FUNC_GET_SYS_PARAMS 1
#define APMF_FUNC_SBIOS_REQUESTS 2
#define APMF_FUNC_SBIOS_HEARTBEAT 4
#define APMF_FUNC_AUTO_MODE 5
#define APMF_FUNC_SET_FAN_IDX 7
#define APMF_FUNC_STATIC_SLIDER_GRANULAR 9
/* Message Definitions */
#define SET_SPL 0x03 /* SPL: Sustained Power Limit */
#define SET_SPPT 0x05 /* SPPT: Slow Package Power Tracking */
#define SET_FPPT 0x07 /* FPPT: Fast Package Power Tracking */
#define GET_SPL 0x0B
#define GET_SPPT 0x0D
#define GET_FPPT 0x0F
#define SET_DRAM_ADDR_HIGH 0x14
#define SET_DRAM_ADDR_LOW 0x15
#define SET_TRANSFER_TABLE 0x16
#define SET_STT_MIN_LIMIT 0x18 /* STT: Skin Temperature Tracking */
#define SET_STT_LIMIT_APU 0x19
#define SET_STT_LIMIT_HS2 0x1A
#define SET_SPPT_APU_ONLY 0x1D
#define GET_SPPT_APU_ONLY 0x1E
#define GET_STT_MIN_LIMIT 0x1F
#define GET_STT_LIMIT_APU 0x20
#define GET_STT_LIMIT_HS2 0x21
/* Fan Index for Auto Mode */
#define FAN_INDEX_AUTO 0xFFFFFFFF
#define ARG_NONE 0
#define AVG_SAMPLE_SIZE 3
/* AMD PMF BIOS interfaces */
struct apmf_verify_interface {
u16 size;
u16 version;
u32 notification_mask;
u32 supported_functions;
} __packed;
struct apmf_system_params {
u16 size;
u32 valid_mask;
u32 flags;
u8 command_code;
u32 heartbeat_int;
} __packed;
struct apmf_sbios_req {
u16 size;
u32 pending_req;
u8 rsd;
u8 cql_event;
u8 amt_event;
u32 fppt;
u32 sppt;
u32 fppt_apu_only;
u32 spl;
u32 stt_min_limit;
u8 skin_temp_apu;
u8 skin_temp_hs2;
} __packed;
struct apmf_fan_idx {
u16 size;
u8 fan_ctl_mode;
u32 fan_ctl_idx;
} __packed;
struct smu_pmf_metrics {
u16 gfxclk_freq; /* in MHz */
u16 socclk_freq; /* in MHz */
u16 vclk_freq; /* in MHz */
u16 dclk_freq; /* in MHz */
u16 memclk_freq; /* in MHz */
u16 spare;
u16 gfx_activity; /* in Centi */
u16 uvd_activity; /* in Centi */
u16 voltage[2]; /* in mV */
u16 currents[2]; /* in mA */
u16 power[2];/* in mW */
u16 core_freq[8]; /* in MHz */
u16 core_power[8]; /* in mW */
u16 core_temp[8]; /* in centi-Celsius */
u16 l3_freq; /* in MHz */
u16 l3_temp; /* in centi-Celsius */
u16 gfx_temp; /* in centi-Celsius */
u16 soc_temp; /* in centi-Celsius */
u16 throttler_status;
u16 current_socketpower; /* in mW */
u16 stapm_orig_limit; /* in W */
u16 stapm_cur_limit; /* in W */
u32 apu_power; /* in mW */
u32 dgpu_power; /* in mW */
u16 vdd_tdc_val; /* in mA */
u16 soc_tdc_val; /* in mA */
u16 vdd_edc_val; /* in mA */
u16 soc_edcv_al; /* in mA */
u16 infra_cpu_maxfreq; /* in MHz */
u16 infra_gfx_maxfreq; /* in MHz */
u16 skin_temp; /* in centi-Celsius */
u16 device_state;
} __packed;
enum amd_stt_skin_temp {
STT_TEMP_APU,
STT_TEMP_HS2,
STT_TEMP_COUNT,
};
enum amd_slider_op {
SLIDER_OP_GET,
SLIDER_OP_SET,
};
enum power_source {
POWER_SOURCE_AC,
POWER_SOURCE_DC,
POWER_SOURCE_MAX,
};
enum power_modes {
POWER_MODE_PERFORMANCE,
POWER_MODE_BALANCED_POWER,
POWER_MODE_POWER_SAVER,
POWER_MODE_MAX,
};
struct amd_pmf_dev {
void __iomem *regbase;
void __iomem *smu_virt_addr;
void *buf;
u32 base_addr;
u32 cpu_id;
struct device *dev;
struct mutex lock; /* protects the PMF interface */
u32 supported_func;
enum platform_profile_option current_profile;
struct platform_profile_handler pprof;
struct dentry *dbgfs_dir;
int hb_interval; /* SBIOS heartbeat interval */
struct delayed_work heart_beat;
struct smu_pmf_metrics m_table;
struct delayed_work work_buffer;
ktime_t start_time;
int socket_power_history[AVG_SAMPLE_SIZE];
int socket_power_history_idx;
bool amt_enabled;
struct mutex update_mutex; /* protects race between ACPI handler and metrics thread */
};
struct apmf_sps_prop_granular {
u32 fppt;
u32 sppt;
u32 sppt_apu_only;
u32 spl;
u32 stt_min;
u8 stt_skin_temp[STT_TEMP_COUNT];
u32 fan_id;
} __packed;
/* Static Slider */
struct apmf_static_slider_granular_output {
u16 size;
struct apmf_sps_prop_granular prop[POWER_SOURCE_MAX * POWER_MODE_MAX];
} __packed;
struct amd_pmf_static_slider_granular {
u16 size;
struct apmf_sps_prop_granular prop[POWER_SOURCE_MAX][POWER_MODE_MAX];
};
struct fan_table_control {
bool manual;
unsigned long fan_id;
};
struct power_table_control {
u32 spl;
u32 sppt;
u32 fppt;
u32 sppt_apu_only;
u32 stt_min;
u32 stt_skin_temp[STT_TEMP_COUNT];
u32 reserved[16];
};
/* Auto Mode Layer */
enum auto_mode_transition_priority {
AUTO_TRANSITION_TO_PERFORMANCE, /* Any other mode to Performance Mode */
AUTO_TRANSITION_FROM_QUIET_TO_BALANCE, /* Quiet Mode to Balance Mode */
AUTO_TRANSITION_TO_QUIET, /* Any other mode to Quiet Mode */
AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE, /* Performance Mode to Balance Mode */
AUTO_TRANSITION_MAX,
};
enum auto_mode_mode {
AUTO_QUIET,
AUTO_BALANCE,
AUTO_PERFORMANCE_ON_LAP,
AUTO_PERFORMANCE,
AUTO_MODE_MAX,
};
struct auto_mode_trans_params {
u32 time_constant; /* minimum time required to switch to next mode */
u32 power_delta; /* delta power to shift mode */
u32 power_threshold;
u32 timer; /* elapsed time. if timer > TimeThreshold, it will move to next mode */
u32 applied;
enum auto_mode_mode target_mode;
u32 shifting_up;
};
struct auto_mode_mode_settings {
struct power_table_control power_control;
struct fan_table_control fan_control;
u32 power_floor;
};
struct auto_mode_mode_config {
struct auto_mode_trans_params transition[AUTO_TRANSITION_MAX];
struct auto_mode_mode_settings mode_set[AUTO_MODE_MAX];
enum auto_mode_mode current_mode;
};
struct apmf_auto_mode {
u16 size;
/* time constant */
u32 balanced_to_perf;
u32 perf_to_balanced;
u32 quiet_to_balanced;
u32 balanced_to_quiet;
/* power floor */
u32 pfloor_perf;
u32 pfloor_balanced;
u32 pfloor_quiet;
/* Power delta for mode change */
u32 pd_balanced_to_perf;
u32 pd_perf_to_balanced;
u32 pd_quiet_to_balanced;
u32 pd_balanced_to_quiet;
/* skin temperature limits */
u8 stt_apu_perf_on_lap; /* CQL ON */
u8 stt_hs2_perf_on_lap; /* CQL ON */
u8 stt_apu_perf;
u8 stt_hs2_perf;
u8 stt_apu_balanced;
u8 stt_hs2_balanced;
u8 stt_apu_quiet;
u8 stt_hs2_quiet;
u32 stt_min_limit_perf_on_lap; /* CQL ON */
u32 stt_min_limit_perf;
u32 stt_min_limit_balanced;
u32 stt_min_limit_quiet;
/* SPL based */
u32 fppt_perf_on_lap; /* CQL ON */
u32 sppt_perf_on_lap; /* CQL ON */
u32 spl_perf_on_lap; /* CQL ON */
u32 sppt_apu_only_perf_on_lap; /* CQL ON */
u32 fppt_perf;
u32 sppt_perf;
u32 spl_perf;
u32 sppt_apu_only_perf;
u32 fppt_balanced;
u32 sppt_balanced;
u32 spl_balanced;
u32 sppt_apu_only_balanced;
u32 fppt_quiet;
u32 sppt_quiet;
u32 spl_quiet;
u32 sppt_apu_only_quiet;
/* Fan ID */
u32 fan_id_perf;
u32 fan_id_balanced;
u32 fan_id_quiet;
} __packed;
/* Core Layer */
int apmf_acpi_init(struct amd_pmf_dev *pmf_dev);
void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev);
int is_apmf_func_supported(struct amd_pmf_dev *pdev, unsigned long index);
int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data);
int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev);
int amd_pmf_get_power_source(void);
/* SPS Layer */
int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf);
void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx,
struct amd_pmf_static_slider_granular *table);
int amd_pmf_init_sps(struct amd_pmf_dev *dev);
void amd_pmf_deinit_sps(struct amd_pmf_dev *dev);
int apmf_get_static_slider_granular(struct amd_pmf_dev *pdev,
struct apmf_static_slider_granular_output *output);
int apmf_update_fan_idx(struct amd_pmf_dev *pdev, bool manual, u32 idx);
/* Auto Mode Layer */
int apmf_get_auto_mode_def(struct amd_pmf_dev *pdev, struct apmf_auto_mode *data);
void amd_pmf_init_auto_mode(struct amd_pmf_dev *dev);
void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev);
void amd_pmf_trans_automode(struct amd_pmf_dev *dev, int socket_power, ktime_t time_elapsed_ms);
int apmf_get_sbios_requests(struct amd_pmf_dev *pdev, struct apmf_sbios_req *req);
void amd_pmf_update_2_cql(struct amd_pmf_dev *dev, bool is_cql_event);
int amd_pmf_reset_amt(struct amd_pmf_dev *dev);
void amd_pmf_handle_amt(struct amd_pmf_dev *dev);
#endif /* PMF_H */
// SPDX-License-Identifier: GPL-2.0
/*
* AMD Platform Management Framework (PMF) Driver
*
* Copyright (c) 2022, Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
*/
#include "pmf.h"
static struct amd_pmf_static_slider_granular config_store;
static void amd_pmf_load_defaults_sps(struct amd_pmf_dev *dev)
{
struct apmf_static_slider_granular_output output;
int i, j, idx = 0;
memset(&config_store, 0, sizeof(config_store));
apmf_get_static_slider_granular(dev, &output);
for (i = 0; i < POWER_SOURCE_MAX; i++) {
for (j = 0; j < POWER_MODE_MAX; j++) {
config_store.prop[i][j].spl = output.prop[idx].spl;
config_store.prop[i][j].sppt = output.prop[idx].sppt;
config_store.prop[i][j].sppt_apu_only =
output.prop[idx].sppt_apu_only;
config_store.prop[i][j].fppt = output.prop[idx].fppt;
config_store.prop[i][j].stt_min = output.prop[idx].stt_min;
config_store.prop[i][j].stt_skin_temp[STT_TEMP_APU] =
output.prop[idx].stt_skin_temp[STT_TEMP_APU];
config_store.prop[i][j].stt_skin_temp[STT_TEMP_HS2] =
output.prop[idx].stt_skin_temp[STT_TEMP_HS2];
config_store.prop[i][j].fan_id = output.prop[idx].fan_id;
idx++;
}
}
}
void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx,
struct amd_pmf_static_slider_granular *table)
{
int src = amd_pmf_get_power_source();
if (op == SLIDER_OP_SET) {
amd_pmf_send_cmd(dev, SET_SPL, false, config_store.prop[src][idx].spl, NULL);
amd_pmf_send_cmd(dev, SET_FPPT, false, config_store.prop[src][idx].fppt, NULL);
amd_pmf_send_cmd(dev, SET_SPPT, false, config_store.prop[src][idx].sppt, NULL);
amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false,
config_store.prop[src][idx].sppt_apu_only, NULL);
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false,
config_store.prop[src][idx].stt_min, NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU], NULL);
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2], NULL);
} else if (op == SLIDER_OP_GET) {
amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl);
amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt);
amd_pmf_send_cmd(dev, GET_SPPT, true, ARG_NONE, &table->prop[src][idx].sppt);
amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, true, ARG_NONE,
&table->prop[src][idx].sppt_apu_only);
amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, true, ARG_NONE,
&table->prop[src][idx].stt_min);
amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, true, ARG_NONE,
(u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_APU]);
amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, true, ARG_NONE,
(u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_HS2]);
}
}
static int amd_pmf_profile_get(struct platform_profile_handler *pprof,
enum platform_profile_option *profile)
{
struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof);
*profile = pmf->current_profile;
return 0;
}
int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf)
{
int mode;
switch (pmf->current_profile) {
case PLATFORM_PROFILE_PERFORMANCE:
mode = POWER_MODE_PERFORMANCE;
break;
case PLATFORM_PROFILE_BALANCED:
mode = POWER_MODE_BALANCED_POWER;
break;
case PLATFORM_PROFILE_LOW_POWER:
mode = POWER_MODE_POWER_SAVER;
break;
default:
dev_err(pmf->dev, "Unknown Platform Profile.\n");
return -EOPNOTSUPP;
}
return mode;
}
static int amd_pmf_profile_set(struct platform_profile_handler *pprof,
enum platform_profile_option profile)
{
struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof);
int mode;
pmf->current_profile = profile;
mode = amd_pmf_get_pprof_modes(pmf);
if (mode < 0)
return mode;
amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL);
return 0;
}
int amd_pmf_init_sps(struct amd_pmf_dev *dev)
{
int err;
dev->current_profile = PLATFORM_PROFILE_BALANCED;
amd_pmf_load_defaults_sps(dev);
dev->pprof.profile_get = amd_pmf_profile_get;
dev->pprof.profile_set = amd_pmf_profile_set;
/* Setup supported modes */
set_bit(PLATFORM_PROFILE_LOW_POWER, dev->pprof.choices);
set_bit(PLATFORM_PROFILE_BALANCED, dev->pprof.choices);
set_bit(PLATFORM_PROFILE_PERFORMANCE, dev->pprof.choices);
/* Create platform_profile structure and register */
err = platform_profile_register(&dev->pprof);
if (err)
dev_err(dev->dev, "Failed to register SPS support, this is most likely an SBIOS bug: %d\n",
err);
return err;
}
void amd_pmf_deinit_sps(struct amd_pmf_dev *dev)
{
platform_profile_remove();
}
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