]> Git Repo - linux.git/blob - drivers/platform/x86/amd/pmf/spc.c
dma-mapping: don't return errors from dma_set_max_seg_size
[linux.git] / drivers / platform / x86 / amd / pmf / spc.c
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 <[email protected]>
9  *          Patil Rajesh Reddy <[email protected]>
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 *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
33 void 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 #else
53 void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) {}
54 #endif
55
56 static void amd_pmf_get_smu_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
57 {
58         u16 max, avg = 0;
59         int i;
60
61         memset(dev->buf, 0, sizeof(dev->m_table));
62         amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL);
63         memcpy(&dev->m_table, dev->buf, sizeof(dev->m_table));
64
65         in->ev_info.socket_power = dev->m_table.apu_power + dev->m_table.dgpu_power;
66         in->ev_info.skin_temperature = dev->m_table.skin_temp;
67
68         /* Get the avg and max C0 residency of all the cores */
69         max = dev->m_table.avg_core_c0residency[0];
70         for (i = 0; i < ARRAY_SIZE(dev->m_table.avg_core_c0residency); i++) {
71                 avg += dev->m_table.avg_core_c0residency[i];
72                 if (dev->m_table.avg_core_c0residency[i] > max)
73                         max = dev->m_table.avg_core_c0residency[i];
74         }
75
76         avg = DIV_ROUND_CLOSEST(avg, ARRAY_SIZE(dev->m_table.avg_core_c0residency));
77         in->ev_info.avg_c0residency = avg;
78         in->ev_info.max_c0residency = max;
79         in->ev_info.gfx_busy = dev->m_table.avg_gfx_activity;
80 }
81
82 static const char * const pmf_battery_supply_name[] = {
83         "BATT",
84         "BAT0",
85 };
86
87 static int amd_pmf_get_battery_prop(enum power_supply_property prop)
88 {
89         union power_supply_propval value;
90         struct power_supply *psy;
91         int i, ret;
92
93         for (i = 0; i < ARRAY_SIZE(pmf_battery_supply_name); i++) {
94                 psy = power_supply_get_by_name(pmf_battery_supply_name[i]);
95                 if (!psy)
96                         continue;
97
98                 ret = power_supply_get_property(psy, prop, &value);
99                 if (ret) {
100                         power_supply_put(psy);
101                         return ret;
102                 }
103         }
104
105         return value.intval;
106 }
107
108 static int amd_pmf_get_battery_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
109 {
110         int val;
111
112         val = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_PRESENT);
113         if (val < 0)
114                 return val;
115         if (val != 1)
116                 return -ENODEV;
117
118         in->ev_info.bat_percentage = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_CAPACITY);
119         /* all values in mWh metrics */
120         in->ev_info.bat_design = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN) /
121                 MILLIWATT_PER_WATT;
122         in->ev_info.full_charge_capacity = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_ENERGY_FULL) /
123                 MILLIWATT_PER_WATT;
124         in->ev_info.drain_rate = amd_pmf_get_battery_prop(POWER_SUPPLY_PROP_POWER_NOW) /
125                 MILLIWATT_PER_WATT;
126
127         return 0;
128 }
129
130 static int amd_pmf_get_slider_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
131 {
132         int val;
133
134         switch (dev->current_profile) {
135         case PLATFORM_PROFILE_PERFORMANCE:
136                 val = TA_BEST_PERFORMANCE;
137                 break;
138         case PLATFORM_PROFILE_BALANCED:
139                 val = TA_BETTER_PERFORMANCE;
140                 break;
141         case PLATFORM_PROFILE_LOW_POWER:
142                 val = TA_BEST_BATTERY;
143                 break;
144         default:
145                 dev_err(dev->dev, "Unknown Platform Profile.\n");
146                 return -EOPNOTSUPP;
147         }
148         in->ev_info.power_slider = val;
149
150         return 0;
151 }
152
153 static void amd_pmf_get_sensor_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
154 {
155         struct amd_sfh_info sfh_info;
156
157         /* Get the latest information from SFH */
158         in->ev_info.user_present = false;
159
160         /* Get ALS data */
161         if (!amd_get_sfh_info(&sfh_info, MT_ALS))
162                 in->ev_info.ambient_light = sfh_info.ambient_light;
163         else
164                 dev_dbg(dev->dev, "ALS is not enabled/detected\n");
165
166         /* get HPD data */
167         if (!amd_get_sfh_info(&sfh_info, MT_HPD)) {
168                 if (sfh_info.user_present == SFH_USER_PRESENT)
169                         in->ev_info.user_present = true;
170         } else {
171                 dev_dbg(dev->dev, "HPD is not enabled/detected\n");
172         }
173 }
174
175 void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
176 {
177         /* TA side lid open is 1 and close is 0, hence the ! here */
178         in->ev_info.lid_state = !acpi_lid_open();
179         in->ev_info.power_source = amd_pmf_get_power_source();
180         amd_pmf_get_smu_info(dev, in);
181         amd_pmf_get_battery_info(dev, in);
182         amd_pmf_get_slider_info(dev, in);
183         amd_pmf_get_sensor_info(dev, in);
184 }
This page took 0.043256 seconds and 4 git commands to generate.