--- /dev/null
+What: /sys/bus/pci/drivers/intel_vpu/.../sched_mode
+Date: October 2024
+KernelVersion: 6.12
+Contact: dri-devel@lists.freedesktop.org
+Description: Current NPU scheduling mode. Returns one of the following strings:
+ - "HW" - Hardware Scheduler mode
+ - "OS" - Operating System Scheduler mode
+ Read-only.
+ Deprecated since the "OS" scheduling mode is not usable
+ and will be removed from future versions of the driver.
+ Will be removed in 2027
+
+What: /sys/bus/pci/drivers/intel_vpu/.../npu_max_frequency_mhz
+Date: April 2025
+KernelVersion: 6.15
+Contact: dri-devel@lists.freedesktop.org
+Description: Legacy alias for /sys/bus/pci/drivers/intel_vpu/.../freq/hw_max_freq.
+ Shows maximum frequency in MHz of the NPU's data processing unit.
+ Read-only.
+ Will be removed in 2027
+
+What: /sys/bus/pci/drivers/intel_vpu/.../npu_current_frequency_mhz
+Date: April 2025
+KernelVersion: 6.15
+Contact: dri-devel@lists.freedesktop.org
+Description: Legacy alias for /sys/bus/pci/drivers/intel_vpu/.../freq/current_freq.
+ Shows current frequency in MHz of the NPU's data processing unit.
+ The value is read only when the device is active; otherwise it returns 0.
+ Read-only.
+ Will be removed in 2027
--- /dev/null
+What: /sys/bus/pci/drivers/intel_vpu/.../npu_busy_time_us
+Date: May 2024
+KernelVersion: 6.11
+Contact: dri-devel@lists.freedesktop.org
+Description: Time in microseconds that the device spent executing jobs. The time is
+ counted when and only when there are jobs submitted to firmware. This time
+ can be used to measure the utilization of NPU, either by calculating the
+ difference between two timepoints or monitoring utilization percentage by
+ reading periodically. Recommended read period is 1 second to avoid impact
+ on job submission performance. Read-only.
+
+What: /sys/bus/pci/drivers/intel_vpu/.../npu_memory_utilization
+Date: Jan 2025
+KernelVersion: 6.15
+Contact: dri-devel@lists.freedesktop.org
+Description: Current NPU memory utilization in bytes. Reports the total size of all
+ resident buffer objects allocated for NPU use. Read-only.
+
+What: /sys/bus/pci/drivers/intel_vpu/.../freq/hw_min_freq
+Date: April 2026
+KernelVersion: 7.2
+Contact: dri-devel@lists.freedesktop.org
+Description: Minimum frequency in MHz supported by the NPU hardware. This is a
+ hardware capability and cannot be changed. Read-only.
+
+What: /sys/bus/pci/drivers/intel_vpu/.../freq/hw_efficient_freq
+Date: April 2026
+KernelVersion: 7.2
+Contact: dri-devel@lists.freedesktop.org
+Description: Most efficient operating frequency in MHz for the NPU. This represents
+ the frequency at which the NPU operates most efficiently in terms of power
+ and performance. Read-only.
+
+What: /sys/bus/pci/drivers/intel_vpu/.../freq/hw_max_freq
+Date: April 2026
+KernelVersion: 7.2
+Contact: dri-devel@lists.freedesktop.org
+Description: Maximum frequency in MHz supported by the NPU hardware. This is a
+ hardware capability and cannot be changed. Read-only.
+
+What: /sys/bus/pci/drivers/intel_vpu/.../freq/current_freq
+Date: April 2026
+KernelVersion: 7.2
+Contact: dri-devel@lists.freedesktop.org
+Description: Current operating frequency in MHz of the NPU. The value is valid only
+ when the device is active; returns 0 when idle. The actual frequency may
+ be lower than the requested range due to power or thermal constraints.
+ Read-only.
+
+What: /sys/bus/pci/drivers/intel_vpu/.../freq/set_min_freq
+Date: April 2026
+KernelVersion: 7.2
+Contact: dri-devel@lists.freedesktop.org
+Description: Configured minimum operating frequency in MHz (50XX devices and newer).
+ Values written are clamped to hardware limits (hw_min_freq to hw_max_freq).
+ If set_min_freq exceeds set_max_freq, the driver clamps set_min_freq to
+ set_max_freq when selecting the operating frequency. Read-write.
+
+What: /sys/bus/pci/drivers/intel_vpu/.../freq/set_max_freq
+Date: April 2026
+KernelVersion: 7.2
+Contact: dri-devel@lists.freedesktop.org
+Description: Configured maximum operating frequency in MHz (50XX devices and newer).
+ Values written are clamped to hardware limits (hw_min_freq to hw_max_freq).
+ Read-write.
L: dri-devel@lists.freedesktop.org
S: Supported
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
+F: Documentation/ABI/obsolete/sysfs-driver-ivpu
+F: Documentation/ABI/testing/sysfs-driver-ivpu
F: drivers/accel/ivpu/
F: include/uapi/drm/ivpu_accel.h
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2020-2025 Intel Corporation
+ * Copyright (C) 2020-2026 Intel Corporation
*/
#include <linux/firmware.h>
args->value = vdev->platform;
break;
case DRM_IVPU_PARAM_CORE_CLOCK_RATE:
- args->value = ivpu_hw_dpu_max_freq_get(vdev);
+ args->value = ivpu_hw_btrs_pll_ratio_to_hz(vdev, vdev->hw->pll.max_ratio);
break;
case DRM_IVPU_PARAM_NUM_CONTEXTS:
args->value = file_priv->user_limits->max_ctx_count;
ret = ivpu_hw_sched_init(vdev);
if (ret)
goto err_disable_ipc;
+
+ ret = ivpu_hw_btrs_cfg_freq_init(vdev);
+ if (ret)
+ goto err_disable_ipc;
}
return 0;
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2020-2025 Intel Corporation
+ * Copyright (C) 2020-2026 Intel Corporation
*/
#ifndef __IVPU_HW_H__
struct ivpu_addr_range dma;
} ranges;
struct {
+ /* Hardware min and max pll ratio */
u8 min_ratio;
u8 max_ratio;
/*
* performance to power ratio at this frequency.
*/
u8 pn_ratio;
+ /* Pll ratios configured via sysfs interface */
+ u8 cfg_min_ratio;
+ u8 cfg_max_ratio;
u32 profiling_freq;
} pll;
struct {
return range->end - range->start;
}
-static inline u32 ivpu_hw_dpu_max_freq_get(struct ivpu_device *vdev)
-{
- return ivpu_hw_btrs_dpu_max_freq_get(vdev);
-}
-
-static inline u32 ivpu_hw_dpu_freq_get(struct ivpu_device *vdev)
-{
- return ivpu_hw_btrs_dpu_freq_get(vdev);
-}
-
static inline void ivpu_hw_irq_clear(struct ivpu_device *vdev)
{
ivpu_hw_ip_irq_clear(vdev);
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2020-2025 Intel Corporation
+ * Copyright (C) 2020-2026 Intel Corporation
*/
#include <linux/units.h>
#include "ivpu_hw_btrs_lnl_reg.h"
#include "ivpu_hw_btrs_mtl_reg.h"
#include "ivpu_hw_reg_io.h"
+#include "ivpu_jsm_msg.h"
#include "ivpu_pm.h"
#define BTRS_MTL_IRQ_MASK ((REG_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, ATS_ERR)) | \
#define PLL_CDYN_DEFAULT 0x80
#define PLL_EPP_DEFAULT 0x80
-#define PLL_REF_CLK_FREQ 50000000ull
-#define PLL_RATIO_TO_FREQ(x) ((x) * PLL_REF_CLK_FREQ)
+#define PLL_REF_CLK_FREQ_MHZ 50
#define PLL_TIMEOUT_US (1500 * USEC_PER_MSEC)
#define IDLE_TIMEOUT_US (5 * USEC_PER_MSEC)
#define DCT_ENABLE 0x1
#define DCT_DISABLE 0x0
-static u32 pll_ratio_to_dpu_freq(struct ivpu_device *vdev, u32 ratio);
-
int ivpu_hw_btrs_irqs_clear_with_0_mtl(struct ivpu_device *vdev)
{
REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, BTRS_MTL_ALL_IRQ_MASK);
hw->pll.min_ratio = clamp_t(u8, ivpu_pll_min_ratio, hw->pll.min_ratio, hw->pll.max_ratio);
hw->pll.max_ratio = clamp_t(u8, ivpu_pll_max_ratio, hw->pll.min_ratio, hw->pll.max_ratio);
hw->pll.pn_ratio = clamp_t(u8, hw->pll.pn_ratio, hw->pll.min_ratio, hw->pll.max_ratio);
+ hw->pll.cfg_max_ratio = hw->pll.max_ratio;
+ hw->pll.cfg_min_ratio = hw->pll.min_ratio;
}
static bool tile_disable_check(u32 config)
prepare_wp_request(vdev, &wp, enable);
- ivpu_dbg(vdev, PM, "PLL workpoint request: %lu MHz, config: 0x%x, epp: 0x%x, cdyn: 0x%x\n",
- pll_ratio_to_dpu_freq(vdev, wp.target) / HZ_PER_MHZ, wp.cfg, wp.epp, wp.cdyn);
+ ivpu_dbg(vdev, PM, "PLL workpoint request: %u MHz, config: 0x%x, epp: 0x%x, cdyn: 0x%x\n",
+ ivpu_hw_btrs_pll_ratio_to_mhz(vdev, wp.target), wp.cfg, wp.epp, wp.cdyn);
ret = wp_request_send(vdev, &wp);
if (ret) {
return REGB_RD32(VPU_HW_BTRS_LNL_PLL_FREQ);
}
-static u32 pll_ratio_to_dpu_freq_mtl(u16 ratio)
+static u32 pll_ratio_to_mhz_mtl(u8 pll_ratio)
{
- return (PLL_RATIO_TO_FREQ(ratio) * 2) / 3;
+ return (pll_ratio * PLL_REF_CLK_FREQ_MHZ * 2) / 3;
}
-static u32 pll_ratio_to_dpu_freq_lnl(u16 ratio)
+static u32 pll_ratio_to_mhz_lnl(u8 pll_ratio)
{
- return PLL_RATIO_TO_FREQ(ratio) / 2;
+ return (pll_ratio * PLL_REF_CLK_FREQ_MHZ) / 2;
}
-static u32 pll_ratio_to_dpu_freq(struct ivpu_device *vdev, u32 ratio)
+u32 ivpu_hw_btrs_pll_ratio_to_mhz(struct ivpu_device *vdev, u8 pll_ratio)
{
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
- return pll_ratio_to_dpu_freq_mtl(ratio);
+ return pll_ratio_to_mhz_mtl(pll_ratio);
else
- return pll_ratio_to_dpu_freq_lnl(ratio);
+ return pll_ratio_to_mhz_lnl(pll_ratio);
}
-u32 ivpu_hw_btrs_dpu_max_freq_get(struct ivpu_device *vdev)
+u32 ivpu_hw_btrs_pll_ratio_to_hz(struct ivpu_device *vdev, u8 pll_ratio)
{
- return pll_ratio_to_dpu_freq(vdev, vdev->hw->pll.max_ratio);
+ return ivpu_hw_btrs_pll_ratio_to_mhz(vdev, pll_ratio) * HZ_PER_MHZ;
}
-u32 ivpu_hw_btrs_dpu_freq_get(struct ivpu_device *vdev)
+u32 ivpu_hw_btrs_current_freq_get(struct ivpu_device *vdev)
{
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
- return pll_ratio_to_dpu_freq_mtl(pll_config_get_mtl(vdev));
+ return pll_ratio_to_mhz_mtl(pll_config_get_mtl(vdev));
else
- return pll_ratio_to_dpu_freq_lnl(pll_config_get_lnl(vdev));
+ return pll_ratio_to_mhz_lnl(pll_config_get_lnl(vdev));
+}
+
+static int ivpu_hw_btrs_cfg_freq_set(struct ivpu_device *vdev, u8 cfg_min_ratio, u8 cfg_max_ratio)
+{
+ u8 min_ratio = clamp_t(u8, cfg_min_ratio, vdev->hw->pll.min_ratio, cfg_max_ratio);
+ u8 pn_ratio = clamp_t(u8, vdev->hw->pll.pn_ratio, min_ratio, cfg_max_ratio);
+ int ret;
+
+ ivpu_dbg(vdev, PM, "Set frequency range to min: %u, pn: %u, max: %u MHz\n",
+ ivpu_hw_btrs_pll_ratio_to_mhz(vdev, min_ratio),
+ ivpu_hw_btrs_pll_ratio_to_mhz(vdev, pn_ratio),
+ ivpu_hw_btrs_pll_ratio_to_mhz(vdev, cfg_max_ratio));
+
+ ret = ivpu_rpm_get(vdev);
+ if (ret < 0)
+ return ret;
+
+ ret = ivpu_jsm_msg_freq_config(vdev, min_ratio, pn_ratio, cfg_max_ratio);
+ ivpu_rpm_put(vdev);
+
+ if (ret) {
+ ivpu_warn(vdev,
+ "Failed to set frequency to min: %u, pn: %u, max: %u MHz, ret %d\n",
+ ivpu_hw_btrs_pll_ratio_to_mhz(vdev, min_ratio),
+ ivpu_hw_btrs_pll_ratio_to_mhz(vdev, pn_ratio),
+ ivpu_hw_btrs_pll_ratio_to_mhz(vdev, cfg_max_ratio),
+ ret);
+ return ret;
+ }
+
+ vdev->hw->pll.cfg_min_ratio = cfg_min_ratio;
+ vdev->hw->pll.cfg_max_ratio = cfg_max_ratio;
+
+ return 0;
+}
+
+static u8 dpu_mhz_to_pll_ratio_lnl(u32 freq_mhz)
+{
+ return clamp_t(u32, freq_mhz / (PLL_REF_CLK_FREQ_MHZ / 2), 0, U8_MAX);
+}
+
+int ivpu_hw_btrs_cfg_max_freq_set(struct ivpu_device *vdev, u32 max_freq_mhz)
+{
+ u8 ratio = dpu_mhz_to_pll_ratio_lnl(max_freq_mhz);
+ u8 cfg_max_ratio = clamp_t(u8, ratio, vdev->hw->pll.min_ratio, vdev->hw->pll.max_ratio);
+
+ return ivpu_hw_btrs_cfg_freq_set(vdev, vdev->hw->pll.cfg_min_ratio, cfg_max_ratio);
+}
+
+int ivpu_hw_btrs_cfg_min_freq_set(struct ivpu_device *vdev, u32 min_freq_mhz)
+{
+ u8 ratio = dpu_mhz_to_pll_ratio_lnl(min_freq_mhz);
+ u8 cfg_min_ratio = clamp_t(u8, ratio, vdev->hw->pll.min_ratio, vdev->hw->pll.max_ratio);
+
+ return ivpu_hw_btrs_cfg_freq_set(vdev, cfg_min_ratio, vdev->hw->pll.cfg_max_ratio);
+}
+
+int ivpu_hw_btrs_cfg_freq_init(struct ivpu_device *vdev)
+{
+ if (vdev->hw->pll.min_ratio == vdev->hw->pll.cfg_min_ratio &&
+ vdev->hw->pll.max_ratio == vdev->hw->pll.cfg_max_ratio)
+ return 0;
+
+ return ivpu_hw_btrs_cfg_freq_set(vdev,
+ vdev->hw->pll.cfg_min_ratio,
+ vdev->hw->pll.cfg_max_ratio);
}
/* Handler for IRQs from Buttress core (irqB) */
if (REG_TEST_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, FREQ_CHANGE, status)) {
u32 pll = pll_config_get_mtl(vdev);
- ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq, wp %08x, %lu MHz",
- pll, pll_ratio_to_dpu_freq_mtl(pll) / HZ_PER_MHZ);
+ ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq, wp %08x, %u MHz",
+ pll, pll_ratio_to_mhz_mtl(pll));
}
if (REG_TEST_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, ATS_ERR, status)) {
if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, FREQ_CHANGE, status)) {
u32 pll = pll_config_get_lnl(vdev);
- ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq, wp %08x, %lu MHz",
- pll, pll_ratio_to_dpu_freq_lnl(pll) / HZ_PER_MHZ);
+ ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq, wp %08x, %u MHz",
+ pll, pll_ratio_to_mhz_lnl(pll));
}
if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, ATS_ERR, status)) {
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2020-2025 Intel Corporation
+ * Copyright (C) 2020-2026 Intel Corporation
*/
#ifndef __IVPU_HW_BTRS_H__
void ivpu_hw_btrs_profiling_freq_reg_set_lnl(struct ivpu_device *vdev);
void ivpu_hw_btrs_ats_print_lnl(struct ivpu_device *vdev);
void ivpu_hw_btrs_clock_relinquish_disable_lnl(struct ivpu_device *vdev);
-u32 ivpu_hw_btrs_dpu_max_freq_get(struct ivpu_device *vdev);
-u32 ivpu_hw_btrs_dpu_freq_get(struct ivpu_device *vdev);
+u32 ivpu_hw_btrs_pll_ratio_to_mhz(struct ivpu_device *vdev, u8 pll_ratio);
+u32 ivpu_hw_btrs_pll_ratio_to_hz(struct ivpu_device *vdev, u8 pll_ratio);
+u32 ivpu_hw_btrs_current_freq_get(struct ivpu_device *vdev);
+int ivpu_hw_btrs_cfg_min_freq_set(struct ivpu_device *vdev, u32 freq_mhz);
+int ivpu_hw_btrs_cfg_max_freq_set(struct ivpu_device *vdev, u32 freq_mhz);
+int ivpu_hw_btrs_cfg_freq_init(struct ivpu_device *vdev);
bool ivpu_hw_btrs_irq_handler_mtl(struct ivpu_device *vdev, int irq);
bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq);
int ivpu_hw_btrs_dct_get_request(struct ivpu_device *vdev, bool *enable);
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2020-2024 Intel Corporation
+ * Copyright (C) 2020-2026 Intel Corporation
*/
#include "ivpu_drv.h"
IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_ENABLE_DONE);
IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_DISABLE);
IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_DISABLE_DONE);
+ IVPU_CASE_TO_STR(VPU_JSM_MSG_FREQ_CONFIG);
+ IVPU_CASE_TO_STR(VPU_JSM_MSG_FREQ_CONFIG_RSP);
+ IVPU_CASE_TO_STR(VPU_JSM_MSG_RESERVED_111E);
}
#undef IVPU_CASE_TO_STR
return ivpu_ipc_send_and_wait(vdev, &req, VPU_IPC_CHAN_ASYNC_CMD,
vdev->timeout.state_dump_msg);
}
+
+int ivpu_jsm_msg_freq_config(struct ivpu_device *vdev, u16 min_ratio, u16 pn_ratio, u16 max_ratio)
+{
+ struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_FREQ_CONFIG};
+ struct vpu_jsm_msg resp;
+
+ req.payload.freq_config.min_freq_pll_ratio = min_ratio;
+ req.payload.freq_config.pn_freq_pll_ratio = pn_ratio;
+ req.payload.freq_config.max_freq_pll_ratio = max_ratio;
+
+ return ivpu_ipc_send_receive_internal(vdev, &req, VPU_JSM_MSG_FREQ_CONFIG_RSP, &resp,
+ VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
+}
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2020-2024 Intel Corporation
+ * Copyright (C) 2020-2026 Intel Corporation
*/
#ifndef __IVPU_JSM_MSG_H__
int ivpu_jsm_dct_disable(struct ivpu_device *vdev);
int ivpu_jsm_state_dump(struct ivpu_device *vdev);
int ivpu_jsm_state_dump_no_reply(struct ivpu_device *vdev);
+int ivpu_jsm_msg_freq_config(struct ivpu_device *vdev, u16 min_ratio, u16 pn_ratio, u16 max_ratio);
#endif
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
*/
#include <linux/device.h>
* - "OS" - Operating System Scheduler mode
*
*/
-static ssize_t
-sched_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t sched_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct drm_device *drm = dev_get_drvdata(dev);
struct ivpu_device *vdev = to_ivpu_device(drm);
static DEVICE_ATTR_RO(sched_mode);
/**
- * DOC: npu_max_frequency
+ * DOC: NPU frequency control and information
+ *
+ * Hardware frequency capabilities:
+ * freq/hw_min_freq - Minimum frequency supported by the NPU hardware.
+ * freq/hw_max_freq - Maximum frequency supported by the NPU hardware.
+ * freq/hw_efficient_freq - Most efficient operating frequency for the NPU.
+ *
+ * Configurable frequency limits (50XX devices and newer):
+ * freq/set_min_freq - Configured minimum operating frequency.
+ * freq/set_max_freq - Configured maximum operating frequency.
+ *
+ * Clamping behavior: Values written to set_min_freq and set_max_freq are
+ * clamped to hardware limits. If set_min_freq exceeds set_max_freq, the driver
+ * clamps set_min_freq to set_max_freq when selecting the operating frequency.
+ *
+ * Current operating frequency:
+ * freq/current_freq - Current frequency in MHz. Valid only when the device is
+ * active; returns 0 when idle. May be lower than the requested range due to
+ * power or thermal constraints.
*
- * The npu_max_frequency shows maximum frequency in MHz of the NPU's data
- * processing unit
+ * Legacy attributes (backward compatibility):
+ * npu_max_frequency_mhz - Alias for freq/hw_max_freq.
+ * npu_current_frequency_mhz - Alias for freq/current_freq.
*/
+
+static ssize_t hw_min_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.min_ratio);
+
+ return sysfs_emit(buf, "%u\n", freq_mhz);
+}
+
+static DEVICE_ATTR_RO(hw_min_freq);
+
+static ssize_t hw_efficient_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.pn_ratio);
+
+ return sysfs_emit(buf, "%u\n", freq_mhz);
+}
+
+static DEVICE_ATTR_RO(hw_efficient_freq);
+
+static ssize_t hw_max_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.max_ratio);
+
+ return sysfs_emit(buf, "%u\n", freq_mhz);
+}
+
+static DEVICE_ATTR_RO(hw_max_freq);
+
+static ssize_t set_min_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.cfg_min_ratio);
+
+ return sysfs_emit(buf, "%u\n", freq_mhz);
+}
+
static ssize_t
-npu_max_frequency_mhz_show(struct device *dev, struct device_attribute *attr, char *buf)
+set_min_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct drm_device *drm = dev_get_drvdata(dev);
struct ivpu_device *vdev = to_ivpu_device(drm);
- u32 freq = ivpu_hw_dpu_max_freq_get(vdev);
+ u32 freq_mhz;
+ int ret;
+
+ ret = kstrtou32(buf, 10, &freq_mhz);
+ if (ret)
+ return ret;
- return sysfs_emit(buf, "%lu\n", freq / HZ_PER_MHZ);
+ ret = ivpu_hw_btrs_cfg_min_freq_set(vdev, freq_mhz);
+ if (ret)
+ return ret;
+
+ return count;
}
-static DEVICE_ATTR_RO(npu_max_frequency_mhz);
+static DEVICE_ATTR_RW(set_min_freq);
+
+static ssize_t set_max_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ u32 freq_mhz = ivpu_hw_btrs_pll_ratio_to_mhz(vdev, vdev->hw->pll.cfg_max_ratio);
+
+ return sysfs_emit(buf, "%u\n", freq_mhz);
+}
-/**
- * DOC: npu_current_frequency_mhz
- *
- * The npu_current_frequency_mhz shows current frequency in MHz of the NPU's
- * data processing unit
- */
static ssize_t
-npu_current_frequency_mhz_show(struct device *dev, struct device_attribute *attr, char *buf)
+set_max_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ u32 freq_mhz;
+ int ret;
+
+ ret = kstrtou32(buf, 10, &freq_mhz);
+ if (ret)
+ return ret;
+
+ /* Convert MHz to Hz and set max frequency */
+ ret = ivpu_hw_btrs_cfg_max_freq_set(vdev, freq_mhz);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(set_max_freq);
+
+static ssize_t current_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct drm_device *drm = dev_get_drvdata(dev);
struct ivpu_device *vdev = to_ivpu_device(drm);
- u32 freq = 0;
+ u32 freq_mhz = 0;
/* Read frequency only if device is active, otherwise frequency is 0 */
if (pm_runtime_get_if_active(vdev->drm.dev) > 0) {
- freq = ivpu_hw_dpu_freq_get(vdev);
+ freq_mhz = ivpu_hw_btrs_current_freq_get(vdev);
pm_runtime_put_autosuspend(vdev->drm.dev);
}
- return sysfs_emit(buf, "%lu\n", freq / HZ_PER_MHZ);
+ return sysfs_emit(buf, "%u\n", freq_mhz);
}
-static DEVICE_ATTR_RO(npu_current_frequency_mhz);
+static DEVICE_ATTR_RO(current_freq);
+
+/* Alias to current_freq for legacy compat */
+static struct device_attribute dev_attr_npu_max_frequency_mhz =
+ __ATTR(npu_max_frequency_mhz, 0444, hw_max_freq_show, NULL);
+
+static struct device_attribute dev_attr_npu_current_frequency_mhz =
+ __ATTR(npu_current_frequency_mhz, 0444, current_freq_show, NULL);
+
+static struct attribute *ivpu_freq_attrs[] = {
+ &dev_attr_hw_min_freq.attr,
+ &dev_attr_hw_efficient_freq.attr,
+ &dev_attr_hw_max_freq.attr,
+ &dev_attr_current_freq.attr,
+ NULL,
+};
+
+static struct attribute_group ivpu_freq_attr_group = {
+ .name = "freq",
+ .attrs = ivpu_freq_attrs,
+};
static struct attribute *ivpu_dev_attrs[] = {
&dev_attr_npu_busy_time_us.attr,
int ret;
ret = devm_device_add_group(vdev->drm.dev, &ivpu_dev_attr_group);
- if (ret)
- ivpu_warn(vdev, "Failed to add group to device, ret %d", ret);
+ if (ret) {
+ ivpu_warn(vdev, "Failed to add sysfs group to device, ret %d", ret);
+ return;
+ }
+
+ ret = devm_device_add_group(vdev->drm.dev, &ivpu_freq_attr_group);
+ if (ret) {
+ ivpu_warn(vdev, "Failed to add sysfs freq group, ret %d", ret);
+ return;
+ }
+
+ if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_50XX) {
+ ret = sysfs_add_file_to_group(&vdev->drm.dev->kobj,
+ &dev_attr_set_min_freq.attr,
+ "freq");
+ if (ret) {
+ ivpu_warn(vdev, "Failed to add sysfs set_min_freq to device, ret %d", ret);
+ return;
+ }
+
+ ret = sysfs_add_file_to_group(&vdev->drm.dev->kobj,
+ &dev_attr_set_max_freq.attr,
+ "freq");
+ if (ret) {
+ ivpu_warn(vdev, "Failed to add sysfs set_max_freq to device, ret %d", ret);
+ return;
+ }
+ }
}
/*
* Minor version changes when API backward compatibility is preserved.
*/
-#define VPU_JSM_API_VER_MINOR 33
+#define VPU_JSM_API_VER_MINOR 34
/*
* API header changed (field names, documentation, formatting) but API itself has not been changed
* This command has no payload
*/
VPU_JSM_MSG_DCT_DISABLE = 0x111d,
+ /**
+ * Reserved command ID to ensure that the following command requests /
+ * responses have the same lower byte value.
+ */
+ VPU_JSM_MSG_RESERVED_111E = 0x111e,
+ /**
+ * Control command: Configure VPU frequency scaling parameters.
+ * @see vpu_ipc_msg_payload_freq_config
+ */
+ VPU_JSM_MSG_FREQ_CONFIG = 0x111f,
/**
* Dump VPU state. To be used for debug purposes only.
* This command has no payload.
* This command has no payload
*/
VPU_JSM_MSG_DCT_DISABLE_DONE = 0x221e,
+ /**
+ * Response to control command: Configure VPU frequency scaling parameters.
+ * @see vpu_ipc_msg_payload_freq_config
+ */
+ VPU_JSM_MSG_FREQ_CONFIG_RSP = 0x221f,
/**
* Response to state dump control command.
* This command has no payload.
u32 dct_inactive_us;
};
+/**
+ * Payload for @ref VPU_JSM_MSG_FREQ_CONFIG message.
+ *
+ * This payload allows the host to configure the VPU frequency scaling parameters.
+ */
+struct vpu_ipc_msg_payload_freq_config {
+ /** Minimum frequency PLL ratio */
+ u32 min_freq_pll_ratio;
+ /** Efficiency frequency PLL ratio */
+ u32 pn_freq_pll_ratio;
+ /** Maximum frequency PLL ratio */
+ u32 max_freq_pll_ratio;
+ /** Reserved for 64-bit alignment */
+ u32 reserved_0;
+};
+
/*
* Payloads union, used to define complete message format.
*/
struct vpu_ipc_msg_payload_hws_resume_engine hws_resume_engine;
struct vpu_ipc_msg_payload_pwr_d0i3_enter pwr_d0i3_enter;
struct vpu_ipc_msg_payload_pwr_dct_control pwr_dct_control;
+ struct vpu_ipc_msg_payload_freq_config freq_config;
};
/**