drm/virtio: Add drm_panic support
[drm/drm-misc.git] / drivers / platform / x86 / amd / pmf / spc.c
blobf34f3130c3307e72d8dc6adf2540a9c298f32cd9
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * AMD Platform Management Framework Driver - Smart PC Capabilities
5 * Copyright (c) 2023, Advanced Micro Devices, Inc.
6 * All Rights Reserved.
8 * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
9 * Patil Rajesh Reddy <Patil.Reddy@amd.com>
12 #include <acpi/button.h>
13 #include <linux/amd-pmf-io.h>
14 #include <linux/power_supply.h>
15 #include <linux/units.h>
16 #include "pmf.h"
18 #ifdef CONFIG_AMD_PMF_DEBUG
19 static const char *platform_type_as_str(u16 platform_type)
21 switch (platform_type) {
22 case CLAMSHELL:
23 return "CLAMSHELL";
24 case FLAT:
25 return "FLAT";
26 case TENT:
27 return "TENT";
28 case STAND:
29 return "STAND";
30 case TABLET:
31 return "TABLET";
32 case BOOK:
33 return "BOOK";
34 case PRESENTATION:
35 return "PRESENTATION";
36 case PULL_FWD:
37 return "PULL_FWD";
38 default:
39 return "UNKNOWN";
43 static const char *laptop_placement_as_str(u16 device_state)
45 switch (device_state) {
46 case ON_TABLE:
47 return "ON_TABLE";
48 case ON_LAP_MOTION:
49 return "ON_LAP_MOTION";
50 case IN_BAG:
51 return "IN_BAG";
52 case OUT_OF_BAG:
53 return "OUT_OF_BAG";
54 default:
55 return "UNKNOWN";
59 static const char *ta_slider_as_str(unsigned int state)
61 switch (state) {
62 case TA_BEST_PERFORMANCE:
63 return "PERFORMANCE";
64 case TA_BETTER_PERFORMANCE:
65 return "BALANCED";
66 case TA_BEST_BATTERY:
67 return "POWER_SAVER";
68 default:
69 return "Unknown TA Slider State";
73 void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
75 dev_dbg(dev->dev, "==== TA inputs START ====\n");
76 dev_dbg(dev->dev, "Slider State: %s\n", ta_slider_as_str(in->ev_info.power_slider));
77 dev_dbg(dev->dev, "Power Source: %s\n", amd_pmf_source_as_str(in->ev_info.power_source));
78 dev_dbg(dev->dev, "Battery Percentage: %u\n", in->ev_info.bat_percentage);
79 dev_dbg(dev->dev, "Designed Battery Capacity: %u\n", in->ev_info.bat_design);
80 dev_dbg(dev->dev, "Fully Charged Capacity: %u\n", in->ev_info.full_charge_capacity);
81 dev_dbg(dev->dev, "Drain Rate: %d\n", in->ev_info.drain_rate);
82 dev_dbg(dev->dev, "Socket Power: %u\n", in->ev_info.socket_power);
83 dev_dbg(dev->dev, "Skin Temperature: %u\n", in->ev_info.skin_temperature);
84 dev_dbg(dev->dev, "Avg C0 Residency: %u\n", in->ev_info.avg_c0residency);
85 dev_dbg(dev->dev, "Max C0 Residency: %u\n", in->ev_info.max_c0residency);
86 dev_dbg(dev->dev, "GFX Busy: %u\n", in->ev_info.gfx_busy);
87 dev_dbg(dev->dev, "LID State: %s\n", in->ev_info.lid_state ? "close" : "open");
88 dev_dbg(dev->dev, "User Presence: %s\n", in->ev_info.user_present ? "Present" : "Away");
89 dev_dbg(dev->dev, "Ambient Light: %d\n", in->ev_info.ambient_light);
90 dev_dbg(dev->dev, "Platform type: %s\n", platform_type_as_str(in->ev_info.platform_type));
91 dev_dbg(dev->dev, "Laptop placement: %s\n",
92 laptop_placement_as_str(in->ev_info.device_state));
93 dev_dbg(dev->dev, "Custom BIOS input1: %u\n", in->ev_info.bios_input1);
94 dev_dbg(dev->dev, "Custom BIOS input2: %u\n", in->ev_info.bios_input2);
95 dev_dbg(dev->dev, "==== TA inputs END ====\n");
97 #else
98 void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) {}
99 #endif
101 static void amd_pmf_get_custom_bios_inputs(struct amd_pmf_dev *pdev,
102 struct ta_pmf_enact_table *in)
104 if (!pdev->req.pending_req)
105 return;
107 switch (pdev->req.pending_req) {
108 case BIT(NOTIFY_CUSTOM_BIOS_INPUT1):
109 in->ev_info.bios_input1 = pdev->req.custom_policy[APMF_SMARTPC_CUSTOM_BIOS_INPUT1];
110 break;
111 case BIT(NOTIFY_CUSTOM_BIOS_INPUT2):
112 in->ev_info.bios_input2 = pdev->req.custom_policy[APMF_SMARTPC_CUSTOM_BIOS_INPUT2];
113 break;
114 default:
115 dev_dbg(pdev->dev, "Invalid preq for BIOS input: 0x%x\n", pdev->req.pending_req);
118 /* Clear pending requests after handling */
119 memset(&pdev->req, 0, sizeof(pdev->req));
122 static void amd_pmf_get_c0_residency(u16 *core_res, size_t size, struct ta_pmf_enact_table *in)
124 u16 max, avg = 0;
125 int i;
127 /* Get the avg and max C0 residency of all the cores */
128 max = *core_res;
129 for (i = 0; i < size; i++) {
130 avg += core_res[i];
131 if (core_res[i] > max)
132 max = core_res[i];
134 avg = DIV_ROUND_CLOSEST(avg, size);
135 in->ev_info.avg_c0residency = avg;
136 in->ev_info.max_c0residency = max;
139 static void amd_pmf_get_smu_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
141 /* Get the updated metrics table data */
142 memset(dev->buf, 0, dev->mtable_size);
143 amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL);
145 switch (dev->cpu_id) {
146 case AMD_CPU_ID_PS:
147 memcpy(&dev->m_table, dev->buf, dev->mtable_size);
148 in->ev_info.socket_power = dev->m_table.apu_power + dev->m_table.dgpu_power;
149 in->ev_info.skin_temperature = dev->m_table.skin_temp;
150 in->ev_info.gfx_busy = dev->m_table.avg_gfx_activity;
151 amd_pmf_get_c0_residency(dev->m_table.avg_core_c0residency,
152 ARRAY_SIZE(dev->m_table.avg_core_c0residency), in);
153 break;
154 case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
155 case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
156 memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size);
157 in->ev_info.socket_power = dev->m_table_v2.apu_power + dev->m_table_v2.dgpu_power;
158 in->ev_info.skin_temperature = dev->m_table_v2.skin_temp;
159 in->ev_info.gfx_busy = dev->m_table_v2.gfx_activity;
160 amd_pmf_get_c0_residency(dev->m_table_v2.core_c0residency,
161 ARRAY_SIZE(dev->m_table_v2.core_c0residency), in);
162 break;
163 default:
164 dev_err(dev->dev, "Unsupported CPU id: 0x%x", dev->cpu_id);
168 static const char * const pmf_battery_supply_name[] = {
169 "BATT",
170 "BAT0",
173 static int amd_pmf_get_battery_prop(enum power_supply_property prop)
175 union power_supply_propval value;
176 struct power_supply *psy;
177 int i, ret;
179 for (i = 0; i < ARRAY_SIZE(pmf_battery_supply_name); i++) {
180 psy = power_supply_get_by_name(pmf_battery_supply_name[i]);
181 if (!psy)
182 continue;
184 ret = power_supply_get_property(psy, prop, &value);
185 if (ret) {
186 power_supply_put(psy);
187 return ret;
191 return value.intval;
194 static int amd_pmf_get_battery_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
196 int val;
198 val = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_PRESENT);
199 if (val < 0)
200 return val;
201 if (val != 1)
202 return -ENODEV;
204 in->ev_info.bat_percentage = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_CAPACITY);
205 /* all values in mWh metrics */
206 in->ev_info.bat_design = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN) /
207 MILLIWATT_PER_WATT;
208 in->ev_info.full_charge_capacity = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_ENERGY_FULL) /
209 MILLIWATT_PER_WATT;
210 in->ev_info.drain_rate = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_POWER_NOW) /
211 MILLIWATT_PER_WATT;
213 return 0;
216 static int amd_pmf_get_slider_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
218 int val;
220 switch (dev->current_profile) {
221 case PLATFORM_PROFILE_PERFORMANCE:
222 val = TA_BEST_PERFORMANCE;
223 break;
224 case PLATFORM_PROFILE_BALANCED:
225 val = TA_BETTER_PERFORMANCE;
226 break;
227 case PLATFORM_PROFILE_LOW_POWER:
228 val = TA_BEST_BATTERY;
229 break;
230 default:
231 dev_err(dev->dev, "Unknown Platform Profile.\n");
232 return -EOPNOTSUPP;
234 in->ev_info.power_slider = val;
236 return 0;
239 static void amd_pmf_get_sensor_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
241 struct amd_sfh_info sfh_info;
243 /* Get the latest information from SFH */
244 in->ev_info.user_present = false;
246 /* Get ALS data */
247 if (!amd_get_sfh_info(&sfh_info, MT_ALS))
248 in->ev_info.ambient_light = sfh_info.ambient_light;
249 else
250 dev_dbg(dev->dev, "ALS is not enabled/detected\n");
252 /* get HPD data */
253 if (!amd_get_sfh_info(&sfh_info, MT_HPD)) {
254 if (sfh_info.user_present == SFH_USER_PRESENT)
255 in->ev_info.user_present = true;
256 } else {
257 dev_dbg(dev->dev, "HPD is not enabled/detected\n");
260 /* Get SRA (Secondary Accelerometer) data */
261 if (!amd_get_sfh_info(&sfh_info, MT_SRA)) {
262 in->ev_info.platform_type = sfh_info.platform_type;
263 in->ev_info.device_state = sfh_info.laptop_placement;
264 } else {
265 dev_dbg(dev->dev, "SRA is not enabled/detected\n");
269 void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
271 /* TA side lid open is 1 and close is 0, hence the ! here */
272 in->ev_info.lid_state = !acpi_lid_open();
273 in->ev_info.power_source = amd_pmf_get_power_source();
274 amd_pmf_get_smu_info(dev, in);
275 amd_pmf_get_battery_info(dev, in);
276 amd_pmf_get_slider_info(dev, in);
277 amd_pmf_get_sensor_info(dev, in);
278 amd_pmf_get_custom_bios_inputs(dev, in);