1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * AMD Platform Management Framework Driver - Smart PC Capabilities 4 * 5 * Copyright (c) 2023, Advanced Micro Devices, Inc. 6 * All Rights Reserved. 7 * 8 * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> 9 * Patil Rajesh Reddy <Patil.Reddy@amd.com> 10 */ 11 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" 17 18 #ifdef CONFIG_AMD_PMF_DEBUG 19 static const char *platform_type_as_str(u16 platform_type) 20 { 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"; 40 } 41 } 42 43 static const char *laptop_placement_as_str(u16 device_state) 44 { 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"; 56 } 57 } 58 59 static const char *ta_slider_as_str(unsigned int state) 60 { 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"; 70 } 71 } 72 73 static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index) 74 { 75 switch (index) { 76 case 0 ... 1: 77 return in->ev_info.bios_input_1[index]; 78 case 2 ... 9: 79 return in->ev_info.bios_input_2[index - 2]; 80 default: 81 return 0; 82 } 83 } 84 85 void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) 86 { 87 int i; 88 89 dev_dbg(dev->dev, "==== TA inputs START ====\n"); 90 dev_dbg(dev->dev, "Slider State: %s\n", ta_slider_as_str(in->ev_info.power_slider)); 91 dev_dbg(dev->dev, "Power Source: %s\n", amd_pmf_source_as_str(in->ev_info.power_source)); 92 dev_dbg(dev->dev, "Battery Percentage: %u\n", in->ev_info.bat_percentage); 93 dev_dbg(dev->dev, "Designed Battery Capacity: %u\n", in->ev_info.bat_design); 94 dev_dbg(dev->dev, "Fully Charged Capacity: %u\n", in->ev_info.full_charge_capacity); 95 dev_dbg(dev->dev, "Drain Rate: %d\n", in->ev_info.drain_rate); 96 dev_dbg(dev->dev, "Socket Power: %u\n", in->ev_info.socket_power); 97 dev_dbg(dev->dev, "Skin Temperature: %u\n", in->ev_info.skin_temperature); 98 dev_dbg(dev->dev, "Avg C0 Residency: %u\n", in->ev_info.avg_c0residency); 99 dev_dbg(dev->dev, "Max C0 Residency: %u\n", in->ev_info.max_c0residency); 100 dev_dbg(dev->dev, "GFX Busy: %u\n", in->ev_info.gfx_busy); 101 dev_dbg(dev->dev, "LID State: %s\n", in->ev_info.lid_state ? "close" : "open"); 102 dev_dbg(dev->dev, "User Presence: %s\n", in->ev_info.user_present ? "Present" : "Away"); 103 dev_dbg(dev->dev, "Ambient Light: %d\n", in->ev_info.ambient_light); 104 dev_dbg(dev->dev, "Platform type: %s\n", platform_type_as_str(in->ev_info.platform_type)); 105 dev_dbg(dev->dev, "Laptop placement: %s\n", 106 laptop_placement_as_str(in->ev_info.device_state)); 107 for (i = 0; i < ARRAY_SIZE(custom_bios_inputs); i++) 108 dev_dbg(dev->dev, "Custom BIOS input%d: %u\n", i + 1, 109 amd_pmf_get_ta_custom_bios_inputs(in, i)); 110 dev_dbg(dev->dev, "==== TA inputs END ====\n"); 111 } 112 #else 113 void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) {} 114 #endif 115 116 /* 117 * This helper function sets the appropriate BIOS input value in the TA enact 118 * table based on the provided index. We need this approach because the custom 119 * BIOS input array is not continuous, due to the existing TA structure layout. 120 */ 121 static void amd_pmf_set_ta_custom_bios_input(struct ta_pmf_enact_table *in, int index, u32 value) 122 { 123 switch (index) { 124 case 0 ... 1: 125 in->ev_info.bios_input_1[index] = value; 126 break; 127 case 2 ... 9: 128 in->ev_info.bios_input_2[index - 2] = value; 129 break; 130 default: 131 return; 132 } 133 } 134 135 static void amd_pmf_update_bios_inputs(struct amd_pmf_dev *pdev, u32 pending_req, 136 const struct amd_pmf_pb_bitmap *inputs, 137 const u32 *custom_policy, struct ta_pmf_enact_table *in) 138 { 139 unsigned int i; 140 141 for (i = 0; i < ARRAY_SIZE(custom_bios_inputs); i++) { 142 if (!(pending_req & inputs[i].bit_mask)) 143 continue; 144 amd_pmf_set_ta_custom_bios_input(in, i, custom_policy[i]); 145 pdev->cb_prev.custom_bios_inputs[i] = custom_policy[i]; 146 dev_dbg(pdev->dev, "Custom BIOS Input[%d]: %u\n", i, custom_policy[i]); 147 } 148 } 149 150 static void amd_pmf_get_custom_bios_inputs(struct amd_pmf_dev *pdev, 151 struct ta_pmf_enact_table *in) 152 { 153 unsigned int i; 154 155 for (i = 0; i < ARRAY_SIZE(custom_bios_inputs); i++) 156 amd_pmf_set_ta_custom_bios_input(in, i, pdev->cb_prev.custom_bios_inputs[i]); 157 158 if (!(pdev->req.pending_req || pdev->req1.pending_req)) 159 return; 160 161 if (!pdev->smart_pc_enabled) 162 return; 163 164 switch (pdev->pmf_if_version) { 165 case PMF_IF_V1: 166 if (!is_apmf_bios_input_notifications_supported(pdev)) 167 return; 168 amd_pmf_update_bios_inputs(pdev, pdev->req1.pending_req, custom_bios_inputs_v1, 169 pdev->req1.custom_policy, in); 170 break; 171 case PMF_IF_V2: 172 amd_pmf_update_bios_inputs(pdev, pdev->req.pending_req, custom_bios_inputs, 173 pdev->req.custom_policy, in); 174 break; 175 default: 176 break; 177 } 178 179 /* Clear pending requests after handling */ 180 memset(&pdev->req, 0, sizeof(pdev->req)); 181 memset(&pdev->req1, 0, sizeof(pdev->req1)); 182 } 183 184 static void amd_pmf_get_c0_residency(u16 *core_res, size_t size, struct ta_pmf_enact_table *in) 185 { 186 u16 max, avg = 0; 187 int i; 188 189 /* Get the avg and max C0 residency of all the cores */ 190 max = *core_res; 191 for (i = 0; i < size; i++) { 192 avg += core_res[i]; 193 if (core_res[i] > max) 194 max = core_res[i]; 195 } 196 avg = DIV_ROUND_CLOSEST(avg, size); 197 in->ev_info.avg_c0residency = avg; 198 in->ev_info.max_c0residency = max; 199 } 200 201 static void amd_pmf_get_smu_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) 202 { 203 /* Get the updated metrics table data */ 204 memset(dev->buf, 0, dev->mtable_size); 205 amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL); 206 207 switch (dev->cpu_id) { 208 case AMD_CPU_ID_PS: 209 memcpy(&dev->m_table, dev->buf, dev->mtable_size); 210 in->ev_info.socket_power = dev->m_table.apu_power + dev->m_table.dgpu_power; 211 in->ev_info.skin_temperature = dev->m_table.skin_temp; 212 in->ev_info.gfx_busy = dev->m_table.avg_gfx_activity; 213 amd_pmf_get_c0_residency(dev->m_table.avg_core_c0residency, 214 ARRAY_SIZE(dev->m_table.avg_core_c0residency), in); 215 break; 216 case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT: 217 case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT: 218 memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size); 219 in->ev_info.socket_power = dev->m_table_v2.apu_power + dev->m_table_v2.dgpu_power; 220 in->ev_info.skin_temperature = dev->m_table_v2.skin_temp; 221 in->ev_info.gfx_busy = dev->m_table_v2.gfx_activity; 222 amd_pmf_get_c0_residency(dev->m_table_v2.core_c0residency, 223 ARRAY_SIZE(dev->m_table_v2.core_c0residency), in); 224 break; 225 default: 226 dev_err(dev->dev, "Unsupported CPU id: 0x%x", dev->cpu_id); 227 } 228 } 229 230 static const char * const pmf_battery_supply_name[] = { 231 "BATT", 232 "BAT0", 233 }; 234 235 static int amd_pmf_get_battery_prop(enum power_supply_property prop) 236 { 237 union power_supply_propval value; 238 struct power_supply *psy; 239 int i, ret; 240 241 for (i = 0; i < ARRAY_SIZE(pmf_battery_supply_name); i++) { 242 psy = power_supply_get_by_name(pmf_battery_supply_name[i]); 243 if (!psy) 244 continue; 245 246 ret = power_supply_get_property(psy, prop, &value); 247 if (ret) { 248 power_supply_put(psy); 249 return ret; 250 } 251 } 252 253 return value.intval; 254 } 255 256 static int amd_pmf_get_battery_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) 257 { 258 int val; 259 260 val = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_PRESENT); 261 if (val < 0) 262 return val; 263 if (val != 1) 264 return -ENODEV; 265 266 in->ev_info.bat_percentage = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_CAPACITY); 267 /* all values in mWh metrics */ 268 in->ev_info.bat_design = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN) / 269 MILLIWATT_PER_WATT; 270 in->ev_info.full_charge_capacity = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_ENERGY_FULL) / 271 MILLIWATT_PER_WATT; 272 in->ev_info.drain_rate = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_POWER_NOW) / 273 MILLIWATT_PER_WATT; 274 275 return 0; 276 } 277 278 static int amd_pmf_get_slider_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) 279 { 280 int val; 281 282 switch (dev->current_profile) { 283 case PLATFORM_PROFILE_PERFORMANCE: 284 case PLATFORM_PROFILE_BALANCED_PERFORMANCE: 285 val = TA_BEST_PERFORMANCE; 286 break; 287 case PLATFORM_PROFILE_BALANCED: 288 val = TA_BETTER_PERFORMANCE; 289 break; 290 case PLATFORM_PROFILE_LOW_POWER: 291 case PLATFORM_PROFILE_QUIET: 292 val = TA_BEST_BATTERY; 293 break; 294 default: 295 dev_err(dev->dev, "Unknown Platform Profile.\n"); 296 return -EOPNOTSUPP; 297 } 298 in->ev_info.power_slider = val; 299 300 return 0; 301 } 302 303 static void amd_pmf_get_sensor_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) 304 { 305 struct amd_sfh_info sfh_info; 306 307 /* Get the latest information from SFH */ 308 in->ev_info.user_present = false; 309 310 /* Get ALS data */ 311 if (!amd_get_sfh_info(&sfh_info, MT_ALS)) 312 in->ev_info.ambient_light = sfh_info.ambient_light; 313 else 314 dev_dbg(dev->dev, "ALS is not enabled/detected\n"); 315 316 /* get HPD data */ 317 if (!amd_get_sfh_info(&sfh_info, MT_HPD)) { 318 if (sfh_info.user_present == SFH_USER_PRESENT) 319 in->ev_info.user_present = true; 320 } else { 321 dev_dbg(dev->dev, "HPD is not enabled/detected\n"); 322 } 323 324 /* Get SRA (Secondary Accelerometer) data */ 325 if (!amd_get_sfh_info(&sfh_info, MT_SRA)) { 326 in->ev_info.platform_type = sfh_info.platform_type; 327 in->ev_info.device_state = sfh_info.laptop_placement; 328 } else { 329 dev_dbg(dev->dev, "SRA is not enabled/detected\n"); 330 } 331 } 332 333 void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) 334 { 335 /* TA side lid open is 1 and close is 0, hence the ! here */ 336 in->ev_info.lid_state = !acpi_lid_open(); 337 in->ev_info.power_source = amd_pmf_get_power_source(); 338 amd_pmf_get_smu_info(dev, in); 339 amd_pmf_get_battery_info(dev, in); 340 amd_pmf_get_slider_info(dev, in); 341 amd_pmf_get_sensor_info(dev, in); 342 amd_pmf_get_custom_bios_inputs(dev, in); 343 } 344