1*a5edf10eSShyam Sundar S K // SPDX-License-Identifier: GPL-2.0-or-later
2*a5edf10eSShyam Sundar S K /*
3*a5edf10eSShyam Sundar S K * AMD Platform Management Framework Test Tool
4*a5edf10eSShyam Sundar S K *
5*a5edf10eSShyam Sundar S K * Copyright (c) 2026, Advanced Micro Devices, Inc.
6*a5edf10eSShyam Sundar S K * All Rights Reserved.
7*a5edf10eSShyam Sundar S K *
8*a5edf10eSShyam Sundar S K * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
9*a5edf10eSShyam Sundar S K * Sanket Goswami <Sanket.Goswami@amd.com>
10*a5edf10eSShyam Sundar S K */
11*a5edf10eSShyam Sundar S K
12*a5edf10eSShyam Sundar S K #include <errno.h>
13*a5edf10eSShyam Sundar S K #include <fcntl.h>
14*a5edf10eSShyam Sundar S K #include <inttypes.h>
15*a5edf10eSShyam Sundar S K #include <stdbool.h>
16*a5edf10eSShyam Sundar S K #include <stdint.h>
17*a5edf10eSShyam Sundar S K #include <stdio.h>
18*a5edf10eSShyam Sundar S K #include <string.h>
19*a5edf10eSShyam Sundar S K #include <sys/ioctl.h>
20*a5edf10eSShyam Sundar S K #include <unistd.h>
21*a5edf10eSShyam Sundar S K
22*a5edf10eSShyam Sundar S K #include <linux/amd-pmf.h>
23*a5edf10eSShyam Sundar S K #include <linux/kernel.h>
24*a5edf10eSShyam Sundar S K
25*a5edf10eSShyam Sundar S K #define DEVICE_NODE "/dev/amdpmf_interface"
26*a5edf10eSShyam Sundar S K
27*a5edf10eSShyam Sundar S K /* Feature flag names */
28*a5edf10eSShyam Sundar S K static const char * const feature_names[] = {
29*a5edf10eSShyam Sundar S K "Auto Mode",
30*a5edf10eSShyam Sundar S K "Static Power Slider",
31*a5edf10eSShyam Sundar S K "Policy Builder (Smart PC)",
32*a5edf10eSShyam Sundar S K "Dynamic Power Slider AC",
33*a5edf10eSShyam Sundar S K "Dynamic Power Slider DC",
34*a5edf10eSShyam Sundar S K };
35*a5edf10eSShyam Sundar S K
36*a5edf10eSShyam Sundar S K static const char *banner =
37*a5edf10eSShyam Sundar S K "====================================================\n"
38*a5edf10eSShyam Sundar S K " AMD PMF Metrics info and Feature Status\n"
39*a5edf10eSShyam Sundar S K "====================================================\n\n";
40*a5edf10eSShyam Sundar S K
41*a5edf10eSShyam Sundar S K /* Print feature flags */
pmf_print_features(uint32_t flags)42*a5edf10eSShyam Sundar S K static void pmf_print_features(uint32_t flags)
43*a5edf10eSShyam Sundar S K {
44*a5edf10eSShyam Sundar S K size_t i;
45*a5edf10eSShyam Sundar S K
46*a5edf10eSShyam Sundar S K for (i = 0; i < ARRAY_SIZE(feature_names); i++)
47*a5edf10eSShyam Sundar S K printf(" [%c] %s\n", (flags & (1U << i)) ? 'x' : ' ', feature_names[i]);
48*a5edf10eSShyam Sundar S K }
49*a5edf10eSShyam Sundar S K
50*a5edf10eSShyam Sundar S K /* Print BIOS parameters */
pmf_print_bios_params(const char * type,const __u32 * params)51*a5edf10eSShyam Sundar S K static void pmf_print_bios_params(const char *type, const __u32 *params)
52*a5edf10eSShyam Sundar S K {
53*a5edf10eSShyam Sundar S K int i;
54*a5edf10eSShyam Sundar S K
55*a5edf10eSShyam Sundar S K for (i = 0; i < AMD_PMF_BIOS_PARAMS_MAX; i++)
56*a5edf10eSShyam Sundar S K printf(" Custom BIOS %s%d: %u\n", type, i + 1, params[i]);
57*a5edf10eSShyam Sundar S K }
58*a5edf10eSShyam Sundar S K
59*a5edf10eSShyam Sundar S K /* Open the PMF device */
pmf_open_device(void)60*a5edf10eSShyam Sundar S K static int pmf_open_device(void)
61*a5edf10eSShyam Sundar S K {
62*a5edf10eSShyam Sundar S K int fd;
63*a5edf10eSShyam Sundar S K
64*a5edf10eSShyam Sundar S K fd = open(DEVICE_NODE, O_RDONLY);
65*a5edf10eSShyam Sundar S K if (fd < 0)
66*a5edf10eSShyam Sundar S K fprintf(stderr, "Error: Cannot open %s: %s\n", DEVICE_NODE, strerror(errno));
67*a5edf10eSShyam Sundar S K
68*a5edf10eSShyam Sundar S K return fd;
69*a5edf10eSShyam Sundar S K }
70*a5edf10eSShyam Sundar S K
71*a5edf10eSShyam Sundar S K /* Query PMF info using the single IOCTL */
pmf_get_info(int fd,struct amd_pmf_info * info)72*a5edf10eSShyam Sundar S K static int pmf_get_info(int fd, struct amd_pmf_info *info)
73*a5edf10eSShyam Sundar S K {
74*a5edf10eSShyam Sundar S K int ret;
75*a5edf10eSShyam Sundar S K
76*a5edf10eSShyam Sundar S K /* Zero-initialize and set size for versioning */
77*a5edf10eSShyam Sundar S K memset(info, 0, sizeof(*info));
78*a5edf10eSShyam Sundar S K info->size = sizeof(*info);
79*a5edf10eSShyam Sundar S K
80*a5edf10eSShyam Sundar S K ret = ioctl(fd, IOCTL_AMD_PMF_POPULATE_DATA, info);
81*a5edf10eSShyam Sundar S K if (ret < 0) {
82*a5edf10eSShyam Sundar S K fprintf(stderr, "Error: IOCTL_AMD_PMF_POPULATE_DATA failed: %s\n", strerror(errno));
83*a5edf10eSShyam Sundar S K return ret;
84*a5edf10eSShyam Sundar S K }
85*a5edf10eSShyam Sundar S K
86*a5edf10eSShyam Sundar S K return 0;
87*a5edf10eSShyam Sundar S K }
88*a5edf10eSShyam Sundar S K
pmf_print_info(const struct amd_pmf_info * info)89*a5edf10eSShyam Sundar S K static void pmf_print_info(const struct amd_pmf_info *info)
90*a5edf10eSShyam Sundar S K {
91*a5edf10eSShyam Sundar S K printf("%s", banner);
92*a5edf10eSShyam Sundar S K
93*a5edf10eSShyam Sundar S K /* Feature status */
94*a5edf10eSShyam Sundar S K printf("Feature Status:\n");
95*a5edf10eSShyam Sundar S K pmf_print_features(info->features_supported);
96*a5edf10eSShyam Sundar S K
97*a5edf10eSShyam Sundar S K /* Device states */
98*a5edf10eSShyam Sundar S K printf("\nDevice States:\n");
99*a5edf10eSShyam Sundar S K printf(" Platform Type: %s\n", amd_pmf_get_platform_type(info->platform_type));
100*a5edf10eSShyam Sundar S K printf(" Laptop Placement: %s\n", amd_pmf_get_laptop_placement(info->laptop_placement));
101*a5edf10eSShyam Sundar S K printf(" Lid State: %s\n", info->lid_state ? "Closed" : "Open");
102*a5edf10eSShyam Sundar S K printf(" User Presence: %s\n", info->user_presence ? "Present" : "Away");
103*a5edf10eSShyam Sundar S K printf(" Slider Position: %s\n", amd_pmf_get_slider_position(info->slider_position));
104*a5edf10eSShyam Sundar S K
105*a5edf10eSShyam Sundar S K /* Thermal and power metrics */
106*a5edf10eSShyam Sundar S K printf("\nThermal/Power Metrics:\n");
107*a5edf10eSShyam Sundar S K printf(" Skin Temperature: %d\n", info->skin_temp / 100);
108*a5edf10eSShyam Sundar S K printf(" GFX Busy: %u\n", info->gfx_busy);
109*a5edf10eSShyam Sundar S K printf(" Ambient Light: %d\n", info->ambient_light);
110*a5edf10eSShyam Sundar S K printf(" Avg C0 Residency: %u\n", info->avg_c0_residency);
111*a5edf10eSShyam Sundar S K printf(" Max C0 Residency: %u\n", info->max_c0_residency);
112*a5edf10eSShyam Sundar S K printf(" Socket Power: %u\n", info->socket_power);
113*a5edf10eSShyam Sundar S K
114*a5edf10eSShyam Sundar S K /* BIOS parameters */
115*a5edf10eSShyam Sundar S K printf("\nCustom BIOS Input Parameters:\n");
116*a5edf10eSShyam Sundar S K pmf_print_bios_params("Input", info->bios_input);
117*a5edf10eSShyam Sundar S K printf("\nCustom BIOS Output Parameters:\n");
118*a5edf10eSShyam Sundar S K pmf_print_bios_params("Output", info->bios_output);
119*a5edf10eSShyam Sundar S K
120*a5edf10eSShyam Sundar S K printf("\n=================================================\n");
121*a5edf10eSShyam Sundar S K }
122*a5edf10eSShyam Sundar S K
main(void)123*a5edf10eSShyam Sundar S K int main(void)
124*a5edf10eSShyam Sundar S K {
125*a5edf10eSShyam Sundar S K struct amd_pmf_info info;
126*a5edf10eSShyam Sundar S K int fd, ret;
127*a5edf10eSShyam Sundar S K
128*a5edf10eSShyam Sundar S K fd = pmf_open_device();
129*a5edf10eSShyam Sundar S K if (fd < 0)
130*a5edf10eSShyam Sundar S K return -1;
131*a5edf10eSShyam Sundar S K
132*a5edf10eSShyam Sundar S K /* Query all info with single IOCTL */
133*a5edf10eSShyam Sundar S K ret = pmf_get_info(fd, &info);
134*a5edf10eSShyam Sundar S K close(fd);
135*a5edf10eSShyam Sundar S K
136*a5edf10eSShyam Sundar S K if (ret < 0)
137*a5edf10eSShyam Sundar S K return -1;
138*a5edf10eSShyam Sundar S K
139*a5edf10eSShyam Sundar S K pmf_print_info(&info);
140*a5edf10eSShyam Sundar S K
141*a5edf10eSShyam Sundar S K return 0;
142*a5edf10eSShyam Sundar S K }
143