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/power_supply.h> 14 #include <linux/units.h> 15 #include "pmf.h" 16 17 #ifdef CONFIG_AMD_PMF_DEBUG 18 static const char *ta_slider_as_str(unsigned int state) 19 { 20 switch (state) { 21 case TA_BEST_PERFORMANCE: 22 return "PERFORMANCE"; 23 case TA_BETTER_PERFORMANCE: 24 return "BALANCED"; 25 case TA_BEST_BATTERY: 26 return "POWER_SAVER"; 27 default: 28 return "Unknown TA Slider State"; 29 } 30 } 31 32 void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) 33 { 34 dev_dbg(dev->dev, "==== TA inputs START ====\n"); 35 dev_dbg(dev->dev, "Slider State: %s\n", ta_slider_as_str(in->ev_info.power_slider)); 36 dev_dbg(dev->dev, "Power Source: %s\n", amd_pmf_source_as_str(in->ev_info.power_source)); 37 dev_dbg(dev->dev, "Battery Percentage: %u\n", in->ev_info.bat_percentage); 38 dev_dbg(dev->dev, "Designed Battery Capacity: %u\n", in->ev_info.bat_design); 39 dev_dbg(dev->dev, "Fully Charged Capacity: %u\n", in->ev_info.full_charge_capacity); 40 dev_dbg(dev->dev, "Drain Rate: %d\n", in->ev_info.drain_rate); 41 dev_dbg(dev->dev, "Socket Power: %u\n", in->ev_info.socket_power); 42 dev_dbg(dev->dev, "Skin Temperature: %u\n", in->ev_info.skin_temperature); 43 dev_dbg(dev->dev, "Avg C0 Residency: %u\n", in->ev_info.avg_c0residency); 44 dev_dbg(dev->dev, "Max C0 Residency: %u\n", in->ev_info.max_c0residency); 45 dev_dbg(dev->dev, "GFX Busy: %u\n", in->ev_info.gfx_busy); 46 dev_dbg(dev->dev, "LID State: %s\n", in->ev_info.lid_state ? "close" : "open"); 47 dev_dbg(dev->dev, "==== TA inputs END ====\n"); 48 } 49 #else 50 void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) {} 51 #endif 52 53 static void amd_pmf_get_smu_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) 54 { 55 u16 max, avg = 0; 56 int i; 57 58 memset(dev->buf, 0, sizeof(dev->m_table)); 59 amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL); 60 memcpy(&dev->m_table, dev->buf, sizeof(dev->m_table)); 61 62 in->ev_info.socket_power = dev->m_table.apu_power + dev->m_table.dgpu_power; 63 in->ev_info.skin_temperature = dev->m_table.skin_temp; 64 65 /* Get the avg and max C0 residency of all the cores */ 66 max = dev->m_table.avg_core_c0residency[0]; 67 for (i = 0; i < ARRAY_SIZE(dev->m_table.avg_core_c0residency); i++) { 68 avg += dev->m_table.avg_core_c0residency[i]; 69 if (dev->m_table.avg_core_c0residency[i] > max) 70 max = dev->m_table.avg_core_c0residency[i]; 71 } 72 73 avg = DIV_ROUND_CLOSEST(avg, ARRAY_SIZE(dev->m_table.avg_core_c0residency)); 74 in->ev_info.avg_c0residency = avg; 75 in->ev_info.max_c0residency = max; 76 in->ev_info.gfx_busy = dev->m_table.avg_gfx_activity; 77 } 78 79 static const char * const pmf_battery_supply_name[] = { 80 "BATT", 81 "BAT0", 82 }; 83 84 static int amd_pmf_get_battery_prop(enum power_supply_property prop) 85 { 86 union power_supply_propval value; 87 struct power_supply *psy; 88 int i, ret; 89 90 for (i = 0; i < ARRAY_SIZE(pmf_battery_supply_name); i++) { 91 psy = power_supply_get_by_name(pmf_battery_supply_name[i]); 92 if (!psy) 93 continue; 94 95 ret = power_supply_get_property(psy, prop, &value); 96 if (ret) { 97 power_supply_put(psy); 98 return ret; 99 } 100 } 101 102 return value.intval; 103 } 104 105 static int amd_pmf_get_battery_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) 106 { 107 int val; 108 109 val = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_PRESENT); 110 if (val < 0) 111 return val; 112 if (val != 1) 113 return -ENODEV; 114 115 in->ev_info.bat_percentage = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_CAPACITY); 116 /* all values in mWh metrics */ 117 in->ev_info.bat_design = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN) / 118 MILLIWATT_PER_WATT; 119 in->ev_info.full_charge_capacity = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_ENERGY_FULL) / 120 MILLIWATT_PER_WATT; 121 in->ev_info.drain_rate = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_POWER_NOW) / 122 MILLIWATT_PER_WATT; 123 124 return 0; 125 } 126 127 static int amd_pmf_get_slider_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) 128 { 129 int val; 130 131 switch (dev->current_profile) { 132 case PLATFORM_PROFILE_PERFORMANCE: 133 val = TA_BEST_PERFORMANCE; 134 break; 135 case PLATFORM_PROFILE_BALANCED: 136 val = TA_BETTER_PERFORMANCE; 137 break; 138 case PLATFORM_PROFILE_LOW_POWER: 139 val = TA_BEST_BATTERY; 140 break; 141 default: 142 dev_err(dev->dev, "Unknown Platform Profile.\n"); 143 return -EOPNOTSUPP; 144 } 145 in->ev_info.power_slider = val; 146 147 return 0; 148 } 149 150 void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) 151 { 152 /* TA side lid open is 1 and close is 0, hence the ! here */ 153 in->ev_info.lid_state = !acpi_lid_open(); 154 in->ev_info.power_source = amd_pmf_get_power_source(); 155 amd_pmf_get_smu_info(dev, in); 156 amd_pmf_get_battery_info(dev, in); 157 amd_pmf_get_slider_info(dev, in); 158 } 159