File Index
Files and directories
Sign in
FILE

core.c

File preview with syntax highlighting.

linux-6.19.14/drivers/platform/x86/amd/pmf/core.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * AMD Platform Management Framework Driver
  4 *
  5 * Copyright (c) 2022, Advanced Micro Devices, Inc.
  6 * All Rights Reserved.
  7 *
  8 * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
  9 */
 10
 11#include <linux/debugfs.h>
 12#include <linux/iopoll.h>
 13#include <linux/module.h>
 14#include <linux/pci.h>
 15#include <linux/platform_device.h>
 16#include <linux/power_supply.h>
 17#include <asm/amd/node.h>
 18#include "pmf.h"
 19
 20/* PMF-SMU communication registers */
 21#define AMD_PMF_REGISTER_MESSAGE	0xA18
 22#define AMD_PMF_REGISTER_RESPONSE	0xA78
 23#define AMD_PMF_REGISTER_ARGUMENT	0xA58
 24
 25/* Base address of SMU for mapping physical address to virtual address */
 26#define AMD_PMF_MAPPING_SIZE		0x01000
 27#define AMD_PMF_BASE_ADDR_OFFSET	0x10000
 28#define AMD_PMF_BASE_ADDR_LO		0x13B102E8
 29#define AMD_PMF_BASE_ADDR_HI		0x13B102EC
 30#define AMD_PMF_BASE_ADDR_LO_MASK	GENMASK(15, 0)
 31#define AMD_PMF_BASE_ADDR_HI_MASK	GENMASK(31, 20)
 32
 33/* SMU Response Codes */
 34#define AMD_PMF_RESULT_OK                    0x01
 35#define AMD_PMF_RESULT_CMD_REJECT_BUSY       0xFC
 36#define AMD_PMF_RESULT_CMD_REJECT_PREREQ     0xFD
 37#define AMD_PMF_RESULT_CMD_UNKNOWN           0xFE
 38#define AMD_PMF_RESULT_FAILED                0xFF
 39
 40#define PMF_MSG_DELAY_MIN_US		50
 41#define RESPONSE_REGISTER_LOOP_MAX	20000
 42
 43#define DELAY_MIN_US	2000
 44#define DELAY_MAX_US	3000
 45
 46/* override Metrics Table sample size time (in ms) */
 47static int metrics_table_loop_ms = 1000;
 48module_param(metrics_table_loop_ms, int, 0644);
 49MODULE_PARM_DESC(metrics_table_loop_ms, "Metrics Table sample size time (default = 1000ms)");
 50
 51/* Force load on supported older platforms */
 52static bool force_load;
 53module_param(force_load, bool, 0444);
 54MODULE_PARM_DESC(force_load, "Force load this driver on supported older platforms (experimental)");
 55
 56static int amd_pmf_pwr_src_notify_call(struct notifier_block *nb, unsigned long event, void *data)
 57{
 58	struct amd_pmf_dev *pmf = container_of(nb, struct amd_pmf_dev, pwr_src_notifier);
 59
 60	if (event != PSY_EVENT_PROP_CHANGED)
 61		return NOTIFY_OK;
 62
 63	if (is_apmf_func_supported(pmf, APMF_FUNC_AUTO_MODE) ||
 64	    is_apmf_func_supported(pmf, APMF_FUNC_DYN_SLIDER_DC) ||
 65	    is_apmf_func_supported(pmf, APMF_FUNC_DYN_SLIDER_AC)) {
 66		if ((pmf->amt_enabled || pmf->cnqf_enabled) && is_pprof_balanced(pmf))
 67			return NOTIFY_DONE;
 68	}
 69
 70	if (is_apmf_func_supported(pmf, APMF_FUNC_STATIC_SLIDER_GRANULAR))
 71		amd_pmf_set_sps_power_limits(pmf);
 72
 73	if (is_apmf_func_supported(pmf, APMF_FUNC_OS_POWER_SLIDER_UPDATE))
 74		amd_pmf_power_slider_update_event(pmf);
 75
 76	return NOTIFY_OK;
 77}
 78
 79static int current_power_limits_show(struct seq_file *seq, void *unused)
 80{
 81	struct amd_pmf_dev *dev = seq->private;
 82	struct amd_pmf_static_slider_granular table;
 83	int mode, src = 0;
 84
 85	mode = amd_pmf_get_pprof_modes(dev);
 86	if (mode < 0)
 87		return mode;
 88
 89	src = amd_pmf_get_power_source();
 90	amd_pmf_update_slider(dev, SLIDER_OP_GET, mode, &table);
 91	seq_printf(seq, "spl:%u fppt:%u sppt:%u sppt_apu_only:%u stt_min:%u stt[APU]:%u stt[HS2]: %u\n",
 92		   table.prop[src][mode].spl,
 93		   table.prop[src][mode].fppt,
 94		   table.prop[src][mode].sppt,
 95		   table.prop[src][mode].sppt_apu_only,
 96		   table.prop[src][mode].stt_min,
 97		   table.prop[src][mode].stt_skin_temp[STT_TEMP_APU],
 98		   table.prop[src][mode].stt_skin_temp[STT_TEMP_HS2]);
 99	return 0;
100}
101DEFINE_SHOW_ATTRIBUTE(current_power_limits);
102
103static void amd_pmf_dbgfs_unregister(struct amd_pmf_dev *dev)
104{
105	debugfs_remove_recursive(dev->dbgfs_dir);
106}
107
108static void amd_pmf_dbgfs_register(struct amd_pmf_dev *dev)
109{
110	dev->dbgfs_dir = debugfs_create_dir("amd_pmf", NULL);
111	if (dev->pmf_if_version == PMF_IF_V1)
112		debugfs_create_file("current_power_limits", 0644, dev->dbgfs_dir, dev,
113				    &current_power_limits_fops);
114}
115
116int amd_pmf_get_power_source(void)
117{
118	if (power_supply_is_system_supplied() > 0)
119		return POWER_SOURCE_AC;
120	else
121		return POWER_SOURCE_DC;
122}
123
124static void amd_pmf_get_metrics(struct work_struct *work)
125{
126	struct amd_pmf_dev *dev = container_of(work, struct amd_pmf_dev, work_buffer.work);
127	ktime_t time_elapsed_ms;
128	int socket_power;
129
130	guard(mutex)(&dev->update_mutex);
131
132	/* Transfer table contents */
133	memset(dev->buf, 0, sizeof(dev->m_table));
134	amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL);
135	memcpy(&dev->m_table, dev->buf, sizeof(dev->m_table));
136
137	time_elapsed_ms = ktime_to_ms(ktime_get()) - dev->start_time;
138	/* Calculate the avg SoC power consumption */
139	socket_power = dev->m_table.apu_power + dev->m_table.dgpu_power;
140
141	if (dev->amt_enabled) {
142		/* Apply the Auto Mode transition */
143		amd_pmf_trans_automode(dev, socket_power, time_elapsed_ms);
144	}
145
146	if (dev->cnqf_enabled) {
147		/* Apply the CnQF transition */
148		amd_pmf_trans_cnqf(dev, socket_power, time_elapsed_ms);
149	}
150
151	dev->start_time = ktime_to_ms(ktime_get());
152	schedule_delayed_work(&dev->work_buffer, msecs_to_jiffies(metrics_table_loop_ms));
153}
154
155static inline u32 amd_pmf_reg_read(struct amd_pmf_dev *dev, int reg_offset)
156{
157	return ioread32(dev->regbase + reg_offset);
158}
159
160static inline void amd_pmf_reg_write(struct amd_pmf_dev *dev, int reg_offset, u32 val)
161{
162	iowrite32(val, dev->regbase + reg_offset);
163}
164
165static void __maybe_unused amd_pmf_dump_registers(struct amd_pmf_dev *dev)
166{
167	u32 value;
168
169	value = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_RESPONSE);
170	dev_dbg(dev->dev, "AMD_PMF_REGISTER_RESPONSE:%x\n", value);
171
172	value = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_ARGUMENT);
173	dev_dbg(dev->dev, "AMD_PMF_REGISTER_ARGUMENT:%d\n", value);
174
175	value = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_MESSAGE);
176	dev_dbg(dev->dev, "AMD_PMF_REGISTER_MESSAGE:%x\n", value);
177}
178
179/**
180 * fixp_q88_fromint: Convert integer to Q8.8
181 * @val: input value
182 *
183 * Converts an integer into binary fixed point format where 8 bits
184 * are used for integer and 8 bits are used for the decimal.
185 *
186 * Return: unsigned integer converted to Q8.8 format
187 */
188u32 fixp_q88_fromint(u32 val)
189{
190	return val << 8;
191}
192
193int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data)
194{
195	int rc;
196	u32 val;
197
198	guard(mutex)(&dev->lock);
199
200	/* Wait until we get a valid response */
201	rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMF_REGISTER_RESPONSE,
202				val, val != 0, PMF_MSG_DELAY_MIN_US,
203				PMF_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX);
204	if (rc) {
205		dev_err(dev->dev, "failed to talk to SMU\n");
206		return rc;
207	}
208
209	/* Write zero to response register */
210	amd_pmf_reg_write(dev, AMD_PMF_REGISTER_RESPONSE, 0);
211
212	/* Write argument into argument register */
213	amd_pmf_reg_write(dev, AMD_PMF_REGISTER_ARGUMENT, arg);
214
215	/* Write message ID to message ID register */
216	amd_pmf_reg_write(dev, AMD_PMF_REGISTER_MESSAGE, message);
217
218	/* Wait until we get a valid response */
219	rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMF_REGISTER_RESPONSE,
220				val, val != 0, PMF_MSG_DELAY_MIN_US,
221				PMF_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX);
222	if (rc) {
223		dev_err(dev->dev, "SMU response timed out\n");
224		return rc;
225	}
226
227	switch (val) {
228	case AMD_PMF_RESULT_OK:
229		if (get) {
230			/* PMFW may take longer time to return back the data */
231			usleep_range(DELAY_MIN_US, 10 * DELAY_MAX_US);
232			*data = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_ARGUMENT);
233		}
234		break;
235	case AMD_PMF_RESULT_CMD_REJECT_BUSY:
236		dev_err(dev->dev, "SMU not ready. err: 0x%x\n", val);
237		rc = -EBUSY;
238		break;
239	case AMD_PMF_RESULT_CMD_UNKNOWN:
240		dev_err(dev->dev, "SMU cmd unknown. err: 0x%x\n", val);
241		rc = -EINVAL;
242		break;
243	case AMD_PMF_RESULT_CMD_REJECT_PREREQ:
244	case AMD_PMF_RESULT_FAILED:
245	default:
246		dev_err(dev->dev, "SMU cmd failed. err: 0x%x\n", val);
247		rc = -EIO;
248		break;
249	}
250
251	amd_pmf_dump_registers(dev);
252	return rc;
253}
254
255static const struct pci_device_id pmf_pci_ids[] = {
256	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RMB) },
257	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PS) },
258	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) },
259	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) },
260	{ }
261};
262
263int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer)
264{
265	u64 phys_addr;
266	u32 hi, low;
267
268	/* Get Metrics Table Address */
269	if (alloc_buffer) {
270		switch (dev->cpu_id) {
271		case AMD_CPU_ID_PS:
272		case AMD_CPU_ID_RMB:
273			dev->mtable_size = sizeof(dev->m_table);
274			break;
275		case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
276		case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
277			dev->mtable_size = sizeof(dev->m_table_v2);
278			break;
279		default:
280			dev_err(dev->dev, "Invalid CPU id: 0x%x", dev->cpu_id);
281		}
282
283		dev->buf = devm_kzalloc(dev->dev, dev->mtable_size, GFP_KERNEL);
284		if (!dev->buf)
285			return -ENOMEM;
286	}
287
288	phys_addr = virt_to_phys(dev->buf);
289	hi = phys_addr >> 32;
290	low = phys_addr & GENMASK(31, 0);
291
292	amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, SET_CMD, hi, NULL);
293	amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, SET_CMD, low, NULL);
294
295	return 0;
296}
297
298int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
299{
300	int ret;
301
302	INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics);
303
304	ret = amd_pmf_set_dram_addr(dev, true);
305	if (ret)
306		return ret;
307
308	/*
309	 * Start collecting the metrics data after a small delay
310	 * or else, we might end up getting stale values from PMFW.
311	 */
312	schedule_delayed_work(&dev->work_buffer, msecs_to_jiffies(metrics_table_loop_ms * 3));
313
314	return 0;
315}
316
317static int amd_pmf_reinit_ta(struct amd_pmf_dev *pdev)
318{
319	bool status;
320	int ret, i;
321
322	for (i = 0; i < ARRAY_SIZE(amd_pmf_ta_uuid); i++) {
323		ret = amd_pmf_tee_init(pdev, &amd_pmf_ta_uuid[i]);
324		if (ret) {
325			dev_err(pdev->dev, "TEE init failed for UUID[%d] ret: %d\n", i, ret);
326			return ret;
327		}
328
329		ret = amd_pmf_start_policy_engine(pdev);
330		dev_dbg(pdev->dev, "start policy engine ret: %d (UUID idx: %d)\n", ret, i);
331		status = ret == TA_PMF_TYPE_SUCCESS;
332		if (status)
333			break;
334		amd_pmf_tee_deinit(pdev);
335	}
336
337	return 0;
338}
339
340static int amd_pmf_restore_handler(struct device *dev)
341{
342	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
343	int ret;
344
345	if (pdev->buf) {
346		ret = amd_pmf_set_dram_addr(pdev, false);
347		if (ret)
348			return ret;
349	}
350
351	if (pdev->smart_pc_enabled)
352		amd_pmf_reinit_ta(pdev);
353
354	return 0;
355}
356
357static int amd_pmf_freeze_handler(struct device *dev)
358{
359	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
360
361	if (!pdev->smart_pc_enabled)
362		return 0;
363
364	cancel_delayed_work_sync(&pdev->pb_work);
365	/* Clear all TEE resources */
366	amd_pmf_tee_deinit(pdev);
367	pdev->session_id = 0;
368
369	return 0;
370}
371
372static int amd_pmf_suspend_handler(struct device *dev)
373{
374	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
375
376	if (pdev->smart_pc_enabled)
377		cancel_delayed_work_sync(&pdev->pb_work);
378
379	if (is_apmf_func_supported(pdev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
380		amd_pmf_notify_sbios_heartbeat_event_v2(pdev, ON_SUSPEND);
381
382	return 0;
383}
384
385static int amd_pmf_resume_handler(struct device *dev)
386{
387	struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
388	int ret;
389
390	if (pdev->buf) {
391		ret = amd_pmf_set_dram_addr(pdev, false);
392		if (ret)
393			return ret;
394	}
395
396	if (is_apmf_func_supported(pdev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
397		amd_pmf_notify_sbios_heartbeat_event_v2(pdev, ON_RESUME);
398
399	if (pdev->smart_pc_enabled)
400		schedule_delayed_work(&pdev->pb_work, msecs_to_jiffies(2000));
401
402	return 0;
403}
404
405static const struct dev_pm_ops amd_pmf_pm = {
406	.suspend = amd_pmf_suspend_handler,
407	.resume = amd_pmf_resume_handler,
408	.freeze = amd_pmf_freeze_handler,
409	.restore = amd_pmf_restore_handler,
410};
411
412static void amd_pmf_init_features(struct amd_pmf_dev *dev)
413{
414	int ret;
415
416	/* Enable Static Slider */
417	if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR) ||
418	    is_apmf_func_supported(dev, APMF_FUNC_OS_POWER_SLIDER_UPDATE)) {
419		amd_pmf_init_sps(dev);
420		dev->pwr_src_notifier.notifier_call = amd_pmf_pwr_src_notify_call;
421		power_supply_reg_notifier(&dev->pwr_src_notifier);
422		dev_dbg(dev->dev, "SPS enabled and Platform Profiles registered\n");
423	}
424
425	amd_pmf_init_smart_pc(dev);
426	if (dev->smart_pc_enabled) {
427		dev_dbg(dev->dev, "Smart PC Solution Enabled\n");
428		/* If Smart PC is enabled, no need to check for other features */
429		return;
430	}
431
432	if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
433		amd_pmf_init_auto_mode(dev);
434		dev_dbg(dev->dev, "Auto Mode Init done\n");
435	} else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) ||
436			  is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) {
437		ret = amd_pmf_init_cnqf(dev);
438		if (ret)
439			dev_warn(dev->dev, "CnQF Init failed\n");
440	}
441}
442
443static void amd_pmf_deinit_features(struct amd_pmf_dev *dev)
444{
445	if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR) ||
446	    is_apmf_func_supported(dev, APMF_FUNC_OS_POWER_SLIDER_UPDATE)) {
447		power_supply_unreg_notifier(&dev->pwr_src_notifier);
448	}
449
450	if (dev->smart_pc_enabled) {
451		amd_pmf_deinit_smart_pc(dev);
452	} else if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
453		amd_pmf_deinit_auto_mode(dev);
454	} else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) ||
455			  is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) {
456		amd_pmf_deinit_cnqf(dev);
457	}
458}
459
460static const struct acpi_device_id amd_pmf_acpi_ids[] = {
461	{"AMDI0100", 0x100},
462	{"AMDI0102", 0},
463	{"AMDI0103", 0},
464	{"AMDI0105", 0},
465	{"AMDI0107", 0},
466	{"AMDI0108", 0},
467	{ }
468};
469MODULE_DEVICE_TABLE(acpi, amd_pmf_acpi_ids);
470
471static int amd_pmf_probe(struct platform_device *pdev)
472{
473	const struct acpi_device_id *id;
474	struct amd_pmf_dev *dev;
475	struct pci_dev *rdev;
476	u32 base_addr_lo;
477	u32 base_addr_hi;
478	u64 base_addr;
479	u32 val;
480	int err;
481
482	id = acpi_match_device(amd_pmf_acpi_ids, &pdev->dev);
483	if (!id)
484		return -ENODEV;
485
486	if (id->driver_data == 0x100 && !force_load)
487		return -ENODEV;
488
489	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
490	if (!dev)
491		return -ENOMEM;
492
493	dev->dev = &pdev->dev;
494
495	rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
496	if (!rdev || !pci_match_id(pmf_pci_ids, rdev)) {
497		pci_dev_put(rdev);
498		return -ENODEV;
499	}
500
501	dev->cpu_id = rdev->device;
502
503	err = amd_smn_read(0, AMD_PMF_BASE_ADDR_LO, &val);
504	if (err) {
505		pci_dev_put(rdev);
506		return dev_err_probe(dev->dev, pcibios_err_to_errno(err),
507				     "error in reading from 0x%x\n", AMD_PMF_BASE_ADDR_LO);
508	}
509
510	base_addr_lo = val & AMD_PMF_BASE_ADDR_HI_MASK;
511
512	err = amd_smn_read(0, AMD_PMF_BASE_ADDR_HI, &val);
513	if (err) {
514		pci_dev_put(rdev);
515		return dev_err_probe(dev->dev, pcibios_err_to_errno(err),
516				     "error in reading from 0x%x\n", AMD_PMF_BASE_ADDR_HI);
517	}
518
519	base_addr_hi = val & AMD_PMF_BASE_ADDR_LO_MASK;
520	pci_dev_put(rdev);
521	base_addr = ((u64)base_addr_hi << 32 | base_addr_lo);
522
523	dev->regbase = devm_ioremap(dev->dev, base_addr + AMD_PMF_BASE_ADDR_OFFSET,
524				    AMD_PMF_MAPPING_SIZE);
525	if (!dev->regbase)
526		return -ENOMEM;
527
528	err = devm_mutex_init(dev->dev, &dev->lock);
529	if (err)
530		return err;
531
532	err = devm_mutex_init(dev->dev, &dev->update_mutex);
533	if (err)
534		return err;
535
536	err = devm_mutex_init(dev->dev, &dev->cb_mutex);
537	if (err)
538		return err;
539
540	apmf_acpi_init(dev);
541	platform_set_drvdata(pdev, dev);
542	amd_pmf_dbgfs_register(dev);
543	amd_pmf_init_features(dev);
544	apmf_install_handler(dev);
545	if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
546		amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_LOAD);
547
548	dev_info(dev->dev, "registered PMF device successfully\n");
549
550	return 0;
551}
552
553static void amd_pmf_remove(struct platform_device *pdev)
554{
555	struct amd_pmf_dev *dev = platform_get_drvdata(pdev);
556
557	amd_pmf_deinit_features(dev);
558	if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
559		amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_UNLOAD);
560	apmf_acpi_deinit(dev);
561	amd_pmf_dbgfs_unregister(dev);
562}
563
564static const struct attribute_group *amd_pmf_driver_groups[] = {
565	&cnqf_feature_attribute_group,
566	NULL,
567};
568
569static struct platform_driver amd_pmf_driver = {
570	.driver = {
571		.name = "amd-pmf",
572		.acpi_match_table = amd_pmf_acpi_ids,
573		.dev_groups = amd_pmf_driver_groups,
574		.pm = pm_sleep_ptr(&amd_pmf_pm),
575	},
576	.probe = amd_pmf_probe,
577	.remove = amd_pmf_remove,
578};
579module_platform_driver(amd_pmf_driver);
580
581MODULE_LICENSE("GPL");
582MODULE_DESCRIPTION("AMD Platform Management Framework Driver");
583MODULE_SOFTDEP("pre: amdtee");
~/ Read-only file preview.