Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * AMD Platform Management Framework Driver
 *
 * Copyright (c) 2022, Advanced Micro Devices, Inc.
 * All Rights Reserved.
 *
 * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
 */

#ifndef PMF_H
#define PMF_H

#include <linux/acpi.h>
#include <linux/platform_profile.h>

/* APMF Functions */
#define APMF_FUNC_VERIFY_INTERFACE			0
#define APMF_FUNC_GET_SYS_PARAMS			1
#define APMF_FUNC_SBIOS_REQUESTS			2
#define APMF_FUNC_SBIOS_HEARTBEAT			4
#define APMF_FUNC_AUTO_MODE					5
#define APMF_FUNC_SET_FAN_IDX				7
#define APMF_FUNC_OS_POWER_SLIDER_UPDATE		8
#define APMF_FUNC_STATIC_SLIDER_GRANULAR       9
#define APMF_FUNC_DYN_SLIDER_AC				11
#define APMF_FUNC_DYN_SLIDER_DC				12

/* Message Definitions */
#define SET_SPL				0x03 /* SPL: Sustained Power Limit */
#define SET_SPPT			0x05 /* SPPT: Slow Package Power Tracking */
#define SET_FPPT			0x07 /* FPPT: Fast Package Power Tracking */
#define GET_SPL				0x0B
#define GET_SPPT			0x0D
#define GET_FPPT			0x0F
#define SET_DRAM_ADDR_HIGH	0x14
#define SET_DRAM_ADDR_LOW	0x15
#define SET_TRANSFER_TABLE	0x16
#define SET_STT_MIN_LIMIT	0x18 /* STT: Skin Temperature Tracking */
#define SET_STT_LIMIT_APU	0x19
#define SET_STT_LIMIT_HS2	0x1A
#define SET_SPPT_APU_ONLY	0x1D
#define GET_SPPT_APU_ONLY	0x1E
#define GET_STT_MIN_LIMIT	0x1F
#define GET_STT_LIMIT_APU	0x20
#define GET_STT_LIMIT_HS2	0x21

/* OS slider update notification */
#define DC_BEST_PERF		0
#define DC_BETTER_PERF		1
#define DC_BATTERY_SAVER	3
#define AC_BEST_PERF		4
#define AC_BETTER_PERF		5
#define AC_BETTER_BATTERY	6

/* Fan Index for Auto Mode */
#define FAN_INDEX_AUTO		0xFFFFFFFF

#define ARG_NONE 0
#define AVG_SAMPLE_SIZE 3

/* AMD PMF BIOS interfaces */
struct apmf_verify_interface {
	u16 size;
	u16 version;
	u32 notification_mask;
	u32 supported_functions;
} __packed;

struct apmf_system_params {
	u16 size;
	u32 valid_mask;
	u32 flags;
	u8 command_code;
	u32 heartbeat_int;
} __packed;

struct apmf_sbios_req {
	u16 size;
	u32 pending_req;
	u8 rsd;
	u8 cql_event;
	u8 amt_event;
	u32 fppt;
	u32 sppt;
	u32 fppt_apu_only;
	u32 spl;
	u32 stt_min_limit;
	u8 skin_temp_apu;
	u8 skin_temp_hs2;
} __packed;

struct apmf_fan_idx {
	u16 size;
	u8 fan_ctl_mode;
	u32 fan_ctl_idx;
} __packed;

struct smu_pmf_metrics {
	u16 gfxclk_freq; /* in MHz */
	u16 socclk_freq; /* in MHz */
	u16 vclk_freq; /* in MHz */
	u16 dclk_freq; /* in MHz */
	u16 memclk_freq; /* in MHz */
	u16 spare;
	u16 gfx_activity; /* in Centi */
	u16 uvd_activity; /* in Centi */
	u16 voltage[2]; /* in mV */
	u16 currents[2]; /* in mA */
	u16 power[2];/* in mW */
	u16 core_freq[8]; /* in MHz */
	u16 core_power[8]; /* in mW */
	u16 core_temp[8]; /* in centi-Celsius */
	u16 l3_freq; /* in MHz */
	u16 l3_temp; /* in centi-Celsius */
	u16 gfx_temp; /* in centi-Celsius */
	u16 soc_temp; /* in centi-Celsius */
	u16 throttler_status;
	u16 current_socketpower; /* in mW */
	u16 stapm_orig_limit; /* in W */
	u16 stapm_cur_limit; /* in W */
	u32 apu_power; /* in mW */
	u32 dgpu_power; /* in mW */
	u16 vdd_tdc_val; /* in mA */
	u16 soc_tdc_val; /* in mA */
	u16 vdd_edc_val; /* in mA */
	u16 soc_edcv_al; /* in mA */
	u16 infra_cpu_maxfreq; /* in MHz */
	u16 infra_gfx_maxfreq; /* in MHz */
	u16 skin_temp; /* in centi-Celsius */
	u16 device_state;
} __packed;

enum amd_stt_skin_temp {
	STT_TEMP_APU,
	STT_TEMP_HS2,
	STT_TEMP_COUNT,
};

enum amd_slider_op {
	SLIDER_OP_GET,
	SLIDER_OP_SET,
};

enum power_source {
	POWER_SOURCE_AC,
	POWER_SOURCE_DC,
	POWER_SOURCE_MAX,
};

enum power_modes {
	POWER_MODE_PERFORMANCE,
	POWER_MODE_BALANCED_POWER,
	POWER_MODE_POWER_SAVER,
	POWER_MODE_MAX,
};

struct amd_pmf_dev {
	void __iomem *regbase;
	void __iomem *smu_virt_addr;
	void *buf;
	u32 base_addr;
	u32 cpu_id;
	struct device *dev;
	struct mutex lock; /* protects the PMF interface */
	u32 supported_func;
	enum platform_profile_option current_profile;
	struct platform_profile_handler pprof;
	struct dentry *dbgfs_dir;
	int hb_interval; /* SBIOS heartbeat interval */
	struct delayed_work heart_beat;
	struct smu_pmf_metrics m_table;
	struct delayed_work work_buffer;
	ktime_t start_time;
	int socket_power_history[AVG_SAMPLE_SIZE];
	int socket_power_history_idx;
	bool amt_enabled;
	struct mutex update_mutex; /* protects race between ACPI handler and metrics thread */
	bool cnqf_enabled;
	bool cnqf_supported;
	struct notifier_block pwr_src_notifier;
};

struct apmf_sps_prop_granular {
	u32 fppt;
	u32 sppt;
	u32 sppt_apu_only;
	u32 spl;
	u32 stt_min;
	u8 stt_skin_temp[STT_TEMP_COUNT];
	u32 fan_id;
} __packed;

/* Static Slider */
struct apmf_static_slider_granular_output {
	u16 size;
	struct apmf_sps_prop_granular prop[POWER_SOURCE_MAX * POWER_MODE_MAX];
} __packed;

struct amd_pmf_static_slider_granular {
	u16 size;
	struct apmf_sps_prop_granular prop[POWER_SOURCE_MAX][POWER_MODE_MAX];
};

struct os_power_slider {
	u16 size;
	u8 slider_event;
} __packed;

struct fan_table_control {
	bool manual;
	unsigned long fan_id;
};

struct power_table_control {
	u32 spl;
	u32 sppt;
	u32 fppt;
	u32 sppt_apu_only;
	u32 stt_min;
	u32 stt_skin_temp[STT_TEMP_COUNT];
	u32 reserved[16];
};

/* Auto Mode Layer */
enum auto_mode_transition_priority {
	AUTO_TRANSITION_TO_PERFORMANCE, /* Any other mode to Performance Mode */
	AUTO_TRANSITION_FROM_QUIET_TO_BALANCE, /* Quiet Mode to Balance Mode */
	AUTO_TRANSITION_TO_QUIET, /* Any other mode to Quiet Mode */
	AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE, /* Performance Mode to Balance Mode */
	AUTO_TRANSITION_MAX,
};

enum auto_mode_mode {
	AUTO_QUIET,
	AUTO_BALANCE,
	AUTO_PERFORMANCE_ON_LAP,
	AUTO_PERFORMANCE,
	AUTO_MODE_MAX,
};

struct auto_mode_trans_params {
	u32 time_constant; /* minimum time required to switch to next mode */
	u32 power_delta; /* delta power to shift mode */
	u32 power_threshold;
	u32 timer; /* elapsed time. if timer > TimeThreshold, it will move to next mode */
	u32 applied;
	enum auto_mode_mode target_mode;
	u32 shifting_up;
};

struct auto_mode_mode_settings {
	struct power_table_control power_control;
	struct fan_table_control fan_control;
	u32 power_floor;
};

struct auto_mode_mode_config {
	struct auto_mode_trans_params transition[AUTO_TRANSITION_MAX];
	struct auto_mode_mode_settings mode_set[AUTO_MODE_MAX];
	enum auto_mode_mode current_mode;
};

struct apmf_auto_mode {
	u16 size;
	/* time constant */
	u32 balanced_to_perf;
	u32 perf_to_balanced;
	u32 quiet_to_balanced;
	u32 balanced_to_quiet;
	/* power floor */
	u32 pfloor_perf;
	u32 pfloor_balanced;
	u32 pfloor_quiet;
	/* Power delta for mode change */
	u32 pd_balanced_to_perf;
	u32 pd_perf_to_balanced;
	u32 pd_quiet_to_balanced;
	u32 pd_balanced_to_quiet;
	/* skin temperature limits */
	u8 stt_apu_perf_on_lap; /* CQL ON */
	u8 stt_hs2_perf_on_lap; /* CQL ON */
	u8 stt_apu_perf;
	u8 stt_hs2_perf;
	u8 stt_apu_balanced;
	u8 stt_hs2_balanced;
	u8 stt_apu_quiet;
	u8 stt_hs2_quiet;
	u32 stt_min_limit_perf_on_lap; /* CQL ON */
	u32 stt_min_limit_perf;
	u32 stt_min_limit_balanced;
	u32 stt_min_limit_quiet;
	/* SPL based */
	u32 fppt_perf_on_lap; /* CQL ON */
	u32 sppt_perf_on_lap; /* CQL ON */
	u32 spl_perf_on_lap; /* CQL ON */
	u32 sppt_apu_only_perf_on_lap; /* CQL ON */
	u32 fppt_perf;
	u32 sppt_perf;
	u32 spl_perf;
	u32 sppt_apu_only_perf;
	u32 fppt_balanced;
	u32 sppt_balanced;
	u32 spl_balanced;
	u32 sppt_apu_only_balanced;
	u32 fppt_quiet;
	u32 sppt_quiet;
	u32 spl_quiet;
	u32 sppt_apu_only_quiet;
	/* Fan ID */
	u32 fan_id_perf;
	u32 fan_id_balanced;
	u32 fan_id_quiet;
} __packed;

/* CnQF Layer */
enum cnqf_trans_priority {
	CNQF_TRANSITION_TO_TURBO, /* Any other mode to Turbo Mode */
	CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE, /* quiet/balance to Performance Mode */
	CNQF_TRANSITION_FROM_QUIET_TO_BALANCE, /* Quiet Mode to Balance Mode */
	CNQF_TRANSITION_TO_QUIET, /* Any other mode to Quiet Mode */
	CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE, /* Performance/Turbo to Balance Mode */
	CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE, /* Turbo mode to Performance Mode */
	CNQF_TRANSITION_MAX,
};

enum cnqf_mode {
	CNQF_MODE_QUIET,
	CNQF_MODE_BALANCE,
	CNQF_MODE_PERFORMANCE,
	CNQF_MODE_TURBO,
	CNQF_MODE_MAX,
};

enum apmf_cnqf_pos {
	APMF_CNQF_TURBO,
	APMF_CNQF_PERFORMANCE,
	APMF_CNQF_BALANCE,
	APMF_CNQF_QUIET,
	APMF_CNQF_MAX,
};

struct cnqf_mode_settings {
	struct power_table_control power_control;
	struct fan_table_control fan_control;
	u32 power_floor;
};

struct cnqf_tran_params {
	u32 time_constant; /* minimum time required to switch to next mode */
	u32 power_threshold;
	u32 timer; /* elapsed time. if timer > timethreshold, it will move to next mode */
	u32 total_power;
	u32 count;
	bool priority;
	bool shifting_up;
	enum cnqf_mode target_mode;
};

struct cnqf_config {
	struct cnqf_tran_params trans_param[POWER_SOURCE_MAX][CNQF_TRANSITION_MAX];
	struct cnqf_mode_settings mode_set[POWER_SOURCE_MAX][CNQF_MODE_MAX];
	struct power_table_control defaults;
	enum cnqf_mode current_mode;
	u32 power_src;
	u32 avg_power;
};

struct apmf_cnqf_power_set {
	u32 pfloor;
	u32 fppt;
	u32 sppt;
	u32 sppt_apu_only;
	u32 spl;
	u32 stt_min_limit;
	u8 stt_skintemp[STT_TEMP_COUNT];
	u32 fan_id;
} __packed;

struct apmf_dyn_slider_output {
	u16 size;
	u16 flags;
	u32 t_perf_to_turbo;
	u32 t_balanced_to_perf;
	u32 t_quiet_to_balanced;
	u32 t_balanced_to_quiet;
	u32 t_perf_to_balanced;
	u32 t_turbo_to_perf;
	struct apmf_cnqf_power_set ps[APMF_CNQF_MAX];
} __packed;

/* Core Layer */
int apmf_acpi_init(struct amd_pmf_dev *pmf_dev);
void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev);
int is_apmf_func_supported(struct amd_pmf_dev *pdev, unsigned long index);
int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data);
int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev);
int amd_pmf_get_power_source(void);
int apmf_install_handler(struct amd_pmf_dev *pmf_dev);
int apmf_os_power_slider_update(struct amd_pmf_dev *dev, u8 flag);

/* SPS Layer */
int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf);
void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx,
			   struct amd_pmf_static_slider_granular *table);
int amd_pmf_init_sps(struct amd_pmf_dev *dev);
void amd_pmf_deinit_sps(struct amd_pmf_dev *dev);
int apmf_get_static_slider_granular(struct amd_pmf_dev *pdev,
				    struct apmf_static_slider_granular_output *output);
bool is_pprof_balanced(struct amd_pmf_dev *pmf);
int amd_pmf_power_slider_update_event(struct amd_pmf_dev *dev);


int apmf_update_fan_idx(struct amd_pmf_dev *pdev, bool manual, u32 idx);
int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf);

/* Auto Mode Layer */
int apmf_get_auto_mode_def(struct amd_pmf_dev *pdev, struct apmf_auto_mode *data);
void amd_pmf_init_auto_mode(struct amd_pmf_dev *dev);
void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev);
void amd_pmf_trans_automode(struct amd_pmf_dev *dev, int socket_power, ktime_t time_elapsed_ms);
int apmf_get_sbios_requests(struct amd_pmf_dev *pdev, struct apmf_sbios_req *req);

void amd_pmf_update_2_cql(struct amd_pmf_dev *dev, bool is_cql_event);
int amd_pmf_reset_amt(struct amd_pmf_dev *dev);
void amd_pmf_handle_amt(struct amd_pmf_dev *dev);

/* CnQF Layer */
int apmf_get_dyn_slider_def_ac(struct amd_pmf_dev *pdev, struct apmf_dyn_slider_output *data);
int apmf_get_dyn_slider_def_dc(struct amd_pmf_dev *pdev, struct apmf_dyn_slider_output *data);
int amd_pmf_init_cnqf(struct amd_pmf_dev *dev);
void amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev);
int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_lapsed_ms);
extern const struct attribute_group cnqf_feature_attribute_group;

#endif /* PMF_H */