+
+#include <linux/backlight.h>
+#include "amdgpu.h"
+
+int amd_pmf_get_gfx_data(struct amd_gpu_pmf_data *pmf)
+{
+ struct drm_device *drm_dev = pci_get_drvdata(pmf->gpu_dev);
+ struct drm_mode_config *mode_config = &drm_dev->mode_config;
+ struct amdgpu_device *adev = drm_to_adev(drm_dev);
+ struct drm_connector_list_iter iter;
+ struct drm_connector *connector;
+ int i = 0;
+
+ /* Reset the count to zero */
+ pmf->display_count = 0;
+ if (!(adev->flags & AMD_IS_APU)) {
+ DRM_ERROR("PMF-AMDGPU interface not supported\n");
+ return -ENODEV;
+ }
+
+ mutex_lock(&mode_config->mutex);
+ drm_connector_list_iter_begin(drm_dev, &iter);
+ drm_for_each_connector_iter(connector, &iter) {
+ if (connector->status == connector_status_connected)
+ pmf->display_count++;
+ if (connector->status != pmf->con_status[i])
+ pmf->con_status[i] = connector->status;
+ if (connector->connector_type != pmf->connector_type[i])
+ pmf->connector_type[i] = connector->connector_type;
+
+ i++;
+ if (i >= MAX_SUPPORTED)
+ break;
+ }
+ drm_connector_list_iter_end(&iter);
+ mutex_unlock(&mode_config->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(amd_pmf_get_gfx_data);
+
+static int amd_pmf_gpu_get_cur_state(struct thermal_cooling_device
*cooling_dev,
+ unsigned long *state)
+{
+ struct backlight_device *bd;
+
+ if (!acpi_video_backlight_use_native())
+ return -ENODEV;
+
+ bd = backlight_device_get_by_type(BACKLIGHT_RAW);
+ if (!bd)
+ return -ENODEV;
+
+ *state = backlight_get_brightness(bd);
+
+ return 0;
+}
+
+static int amd_pmf_gpu_get_max_state(struct thermal_cooling_device
*cooling_dev,
+ unsigned long *state)
+{
+ struct backlight_device *bd;
+
+ if (!acpi_video_backlight_use_native())
+ return -ENODEV;
+
+ bd = backlight_device_get_by_type(BACKLIGHT_RAW);
+ if (!bd)
+ return -ENODEV;
+
+ if (backlight_is_blank(bd))
+ *state = 0;
+ else
+ *state = bd->props.max_brightness;
+
+ return 0;
+}
+
+static const struct thermal_cooling_device_ops bd_cooling_ops = {
+ .get_max_state = amd_pmf_gpu_get_max_state,
+ .get_cur_state = amd_pmf_gpu_get_cur_state,
+};
+
+int amd_pmf_gpu_init(struct amd_gpu_pmf_data *pmf)
+{
+ struct drm_device *drm_dev = pci_get_drvdata(pmf->gpu_dev);
+ struct amdgpu_device *adev = drm_to_adev(drm_dev);
+
+ if (!(adev->flags & AMD_IS_APU)) {
+ DRM_ERROR("PMF-AMDGPU interface not supported\n");
+ return -ENODEV;
+ }
+
+ if (!acpi_video_backlight_use_native())
+ return -ENODEV;
+
+ pmf->raw_bd = backlight_device_get_by_type(BACKLIGHT_RAW);
+ if (!pmf->raw_bd)
+ return -ENODEV;
+
+ pmf->cooling_dev = thermal_cooling_device_register("pmf_gpu_bd",
+ pmf, &bd_cooling_ops);
+ if (IS_ERR(pmf->cooling_dev))
+ return -ENODEV;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(amd_pmf_gpu_init);
+
+void amd_pmf_gpu_deinit(struct amd_gpu_pmf_data *pmf)
+{
+ thermal_cooling_device_unregister(pmf->cooling_dev);
+}
+EXPORT_SYMBOL_GPL(amd_pmf_gpu_deinit);
diff --git a/drivers/platform/x86/amd/pmf/Kconfig
b/drivers/platform/x86/amd/pmf/Kconfig
index f246252bddd8..7f430de7af44 100644
--- a/drivers/platform/x86/amd/pmf/Kconfig
+++ b/drivers/platform/x86/amd/pmf/Kconfig
@@ -10,6 +10,7 @@ config AMD_PMF
depends on AMD_NB
select ACPI_PLATFORM_PROFILE
depends on TEE && AMDTEE
+ depends on DRM_AMDGPU
help
This driver provides support for the AMD Platform Management
Framework.
The goal is to enhance end user experience by making AMD PCs
smarter,
diff --git a/drivers/platform/x86/amd/pmf/core.c
b/drivers/platform/x86/amd/pmf/core.c
index 4b8156033fa6..c59ba527ff49 100644
--- a/drivers/platform/x86/amd/pmf/core.c
+++ b/drivers/platform/x86/amd/pmf/core.c
@@ -411,6 +411,7 @@ static int amd_pmf_probe(struct platform_device
*pdev)
}
dev->cpu_id = rdev->device;
+ dev->root = rdev;
err = amd_smn_read(0, AMD_PMF_BASE_ADDR_LO, &val);
if (err) {
diff --git a/drivers/platform/x86/amd/pmf/pmf.h
b/drivers/platform/x86/amd/pmf/pmf.h
index 8712299ad52b..615cd3a31986 100644
--- a/drivers/platform/x86/amd/pmf/pmf.h
+++ b/drivers/platform/x86/amd/pmf/pmf.h
@@ -13,6 +13,7 @@
#include <linux/acpi.h>
#include <linux/platform_profile.h>
+#include <linux/amd-pmf-io.h>
#define POLICY_BUF_MAX_SZ 0x4b000
#define POLICY_SIGN_COOKIE 0x31535024
@@ -228,9 +229,11 @@ struct amd_pmf_dev {
void *shbuf;
struct delayed_work pb_work;
struct pmf_action_table *prev_data;
+ struct amd_gpu_pmf_data gfx_data;
u64 policy_addr;
void *policy_base;
bool smart_pc_enabled;
+ struct pci_dev *root;
};
struct apmf_sps_prop_granular {
diff --git a/drivers/platform/x86/amd/pmf/spc.c
b/drivers/platform/x86/amd/pmf/spc.c
index 512e0c66efdc..cf4962ef97c2 100644
--- a/drivers/platform/x86/amd/pmf/spc.c
+++ b/drivers/platform/x86/amd/pmf/spc.c
@@ -44,6 +44,10 @@ void amd_pmf_dump_ta_inputs(struct amd_pmf_dev
*dev, struct ta_pmf_enact_table *
dev_dbg(dev->dev, "Max C0 Residency : %u\n",
in->ev_info.max_c0residency);
dev_dbg(dev->dev, "GFX Busy : %u\n", in->ev_info.gfx_busy);
dev_dbg(dev->dev, "Connected Display Count : %u\n",
in->ev_info.monitor_count);
+ dev_dbg(dev->dev, "Primary Display Type : %s\n",
+ drm_get_connector_type_name(in->ev_info.display_type));
+ dev_dbg(dev->dev, "Primary Display State : %s\n",
in->ev_info.display_state ?
+ "Connected" : "disconnected/unknown");
dev_dbg(dev->dev, "LID State : %s\n", in->ev_info.lid_state ?
"Close" : "Open");
dev_dbg(dev->dev, "==== TA inputs END ====\n");
}
@@ -146,6 +150,14 @@ static int amd_pmf_get_slider_info(struct
amd_pmf_dev *dev, struct ta_pmf_enact_
return 0;
}
+static void amd_pmf_get_gpu_info(struct amd_pmf_dev *dev, struct
ta_pmf_enact_table *in)
+{
+ amd_pmf_get_gfx_data(&dev->gfx_data);
+ in->ev_info.monitor_count = dev->gfx_data.display_count;
+ in->ev_info.display_type = dev->gfx_data.connector_type[0];
+ in->ev_info.display_state = dev->gfx_data.con_status[0];
+}
+
void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct
ta_pmf_enact_table *in)
{
/* TA side lid open is 1 and close is 0, hence the ! here */
@@ -154,4 +166,5 @@ void amd_pmf_populate_ta_inputs(struct
amd_pmf_dev *dev, struct ta_pmf_enact_tab
amd_pmf_get_smu_info(dev, in);
amd_pmf_get_battery_info(dev, in);
amd_pmf_get_slider_info(dev, in);
+ amd_pmf_get_gpu_info(dev, in);
}
diff --git a/drivers/platform/x86/amd/pmf/tee-if.c
b/drivers/platform/x86/amd/pmf/tee-if.c
index 2f5fb8623c20..956e66b78605 100644
--- a/drivers/platform/x86/amd/pmf/tee-if.c
+++ b/drivers/platform/x86/amd/pmf/tee-if.c
@@ -9,6 +9,7 @@
*/
#include <linux/debugfs.h>
+#include <linux/pci.h>
#include <linux/tee_drv.h>
#include <linux/uuid.h>
#include "pmf.h"
@@ -357,6 +358,19 @@ static int amd_pmf_get_bios_buffer(struct
amd_pmf_dev *dev)
return amd_pmf_start_policy_engine(dev);
}
+static int amd_pmf_get_gpu_handle(struct pci_dev *pdev, void *data)
+{
+ struct amd_pmf_dev *dev = data;
+
+ if (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->devfn == 0) {
+ /* Found the amdgpu handle from the pci root after walking
through the pci bus */
+ pci_walk_bus(dev->root->bus, amd_pmf_get_gpu_handle, dev);
+ if (!dev->gfx_data.gpu_dev)
+ dev_err(dev->dev, "GPU handle not found!\n");
+
+ if (!amd_pmf_gpu_init(&dev->gfx_data))
+ dev->gfx_data.gpu_dev_en = true;
+
dev->prev_data = kzalloc(sizeof(*dev->prev_data), GFP_KERNEL);
if (!dev->prev_data)
return -ENOMEM;
@@ -461,5 +484,8 @@ void amd_pmf_deinit_smart_pc(struct amd_pmf_dev
*dev)
kfree(dev->prev_data);
kfree(dev->policy_buf);
cancel_delayed_work_sync(&dev->pb_work);
+ if (dev->gfx_data.gpu_dev_en)
+ amd_pmf_gpu_deinit(&dev->gfx_data);
+ pci_dev_put(dev->gfx_data.gpu_dev);
amd_pmf_tee_deinit(dev);
}
diff --git a/include/linux/amd-pmf-io.h b/include/linux/amd-pmf-io.h
new file mode 100644
index 000000000000..5f79e66a41b3
--- /dev/null
+++ b/include/linux/amd-pmf-io.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AMD Platform Management Framework Interface
+ *
+ * Copyright (c) 2023, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Shyam Sundar S K <Shyam-sundar.S-k@xxxxxxx>
+ */
+
+#ifndef AMD_PMF_IO_H
+#define AMD_PMF_IO_H
+
+#include <acpi/video.h>
+#include <drm/drm_connector.h>
+#include <linux/backlight.h>
+#include <linux/thermal.h>
+
+#define MAX_SUPPORTED 4
+
+/* amdgpu */