198432eecSShyam Sundar S K // SPDX-License-Identifier: GPL-2.0-or-later
298432eecSShyam Sundar S K /*
398432eecSShyam Sundar S K * AMD Platform Management Framework Util Layer
498432eecSShyam Sundar S K *
598432eecSShyam Sundar S K * Copyright (c) 2026, Advanced Micro Devices, Inc.
698432eecSShyam Sundar S K * All Rights Reserved.
798432eecSShyam Sundar S K *
898432eecSShyam Sundar S K * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
998432eecSShyam Sundar S K * Sanket Goswami <Sanket.Goswami@amd.com>
1098432eecSShyam Sundar S K */
1198432eecSShyam Sundar S K
1298432eecSShyam Sundar S K #include <linux/amd-pmf.h>
13*5bda82c7SShyam Sundar S K #include <linux/minmax.h>
1498432eecSShyam Sundar S K #include <linux/miscdevice.h>
1598432eecSShyam Sundar S K #include <linux/mutex.h>
1698432eecSShyam Sundar S K #include <linux/uaccess.h>
1798432eecSShyam Sundar S K
1898432eecSShyam Sundar S K #include "pmf.h"
1998432eecSShyam Sundar S K
2098432eecSShyam Sundar S K static struct amd_pmf_dev *pmf_dev_handle;
2198432eecSShyam Sundar S K static DEFINE_MUTEX(pmf_util_lock);
2298432eecSShyam Sundar S K
amd_pmf_populate_data(struct amd_pmf_dev * pdev,struct amd_pmf_info * info)23*5bda82c7SShyam Sundar S K static int amd_pmf_populate_data(struct amd_pmf_dev *pdev, struct amd_pmf_info *info)
24*5bda82c7SShyam Sundar S K {
25*5bda82c7SShyam Sundar S K struct ta_pmf_shared_memory *ta_sm = NULL;
26*5bda82c7SShyam Sundar S K struct ta_pmf_enact_table *in = NULL;
27*5bda82c7SShyam Sundar S K int idx;
28*5bda82c7SShyam Sundar S K
29*5bda82c7SShyam Sundar S K if (!pdev || !info)
30*5bda82c7SShyam Sundar S K return -EINVAL;
31*5bda82c7SShyam Sundar S K
32*5bda82c7SShyam Sundar S K if (!pdev->shbuf)
33*5bda82c7SShyam Sundar S K return -EINVAL;
34*5bda82c7SShyam Sundar S K
35*5bda82c7SShyam Sundar S K ta_sm = pdev->shbuf;
36*5bda82c7SShyam Sundar S K in = &ta_sm->pmf_input.enact_table;
37*5bda82c7SShyam Sundar S K
38*5bda82c7SShyam Sundar S K /* Set size */
39*5bda82c7SShyam Sundar S K info->size = sizeof(*info);
40*5bda82c7SShyam Sundar S K
41*5bda82c7SShyam Sundar S K /* PMF Feature support flags */
42*5bda82c7SShyam Sundar S K if (is_apmf_func_supported(pdev, APMF_FUNC_AUTO_MODE))
43*5bda82c7SShyam Sundar S K info->features_supported |= AMD_PMF_FEAT_AUTO_MODE;
44*5bda82c7SShyam Sundar S K if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
45*5bda82c7SShyam Sundar S K info->features_supported |= AMD_PMF_FEAT_STATIC_POWER_SLIDER;
46*5bda82c7SShyam Sundar S K if (pdev->smart_pc_enabled)
47*5bda82c7SShyam Sundar S K info->features_supported |= AMD_PMF_FEAT_POLICY_BUILDER;
48*5bda82c7SShyam Sundar S K if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_AC))
49*5bda82c7SShyam Sundar S K info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC;
50*5bda82c7SShyam Sundar S K if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_DC))
51*5bda82c7SShyam Sundar S K info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC;
52*5bda82c7SShyam Sundar S K
53*5bda82c7SShyam Sundar S K /* Device States */
54*5bda82c7SShyam Sundar S K info->platform_type = in->ev_info.platform_type;
55*5bda82c7SShyam Sundar S K info->laptop_placement = in->ev_info.device_state;
56*5bda82c7SShyam Sundar S K info->lid_state = in->ev_info.lid_state;
57*5bda82c7SShyam Sundar S K info->user_presence = in->ev_info.user_present;
58*5bda82c7SShyam Sundar S K info->slider_position = in->ev_info.power_slider;
59*5bda82c7SShyam Sundar S K
60*5bda82c7SShyam Sundar S K /* Thermal and Power Metrics */
61*5bda82c7SShyam Sundar S K info->power_source = in->ev_info.power_source;
62*5bda82c7SShyam Sundar S K info->skin_temp = in->ev_info.skin_temperature;
63*5bda82c7SShyam Sundar S K info->gfx_busy = in->ev_info.gfx_busy;
64*5bda82c7SShyam Sundar S K info->ambient_light = in->ev_info.ambient_light;
65*5bda82c7SShyam Sundar S K info->avg_c0_residency = in->ev_info.avg_c0residency;
66*5bda82c7SShyam Sundar S K info->max_c0_residency = in->ev_info.max_c0residency;
67*5bda82c7SShyam Sundar S K info->socket_power = in->ev_info.socket_power;
68*5bda82c7SShyam Sundar S K
69*5bda82c7SShyam Sundar S K /* Custom BIOS input parameters */
70*5bda82c7SShyam Sundar S K for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++)
71*5bda82c7SShyam Sundar S K info->bios_input[idx] = amd_pmf_get_ta_custom_bios_inputs(in, idx);
72*5bda82c7SShyam Sundar S K
73*5bda82c7SShyam Sundar S K /* BIOS output parameters */
74*5bda82c7SShyam Sundar S K for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++)
75*5bda82c7SShyam Sundar S K info->bios_output[idx] = pdev->bios_output[idx];
76*5bda82c7SShyam Sundar S K
77*5bda82c7SShyam Sundar S K return 0;
78*5bda82c7SShyam Sundar S K }
79*5bda82c7SShyam Sundar S K
amd_pmf_set_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)8098432eecSShyam Sundar S K static long amd_pmf_set_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
8198432eecSShyam Sundar S K {
82*5bda82c7SShyam Sundar S K struct amd_pmf_dev *pdev = filp->private_data;
83*5bda82c7SShyam Sundar S K void __user *argp = (void __user *)arg;
84*5bda82c7SShyam Sundar S K struct amd_pmf_info info = {};
85*5bda82c7SShyam Sundar S K size_t copy_size;
86*5bda82c7SShyam Sundar S K __u64 user_size;
87*5bda82c7SShyam Sundar S K int ret;
88*5bda82c7SShyam Sundar S K
89*5bda82c7SShyam Sundar S K if (cmd != IOCTL_AMD_PMF_POPULATE_DATA)
9098432eecSShyam Sundar S K return -ENOTTY;
91*5bda82c7SShyam Sundar S K
92*5bda82c7SShyam Sundar S K /* First read just the size field from userspace */
93*5bda82c7SShyam Sundar S K if (copy_from_user(&user_size, argp, sizeof(user_size)))
94*5bda82c7SShyam Sundar S K return -EFAULT;
95*5bda82c7SShyam Sundar S K
96*5bda82c7SShyam Sundar S K guard(mutex)(&pmf_util_lock);
97*5bda82c7SShyam Sundar S K ret = amd_pmf_populate_data(pdev, &info);
98*5bda82c7SShyam Sundar S K if (ret)
99*5bda82c7SShyam Sundar S K return ret;
100*5bda82c7SShyam Sundar S K
101*5bda82c7SShyam Sundar S K copy_size = min_t(size_t, user_size, sizeof(info));
102*5bda82c7SShyam Sundar S K
103*5bda82c7SShyam Sundar S K /* Set actual size being copied */
104*5bda82c7SShyam Sundar S K info.size = copy_size;
105*5bda82c7SShyam Sundar S K
106*5bda82c7SShyam Sundar S K if (copy_to_user(argp, &info, copy_size))
107*5bda82c7SShyam Sundar S K return -EFAULT;
108*5bda82c7SShyam Sundar S K
109*5bda82c7SShyam Sundar S K return 0;
11098432eecSShyam Sundar S K }
11198432eecSShyam Sundar S K
amd_pmf_open(struct inode * inode,struct file * filp)11298432eecSShyam Sundar S K static int amd_pmf_open(struct inode *inode, struct file *filp)
11398432eecSShyam Sundar S K {
11498432eecSShyam Sundar S K guard(mutex)(&pmf_util_lock);
11598432eecSShyam Sundar S K if (!pmf_dev_handle)
11698432eecSShyam Sundar S K return -ENODEV;
11798432eecSShyam Sundar S K
11898432eecSShyam Sundar S K filp->private_data = pmf_dev_handle;
11998432eecSShyam Sundar S K return 0;
12098432eecSShyam Sundar S K }
12198432eecSShyam Sundar S K
12298432eecSShyam Sundar S K static const struct file_operations pmf_if_ops = {
12398432eecSShyam Sundar S K .owner = THIS_MODULE,
12498432eecSShyam Sundar S K .open = amd_pmf_open,
12598432eecSShyam Sundar S K .unlocked_ioctl = amd_pmf_set_ioctl,
12698432eecSShyam Sundar S K };
12798432eecSShyam Sundar S K
12898432eecSShyam Sundar S K static struct miscdevice amd_pmf_util_if = {
12998432eecSShyam Sundar S K .minor = MISC_DYNAMIC_MINOR,
13098432eecSShyam Sundar S K .name = "amdpmf_interface",
13198432eecSShyam Sundar S K .fops = &pmf_if_ops,
13298432eecSShyam Sundar S K };
13398432eecSShyam Sundar S K
amd_pmf_cdev_register(struct amd_pmf_dev * dev)13498432eecSShyam Sundar S K int amd_pmf_cdev_register(struct amd_pmf_dev *dev)
13598432eecSShyam Sundar S K {
13698432eecSShyam Sundar S K int ret;
13798432eecSShyam Sundar S K
13898432eecSShyam Sundar S K guard(mutex)(&pmf_util_lock);
13998432eecSShyam Sundar S K pmf_dev_handle = dev;
14098432eecSShyam Sundar S K ret = misc_register(&amd_pmf_util_if);
14198432eecSShyam Sundar S K if (ret)
14298432eecSShyam Sundar S K pmf_dev_handle = NULL;
14398432eecSShyam Sundar S K
14498432eecSShyam Sundar S K return ret;
14598432eecSShyam Sundar S K }
14698432eecSShyam Sundar S K
amd_pmf_cdev_unregister(void)14798432eecSShyam Sundar S K void amd_pmf_cdev_unregister(void)
14898432eecSShyam Sundar S K {
14998432eecSShyam Sundar S K guard(mutex)(&pmf_util_lock);
15098432eecSShyam Sundar S K if (pmf_dev_handle)
15198432eecSShyam Sundar S K misc_deregister(&amd_pmf_util_if);
15298432eecSShyam Sundar S K pmf_dev_handle = NULL;
15398432eecSShyam Sundar S K }
154