Commit 35b13763 authored by Jacek Lawrynowicz's avatar Jacek Lawrynowicz Committed by Daniel Vetter

accel/ivpu: Introduce a new DRM driver for Intel VPU

VPU stands for Versatile Processing Unit and it's a CPU-integrated
inference accelerator for Computer Vision and Deep Learning
applications.

The VPU device consist of following components:
  - Buttress - provides CPU to VPU integration, interrupt, frequency and
    power management.
  - Memory Management Unit (based on ARM MMU-600) - translates VPU to
    host DMA addresses, isolates user workloads.
  - RISC based microcontroller - executes firmware that provides job
    execution API for the kernel-mode driver
  - Neural Compute Subsystem (NCS) - does the actual work, provides
    Compute and Copy engines.
  - Network on Chip (NoC) - network fabric connecting all the components

This driver supports VPU IP v2.7 integrated into Intel Meteor Lake
client CPUs (14th generation).

Module sources are at drivers/accel/ivpu and module name is
"intel_vpu.ko".

This patch includes only very besic functionality:
  - module, PCI device and IRQ initialization
  - register definitions and low level register manipulation functions
  - SET/GET_PARAM ioctls
  - power up without firmware
Co-developed-by: default avatarKrystian Pradzynski <krystian.pradzynski@linux.intel.com>
Signed-off-by: default avatarKrystian Pradzynski <krystian.pradzynski@linux.intel.com>
Signed-off-by: default avatarJacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Reviewed-by: default avatarOded Gabbay <ogabbay@kernel.org>
Reviewed-by: default avatarJeffrey Hugo <quic_jhugo@quicinc.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20230117092723.60441-2-jacek.lawrynowicz@linux.intel.com
parent 6f849817
......@@ -6894,6 +6894,15 @@ T: git https://git.kernel.org/pub/scm/linux/kernel/git/ogabbay/accel.git
F: Documentation/accel/
F: drivers/accel/
DRM ACCEL DRIVERS FOR INTEL VPU
M: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
M: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com>
L: dri-devel@lists.freedesktop.org
S: Supported
T: git git://anongit.freedesktop.org/drm/drm-misc
F: drivers/accel/ivpu/
F: include/uapi/drm/ivpu_accel.h
DRM DRIVERS FOR ALLWINNER A10
M: Maxime Ripard <mripard@kernel.org>
M: Chen-Yu Tsai <wens@csie.org>
......
......@@ -189,3 +189,4 @@ obj-$(CONFIG_COUNTER) += counter/
obj-$(CONFIG_MOST) += most/
obj-$(CONFIG_PECI) += peci/
obj-$(CONFIG_HTE) += hte/
obj-$(CONFIG_DRM_ACCEL) += accel/
\ No newline at end of file
......@@ -22,3 +22,5 @@ menuconfig DRM_ACCEL
major number than GPUs, and will be exposed to user-space using
different device files, called accel/accel* (in /dev, sysfs
and debugfs).
source "drivers/accel/ivpu/Kconfig"
# SPDX-License-Identifier: GPL-2.0-only
obj-y += ivpu/
# SPDX-License-Identifier: GPL-2.0-only
config DRM_ACCEL_IVPU
tristate "Intel VPU for Meteor Lake and newer"
depends on DRM_ACCEL
depends on X86_64 && !UML
depends on PCI && PCI_MSI
select FW_LOADER
select SHMEM
help
Choose this option if you have a system that has an 14th generation Intel CPU
or newer. VPU stands for Versatile Processing Unit and it's a CPU-integrated
inference accelerator for Computer Vision and Deep Learning applications.
If "M" is selected, the module will be called intel_vpu.
# SPDX-License-Identifier: GPL-2.0-only
# Copyright (C) 2023 Intel Corporation
intel_vpu-y := \
ivpu_drv.o \
ivpu_hw_mtl.o
obj-$(CONFIG_DRM_ACCEL_IVPU) += intel_vpu.o
\ No newline at end of file
- Move to threaded_irqs to mitigate potential infinite loop in ivpu_ipc_irq_handler()
- Implement support for BLOB IDs
- Add debugfs support to improve debugging and testing
- Add tracing events for performance debugging
- Implement HW based scheduling support
- Use syncobjs for submit/sync
- Refactor IPC protocol to improve message latency
- Implement BO cache and MADVISE IOCTL
- Add support for user allocated buffers using prime import and dma-buf heaps
- Refactor struct ivpu_bo to use struct drm_gem_shmem_object
- Add driver/device documentation
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020-2023 Intel Corporation
*/
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <drm/drm_accel.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_gem.h>
#include <drm/drm_ioctl.h>
#include "ivpu_drv.h"
#include "ivpu_hw.h"
#ifndef DRIVER_VERSION_STR
#define DRIVER_VERSION_STR __stringify(DRM_IVPU_DRIVER_MAJOR) "." \
__stringify(DRM_IVPU_DRIVER_MINOR) "."
#endif
static const struct drm_driver driver;
int ivpu_dbg_mask;
module_param_named(dbg_mask, ivpu_dbg_mask, int, 0644);
MODULE_PARM_DESC(dbg_mask, "Driver debug mask. See IVPU_DBG_* macros.");
u8 ivpu_pll_min_ratio;
module_param_named(pll_min_ratio, ivpu_pll_min_ratio, byte, 0644);
MODULE_PARM_DESC(pll_min_ratio, "Minimum PLL ratio used to set VPU frequency");
u8 ivpu_pll_max_ratio = U8_MAX;
module_param_named(pll_max_ratio, ivpu_pll_max_ratio, byte, 0644);
MODULE_PARM_DESC(pll_max_ratio, "Maximum PLL ratio used to set VPU frequency");
struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv)
{
kref_get(&file_priv->ref);
return file_priv;
}
static void file_priv_release(struct kref *ref)
{
struct ivpu_file_priv *file_priv = container_of(ref, struct ivpu_file_priv, ref);
kfree(file_priv);
}
void ivpu_file_priv_put(struct ivpu_file_priv **link)
{
struct ivpu_file_priv *file_priv = *link;
WARN_ON(!file_priv);
*link = NULL;
kref_put(&file_priv->ref, file_priv_release);
}
static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
{
struct ivpu_file_priv *file_priv = file->driver_priv;
struct ivpu_device *vdev = file_priv->vdev;
struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
struct drm_ivpu_param *args = data;
int ret = 0;
switch (args->param) {
case DRM_IVPU_PARAM_DEVICE_ID:
args->value = pdev->device;
break;
case DRM_IVPU_PARAM_DEVICE_REVISION:
args->value = pdev->revision;
break;
case DRM_IVPU_PARAM_PLATFORM_TYPE:
args->value = vdev->platform;
break;
case DRM_IVPU_PARAM_CORE_CLOCK_RATE:
args->value = ivpu_hw_reg_pll_freq_get(vdev);
break;
case DRM_IVPU_PARAM_NUM_CONTEXTS:
args->value = ivpu_get_context_count(vdev);
break;
case DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS:
args->value = vdev->hw->ranges.user_low.start;
break;
case DRM_IVPU_PARAM_CONTEXT_PRIORITY:
args->value = file_priv->priority;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static int ivpu_set_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
{
struct ivpu_file_priv *file_priv = file->driver_priv;
struct drm_ivpu_param *args = data;
int ret = 0;
switch (args->param) {
case DRM_IVPU_PARAM_CONTEXT_PRIORITY:
if (args->value <= DRM_IVPU_CONTEXT_PRIORITY_REALTIME)
file_priv->priority = args->value;
else
ret = -EINVAL;
break;
default:
ret = -EINVAL;
}
return ret;
}
static int ivpu_open(struct drm_device *dev, struct drm_file *file)
{
struct ivpu_device *vdev = to_ivpu_device(dev);
struct ivpu_file_priv *file_priv;
file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
if (!file_priv)
return -ENOMEM;
file_priv->vdev = vdev;
file_priv->priority = DRM_IVPU_CONTEXT_PRIORITY_NORMAL;
kref_init(&file_priv->ref);
file->driver_priv = file_priv;
return 0;
}
static void ivpu_postclose(struct drm_device *dev, struct drm_file *file)
{
struct ivpu_file_priv *file_priv = file->driver_priv;
ivpu_file_priv_put(&file_priv);
}
static const struct drm_ioctl_desc ivpu_drm_ioctls[] = {
DRM_IOCTL_DEF_DRV(IVPU_GET_PARAM, ivpu_get_param_ioctl, 0),
DRM_IOCTL_DEF_DRV(IVPU_SET_PARAM, ivpu_set_param_ioctl, 0),
};
int ivpu_shutdown(struct ivpu_device *vdev)
{
int ret;
ivpu_hw_irq_disable(vdev);
ret = ivpu_hw_power_down(vdev);
if (ret)
ivpu_warn(vdev, "Failed to power down HW: %d\n", ret);
return ret;
}
static const struct file_operations ivpu_fops = {
.owner = THIS_MODULE,
.mmap = drm_gem_mmap,
DRM_ACCEL_FOPS,
};
static const struct drm_driver driver = {
.driver_features = DRIVER_GEM | DRIVER_COMPUTE_ACCEL,
.open = ivpu_open,
.postclose = ivpu_postclose,
.ioctls = ivpu_drm_ioctls,
.num_ioctls = ARRAY_SIZE(ivpu_drm_ioctls),
.fops = &ivpu_fops,
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
.major = DRM_IVPU_DRIVER_MAJOR,
.minor = DRM_IVPU_DRIVER_MINOR,
};
static int ivpu_irq_init(struct ivpu_device *vdev)
{
struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
int ret;
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX);
if (ret < 0) {
ivpu_err(vdev, "Failed to allocate a MSI IRQ: %d\n", ret);
return ret;
}
vdev->irq = pci_irq_vector(pdev, 0);
ret = devm_request_irq(vdev->drm.dev, vdev->irq, vdev->hw->ops->irq_handler,
IRQF_NO_AUTOEN, DRIVER_NAME, vdev);
if (ret)
ivpu_err(vdev, "Failed to request an IRQ %d\n", ret);
return ret;
}
static int ivpu_pci_init(struct ivpu_device *vdev)
{
struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
struct resource *bar0 = &pdev->resource[0];
struct resource *bar4 = &pdev->resource[4];
int ret;
ivpu_dbg(vdev, MISC, "Mapping BAR0 (RegV) %pR\n", bar0);
vdev->regv = devm_ioremap_resource(vdev->drm.dev, bar0);
if (IS_ERR(vdev->regv)) {
ivpu_err(vdev, "Failed to map bar 0: %pe\n", vdev->regv);
return PTR_ERR(vdev->regv);
}
ivpu_dbg(vdev, MISC, "Mapping BAR4 (RegB) %pR\n", bar4);
vdev->regb = devm_ioremap_resource(vdev->drm.dev, bar4);
if (IS_ERR(vdev->regb)) {
ivpu_err(vdev, "Failed to map bar 4: %pe\n", vdev->regb);
return PTR_ERR(vdev->regb);
}
ret = dma_set_mask_and_coherent(vdev->drm.dev, DMA_BIT_MASK(38));
if (ret) {
ivpu_err(vdev, "Failed to set DMA mask: %d\n", ret);
return ret;
}
/* Clear any pending errors */
pcie_capability_clear_word(pdev, PCI_EXP_DEVSTA, 0x3f);
ret = pcim_enable_device(pdev);
if (ret) {
ivpu_err(vdev, "Failed to enable PCI device: %d\n", ret);
return ret;
}
pci_set_master(pdev);
return 0;
}
static int ivpu_dev_init(struct ivpu_device *vdev)
{
int ret;
vdev->hw = drmm_kzalloc(&vdev->drm, sizeof(*vdev->hw), GFP_KERNEL);
if (!vdev->hw)
return -ENOMEM;
vdev->hw->ops = &ivpu_hw_mtl_ops;
vdev->platform = IVPU_PLATFORM_INVALID;
vdev->context_xa_limit.min = IVPU_GLOBAL_CONTEXT_MMU_SSID + 1;
vdev->context_xa_limit.max = IVPU_CONTEXT_LIMIT;
xa_init_flags(&vdev->context_xa, XA_FLAGS_ALLOC);
ret = ivpu_pci_init(vdev);
if (ret) {
ivpu_err(vdev, "Failed to initialize PCI device: %d\n", ret);
goto err_xa_destroy;
}
ret = ivpu_irq_init(vdev);
if (ret) {
ivpu_err(vdev, "Failed to initialize IRQs: %d\n", ret);
goto err_xa_destroy;
}
/* Init basic HW info based on buttress registers which are accessible before power up */
ret = ivpu_hw_info_init(vdev);
if (ret) {
ivpu_err(vdev, "Failed to initialize HW info: %d\n", ret);
goto err_xa_destroy;
}
/* Power up early so the rest of init code can access VPU registers */
ret = ivpu_hw_power_up(vdev);
if (ret) {
ivpu_err(vdev, "Failed to power up HW: %d\n", ret);
goto err_xa_destroy;
}
return 0;
err_xa_destroy:
xa_destroy(&vdev->context_xa);
return ret;
}
static void ivpu_dev_fini(struct ivpu_device *vdev)
{
ivpu_shutdown(vdev);
drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->context_xa));
xa_destroy(&vdev->context_xa);
}
static struct pci_device_id ivpu_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_MTL) },
{ }
};
MODULE_DEVICE_TABLE(pci, ivpu_pci_ids);
static int ivpu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct ivpu_device *vdev;
int ret;
vdev = devm_drm_dev_alloc(&pdev->dev, &driver, struct ivpu_device, drm);
if (IS_ERR(vdev))
return PTR_ERR(vdev);
pci_set_drvdata(pdev, vdev);
ret = ivpu_dev_init(vdev);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize VPU device: %d\n", ret);
return ret;
}
ret = drm_dev_register(&vdev->drm, 0);
if (ret) {
dev_err(&pdev->dev, "Failed to register DRM device: %d\n", ret);
ivpu_dev_fini(vdev);
}
return ret;
}
static void ivpu_remove(struct pci_dev *pdev)
{
struct ivpu_device *vdev = pci_get_drvdata(pdev);
drm_dev_unregister(&vdev->drm);
ivpu_dev_fini(vdev);
}
static struct pci_driver ivpu_pci_driver = {
.name = KBUILD_MODNAME,
.id_table = ivpu_pci_ids,
.probe = ivpu_probe,
.remove = ivpu_remove,
};
module_pci_driver(ivpu_pci_driver);
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL and additional rights");
MODULE_VERSION(DRIVER_VERSION_STR);
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2020-2023 Intel Corporation
*/
#ifndef __IVPU_DRV_H__
#define __IVPU_DRV_H__
#include <drm/drm_device.h>
#include <drm/drm_managed.h>
#include <drm/drm_mm.h>
#include <drm/drm_print.h>
#include <linux/pci.h>
#include <linux/xarray.h>
#include <uapi/drm/ivpu_accel.h>
#define DRIVER_NAME "intel_vpu"
#define DRIVER_DESC "Driver for Intel Versatile Processing Unit (VPU)"
#define DRIVER_DATE "20230117"
#define PCI_DEVICE_ID_MTL 0x7d1d
#define IVPU_GLOBAL_CONTEXT_MMU_SSID 0
#define IVPU_CONTEXT_LIMIT 64
#define IVPU_NUM_ENGINES 2
#define IVPU_PLATFORM_SILICON 0
#define IVPU_PLATFORM_SIMICS 2
#define IVPU_PLATFORM_FPGA 3
#define IVPU_PLATFORM_INVALID 8
#define IVPU_DBG_REG BIT(0)
#define IVPU_DBG_IRQ BIT(1)
#define IVPU_DBG_MMU BIT(2)
#define IVPU_DBG_FILE BIT(3)
#define IVPU_DBG_MISC BIT(4)
#define IVPU_DBG_FW_BOOT BIT(5)
#define IVPU_DBG_PM BIT(6)
#define IVPU_DBG_IPC BIT(7)
#define IVPU_DBG_BO BIT(8)
#define IVPU_DBG_JOB BIT(9)
#define IVPU_DBG_JSM BIT(10)
#define IVPU_DBG_KREF BIT(11)
#define IVPU_DBG_RPM BIT(12)
#define ivpu_err(vdev, fmt, ...) \
drm_err(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__)
#define ivpu_err_ratelimited(vdev, fmt, ...) \
drm_err_ratelimited(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__)
#define ivpu_warn(vdev, fmt, ...) \
drm_warn(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__)
#define ivpu_warn_ratelimited(vdev, fmt, ...) \
drm_err_ratelimited(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__)
#define ivpu_info(vdev, fmt, ...) drm_info(&(vdev)->drm, fmt, ##__VA_ARGS__)
#define ivpu_dbg(vdev, type, fmt, args...) do { \
if (unlikely(IVPU_DBG_##type & ivpu_dbg_mask)) \
dev_dbg((vdev)->drm.dev, "[%s] " fmt, #type, ##args); \
} while (0)
#define IVPU_WA(wa_name) (vdev->wa.wa_name)
struct ivpu_wa_table {
bool punit_disabled;
bool clear_runtime_mem;
};
struct ivpu_hw_info;
struct ivpu_device {
struct drm_device drm;
void __iomem *regb;
void __iomem *regv;
u32 platform;
u32 irq;
struct ivpu_wa_table wa;
struct ivpu_hw_info *hw;
struct xarray context_xa;
struct xa_limit context_xa_limit;
struct {
int boot;
int jsm;
int tdr;
int reschedule_suspend;
} timeout;
};
/*
* file_priv has its own refcount (ref) that allows user space to close the fd
* without blocking even if VPU is still processing some jobs.
*/
struct ivpu_file_priv {
struct kref ref;
struct ivpu_device *vdev;
u32 priority;
};
extern int ivpu_dbg_mask;
extern u8 ivpu_pll_min_ratio;
extern u8 ivpu_pll_max_ratio;
struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv);
void ivpu_file_priv_put(struct ivpu_file_priv **link);
int ivpu_shutdown(struct ivpu_device *vdev);
static inline bool ivpu_is_mtl(struct ivpu_device *vdev)
{
return to_pci_dev(vdev->drm.dev)->device == PCI_DEVICE_ID_MTL;
}
static inline u8 ivpu_revision(struct ivpu_device *vdev)
{
return to_pci_dev(vdev->drm.dev)->revision;
}
static inline u16 ivpu_device_id(struct ivpu_device *vdev)
{
return to_pci_dev(vdev->drm.dev)->device;
}
static inline struct ivpu_device *to_ivpu_device(struct drm_device *dev)
{
return container_of(dev, struct ivpu_device, drm);
}
static inline u32 ivpu_get_context_count(struct ivpu_device *vdev)
{
struct xa_limit ctx_limit = vdev->context_xa_limit;
return (ctx_limit.max - ctx_limit.min + 1);
}
static inline u32 ivpu_get_platform(struct ivpu_device *vdev)
{
WARN_ON_ONCE(vdev->platform == IVPU_PLATFORM_INVALID);
return vdev->platform;
}
static inline bool ivpu_is_silicon(struct ivpu_device *vdev)
{
return ivpu_get_platform(vdev) == IVPU_PLATFORM_SILICON;
}
static inline bool ivpu_is_simics(struct ivpu_device *vdev)
{
return ivpu_get_platform(vdev) == IVPU_PLATFORM_SIMICS;
}
static inline bool ivpu_is_fpga(struct ivpu_device *vdev)
{
return ivpu_get_platform(vdev) == IVPU_PLATFORM_FPGA;
}
#endif /* __IVPU_DRV_H__ */
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2020-2023 Intel Corporation
*/
#ifndef __IVPU_HW_H__
#define __IVPU_HW_H__
#include "ivpu_drv.h"
struct ivpu_hw_ops {
int (*info_init)(struct ivpu_device *vdev);
int (*power_up)(struct ivpu_device *vdev);
int (*boot_fw)(struct ivpu_device *vdev);
int (*power_down)(struct ivpu_device *vdev);
bool (*is_idle)(struct ivpu_device *vdev);
void (*wdt_disable)(struct ivpu_device *vdev);
void (*diagnose_failure)(struct ivpu_device *vdev);
u32 (*reg_pll_freq_get)(struct ivpu_device *vdev);
u32 (*reg_telemetry_offset_get)(struct ivpu_device *vdev);
u32 (*reg_telemetry_size_get)(struct ivpu_device *vdev);
u32 (*reg_telemetry_enable_get)(struct ivpu_device *vdev);
void (*reg_db_set)(struct ivpu_device *vdev, u32 db_id);
u32 (*reg_ipc_rx_addr_get)(struct ivpu_device *vdev);
u32 (*reg_ipc_rx_count_get)(struct ivpu_device *vdev);
void (*reg_ipc_tx_set)(struct ivpu_device *vdev, u32 vpu_addr);
void (*irq_clear)(struct ivpu_device *vdev);
void (*irq_enable)(struct ivpu_device *vdev);
void (*irq_disable)(struct ivpu_device *vdev);
irqreturn_t (*irq_handler)(int irq, void *ptr);
};
struct ivpu_addr_range {
resource_size_t start;
resource_size_t end;
};
struct ivpu_hw_info {
const struct ivpu_hw_ops *ops;
struct {
struct ivpu_addr_range global_low;
struct ivpu_addr_range global_high;
struct ivpu_addr_range user_low;
struct ivpu_addr_range user_high;
struct ivpu_addr_range global_aliased_pio;
} ranges;
struct {
u8 min_ratio;
u8 max_ratio;
/*
* Pll ratio for the efficiency frequency. The VPU has optimum
* performance to power ratio at this frequency.
*/
u8 pn_ratio;
u32 profiling_freq;
} pll;
u32 tile_fuse;
u32 sku;
u16 config;
};
extern const struct ivpu_hw_ops ivpu_hw_mtl_ops;
static inline int ivpu_hw_info_init(struct ivpu_device *vdev)
{
return vdev->hw->ops->info_init(vdev);
};
static inline int ivpu_hw_power_up(struct ivpu_device *vdev)
{
ivpu_dbg(vdev, PM, "HW power up\n");
return vdev->hw->ops->power_up(vdev);
};
static inline int ivpu_hw_boot_fw(struct ivpu_device *vdev)
{
return vdev->hw->ops->boot_fw(vdev);
};
static inline bool ivpu_hw_is_idle(struct ivpu_device *vdev)
{
return vdev->hw->ops->is_idle(vdev);
};
static inline int ivpu_hw_power_down(struct ivpu_device *vdev)
{
ivpu_dbg(vdev, PM, "HW power down\n");
return vdev->hw->ops->power_down(vdev);
};
static inline void ivpu_hw_wdt_disable(struct ivpu_device *vdev)
{
vdev->hw->ops->wdt_disable(vdev);
};
/* Register indirect accesses */
static inline u32 ivpu_hw_reg_pll_freq_get(struct ivpu_device *vdev)
{
return vdev->hw->ops->reg_pll_freq_get(vdev);
};
static inline u32 ivpu_hw_reg_telemetry_offset_get(struct ivpu_device *vdev)
{
return vdev->hw->ops->reg_telemetry_offset_get(vdev);
};
static inline u32 ivpu_hw_reg_telemetry_size_get(struct ivpu_device *vdev)
{
return vdev->hw->ops->reg_telemetry_size_get(vdev);
};
static inline u32 ivpu_hw_reg_telemetry_enable_get(struct ivpu_device *vdev)
{
return vdev->hw->ops->reg_telemetry_enable_get(vdev);
};
static inline void ivpu_hw_reg_db_set(struct ivpu_device *vdev, u32 db_id)
{
vdev->hw->ops->reg_db_set(vdev, db_id);
};
static inline u32 ivpu_hw_reg_ipc_rx_addr_get(struct ivpu_device *vdev)
{
return vdev->hw->ops->reg_ipc_rx_addr_get(vdev);
};
static inline u32 ivpu_hw_reg_ipc_rx_count_get(struct ivpu_device *vdev)
{
return vdev->hw->ops->reg_ipc_rx_count_get(vdev);
};
static inline void ivpu_hw_reg_ipc_tx_set(struct ivpu_device *vdev, u32 vpu_addr)
{
vdev->hw->ops->reg_ipc_tx_set(vdev, vpu_addr);
};
static inline void ivpu_hw_irq_clear(struct ivpu_device *vdev)
{
vdev->hw->ops->irq_clear(vdev);
};
static inline void ivpu_hw_irq_enable(struct ivpu_device *vdev)
{
vdev->hw->ops->irq_enable(vdev);
};
static inline void ivpu_hw_irq_disable(struct ivpu_device *vdev)
{
vdev->hw->ops->irq_disable(vdev);
};
static inline void ivpu_hw_init_range(struct ivpu_addr_range *range, u64 start, u64 size)
{
range->start = start;
range->end = start + size;
}
static inline u64 ivpu_hw_range_size(const struct ivpu_addr_range *range)
{
return range->end - range->start;
}
static inline void ivpu_hw_diagnose_failure(struct ivpu_device *vdev)
{
vdev->hw->ops->diagnose_failure(vdev);
}
#endif /* __IVPU_HW_H__ */
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2020-2023 Intel Corporation
*/
#ifndef __IVPU_HW_REG_IO_H__
#define __IVPU_HW_REG_IO_H__
#include <linux/bitfield.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include "ivpu_drv.h"
#define REG_POLL_SLEEP_US 50
#define REG_IO_ERROR 0xffffffff
#define REGB_RD32(reg) ivpu_hw_reg_rd32(vdev, vdev->regb, (reg), #reg, __func__)
#define REGB_RD32_SILENT(reg) readl(vdev->regb + (reg))
#define REGB_RD64(reg) ivpu_hw_reg_rd64(vdev, vdev->regb, (reg), #reg, __func__)
#define REGB_WR32(reg, val) ivpu_hw_reg_wr32(vdev, vdev->regb, (reg), (val), #reg, __func__)
#define REGB_WR64(reg, val) ivpu_hw_reg_wr64(vdev, vdev->regb, (reg), (val), #reg, __func__)
#define REGV_RD32(reg) ivpu_hw_reg_rd32(vdev, vdev->regv, (reg), #reg, __func__)
#define REGV_RD32_SILENT(reg) readl(vdev->regv + (reg))
#define REGV_RD64(reg) ivpu_hw_reg_rd64(vdev, vdev->regv, (reg), #reg, __func__)
#define REGV_WR32(reg, val) ivpu_hw_reg_wr32(vdev, vdev->regv, (reg), (val), #reg, __func__)
#define REGV_WR64(reg, val) ivpu_hw_reg_wr64(vdev, vdev->regv, (reg), (val), #reg, __func__)
#define REGV_WR32I(reg, stride, index, val) \
ivpu_hw_reg_wr32_index(vdev, vdev->regv, (reg), (stride), (index), (val), #reg, __func__)
#define REG_FLD(REG, FLD) \
(REG##_##FLD##_MASK)
#define REG_FLD_NUM(REG, FLD, num) \
FIELD_PREP(REG##_##FLD##_MASK, num)
#define REG_GET_FLD(REG, FLD, val) \
FIELD_GET(REG##_##FLD##_MASK, val)
#define REG_CLR_FLD(REG, FLD, val) \
((val) & ~(REG##_##FLD##_MASK))
#define REG_SET_FLD(REG, FLD, val) \
((val) | (REG##_##FLD##_MASK))
#define REG_SET_FLD_NUM(REG, FLD, num, val) \
(((val) & ~(REG##_##FLD##_MASK)) | FIELD_PREP(REG##_##FLD##_MASK, num))
#define REG_TEST_FLD(REG, FLD, val) \
((REG##_##FLD##_MASK) == ((val) & (REG##_##FLD##_MASK)))
#define REG_TEST_FLD_NUM(REG, FLD, num, val) \
((num) == FIELD_GET(REG##_##FLD##_MASK, val))
#define REGB_POLL(reg, var, cond, timeout_us) \
read_poll_timeout(REGB_RD32_SILENT, var, cond, REG_POLL_SLEEP_US, timeout_us, false, reg)
#define REGV_POLL(reg, var, cond, timeout_us) \
read_poll_timeout(REGV_RD32_SILENT, var, cond, REG_POLL_SLEEP_US, timeout_us, false, reg)
#define REGB_POLL_FLD(reg, fld, val, timeout_us) \
({ \
u32 var; \
REGB_POLL(reg, var, (FIELD_GET(reg##_##fld##_MASK, var) == (val)), timeout_us); \
})
#define REGV_POLL_FLD(reg, fld, val, timeout_us) \
({ \
u32 var; \
REGV_POLL(reg, var, (FIELD_GET(reg##_##fld##_MASK, var) == (val)), timeout_us); \
})
static inline u32
ivpu_hw_reg_rd32(struct ivpu_device *vdev, void __iomem *base, u32 reg,
const char *name, const char *func)
{
u32 val = readl(base + reg);
ivpu_dbg(vdev, REG, "%s RD: %s (0x%08x) => 0x%08x\n", func, name, reg, val);
return val;
}
static inline u64
ivpu_hw_reg_rd64(struct ivpu_device *vdev, void __iomem *base, u32 reg,
const char *name, const char *func)
{
u64 val = readq(base + reg);
ivpu_dbg(vdev, REG, "%s RD: %s (0x%08x) => 0x%016llx\n", func, name, reg, val);
return val;
}
static inline void
ivpu_hw_reg_wr32(struct ivpu_device *vdev, void __iomem *base, u32 reg, u32 val,
const char *name, const char *func)
{
ivpu_dbg(vdev, REG, "%s WR: %s (0x%08x) <= 0x%08x\n", func, name, reg, val);
writel(val, base + reg);
}
static inline void
ivpu_hw_reg_wr64(struct ivpu_device *vdev, void __iomem *base, u32 reg, u64 val,
const char *name, const char *func)
{
ivpu_dbg(vdev, REG, "%s WR: %s (0x%08x) <= 0x%016llx\n", func, name, reg, val);
writeq(val, base + reg);
}
static inline void
ivpu_hw_reg_wr32_index(struct ivpu_device *vdev, void __iomem *base, u32 reg,
u32 stride, u32 index, u32 val, const char *name,
const char *func)
{
reg += index * stride;
ivpu_dbg(vdev, REG, "%s WR: %s_%d (0x%08x) <= 0x%08x\n", func, name, index, reg, val);
writel(val, base + reg);
}
#endif /* __IVPU_HW_REG_IO_H__ */
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
* Copyright (C) 2020-2023 Intel Corporation
*/
#ifndef __UAPI_IVPU_DRM_H__
#define __UAPI_IVPU_DRM_H__
#include "drm.h"
#if defined(__cplusplus)
extern "C" {
#endif
#define DRM_IVPU_DRIVER_MAJOR 1
#define DRM_IVPU_DRIVER_MINOR 0
#define DRM_IVPU_GET_PARAM 0x00
#define DRM_IVPU_SET_PARAM 0x01
#define DRM_IOCTL_IVPU_GET_PARAM \
DRM_IOWR(DRM_COMMAND_BASE + DRM_IVPU_GET_PARAM, struct drm_ivpu_param)
#define DRM_IOCTL_IVPU_SET_PARAM \
DRM_IOW(DRM_COMMAND_BASE + DRM_IVPU_SET_PARAM, struct drm_ivpu_param)
/**
* DOC: contexts
*
* VPU contexts have private virtual address space, job queues and priority.
* Each context is identified by an unique ID. Context is created on open().
*/
#define DRM_IVPU_PARAM_DEVICE_ID 0
#define DRM_IVPU_PARAM_DEVICE_REVISION 1
#define DRM_IVPU_PARAM_PLATFORM_TYPE 2
#define DRM_IVPU_PARAM_CORE_CLOCK_RATE 3
#define DRM_IVPU_PARAM_NUM_CONTEXTS 4
#define DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS 5
#define DRM_IVPU_PARAM_CONTEXT_PRIORITY 6
#define DRM_IVPU_PLATFORM_TYPE_SILICON 0
#define DRM_IVPU_CONTEXT_PRIORITY_IDLE 0
#define DRM_IVPU_CONTEXT_PRIORITY_NORMAL 1
#define DRM_IVPU_CONTEXT_PRIORITY_FOCUS 2
#define DRM_IVPU_CONTEXT_PRIORITY_REALTIME 3
/**
* struct drm_ivpu_param - Get/Set VPU parameters
*/
struct drm_ivpu_param {
/**
* @param:
*
* Supported params:
*
* %DRM_IVPU_PARAM_DEVICE_ID:
* PCI Device ID of the VPU device (read-only)
*
* %DRM_IVPU_PARAM_DEVICE_REVISION:
* VPU device revision (read-only)
*
* %DRM_IVPU_PARAM_PLATFORM_TYPE:
* Returns %DRM_IVPU_PLATFORM_TYPE_SILICON on real hardware or device specific
* platform type when executing on a simulator or emulator (read-only)
*
* %DRM_IVPU_PARAM_CORE_CLOCK_RATE:
* Current PLL frequency (read-only)
*
* %DRM_IVPU_PARAM_NUM_CONTEXTS:
* Maximum number of simultaneously existing contexts (read-only)
*
* %DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS:
* Lowest VPU virtual address available in the current context (read-only)
*
* %DRM_IVPU_PARAM_CONTEXT_PRIORITY:
* Value of current context scheduling priority (read-write).
* See DRM_IVPU_CONTEXT_PRIORITY_* for possible values.
*
*/
__u32 param;
/** @index: Index for params that have multiple instances */
__u32 index;
/** @value: Param value */
__u64 value;
};
#if defined(__cplusplus)
}
#endif
#endif /* __UAPI_IVPU_DRM_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment