brintos

brintos / linux-shallow public Read only

0
0
Text · 6.2 KiB · 06226eb Raw
205 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * AMD Platform Management Framework Driver - Smart PC Capabilities4 *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_DEBUG19static const char *ta_slider_as_str(unsigned int state)20{21	switch (state) {22	case TA_BEST_PERFORMANCE:23		return "PERFORMANCE";24	case TA_BETTER_PERFORMANCE:25		return "BALANCED";26	case TA_BEST_BATTERY:27		return "POWER_SAVER";28	default:29		return "Unknown TA Slider State";30	}31}32 33void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)34{35	dev_dbg(dev->dev, "==== TA inputs START ====\n");36	dev_dbg(dev->dev, "Slider State: %s\n", ta_slider_as_str(in->ev_info.power_slider));37	dev_dbg(dev->dev, "Power Source: %s\n", amd_pmf_source_as_str(in->ev_info.power_source));38	dev_dbg(dev->dev, "Battery Percentage: %u\n", in->ev_info.bat_percentage);39	dev_dbg(dev->dev, "Designed Battery Capacity: %u\n", in->ev_info.bat_design);40	dev_dbg(dev->dev, "Fully Charged Capacity: %u\n", in->ev_info.full_charge_capacity);41	dev_dbg(dev->dev, "Drain Rate: %d\n", in->ev_info.drain_rate);42	dev_dbg(dev->dev, "Socket Power: %u\n", in->ev_info.socket_power);43	dev_dbg(dev->dev, "Skin Temperature: %u\n", in->ev_info.skin_temperature);44	dev_dbg(dev->dev, "Avg C0 Residency: %u\n", in->ev_info.avg_c0residency);45	dev_dbg(dev->dev, "Max C0 Residency: %u\n", in->ev_info.max_c0residency);46	dev_dbg(dev->dev, "GFX Busy: %u\n", in->ev_info.gfx_busy);47	dev_dbg(dev->dev, "LID State: %s\n", in->ev_info.lid_state ? "close" : "open");48	dev_dbg(dev->dev, "User Presence: %s\n", in->ev_info.user_present ? "Present" : "Away");49	dev_dbg(dev->dev, "Ambient Light: %d\n", in->ev_info.ambient_light);50	dev_dbg(dev->dev, "==== TA inputs END ====\n");51}52#else53void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) {}54#endif55 56static void amd_pmf_get_c0_residency(u16 *core_res, size_t size, struct ta_pmf_enact_table *in)57{58	u16 max, avg = 0;59	int i;60 61	/* Get the avg and max C0 residency of all the cores */62	max = *core_res;63	for (i = 0; i < size; i++) {64		avg += core_res[i];65		if (core_res[i] > max)66			max = core_res[i];67	}68	avg = DIV_ROUND_CLOSEST(avg, size);69	in->ev_info.avg_c0residency = avg;70	in->ev_info.max_c0residency = max;71}72 73static void amd_pmf_get_smu_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)74{75	/* Get the updated metrics table data */76	memset(dev->buf, 0, dev->mtable_size);77	amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL);78 79	switch (dev->cpu_id) {80	case AMD_CPU_ID_PS:81		memcpy(&dev->m_table, dev->buf, dev->mtable_size);82		in->ev_info.socket_power = dev->m_table.apu_power + dev->m_table.dgpu_power;83		in->ev_info.skin_temperature = dev->m_table.skin_temp;84		in->ev_info.gfx_busy = dev->m_table.avg_gfx_activity;85		amd_pmf_get_c0_residency(dev->m_table.avg_core_c0residency,86					 ARRAY_SIZE(dev->m_table.avg_core_c0residency), in);87		break;88	case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:89	case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:90		memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size);91		in->ev_info.socket_power = dev->m_table_v2.apu_power + dev->m_table_v2.dgpu_power;92		in->ev_info.skin_temperature = dev->m_table_v2.skin_temp;93		in->ev_info.gfx_busy = dev->m_table_v2.gfx_activity;94		amd_pmf_get_c0_residency(dev->m_table_v2.core_c0residency,95					 ARRAY_SIZE(dev->m_table_v2.core_c0residency), in);96		break;97	default:98		dev_err(dev->dev, "Unsupported CPU id: 0x%x", dev->cpu_id);99	}100}101 102static const char * const pmf_battery_supply_name[] = {103	"BATT",104	"BAT0",105};106 107static int amd_pmf_get_battery_prop(enum power_supply_property prop)108{109	union power_supply_propval value;110	struct power_supply *psy;111	int i, ret;112 113	for (i = 0; i < ARRAY_SIZE(pmf_battery_supply_name); i++) {114		psy = power_supply_get_by_name(pmf_battery_supply_name[i]);115		if (!psy)116			continue;117 118		ret = power_supply_get_property(psy, prop, &value);119		if (ret) {120			power_supply_put(psy);121			return ret;122		}123	}124 125	return value.intval;126}127 128static int amd_pmf_get_battery_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)129{130	int val;131 132	val = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_PRESENT);133	if (val < 0)134		return val;135	if (val != 1)136		return -ENODEV;137 138	in->ev_info.bat_percentage = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_CAPACITY);139	/* all values in mWh metrics */140	in->ev_info.bat_design = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN) /141		MILLIWATT_PER_WATT;142	in->ev_info.full_charge_capacity = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_ENERGY_FULL) /143		MILLIWATT_PER_WATT;144	in->ev_info.drain_rate = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_POWER_NOW) /145		MILLIWATT_PER_WATT;146 147	return 0;148}149 150static int amd_pmf_get_slider_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)151{152	int val;153 154	switch (dev->current_profile) {155	case PLATFORM_PROFILE_PERFORMANCE:156		val = TA_BEST_PERFORMANCE;157		break;158	case PLATFORM_PROFILE_BALANCED:159		val = TA_BETTER_PERFORMANCE;160		break;161	case PLATFORM_PROFILE_LOW_POWER:162		val = TA_BEST_BATTERY;163		break;164	default:165		dev_err(dev->dev, "Unknown Platform Profile.\n");166		return -EOPNOTSUPP;167	}168	in->ev_info.power_slider = val;169 170	return 0;171}172 173static void amd_pmf_get_sensor_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)174{175	struct amd_sfh_info sfh_info;176 177	/* Get the latest information from SFH */178	in->ev_info.user_present = false;179 180	/* Get ALS data */181	if (!amd_get_sfh_info(&sfh_info, MT_ALS))182		in->ev_info.ambient_light = sfh_info.ambient_light;183	else184		dev_dbg(dev->dev, "ALS is not enabled/detected\n");185 186	/* get HPD data */187	if (!amd_get_sfh_info(&sfh_info, MT_HPD)) {188		if (sfh_info.user_present == SFH_USER_PRESENT)189			in->ev_info.user_present = true;190	} else {191		dev_dbg(dev->dev, "HPD is not enabled/detected\n");192	}193}194 195void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)196{197	/* TA side lid open is 1 and close is 0, hence the ! here */198	in->ev_info.lid_state = !acpi_lid_open();199	in->ev_info.power_source = amd_pmf_get_power_source();200	amd_pmf_get_smu_info(dev, in);201	amd_pmf_get_battery_info(dev, in);202	amd_pmf_get_slider_info(dev, in);203	amd_pmf_get_sensor_info(dev, in);204}205