msm: npu: Add NPU driver support for kernel 6.1
NPU driver snapshot from msm-5.15 branch commit f5053f87777d ("msm: npu: Fix OOB issue in IPC between driver and firmware"). Change-Id: Iea68b912dd7efd9a979969a91fb38d3611e3ff8c Signed-off-by: Priyanka G Pai <quic_pgpai@quicinc.com>
This commit is contained in:
parent
9cfdeb74ee
commit
1a6163e69c
@ -7,3 +7,14 @@ config VIRTIO_NPU
|
||||
which provides acceleration for neural network processing.
|
||||
This driver is based on virtio.
|
||||
Say Y if you want to support virtual NPU.
|
||||
|
||||
config MSM_NPU
|
||||
tristate "QTI MSM Neural Processing Unit support"
|
||||
depends on ARCH_QCOM
|
||||
help
|
||||
Enable support for Neural Processing Unit
|
||||
for specific QTI chipsets.
|
||||
This module serves as the common driver
|
||||
for npu which provides acceleration for neural
|
||||
network processing.
|
||||
|
||||
|
@ -1,3 +1,14 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
ifneq ($(CONFIG_VIRTIO_NPU),)
|
||||
obj-$(CONFIG_VIRTIO_NPU) := virtio_npu.o
|
||||
else
|
||||
msm_npu-objs := npu_dbg.o \
|
||||
npu_dev.o \
|
||||
npu_debugfs.o \
|
||||
npu_host_ipc.o \
|
||||
npu_hw_access.o \
|
||||
npu_mgr.o
|
||||
|
||||
obj-$(CONFIG_MSM_NPU) := msm_npu.o
|
||||
endif
|
||||
|
277
drivers/media/platform/msm/npu/npu_common.h
Normal file
277
drivers/media/platform/msm/npu/npu_common.h
Normal file
@ -0,0 +1,277 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _NPU_COMMON_H
|
||||
#define _NPU_COMMON_H
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Includes
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mailbox_controller.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/msm_npu.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/mailbox/qmp.h>
|
||||
|
||||
#include "npu_mgr.h"
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Defines
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#define NPU_MAX_MBOX_NUM 2
|
||||
#define NPU_MBOX_LOW_PRI 0
|
||||
#define NPU_MBOX_HIGH_PRI 1
|
||||
|
||||
#define DEFAULT_REG_DUMP_NUM 64
|
||||
#define ROW_BYTES 16
|
||||
#define GROUP_BYTES 4
|
||||
|
||||
#define NUM_MAX_CLK_NUM 24
|
||||
#define NPU_MAX_REGULATOR_NUM 2
|
||||
#define NPU_MAX_DT_NAME_LEN 21
|
||||
#define NPU_MAX_PWRLEVELS 8
|
||||
#define NPU_MAX_STATS_BUF_SIZE 16384
|
||||
#define NPU_MAX_PATCH_NUM 160
|
||||
|
||||
#define PERF_MODE_DEFAULT 0
|
||||
|
||||
enum npu_power_level {
|
||||
NPU_PWRLEVEL_MINSVS = 0,
|
||||
NPU_PWRLEVEL_LOWSVS,
|
||||
NPU_PWRLEVEL_SVS,
|
||||
NPU_PWRLEVEL_SVS_L1,
|
||||
NPU_PWRLEVEL_NOM,
|
||||
NPU_PWRLEVEL_NOM_L1,
|
||||
NPU_PWRLEVEL_TURBO,
|
||||
NPU_PWRLEVEL_TURBO_L1,
|
||||
NPU_PWRLEVEL_OFF = 0xFFFFFFFF,
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Data Structures
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
struct npu_smmu_ctx {
|
||||
int domain;
|
||||
struct dma_iommu_mapping *mmu_mapping;
|
||||
struct reg_bus_client *reg_bus_clt;
|
||||
int32_t attach_cnt;
|
||||
};
|
||||
|
||||
struct npu_ion_buf {
|
||||
int fd;
|
||||
struct dma_buf *dma_buf;
|
||||
struct dma_buf_attachment *attachment;
|
||||
struct sg_table *table;
|
||||
dma_addr_t iova;
|
||||
uint32_t size;
|
||||
void *phys_addr;
|
||||
void *buf;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct npu_clk {
|
||||
struct clk *clk;
|
||||
char clk_name[NPU_MAX_DT_NAME_LEN];
|
||||
};
|
||||
|
||||
struct npu_regulator {
|
||||
struct regulator *regulator;
|
||||
char regulator_name[NPU_MAX_DT_NAME_LEN];
|
||||
};
|
||||
|
||||
struct npu_debugfs_ctx {
|
||||
struct dentry *root;
|
||||
uint32_t reg_off;
|
||||
uint32_t reg_cnt;
|
||||
};
|
||||
|
||||
struct npu_debugfs_reg_ctx {
|
||||
char *buf;
|
||||
size_t buf_len;
|
||||
struct npu_device *npu_dev;
|
||||
};
|
||||
|
||||
struct npu_mbox {
|
||||
struct mbox_client client;
|
||||
struct mbox_chan *chan;
|
||||
struct npu_device *npu_dev;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct npu_pwrlevel - Struct holding different pwrlevel info obtained
|
||||
* from dtsi file
|
||||
* @pwr_level: NPU power level
|
||||
* @freq[]: NPU frequency vote in Hz
|
||||
*/
|
||||
struct npu_pwrlevel {
|
||||
uint32_t pwr_level;
|
||||
long clk_freq[NUM_MAX_CLK_NUM];
|
||||
};
|
||||
|
||||
/*
|
||||
* struct npu_reg - Struct holding npu register information
|
||||
* @ off - register offset
|
||||
* @ val - register value
|
||||
* @ valid - if register value is valid
|
||||
*/
|
||||
struct npu_reg {
|
||||
uint32_t off;
|
||||
uint32_t val;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct npu_pwrctrl - Power control settings for a NPU device
|
||||
* @pwr_vote_num - voting information for power enable
|
||||
* @pwrlevels - List of supported power levels
|
||||
* @active_pwrlevel - The currently active power level
|
||||
* @default_pwrlevel - device wake up power level
|
||||
* @max_pwrlevel - maximum allowable powerlevel per the user
|
||||
* @min_pwrlevel - minimum allowable powerlevel per the user
|
||||
* @num_pwrlevels - number of available power levels
|
||||
* @cdsprm_pwrlevel - maximum power level from cdsprm
|
||||
* @fmax_pwrlevel - maximum power level from qfprom fmax setting
|
||||
* @uc_pwrlevel - power level from user driver setting
|
||||
* @perf_mode_override - perf mode from sysfs to override perf mode
|
||||
* settings from user driver
|
||||
* @dcvs_mode - dcvs mode from sysfs to turn on dcvs mode
|
||||
* settings from user driver
|
||||
* @devbw - bw device
|
||||
*/
|
||||
struct npu_pwrctrl {
|
||||
int32_t pwr_vote_num;
|
||||
|
||||
struct npu_pwrlevel pwrlevels[NPU_MAX_PWRLEVELS];
|
||||
uint32_t active_pwrlevel;
|
||||
uint32_t default_pwrlevel;
|
||||
uint32_t max_pwrlevel;
|
||||
uint32_t min_pwrlevel;
|
||||
uint32_t num_pwrlevels;
|
||||
|
||||
struct device *devbw;
|
||||
uint32_t bwmon_enabled;
|
||||
uint32_t uc_pwrlevel;
|
||||
uint32_t cdsprm_pwrlevel;
|
||||
uint32_t fmax_pwrlevel;
|
||||
uint32_t perf_mode_override;
|
||||
uint32_t dcvs_mode;
|
||||
uint32_t cur_dcvs_activity;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct npu_thermalctrl - Thermal control settings for a NPU device
|
||||
* @max_state - maximum thermal mitigation state
|
||||
* @current_state - current thermal mitigation state
|
||||
* @pwr_level -power level that thermal control requested
|
||||
*/
|
||||
struct npu_thermalctrl {
|
||||
unsigned long max_state;
|
||||
unsigned long current_state;
|
||||
uint32_t pwr_level;
|
||||
};
|
||||
|
||||
#define NPU_MAX_IRQ 3
|
||||
|
||||
struct npu_irq {
|
||||
char *name;
|
||||
int irq;
|
||||
int irq_type;
|
||||
};
|
||||
|
||||
struct npu_io_data {
|
||||
size_t size;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
struct npu_fw_io_data {
|
||||
phys_addr_t mem_phys;
|
||||
phys_addr_t mem_reloc;
|
||||
void *mem_region;
|
||||
size_t mem_size;
|
||||
};
|
||||
|
||||
struct npu_device {
|
||||
struct mutex dev_lock;
|
||||
|
||||
struct platform_device *pdev;
|
||||
|
||||
dev_t dev_num;
|
||||
struct cdev cdev;
|
||||
struct class *class;
|
||||
struct device *device;
|
||||
|
||||
struct npu_io_data core_io;
|
||||
struct npu_io_data tcm_io;
|
||||
struct npu_io_data bwmon_io;
|
||||
struct npu_io_data qfprom_io;
|
||||
struct npu_fw_io_data fw_io;
|
||||
|
||||
uint32_t core_clk_num;
|
||||
struct npu_clk core_clks[NUM_MAX_CLK_NUM];
|
||||
|
||||
uint32_t regulator_num;
|
||||
struct npu_regulator regulators[NPU_MAX_DT_NAME_LEN];
|
||||
|
||||
struct npu_irq irq[NPU_MAX_IRQ];
|
||||
|
||||
struct device *cb_device;
|
||||
|
||||
struct npu_host_ctx host_ctx;
|
||||
struct npu_smmu_ctx smmu_ctx;
|
||||
struct npu_debugfs_ctx debugfs_ctx;
|
||||
|
||||
struct npu_mbox mbox_aop;
|
||||
|
||||
struct thermal_cooling_device *tcdev;
|
||||
struct npu_pwrctrl pwrctrl;
|
||||
struct npu_thermalctrl thermalctrl;
|
||||
|
||||
struct llcc_slice_desc *sys_cache;
|
||||
uint32_t execute_v2_flag;
|
||||
bool cxlimit_registered;
|
||||
struct icc_path *icc_npu_cdspmem;
|
||||
struct icc_path *icc_cpu_imemcfg;
|
||||
uint32_t hw_version;
|
||||
};
|
||||
|
||||
struct npu_client {
|
||||
struct npu_device *npu_dev;
|
||||
struct mutex list_lock;
|
||||
struct list_head mapped_buffer_list;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Function Prototypes
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
int npu_debugfs_init(struct npu_device *npu_dev);
|
||||
void npu_debugfs_deinit(struct npu_device *npu_dev);
|
||||
|
||||
int npu_enable_core_power(struct npu_device *npu_dev);
|
||||
void npu_disable_core_power(struct npu_device *npu_dev);
|
||||
int npu_enable_post_pil_clocks(struct npu_device *npu_dev);
|
||||
void npu_disable_post_pil_clocks(struct npu_device *npu_dev);
|
||||
|
||||
irqreturn_t npu_intr_hdler(int irq, void *ptr);
|
||||
|
||||
int npu_set_uc_power_level(struct npu_device *npu_dev,
|
||||
uint32_t pwr_level);
|
||||
|
||||
int fw_init(struct npu_device *npu_dev);
|
||||
void fw_deinit(struct npu_device *npu_dev, bool ssr, bool fw_alive);
|
||||
int npu_notify_cdsprm_cxlimit_activity(struct npu_device *npu_dev, bool enable);
|
||||
|
||||
#endif /* _NPU_COMMON_H */
|
33
drivers/media/platform/msm/npu/npu_dbg.c
Normal file
33
drivers/media/platform/msm/npu/npu_dbg.c
Normal file
@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Includes
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#include "npu_common.h"
|
||||
#include "npu_firmware.h"
|
||||
#include "npu_hw.h"
|
||||
#include "npu_hw_access.h"
|
||||
#include "npu_mgr.h"
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Function Definitions - Debug
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
void npu_dump_debug_timeout_stats(struct npu_device *npu_dev)
|
||||
{
|
||||
uint32_t reg_val;
|
||||
|
||||
reg_val = REGR(npu_dev, REG_FW_JOB_CNT_START);
|
||||
pr_info("fw jobs execute started count = %d\n", reg_val);
|
||||
reg_val = REGR(npu_dev, REG_FW_JOB_CNT_END);
|
||||
pr_info("fw jobs execute finished count = %d\n", reg_val);
|
||||
reg_val = REGR(npu_dev, REG_NPU_FW_DEBUG_DATA);
|
||||
pr_info("fw jobs aco parser debug = %d\n", reg_val);
|
||||
}
|
184
drivers/media/platform/msm/npu/npu_debugfs.c
Normal file
184
drivers/media/platform/msm/npu/npu_debugfs.c
Normal file
@ -0,0 +1,184 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Includes
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include "npu_hw.h"
|
||||
#include "npu_hw_access.h"
|
||||
#include "npu_common.h"
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Defines
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#define NPU_LOG_BUF_SIZE 4096
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Function Prototypes
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
static int npu_debug_open(struct inode *inode, struct file *file);
|
||||
static int npu_debug_release(struct inode *inode, struct file *file);
|
||||
static ssize_t npu_debug_ctrl_write(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos);
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Variables
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
static struct npu_device *g_npu_dev;
|
||||
|
||||
static const struct file_operations npu_ctrl_fops = {
|
||||
.open = npu_debug_open,
|
||||
.release = npu_debug_release,
|
||||
.read = NULL,
|
||||
.write = npu_debug_ctrl_write,
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Function Implementations
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
static int npu_debug_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
/* non-seekable */
|
||||
file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
|
||||
file->private_data = inode->i_private;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int npu_debug_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Function Implementations - DebugFS Control
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
static ssize_t npu_debug_ctrl_write(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
char buf[24];
|
||||
struct npu_device *npu_dev = file->private_data;
|
||||
struct npu_debugfs_ctx *debugfs;
|
||||
int32_t rc = 0;
|
||||
uint32_t val;
|
||||
|
||||
pr_debug("npu_dev %pK %pK\n", npu_dev, g_npu_dev);
|
||||
npu_dev = g_npu_dev;
|
||||
debugfs = &npu_dev->debugfs_ctx;
|
||||
|
||||
if (count >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(buf, user_buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
buf[count] = 0; /* end of string */
|
||||
|
||||
if (count >= 2)
|
||||
buf[count-1] = 0;/* remove line feed */
|
||||
|
||||
if (strcmp(buf, "on") == 0) {
|
||||
pr_info("triggering fw_init\n");
|
||||
if (fw_init(npu_dev) != 0)
|
||||
pr_info("error in fw_init\n");
|
||||
} else if (strcmp(buf, "off") == 0) {
|
||||
pr_info("triggering fw_deinit\n");
|
||||
fw_deinit(npu_dev, false, true);
|
||||
} else if (strcmp(buf, "ssr") == 0) {
|
||||
pr_info("trigger error irq\n");
|
||||
if (npu_enable_core_power(npu_dev))
|
||||
return -EPERM;
|
||||
|
||||
REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_SET(1), 2);
|
||||
REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_SET(0), 2);
|
||||
npu_disable_core_power(npu_dev);
|
||||
} else if (strcmp(buf, "ssr_wdt") == 0) {
|
||||
pr_info("trigger wdt irq\n");
|
||||
npu_disable_post_pil_clocks(npu_dev);
|
||||
} else if (strcmp(buf, "loopback") == 0) {
|
||||
pr_debug("loopback test\n");
|
||||
rc = npu_host_loopback_test(npu_dev);
|
||||
pr_debug("loopback test end: %d\n", rc);
|
||||
} else {
|
||||
rc = kstrtou32(buf, 10, &val);
|
||||
if (rc) {
|
||||
pr_err("Invalid input for power level settings\n");
|
||||
} else {
|
||||
val = min(val, npu_dev->pwrctrl.max_pwrlevel);
|
||||
npu_dev->pwrctrl.active_pwrlevel = val;
|
||||
pr_info("setting power state to %d\n", val);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
/* -------------------------------------------------------------------------
|
||||
* Function Implementations - DebugFS
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
int npu_debugfs_init(struct npu_device *npu_dev)
|
||||
{
|
||||
struct npu_debugfs_ctx *debugfs = &npu_dev->debugfs_ctx;
|
||||
struct npu_host_ctx *host_ctx = &npu_dev->host_ctx;
|
||||
struct npu_pwrctrl *pwr = &npu_dev->pwrctrl;
|
||||
|
||||
g_npu_dev = npu_dev;
|
||||
|
||||
debugfs->root = debugfs_create_dir("npu", NULL);
|
||||
if (IS_ERR_OR_NULL(debugfs->root)) {
|
||||
pr_err("debugfs_create_dir for npu failed, error %ld\n",
|
||||
PTR_ERR(debugfs->root));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!debugfs_create_file("ctrl", 0644, debugfs->root,
|
||||
npu_dev, &npu_ctrl_fops)) {
|
||||
pr_err("debugfs_create_file ctrl fail\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
debugfs_create_bool("sys_cache_disable", 0644,
|
||||
debugfs->root, &(host_ctx->sys_cache_disable));
|
||||
|
||||
debugfs_create_u32("fw_dbg_mode", 0644,
|
||||
debugfs->root, &(host_ctx->fw_dbg_mode));
|
||||
|
||||
debugfs_create_u32("fw_state", 0444,
|
||||
debugfs->root, &(host_ctx->fw_state));
|
||||
|
||||
debugfs_create_u32("pwr_level", 0444,
|
||||
debugfs->root, &(pwr->active_pwrlevel));
|
||||
|
||||
debugfs_create_u32("exec_flags", 0644,
|
||||
debugfs->root, &(host_ctx->exec_flags_override));
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
npu_debugfs_deinit(npu_dev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
void npu_debugfs_deinit(struct npu_device *npu_dev)
|
||||
{
|
||||
struct npu_debugfs_ctx *debugfs = &npu_dev->debugfs_ctx;
|
||||
|
||||
if (!IS_ERR_OR_NULL(debugfs->root)) {
|
||||
debugfs_remove_recursive(debugfs->root);
|
||||
debugfs->root = NULL;
|
||||
}
|
||||
}
|
2428
drivers/media/platform/msm/npu/npu_dev.c
Normal file
2428
drivers/media/platform/msm/npu/npu_dev.c
Normal file
File diff suppressed because it is too large
Load Diff
176
drivers/media/platform/msm/npu/npu_firmware.h
Normal file
176
drivers/media/platform/msm/npu/npu_firmware.h
Normal file
@ -0,0 +1,176 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _NPU_FIRMWARE_H
|
||||
#define _NPU_FIRMWARE_H
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Includes
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Defines
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
/* NPU Firmware Control/Status Register, written by FW and read HOST */
|
||||
#define REG_NPU_FW_CTRL_STATUS NPU_GPR0
|
||||
/* written by HOST and read by FW for control */
|
||||
#define REG_NPU_HOST_CTRL_STATUS NPU_GPR1
|
||||
/* Data value for control */
|
||||
#define REG_NPU_HOST_CTRL_VALUE NPU_GPR2
|
||||
/* Simulates an interrupt for FW->HOST, used for pre-silicon */
|
||||
#define REG_FW_TO_HOST_EVENT NPU_GPR3
|
||||
/* Read/Written by both host and dsp for sync between driver and dsp */
|
||||
#define REG_HOST_DSP_CTRL_STATUS NPU_GPR4
|
||||
/* Data value for debug */
|
||||
#define REG_NPU_FW_DEBUG_DATA NPU_GPR13
|
||||
|
||||
/* Started job count */
|
||||
#define REG_FW_JOB_CNT_START NPU_GPR14
|
||||
/* Finished job count */
|
||||
#define REG_FW_JOB_CNT_END NPU_GPR15
|
||||
|
||||
/* NPU FW Control/Status Register */
|
||||
/* bit fields definitions in CTRL STATUS REG */
|
||||
#define FW_CTRL_STATUS_IPC_READY_BIT 0
|
||||
#define FW_CTRL_STATUS_LOG_READY_BIT 1
|
||||
#define FW_CTRL_STATUS_EXECUTE_THREAD_READY_BIT 2
|
||||
#define FW_CTRL_STATUS_MAIN_THREAD_READY_BIT 3
|
||||
#define FW_CTRL_STATUS_LOADED_ACO_BIT 4
|
||||
#define FW_CTRL_STATUS_EXECUTING_ACO_BIT 5
|
||||
#define FW_CTRL_STATUS_SHUTDOWN_DONE_BIT 12
|
||||
#define FW_CTRL_STATUS_STACK_CORRUPT_BIT 13
|
||||
|
||||
/* 32 bit values of the bit fields above */
|
||||
#define FW_CTRL_STATUS_IPC_READY_VAL (1 << FW_CTRL_STATUS_IPC_READY_BIT)
|
||||
#define FW_CTRL_STATUS_LOG_READY_VAL (1 << FW_CTRL_STATUS_LOG_READY_BIT)
|
||||
#define FW_CTRL_STATUS_EXECUTE_THREAD_READY_VAL \
|
||||
(1 << FW_CTRL_STATUS_EXECUTE_THREAD_READY_BIT)
|
||||
#define FW_CTRL_STATUS_MAIN_THREAD_READY_VAL \
|
||||
(1 << FW_CTRL_STATUS_MAIN_THREAD_READY_BIT)
|
||||
#define FW_CTRL_STATUS_LOADED_ACO_VAL \
|
||||
(1 << FW_CTRL_STATUS_LOADED_ACO_BIT)
|
||||
#define FW_CTRL_STATUS_EXECUTING_ACO_VAL \
|
||||
(1 << FW_CTRL_STATUS_EXECUTING_ACO_BIT)
|
||||
#define FW_CTRL_STATUS_SHUTDOWN_DONE_VAL \
|
||||
(1 << FW_CTRL_STATUS_SHUTDOWN_DONE_BIT)
|
||||
#define FW_CTRL_STATUS_STACK_CORRUPT_VAL \
|
||||
(1 << FW_CTRL_STATUS_STACK_CORRUPT_BIT)
|
||||
|
||||
/* NPU HOST Control/Status Register */
|
||||
/* bit fields definitions in CTRL STATUS REG */
|
||||
/* Host has programmed IPC address into the REG_NPU_HOST_CTRL_VALUE register */
|
||||
#define HOST_CTRL_STATUS_IPC_ADDRESS_READY_BIT 0
|
||||
/* Host has enabled logging during boot */
|
||||
#define HOST_CTRL_STATUS_BOOT_ENABLE_LOGGING_BIT 1
|
||||
/* Host has enabled the clk gating of CAL during boot */
|
||||
#define HOST_CTRL_STATUS_BOOT_ENABLE_CLK_GATE_BIT 2
|
||||
/* Host requests to pause fw during boot up */
|
||||
#define HOST_CTRL_STATUS_FW_PAUSE 3
|
||||
/* Host requests to disable watchdog */
|
||||
#define HOST_CTRL_STATUS_DISABLE_WDOG_BIT 4
|
||||
|
||||
/* 32 bit values of the bit fields above */
|
||||
#define HOST_CTRL_STATUS_IPC_ADDRESS_READY_VAL \
|
||||
(1 << HOST_CTRL_STATUS_IPC_ADDRESS_READY_BIT)
|
||||
#define HOST_CTRL_STATUS_BOOT_ENABLE_LOGGING_VAL \
|
||||
(1 << HOST_CTRL_STATUS_BOOT_ENABLE_LOGGING_BIT)
|
||||
#define HOST_CTRL_STATUS_BOOT_ENABLE_CLK_GATE_VAL \
|
||||
(1 << HOST_CTRL_STATUS_BOOT_ENABLE_CLK_GATE_BIT)
|
||||
#define HOST_CTRL_STATUS_FW_PAUSE_VAL \
|
||||
(1 << HOST_CTRL_STATUS_FW_PAUSE)
|
||||
#define HOST_CTRL_STATUS_DISABLE_WDOG_VAL \
|
||||
(1 << HOST_CTRL_STATUS_DISABLE_WDOG_BIT)
|
||||
|
||||
|
||||
/* NPU HOST DSP Control/Status Register */
|
||||
/* notification of power up */
|
||||
/* following bits are set by host and read by dsp */
|
||||
#define HOST_DSP_CTRL_STATUS_PWR_UP_BIT 0
|
||||
/* notification of power dwn */
|
||||
#define HOST_DSP_CTRL_STATUS_PWR_DWN_BIT 1
|
||||
/* following bits are set by dsp and read by host */
|
||||
/* notification of power up acknowlegement*/
|
||||
#define HOST_DSP_CTRL_STATUS_PWR_UP_ACK_BIT 4
|
||||
/* notification of power down acknowlegement*/
|
||||
#define HOST_DSP_CTRL_STATUS_PWR_DWN_ACK_BIT 5
|
||||
|
||||
|
||||
/* 32 bit values of the bit fields above */
|
||||
#define HOST_DSP_CTRL_STATUS_PWR_UP_VAL \
|
||||
(1 << HOST_DSP_CTRL_STATUS_PWR_UP_BIT)
|
||||
#define HOST_DSP_CTRL_STATUS_PWR_DWN_VAL \
|
||||
(1 << HOST_DSP_CTRL_STATUS_PWR_DWN_BIT)
|
||||
#define HOST_DSP_CTRL_STATUS_PWR_UP_ACK_VAL \
|
||||
(1 << HOST_DSP_CTRL_STATUS_PWR_UP_ACK_BIT)
|
||||
#define HOST_DSP_CTRL_STATUS_PWR_DWN_ACK_VAL \
|
||||
(1 << HOST_DSP_CTRL_STATUS_PWR_DWN_ACK_BIT)
|
||||
|
||||
/* Queue table header definition */
|
||||
struct hfi_queue_tbl_header {
|
||||
uint32_t qtbl_version; /* queue table version number */
|
||||
uint32_t qtbl_size; /* total tables+queues size in bytes */
|
||||
uint32_t qtbl_qhdr0_offset; /* offset of the 1st queue header entry */
|
||||
uint32_t qtbl_qhdr_size; /* queue header size */
|
||||
uint32_t qtbl_num_q; /* total number of queues */
|
||||
uint32_t qtbl_num_active_q; /* number of active queues */
|
||||
};
|
||||
|
||||
/* Queue header definition */
|
||||
struct hfi_queue_header {
|
||||
uint32_t qhdr_status; /* 0 == inactive, 1 == active */
|
||||
/* 4 byte-aligned start offset from start of q table */
|
||||
uint32_t qhdr_start_offset;
|
||||
/* queue type */
|
||||
uint32_t qhdr_type;
|
||||
/* in bytes, value of 0 means packets are variable size.*/
|
||||
uint32_t qhdr_q_size;
|
||||
/* size of the Queue packet entries, in bytes, 0 means variable size */
|
||||
uint32_t qhdr_pkt_size;
|
||||
|
||||
uint32_t qhdr_pkt_drop_cnt;
|
||||
/* receiver watermark in # of queue packets */
|
||||
uint32_t qhdr_rx_wm;
|
||||
/* transmitter watermark in # of queue packets */
|
||||
uint32_t qhdr_tx_wm;
|
||||
/*
|
||||
* set to request an interrupt from transmitter
|
||||
* if qhdr_tx_wm is reached
|
||||
*/
|
||||
uint32_t qhdr_rx_req;
|
||||
/*
|
||||
* set to request an interrupt from receiver
|
||||
* if qhdr_rx_wm is reached
|
||||
*/
|
||||
uint32_t qhdr_tx_req;
|
||||
uint32_t qhdr_rx_irq_status; /* Not used */
|
||||
uint32_t qhdr_tx_irq_status; /* Not used */
|
||||
uint32_t qhdr_read_idx; /* read index in bytes */
|
||||
uint32_t qhdr_write_idx; /* write index in bytes */
|
||||
};
|
||||
|
||||
/* in bytes */
|
||||
#define HFI_QUEUE_TABLE_HEADER_SIZE (sizeof(struct hfi_queue_tbl_header))
|
||||
#define HFI_QUEUE_HEADER_SIZE (sizeof(struct hfi_queue_header))
|
||||
#define HFI_QUEUE_TABLE_SIZE (HFI_QUEUE_TABLE_HEADER_SIZE + \
|
||||
(NPU_HFI_NUMBER_OF_QS * HFI_QUEUE_HEADER_SIZE))
|
||||
|
||||
/* Queue Indexes */
|
||||
#define IPC_QUEUE_CMD_HIGH_PRIORITY 0 /* High priority Queue APPS->M0 */
|
||||
#define IPC_QUEUE_APPS_EXEC 1 /* APPS Execute Queue APPS->M0 */
|
||||
#define IPC_QUEUE_DSP_EXEC 2 /* DSP Execute Queue DSP->M0 */
|
||||
#define IPC_QUEUE_APPS_RSP 3 /* APPS Message Queue M0->APPS */
|
||||
#define IPC_QUEUE_DSP_RSP 4 /* DSP Message Queue DSP->APPS */
|
||||
#define IPC_QUEUE_LOG 5 /* Log Message Queue M0->APPS */
|
||||
|
||||
#define NPU_HFI_NUMBER_OF_QS 6
|
||||
#define NPU_HFI_NUMBER_OF_ACTIVE_QS 6
|
||||
|
||||
#define NPU_HFI_QUEUES_PER_CHANNEL 2
|
||||
|
||||
#endif /* _NPU_FIRMWARE_H */
|
438
drivers/media/platform/msm/npu/npu_host_ipc.c
Normal file
438
drivers/media/platform/msm/npu/npu_host_ipc.c
Normal file
@ -0,0 +1,438 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Includes
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#include "npu_hw_access.h"
|
||||
#include "npu_mgr.h"
|
||||
#include "npu_firmware.h"
|
||||
#include "npu_hw.h"
|
||||
#include "npu_host_ipc.h"
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Defines
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
/* HFI IPC interface */
|
||||
#define TX_HDR_TYPE 0x01000000
|
||||
#define RX_HDR_TYPE 0x00010000
|
||||
#define HFI_QTBL_STATUS_ENABLED 0x00000001
|
||||
|
||||
#define QUEUE_TBL_VERSION 0x87654321
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Data Structures
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
struct npu_queue_tuple {
|
||||
uint32_t size;
|
||||
uint32_t hdr;
|
||||
uint32_t start_offset;
|
||||
};
|
||||
|
||||
static struct npu_queue_tuple npu_q_setup[6] = {
|
||||
{ 1024, IPC_QUEUE_CMD_HIGH_PRIORITY | TX_HDR_TYPE | RX_HDR_TYPE, 0},
|
||||
{ 4096, IPC_QUEUE_APPS_EXEC | TX_HDR_TYPE | RX_HDR_TYPE, 0},
|
||||
{ 4096, IPC_QUEUE_DSP_EXEC | TX_HDR_TYPE | RX_HDR_TYPE, 0},
|
||||
{ 4096, IPC_QUEUE_APPS_RSP | TX_HDR_TYPE | RX_HDR_TYPE, 0},
|
||||
{ 4096, IPC_QUEUE_DSP_RSP | TX_HDR_TYPE | RX_HDR_TYPE, 0},
|
||||
{ 1024, IPC_QUEUE_LOG | TX_HDR_TYPE | RX_HDR_TYPE, 0},
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* File Scope Function Prototypes
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
static int npu_host_ipc_init_hfi(struct npu_device *npu_dev);
|
||||
static int npu_host_ipc_send_cmd_hfi(struct npu_device *npu_dev,
|
||||
uint32_t q_idx, void *cmd_ptr);
|
||||
static int npu_host_ipc_read_msg_hfi(struct npu_device *npu_dev,
|
||||
uint32_t q_idx, uint32_t *msg_ptr);
|
||||
static int ipc_queue_read(struct npu_device *npu_dev, uint32_t target_que,
|
||||
uint8_t *packet, uint8_t *is_tx_req_set);
|
||||
static int ipc_queue_write(struct npu_device *npu_dev, uint32_t target_que,
|
||||
uint8_t *packet, uint8_t *is_rx_req_set);
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Function Definitions
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
static int npu_host_ipc_init_hfi(struct npu_device *npu_dev)
|
||||
{
|
||||
int status = 0;
|
||||
struct hfi_queue_tbl_header *q_tbl_hdr = NULL;
|
||||
struct hfi_queue_header *q_hdr_arr = NULL;
|
||||
struct hfi_queue_header *q_hdr = NULL;
|
||||
void *q_tbl_addr = NULL;
|
||||
uint32_t reg_val = 0;
|
||||
uint32_t q_idx = 0;
|
||||
uint32_t q_tbl_size = sizeof(struct hfi_queue_tbl_header) +
|
||||
(NPU_HFI_NUMBER_OF_QS * sizeof(struct hfi_queue_header));
|
||||
uint32_t q_size = 0;
|
||||
uint32_t cur_start_offset = 0;
|
||||
|
||||
reg_val = REGR(npu_dev, REG_NPU_FW_CTRL_STATUS);
|
||||
|
||||
/*
|
||||
* If the firmware is already running and we're just attaching,
|
||||
* we do not need to do this
|
||||
*/
|
||||
if ((reg_val & FW_CTRL_STATUS_LOG_READY_VAL) != 0)
|
||||
return status;
|
||||
|
||||
/* check for valid interface queue table start address */
|
||||
q_tbl_addr = kzalloc(q_tbl_size, GFP_KERNEL);
|
||||
if (q_tbl_addr == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* retrieve interface queue table start address */
|
||||
q_tbl_hdr = q_tbl_addr;
|
||||
q_hdr_arr = (struct hfi_queue_header *)((uint8_t *)q_tbl_addr +
|
||||
sizeof(struct hfi_queue_tbl_header));
|
||||
|
||||
/* initialize the interface queue table header */
|
||||
q_tbl_hdr->qtbl_version = QUEUE_TBL_VERSION;
|
||||
q_tbl_hdr->qtbl_size = q_tbl_size;
|
||||
q_tbl_hdr->qtbl_qhdr0_offset = sizeof(struct hfi_queue_tbl_header);
|
||||
q_tbl_hdr->qtbl_qhdr_size = sizeof(struct hfi_queue_header);
|
||||
q_tbl_hdr->qtbl_num_q = NPU_HFI_NUMBER_OF_QS;
|
||||
q_tbl_hdr->qtbl_num_active_q = NPU_HFI_NUMBER_OF_ACTIVE_QS;
|
||||
|
||||
cur_start_offset = q_tbl_size;
|
||||
|
||||
for (q_idx = IPC_QUEUE_CMD_HIGH_PRIORITY;
|
||||
q_idx <= IPC_QUEUE_LOG; q_idx++) {
|
||||
q_hdr = &q_hdr_arr[q_idx];
|
||||
/* queue is active */
|
||||
q_hdr->qhdr_status = 0x01;
|
||||
q_hdr->qhdr_start_offset = cur_start_offset;
|
||||
npu_q_setup[q_idx].start_offset = cur_start_offset;
|
||||
q_size = npu_q_setup[q_idx].size;
|
||||
q_hdr->qhdr_type = npu_q_setup[q_idx].hdr;
|
||||
/* in bytes */
|
||||
q_hdr->qhdr_q_size = q_size;
|
||||
/* variable size packets */
|
||||
q_hdr->qhdr_pkt_size = 0;
|
||||
q_hdr->qhdr_pkt_drop_cnt = 0;
|
||||
q_hdr->qhdr_rx_wm = 0x1;
|
||||
q_hdr->qhdr_tx_wm = 0x1;
|
||||
/* since queue is initially empty */
|
||||
q_hdr->qhdr_rx_req = 0x1;
|
||||
q_hdr->qhdr_tx_req = 0x0;
|
||||
/* not used */
|
||||
q_hdr->qhdr_rx_irq_status = 0;
|
||||
/* not used */
|
||||
q_hdr->qhdr_tx_irq_status = 0;
|
||||
q_hdr->qhdr_read_idx = 0;
|
||||
q_hdr->qhdr_write_idx = 0;
|
||||
cur_start_offset += q_size;
|
||||
}
|
||||
|
||||
MEMW(npu_dev, IPC_ADDR, (uint8_t *)q_tbl_hdr, q_tbl_size);
|
||||
kfree(q_tbl_addr);
|
||||
/* Write in the NPU's address for where IPC starts */
|
||||
REGW(npu_dev, (uint32_t)REG_NPU_HOST_CTRL_VALUE,
|
||||
(uint32_t)IPC_MEM_OFFSET_FROM_SSTCM);
|
||||
/* Set value bit */
|
||||
reg_val = REGR(npu_dev, (uint32_t)REG_NPU_HOST_CTRL_STATUS);
|
||||
REGW(npu_dev, (uint32_t)REG_NPU_HOST_CTRL_STATUS, reg_val |
|
||||
HOST_CTRL_STATUS_IPC_ADDRESS_READY_VAL);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int npu_host_ipc_send_cmd_hfi(struct npu_device *npu_dev,
|
||||
uint32_t q_idx, void *cmd_ptr)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t is_rx_req_set = 0;
|
||||
uint32_t retry_cnt = 5;
|
||||
|
||||
status = ipc_queue_write(npu_dev, q_idx, (uint8_t *)cmd_ptr,
|
||||
&is_rx_req_set);
|
||||
|
||||
if (status == -ENOSPC) {
|
||||
do {
|
||||
msleep(20);
|
||||
status = ipc_queue_write(npu_dev, q_idx,
|
||||
(uint8_t *)cmd_ptr, &is_rx_req_set);
|
||||
} while ((status == -ENOSPC) && (--retry_cnt > 0));
|
||||
}
|
||||
|
||||
if (status == 0) {
|
||||
if (is_rx_req_set == 1)
|
||||
status = INTERRUPT_RAISE_NPU(npu_dev);
|
||||
}
|
||||
|
||||
if (status == 0)
|
||||
pr_debug("Cmd Msg put on Command Queue - SUCCESSS\n");
|
||||
else
|
||||
pr_err("Cmd Msg put on Command Queue - FAILURE\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int npu_host_ipc_read_msg_hfi(struct npu_device *npu_dev,
|
||||
uint32_t q_idx, uint32_t *msg_ptr)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t is_tx_req_set;
|
||||
|
||||
status = ipc_queue_read(npu_dev, q_idx, (uint8_t *)msg_ptr,
|
||||
&is_tx_req_set);
|
||||
|
||||
if (status == 0) {
|
||||
/* raise interrupt if qhdr_tx_req is set */
|
||||
if (is_tx_req_set == 1)
|
||||
status = INTERRUPT_RAISE_NPU(npu_dev);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ipc_queue_read(struct npu_device *npu_dev,
|
||||
uint32_t target_que, uint8_t *packet,
|
||||
uint8_t *is_tx_req_set)
|
||||
{
|
||||
int status = 0;
|
||||
struct hfi_queue_header queue;
|
||||
uint32_t packet_size, new_read_idx;
|
||||
size_t read_ptr;
|
||||
size_t offset = 0;
|
||||
|
||||
offset = (size_t)IPC_ADDR + sizeof(struct hfi_queue_tbl_header) +
|
||||
target_que * sizeof(struct hfi_queue_header);
|
||||
|
||||
if ((packet == NULL) || (is_tx_req_set == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
/* Read the queue */
|
||||
MEMR(npu_dev, (void *)((size_t)offset), (uint8_t *)&queue,
|
||||
HFI_QUEUE_HEADER_SIZE);
|
||||
|
||||
if (queue.qhdr_type != npu_q_setup[target_que].hdr ||
|
||||
queue.qhdr_q_size != npu_q_setup[target_que].size ||
|
||||
queue.qhdr_read_idx >= queue.qhdr_q_size ||
|
||||
queue.qhdr_write_idx >= queue.qhdr_q_size ||
|
||||
queue.qhdr_start_offset !=
|
||||
npu_q_setup[target_que].start_offset) {
|
||||
pr_err("Invalid Queue header\n");
|
||||
status = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* check if queue is empty */
|
||||
if (queue.qhdr_read_idx == queue.qhdr_write_idx) {
|
||||
/*
|
||||
* set qhdr_rx_req, to inform the sender that the Interrupt
|
||||
* needs to be raised with the next packet queued
|
||||
*/
|
||||
queue.qhdr_rx_req = 1;
|
||||
*is_tx_req_set = 0;
|
||||
status = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
read_ptr = ((size_t)(size_t)IPC_ADDR +
|
||||
queue.qhdr_start_offset + queue.qhdr_read_idx);
|
||||
|
||||
/* Read packet size */
|
||||
MEMR(npu_dev, (void *)((size_t)read_ptr), packet, 4);
|
||||
packet_size = *((uint32_t *)packet);
|
||||
|
||||
pr_debug("target_que: %d, packet_size: %d\n",
|
||||
target_que,
|
||||
packet_size);
|
||||
|
||||
if ((packet_size == 0) ||
|
||||
(packet_size > NPU_IPC_BUF_LENGTH)) {
|
||||
pr_err("Invalid packet size %d\n", packet_size);
|
||||
status = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
new_read_idx = queue.qhdr_read_idx + packet_size;
|
||||
|
||||
if (new_read_idx < (queue.qhdr_q_size)) {
|
||||
MEMR(npu_dev, (void *)((size_t)read_ptr), packet, packet_size);
|
||||
} else {
|
||||
new_read_idx -= (queue.qhdr_q_size);
|
||||
|
||||
MEMR(npu_dev, (void *)((size_t)read_ptr), packet,
|
||||
packet_size - new_read_idx);
|
||||
|
||||
MEMR(npu_dev, (void *)((size_t)IPC_ADDR +
|
||||
queue.qhdr_start_offset),
|
||||
(void *)((size_t)packet + (packet_size-new_read_idx)),
|
||||
new_read_idx);
|
||||
}
|
||||
|
||||
queue.qhdr_read_idx = new_read_idx;
|
||||
|
||||
if (queue.qhdr_read_idx == queue.qhdr_write_idx)
|
||||
/*
|
||||
* receiver wants an interrupt from transmitter
|
||||
* (when next item queued) because queue is empty
|
||||
*/
|
||||
queue.qhdr_rx_req = 1;
|
||||
else
|
||||
/* clear qhdr_rx_req since the queue is not empty */
|
||||
queue.qhdr_rx_req = 0;
|
||||
|
||||
if (queue.qhdr_tx_req == 1)
|
||||
/* transmitter requested an interrupt */
|
||||
*is_tx_req_set = 1;
|
||||
else
|
||||
*is_tx_req_set = 0;
|
||||
exit:
|
||||
/* Update RX interrupt request -- queue.qhdr_rx_req */
|
||||
MEMW(npu_dev, (void *)((size_t)offset +
|
||||
(uint32_t)((size_t)&(queue.qhdr_rx_req) -
|
||||
(size_t)&queue)), (uint8_t *)&queue.qhdr_rx_req,
|
||||
sizeof(queue.qhdr_rx_req));
|
||||
/* Update Read pointer -- queue.qhdr_read_idx */
|
||||
MEMW(npu_dev, (void *)((size_t)offset + (uint32_t)(
|
||||
(size_t)&(queue.qhdr_read_idx) - (size_t)&queue)),
|
||||
(uint8_t *)&queue.qhdr_read_idx, sizeof(queue.qhdr_read_idx));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ipc_queue_write(struct npu_device *npu_dev,
|
||||
uint32_t target_que, uint8_t *packet,
|
||||
uint8_t *is_rx_req_set)
|
||||
{
|
||||
int status = 0;
|
||||
struct hfi_queue_header queue;
|
||||
uint32_t packet_size, new_write_idx;
|
||||
uint32_t empty_space;
|
||||
void *write_ptr;
|
||||
uint32_t read_idx;
|
||||
|
||||
size_t offset = (size_t)IPC_ADDR +
|
||||
sizeof(struct hfi_queue_tbl_header) +
|
||||
target_que * sizeof(struct hfi_queue_header);
|
||||
|
||||
if ((packet == NULL) || (is_rx_req_set == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
MEMR(npu_dev, (void *)((size_t)offset), (uint8_t *)&queue,
|
||||
HFI_QUEUE_HEADER_SIZE);
|
||||
|
||||
if (queue.qhdr_type != npu_q_setup[target_que].hdr ||
|
||||
queue.qhdr_q_size != npu_q_setup[target_que].size ||
|
||||
queue.qhdr_read_idx >= queue.qhdr_q_size ||
|
||||
queue.qhdr_write_idx >= queue.qhdr_q_size ||
|
||||
queue.qhdr_start_offset !=
|
||||
npu_q_setup[target_que].start_offset) {
|
||||
pr_err("Invalid Queue header\n");
|
||||
status = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
packet_size = (*(uint32_t *)packet);
|
||||
if (packet_size == 0) {
|
||||
/* assign failed status and return */
|
||||
status = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* sample Read Idx */
|
||||
read_idx = queue.qhdr_read_idx;
|
||||
|
||||
/* Calculate Empty Space(UWord32) in the Queue */
|
||||
empty_space = (queue.qhdr_write_idx >= read_idx) ?
|
||||
((queue.qhdr_q_size) - (queue.qhdr_write_idx - read_idx)) :
|
||||
(read_idx - queue.qhdr_write_idx);
|
||||
|
||||
if (empty_space <= packet_size) {
|
||||
/*
|
||||
* If Queue is FULL/ no space for message
|
||||
* set qhdr_tx_req.
|
||||
*/
|
||||
queue.qhdr_tx_req = 1;
|
||||
|
||||
/*
|
||||
* Queue is FULL, force raise an interrupt to Receiver
|
||||
*/
|
||||
*is_rx_req_set = 1;
|
||||
|
||||
status = -ENOSPC;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* clear qhdr_tx_req so that receiver does not raise an interrupt
|
||||
* on reading packets from Queue, since there is space to write
|
||||
* the next packet
|
||||
*/
|
||||
queue.qhdr_tx_req = 0;
|
||||
|
||||
new_write_idx = (queue.qhdr_write_idx + packet_size);
|
||||
|
||||
write_ptr = (void *)(size_t)((size_t)IPC_ADDR +
|
||||
queue.qhdr_start_offset + queue.qhdr_write_idx);
|
||||
|
||||
if (new_write_idx < queue.qhdr_q_size) {
|
||||
MEMW(npu_dev, (void *)((size_t)write_ptr), (uint8_t *)packet,
|
||||
packet_size);
|
||||
} else {
|
||||
/* wraparound case */
|
||||
new_write_idx -= (queue.qhdr_q_size);
|
||||
|
||||
MEMW(npu_dev, (void *)((size_t)write_ptr), (uint8_t *)packet,
|
||||
packet_size - new_write_idx);
|
||||
|
||||
MEMW(npu_dev, (void *)((size_t)((size_t)IPC_ADDR +
|
||||
queue.qhdr_start_offset)), (uint8_t *)(packet +
|
||||
(packet_size - new_write_idx)), new_write_idx);
|
||||
}
|
||||
|
||||
/* Update qhdr_write_idx */
|
||||
queue.qhdr_write_idx = new_write_idx;
|
||||
|
||||
*is_rx_req_set = (queue.qhdr_rx_req == 1) ? 1 : 0;
|
||||
|
||||
/* Update Write pointer -- queue.qhdr_write_idx */
|
||||
exit:
|
||||
/* Update TX request -- queue.qhdr_tx_req */
|
||||
MEMW(npu_dev, (void *)((size_t)(offset + (uint32_t)(
|
||||
(size_t)&(queue.qhdr_tx_req) - (size_t)&queue))),
|
||||
&queue.qhdr_tx_req, sizeof(queue.qhdr_tx_req));
|
||||
MEMW(npu_dev, (void *)((size_t)(offset + (uint32_t)(
|
||||
(size_t)&(queue.qhdr_write_idx) - (size_t)&queue))),
|
||||
&queue.qhdr_write_idx, sizeof(queue.qhdr_write_idx));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* IPC Interface functions
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
int npu_host_ipc_send_cmd(struct npu_device *npu_dev, uint32_t q_idx,
|
||||
void *cmd_ptr)
|
||||
{
|
||||
return npu_host_ipc_send_cmd_hfi(npu_dev, q_idx, cmd_ptr);
|
||||
}
|
||||
|
||||
int npu_host_ipc_read_msg(struct npu_device *npu_dev, uint32_t q_idx,
|
||||
uint32_t *msg_ptr)
|
||||
{
|
||||
return npu_host_ipc_read_msg_hfi(npu_dev, q_idx, msg_ptr);
|
||||
}
|
||||
|
||||
int npu_host_ipc_pre_init(struct npu_device *npu_dev)
|
||||
{
|
||||
return npu_host_ipc_init_hfi(npu_dev);
|
||||
}
|
||||
|
||||
int npu_host_ipc_post_init(struct npu_device *npu_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
464
drivers/media/platform/msm/npu/npu_host_ipc.h
Normal file
464
drivers/media/platform/msm/npu/npu_host_ipc.h
Normal file
@ -0,0 +1,464 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef NPU_HOST_IPC_H
|
||||
#define NPU_HOST_IPC_H
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Defines
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
/* Messages sent **to** NPU */
|
||||
/* IPC Message Commands -- uint32_t */
|
||||
/* IPC command start base */
|
||||
#define NPU_IPC_CMD_BASE 0x00000000
|
||||
/* ipc_cmd_load_pkt */
|
||||
#define NPU_IPC_CMD_LOAD 0x00000001
|
||||
/* ipc_cmd_unload_pkt */
|
||||
#define NPU_IPC_CMD_UNLOAD 0x00000002
|
||||
/* ipc_cmd_execute_pkt */
|
||||
#define NPU_IPC_CMD_EXECUTE 0x00000003
|
||||
/* ipc_cmd_set_logging_state */
|
||||
#define NPU_IPC_CMD_CONFIG_LOG 0x00000004
|
||||
#define NPU_IPC_CMD_CONFIG_PERFORMANCE 0x00000005
|
||||
#define NPU_IPC_CMD_CONFIG_DEBUG 0x00000006
|
||||
#define NPU_IPC_CMD_SHUTDOWN 0x00000007
|
||||
/* ipc_cmd_loopback_packet */
|
||||
#define NPU_IPC_CMD_LOOPBACK 0x00000008
|
||||
/* ipc_cmd_load_packet_v2_t */
|
||||
#define NPU_IPC_CMD_LOAD_V2 0x00000009
|
||||
/* ipc_cmd_execute_packet_v2 */
|
||||
#define NPU_IPC_CMD_EXECUTE_V2 0x0000000A
|
||||
/* ipc_cmd_set_property_packet */
|
||||
#define NPU_IPC_CMD_SET_PROPERTY 0x0000000B
|
||||
/* ipc_cmd_get_property_packet */
|
||||
#define NPU_IPC_CMD_GET_PROPERTY 0x0000000C
|
||||
|
||||
/* Messages sent **from** NPU */
|
||||
/* IPC Message Response -- uint32_t */
|
||||
/* IPC response start base */
|
||||
#define NPU_IPC_MSG_BASE 0x00010000
|
||||
/* ipc_msg_load_pkt */
|
||||
#define NPU_IPC_MSG_LOAD_DONE 0x00010001
|
||||
/* ipc_msg_header_pkt */
|
||||
#define NPU_IPC_MSG_UNLOAD_DONE 0x00010002
|
||||
/* ipc_msg_header_pkt */
|
||||
#define NPU_IPC_MSG_EXECUTE_DONE 0x00010003
|
||||
/* ipc_msg_event_notify_pkt */
|
||||
#define NPU_IPC_MSG_EVENT_NOTIFY 0x00010004
|
||||
/* ipc_msg_loopback_pkt */
|
||||
#define NPU_IPC_MSG_LOOPBACK_DONE 0x00010005
|
||||
/* ipc_msg_execute_pkt_v2 */
|
||||
#define NPU_IPC_MSG_EXECUTE_V2_DONE 0x00010006
|
||||
/* ipc_msg_set_property_packet */
|
||||
#define NPU_IPC_MSG_SET_PROPERTY_DONE 0x00010007
|
||||
/* ipc_msg_get_property_packet */
|
||||
#define NPU_IPC_MSG_GET_PROPERTY_DONE 0x00010008
|
||||
/* ipc_msg_general_notify_pkt */
|
||||
#define NPU_IPC_MSG_GENERAL_NOTIFY 0x00010010
|
||||
|
||||
/* IPC Notify Message Type -- uint32_t */
|
||||
#define NPU_NOTIFY_DCVS_MODE 0x00002000
|
||||
|
||||
/* Logging message size */
|
||||
/* Number 32-bit elements for the maximum log message size */
|
||||
#define NPU_LOG_MSG_MAX_SIZE 4
|
||||
|
||||
/* Performance */
|
||||
/* Performance counters for current network layer */
|
||||
/* Amount of data read from all the DMA read channels */
|
||||
#define NPU_PERFORMANCE_DMA_DATA_READ 0x01
|
||||
/* Amount of data written from all the DMA write channels */
|
||||
#define NPU_PERFORMANCE_DMA_DATA_WRITTEN 0x02
|
||||
/* Number of blocks read by DMA channels */
|
||||
#define NPU_PERFORMANCE_DMA_NUM_BLOCKS_READ 0x03
|
||||
/* Number of blocks written by DMA channels */
|
||||
#define NPU_PERFORMANCE_DMA_NUM_BLOCKS_WRITTEN 0x04
|
||||
/* Number of instructions executed by CAL */
|
||||
#define NPU_PERFORMANCE_INSTRUCTIONS_CAL 0x05
|
||||
/* Number of instructions executed by CUB */
|
||||
#define NPU_PERFORMANCE_INSTRUCTIONS_CUB 0x06
|
||||
/* Timestamp of start of network load */
|
||||
#define NPU_PERFORMANCE_TIMESTAMP_LOAD_START 0x07
|
||||
/* Timestamp of end of network load */
|
||||
#define NPU_PERFORMANCE_TIMESTAMP_LOAD_END 0x08
|
||||
/* Timestamp of start of network execute */
|
||||
#define NPU_PERFORMANCE_TIMESTAMP_EXECUTE_START 0x09
|
||||
/* Timestamp of end of network execute */
|
||||
#define NPU_PERFORMANCE_TIMESTAMP_EXECUTE_END 0x10
|
||||
/* Timestamp of CAL start */
|
||||
#define NPU_PERFORMANCE_TIMESTAMP_CAL_START 0x11
|
||||
/* Timestamp of CAL end */
|
||||
#define NPU_PERFORMANCE_TIMESTAMP_CAL_END 0x12
|
||||
/* Timestamp of CUB start */
|
||||
#define NPU_PERFORMANCE_TIMESTAMP_CUB_START 0x13
|
||||
/* Timestamp of CUB end */
|
||||
#define NPU_PERFORMANCE_TIMESTAMP_CUB_END 0x14
|
||||
|
||||
/* Performance enable */
|
||||
/* Select which counters you want back per layer */
|
||||
|
||||
/* Shutdown */
|
||||
/* Immediate shutdown, discard any state, etc */
|
||||
#define NPU_SHUTDOWN_IMMEDIATE 0x01
|
||||
/* Shutdown after current execution (if any) is completed */
|
||||
#define NPU_SHUTDOWN_WAIT_CURRENT_EXECUTION 0x02
|
||||
|
||||
/* Debug stats */
|
||||
#define NUM_LAYER_STATS_PER_EXE_MSG_MAX 110
|
||||
|
||||
/* DCVS */
|
||||
#define NPU_DCVS_ACTIVITY_MAX_PERF 0x100
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Data Structures
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
/* Command Header - Header for all Messages **TO** NPU */
|
||||
/*
|
||||
* command header packet definition for
|
||||
* messages sent from host->NPU
|
||||
*/
|
||||
struct ipc_cmd_header_pkt {
|
||||
uint32_t size;
|
||||
uint32_t cmd_type;
|
||||
uint32_t trans_id;
|
||||
uint32_t flags; /* TDO what flags and why */
|
||||
};
|
||||
|
||||
/* Message Header - Header for all messages **FROM** NPU */
|
||||
/*
|
||||
* message header packet definition for
|
||||
* mesasges sent from NPU->host
|
||||
*/
|
||||
struct ipc_msg_header_pkt {
|
||||
uint32_t size;
|
||||
uint32_t msg_type;
|
||||
uint32_t status;
|
||||
uint32_t trans_id;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
/* Execute */
|
||||
/*
|
||||
* FIRMWARE
|
||||
* keep lastNetworkIDRan = uint32
|
||||
* keep wasLastNetworkChunky = BOOLEAN
|
||||
*/
|
||||
/*
|
||||
* ACO Buffer definition
|
||||
*/
|
||||
struct npu_aco_buffer {
|
||||
/*
|
||||
* used to track if previous network is the same and already loaded,
|
||||
* we can save a dma
|
||||
*/
|
||||
uint32_t network_id;
|
||||
/*
|
||||
* size of header + first chunk ACO buffer -
|
||||
* this saves a dma by dmaing both header and first chunk
|
||||
*/
|
||||
uint32_t buf_size;
|
||||
/*
|
||||
* SMMU 32-bit mapped address that the DMA engine can read -
|
||||
* uses lower 32 bits
|
||||
*/
|
||||
uint64_t address;
|
||||
};
|
||||
|
||||
/*
|
||||
* ACO Buffer V2 definition
|
||||
*/
|
||||
struct npu_aco_buffer_v2 {
|
||||
/*
|
||||
* used to track if previous network is the same and already loaded,
|
||||
* we can save a dma
|
||||
*/
|
||||
uint32_t network_id;
|
||||
/*
|
||||
* size of header + first chunk ACO buffer -
|
||||
* this saves a dma by dmaing both header and first chunk
|
||||
*/
|
||||
uint32_t buf_size;
|
||||
/*
|
||||
* SMMU 32-bit mapped address that the DMA engine can read -
|
||||
* uses lower 32 bits
|
||||
*/
|
||||
uint32_t address;
|
||||
/*
|
||||
* number of layers in the network
|
||||
*/
|
||||
uint32_t num_layers;
|
||||
};
|
||||
|
||||
/*
|
||||
* ACO Patch Parameters
|
||||
*/
|
||||
struct npu_patch_tuple {
|
||||
uint32_t value;
|
||||
uint32_t chunk_id;
|
||||
uint16_t instruction_size_in_bytes;
|
||||
uint16_t variable_size_in_bits;
|
||||
uint16_t shift_value_in_bits;
|
||||
uint32_t loc_offset;
|
||||
};
|
||||
|
||||
/*
|
||||
* ACO Patch Tuple V2
|
||||
*/
|
||||
struct npu_patch_tuple_v2 {
|
||||
uint32_t value;
|
||||
uint32_t chunk_id;
|
||||
uint32_t instruction_size_in_bytes;
|
||||
uint32_t variable_size_in_bits;
|
||||
uint32_t shift_value_in_bits;
|
||||
uint32_t loc_offset;
|
||||
};
|
||||
|
||||
struct npu_patch_params {
|
||||
uint32_t num_params;
|
||||
struct npu_patch_tuple param[2];
|
||||
};
|
||||
|
||||
/*
|
||||
* LOAD command packet definition
|
||||
*/
|
||||
struct ipc_cmd_load_pkt {
|
||||
struct ipc_cmd_header_pkt header;
|
||||
struct npu_aco_buffer buf_pkt;
|
||||
};
|
||||
|
||||
/*
|
||||
* LOAD command packet V2 definition
|
||||
*/
|
||||
struct ipc_cmd_load_pkt_v2 {
|
||||
struct ipc_cmd_header_pkt header;
|
||||
struct npu_aco_buffer_v2 buf_pkt;
|
||||
uint32_t num_patch_params;
|
||||
struct npu_patch_tuple_v2 patch_params[];
|
||||
};
|
||||
|
||||
/*
|
||||
* UNLOAD command packet definition
|
||||
*/
|
||||
struct ipc_cmd_unload_pkt {
|
||||
struct ipc_cmd_header_pkt header;
|
||||
uint32_t network_hdl;
|
||||
};
|
||||
|
||||
/*
|
||||
* Execute packet definition
|
||||
*/
|
||||
struct ipc_cmd_execute_pkt {
|
||||
struct ipc_cmd_header_pkt header;
|
||||
struct npu_patch_params patch_params;
|
||||
uint32_t network_hdl;
|
||||
};
|
||||
|
||||
struct npu_patch_params_v2 {
|
||||
uint32_t value;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
/*
|
||||
* Execute packet V2 definition
|
||||
*/
|
||||
struct ipc_cmd_execute_pkt_v2 {
|
||||
struct ipc_cmd_header_pkt header;
|
||||
uint32_t network_hdl;
|
||||
uint32_t num_patch_params;
|
||||
struct npu_patch_params_v2 patch_params[];
|
||||
};
|
||||
|
||||
/*
|
||||
* Loopback packet definition
|
||||
*/
|
||||
struct ipc_cmd_loopback_pkt {
|
||||
struct ipc_cmd_header_pkt header;
|
||||
uint32_t loopbackParams;
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic property definition
|
||||
*/
|
||||
struct ipc_cmd_prop_pkt {
|
||||
struct ipc_cmd_header_pkt header;
|
||||
uint32_t prop_id;
|
||||
uint32_t num_params;
|
||||
uint32_t network_hdl;
|
||||
uint32_t prop_param[];
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic property response packet definition
|
||||
*/
|
||||
struct ipc_msg_prop_pkt {
|
||||
struct ipc_msg_header_pkt header;
|
||||
uint32_t prop_id;
|
||||
uint32_t num_params;
|
||||
uint32_t network_hdl;
|
||||
uint32_t prop_param[];
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic notify message packet definition
|
||||
*/
|
||||
struct ipc_msg_general_notify_pkt {
|
||||
struct ipc_msg_header_pkt header;
|
||||
uint32_t notify_id;
|
||||
uint32_t num_params;
|
||||
uint32_t network_hdl;
|
||||
uint32_t notify_param[];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* LOAD response packet definition
|
||||
*/
|
||||
struct ipc_msg_load_pkt {
|
||||
struct ipc_msg_header_pkt header;
|
||||
uint32_t network_hdl;
|
||||
};
|
||||
|
||||
/*
|
||||
* UNLOAD response packet definition
|
||||
*/
|
||||
struct ipc_msg_unload_pkt {
|
||||
struct ipc_msg_header_pkt header;
|
||||
uint32_t network_hdl;
|
||||
};
|
||||
|
||||
/*
|
||||
* Layer Stats information returned back during EXECUTE_DONE response
|
||||
*/
|
||||
struct ipc_layer_stats {
|
||||
/*
|
||||
* hardware tick count per layer
|
||||
*/
|
||||
uint32_t tick_count;
|
||||
};
|
||||
|
||||
struct ipc_execute_layer_stats {
|
||||
/*
|
||||
* total number of layers associated with the execution
|
||||
*/
|
||||
uint32_t total_num_layers;
|
||||
/*
|
||||
* pointer to each layer stats
|
||||
*/
|
||||
struct ipc_layer_stats
|
||||
layer_stats_list[NUM_LAYER_STATS_PER_EXE_MSG_MAX];
|
||||
};
|
||||
|
||||
struct ipc_execute_stats {
|
||||
/*
|
||||
* total e2e IPC tick count during EXECUTE cmd
|
||||
*/
|
||||
uint32_t e2e_ipc_tick_count;
|
||||
/*
|
||||
* tick count on ACO loading
|
||||
*/
|
||||
uint32_t aco_load_tick_count;
|
||||
/*
|
||||
* tick count on ACO execution
|
||||
*/
|
||||
uint32_t aco_execution_tick_count;
|
||||
/*
|
||||
* individual layer stats
|
||||
*/
|
||||
struct ipc_execute_layer_stats exe_stats;
|
||||
};
|
||||
|
||||
/*
|
||||
* EXECUTE response packet definition
|
||||
*/
|
||||
struct ipc_msg_execute_pkt {
|
||||
struct ipc_msg_header_pkt header;
|
||||
struct ipc_execute_stats stats;
|
||||
uint32_t network_hdl;
|
||||
};
|
||||
|
||||
/*
|
||||
* EXECUTE V2 response packet definition
|
||||
*/
|
||||
struct ipc_msg_execute_pkt_v2 {
|
||||
struct ipc_msg_header_pkt header;
|
||||
uint32_t network_hdl;
|
||||
uint32_t stats_data[];
|
||||
};
|
||||
|
||||
/*
|
||||
* LOOPBACK response packet definition
|
||||
*/
|
||||
struct ipc_msg_loopback_pkt {
|
||||
struct ipc_msg_header_pkt header;
|
||||
uint32_t loopbackParams;
|
||||
};
|
||||
|
||||
/* Logging Related */
|
||||
|
||||
/*
|
||||
* ipc_log_state_t - Logging state
|
||||
*/
|
||||
struct ipc_log_state {
|
||||
uint32_t module_msk;
|
||||
uint32_t level_msk;
|
||||
};
|
||||
|
||||
struct ipc_cmd_log_state_pkt {
|
||||
struct ipc_cmd_header_pkt header;
|
||||
struct ipc_log_state log_state;
|
||||
};
|
||||
|
||||
struct ipc_msg_log_state_pkt {
|
||||
struct ipc_msg_header_pkt header;
|
||||
struct ipc_log_state log_state;
|
||||
};
|
||||
|
||||
/*
|
||||
* Logging message
|
||||
* This is a message from the NPU that contains the
|
||||
* logging message. The values of part1-4 are not exposed
|
||||
* the receiver has to refer to the logging implementation to
|
||||
* intrepret what these mean and how to parse
|
||||
*/
|
||||
struct ipc_msg_log_pkt {
|
||||
struct ipc_msg_header_pkt header;
|
||||
uint32_t log_msg[NPU_LOG_MSG_MAX_SIZE];
|
||||
};
|
||||
|
||||
/* Performance Related */
|
||||
|
||||
/*
|
||||
* Set counter mask of which counters we want
|
||||
* This is a message from HOST->NPU Firmware
|
||||
*/
|
||||
struct ipc_cmd_set_performance_query {
|
||||
struct ipc_cmd_header_pkt header;
|
||||
uint32_t cnt_msk;
|
||||
};
|
||||
|
||||
/*
|
||||
* Set counter mask of which counters we want
|
||||
* This is a message from HOST->NPU Firmware
|
||||
*/
|
||||
struct ipc_msg_performance_counters {
|
||||
struct ipc_cmd_header_pkt header;
|
||||
uint32_t layer_id;
|
||||
uint32_t num_tulpes;
|
||||
/* Array of tuples [HEADER,value] */
|
||||
uint32_t cnt_tulpes[];
|
||||
};
|
||||
|
||||
/*
|
||||
* ipc_cmd_shutdown - Shutdown command
|
||||
*/
|
||||
struct ipc_cmd_shutdown_pkt {
|
||||
struct ipc_cmd_header_pkt header;
|
||||
uint32_t shutdown_flags;
|
||||
};
|
||||
|
||||
#endif /* NPU_HOST_IPC_H */
|
53
drivers/media/platform/msm/npu/npu_hw.h
Normal file
53
drivers/media/platform/msm/npu/npu_hw.h
Normal file
@ -0,0 +1,53 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef NPU_HW_H
|
||||
#define NPU_HW_H
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Defines
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#define NPU_HW_VERSION (0x00000000)
|
||||
#define NPU_MASTERn_IPC_IRQ_OUT(n) (0x00001004+0x1000*(n))
|
||||
#define NPU_CACHE_ATTR_IDn___POR 0x00011100
|
||||
#define NPU_CACHE_ATTR_IDn(n) (0x00000800+0x4*(n))
|
||||
#define NPU_MASTERn_IPC_IRQ_IN_CTRL(n) (0x00001008+0x1000*(n))
|
||||
#define NPU_MASTER0_IPC_IRQ_IN_CTRL__IRQ_SOURCE_SELECT___S 4
|
||||
#define NPU_MASTERn_IPC_IRQ_OUT_CTRL(n) (0x00001004+0x1000*(n))
|
||||
#define NPU_MASTER0_IPC_IRQ_OUT_CTRL__IRQ_TYPE_PULSE 4
|
||||
#define NPU_GPR0 (0x00000100)
|
||||
#define NPU_MASTERn_ERROR_IRQ_STATUS(n) (0x00001010+0x1000*(n))
|
||||
#define NPU_MASTERn_ERROR_IRQ_INCLUDE(n) (0x00001014+0x1000*(n))
|
||||
#define NPU_MASTERn_ERROR_IRQ_ENABLE(n) (0x00001018+0x1000*(n))
|
||||
#define NPU_MASTERn_ERROR_IRQ_CLEAR(n) (0x0000101C+0x1000*(n))
|
||||
#define NPU_MASTERn_ERROR_IRQ_SET(n) (0x00001020+0x1000*(n))
|
||||
#define NPU_MASTERn_ERROR_IRQ_OWNER(n) (0x00007000+4*(n))
|
||||
#define NPU_ERROR_IRQ_MASK 0x000000E3
|
||||
#define NPU_MASTERn_WDOG_IRQ_STATUS(n) (0x00001030+0x1000*(n))
|
||||
#define NPU_WDOG_BITE_IRQ_STATUS (1 << 1)
|
||||
#define NPU_MASTERn_WDOG_IRQ_INCLUDE(n) (0x00001034+0x1000*(n))
|
||||
#define NPU_WDOG_BITE_IRQ_INCLUDE (1 << 1)
|
||||
#define NPU_MASTERn_WDOG_IRQ_OWNER(n) (0x00007010+4*(n))
|
||||
#define NPU_WDOG_IRQ_MASK 0x00000002
|
||||
|
||||
|
||||
#define NPU_GPR1 (0x00000104)
|
||||
#define NPU_GPR2 (0x00000108)
|
||||
#define NPU_GPR3 (0x0000010C)
|
||||
#define NPU_GPR4 (0x00000110)
|
||||
#define NPU_GPR13 (0x00000134)
|
||||
#define NPU_GPR14 (0x00000138)
|
||||
#define NPU_GPR15 (0x0000013C)
|
||||
|
||||
#define BWMON2_SAMPLING_WINDOW (0x000003A8)
|
||||
#define BWMON2_BYTE_COUNT_THRESHOLD_HIGH (0x000003AC)
|
||||
#define BWMON2_BYTE_COUNT_THRESHOLD_MEDIUM (0x000003B0)
|
||||
#define BWMON2_BYTE_COUNT_THRESHOLD_LOW (0x000003B4)
|
||||
#define BWMON2_ZONE_ACTIONS (0x000003B8)
|
||||
#define BWMON2_ZONE_COUNT_THRESHOLD (0x000003BC)
|
||||
|
||||
#endif /* NPU_HW_H */
|
485
drivers/media/platform/msm/npu/npu_hw_access.c
Normal file
485
drivers/media/platform/msm/npu/npu_hw_access.c
Normal file
@ -0,0 +1,485 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Includes
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#include <linux/msm_dma_iommu_mapping.h>
|
||||
#include <soc/qcom/subsystem_restart.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/qcom_scm.h>
|
||||
#include <linux/soc/qcom/mdt_loader.h>
|
||||
|
||||
#include "npu_hw_access.h"
|
||||
#include "npu_common.h"
|
||||
#include "npu_hw.h"
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Functions - Register
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
static uint32_t npu_reg_read(void __iomem *base, size_t size, uint32_t off)
|
||||
{
|
||||
if (!base) {
|
||||
pr_err("NULL base address\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((off % 4) != 0) {
|
||||
pr_err("offset %x is not aligned\n", off);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (off >= size) {
|
||||
pr_err("offset exceeds io region %x:%x\n", off, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return readl_relaxed(base + off);
|
||||
}
|
||||
|
||||
static void npu_reg_write(void __iomem *base, size_t size, uint32_t off,
|
||||
uint32_t val)
|
||||
{
|
||||
if (!base) {
|
||||
pr_err("NULL base address\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((off % 4) != 0) {
|
||||
pr_err("offset %x is not aligned\n", off);
|
||||
return;
|
||||
}
|
||||
|
||||
if (off >= size) {
|
||||
pr_err("offset exceeds io region %x:%x\n", off, size);
|
||||
return;
|
||||
}
|
||||
|
||||
writel_relaxed(val, base + off);
|
||||
__iowmb();
|
||||
}
|
||||
|
||||
uint32_t npu_core_reg_read(struct npu_device *npu_dev, uint32_t off)
|
||||
{
|
||||
return npu_reg_read(npu_dev->core_io.base, npu_dev->core_io.size, off);
|
||||
}
|
||||
|
||||
void npu_core_reg_write(struct npu_device *npu_dev, uint32_t off, uint32_t val)
|
||||
{
|
||||
npu_reg_write(npu_dev->core_io.base, npu_dev->core_io.size,
|
||||
off, val);
|
||||
}
|
||||
|
||||
uint32_t npu_bwmon_reg_read(struct npu_device *npu_dev, uint32_t off)
|
||||
{
|
||||
return npu_reg_read(npu_dev->bwmon_io.base, npu_dev->bwmon_io.size,
|
||||
off);
|
||||
}
|
||||
|
||||
void npu_bwmon_reg_write(struct npu_device *npu_dev, uint32_t off,
|
||||
uint32_t val)
|
||||
{
|
||||
npu_reg_write(npu_dev->bwmon_io.base, npu_dev->bwmon_io.size,
|
||||
off, val);
|
||||
}
|
||||
|
||||
uint32_t npu_qfprom_reg_read(struct npu_device *npu_dev, uint32_t off)
|
||||
{
|
||||
return npu_reg_read(npu_dev->qfprom_io.base,
|
||||
npu_dev->qfprom_io.size, off);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Functions - Memory
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
void npu_mem_write(struct npu_device *npu_dev, void *dst, void *src,
|
||||
uint32_t size)
|
||||
{
|
||||
size_t dst_off = (size_t)dst;
|
||||
uint32_t *src_ptr32 = (uint32_t *)src;
|
||||
uint8_t *src_ptr8 = NULL;
|
||||
uint32_t i = 0;
|
||||
uint32_t num = 0;
|
||||
|
||||
if (dst_off >= npu_dev->tcm_io.size ||
|
||||
(npu_dev->tcm_io.size - dst_off) < size) {
|
||||
pr_err("memory write exceeds io region %x:%x:%x\n",
|
||||
dst_off, size, npu_dev->tcm_io.size);
|
||||
return;
|
||||
}
|
||||
|
||||
num = size/4;
|
||||
for (i = 0; i < num; i++) {
|
||||
writel_relaxed(src_ptr32[i], npu_dev->tcm_io.base + dst_off);
|
||||
dst_off += 4;
|
||||
}
|
||||
|
||||
if (size%4 != 0) {
|
||||
src_ptr8 = (uint8_t *)((size_t)src + (num*4));
|
||||
num = size%4;
|
||||
for (i = 0; i < num; i++) {
|
||||
writeb_relaxed(src_ptr8[i], npu_dev->tcm_io.base +
|
||||
dst_off);
|
||||
dst_off += 1;
|
||||
}
|
||||
}
|
||||
|
||||
__iowmb();
|
||||
}
|
||||
|
||||
int32_t npu_mem_read(struct npu_device *npu_dev, void *src, void *dst,
|
||||
uint32_t size)
|
||||
{
|
||||
size_t src_off = (size_t)src;
|
||||
uint32_t *out32 = (uint32_t *)dst;
|
||||
uint8_t *out8 = NULL;
|
||||
uint32_t i = 0;
|
||||
uint32_t num = 0;
|
||||
|
||||
if (src_off >= npu_dev->tcm_io.size ||
|
||||
(npu_dev->tcm_io.size - src_off) < size) {
|
||||
pr_err("memory read exceeds io region %x:%x:%x\n",
|
||||
src_off, size, npu_dev->tcm_io.size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
num = size/4;
|
||||
for (i = 0; i < num; i++) {
|
||||
out32[i] = readl_relaxed(npu_dev->tcm_io.base + src_off);
|
||||
src_off += 4;
|
||||
}
|
||||
|
||||
if (size%4 != 0) {
|
||||
out8 = (uint8_t *)((size_t)dst + (num*4));
|
||||
num = size%4;
|
||||
for (i = 0; i < num; i++) {
|
||||
out8[i] = readb_relaxed(npu_dev->tcm_io.base + src_off);
|
||||
src_off += 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *npu_ipc_addr(void)
|
||||
{
|
||||
return (void *)(IPC_MEM_OFFSET_FROM_SSTCM);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Functions - Interrupt
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
void npu_interrupt_ack(struct npu_device *npu_dev, uint32_t intr_num)
|
||||
{
|
||||
struct npu_host_ctx *host_ctx = &npu_dev->host_ctx;
|
||||
uint32_t wdg_irq_sts = 0, error_irq_sts = 0;
|
||||
|
||||
/* Clear irq state */
|
||||
REGW(npu_dev, NPU_MASTERn_IPC_IRQ_OUT(0), 0x0);
|
||||
|
||||
wdg_irq_sts = REGR(npu_dev, NPU_MASTERn_WDOG_IRQ_STATUS(0));
|
||||
if (wdg_irq_sts != 0) {
|
||||
pr_err("wdg irq %x\n", wdg_irq_sts);
|
||||
host_ctx->wdg_irq_sts |= wdg_irq_sts;
|
||||
host_ctx->fw_error = true;
|
||||
}
|
||||
|
||||
error_irq_sts = REGR(npu_dev, NPU_MASTERn_ERROR_IRQ_STATUS(0));
|
||||
error_irq_sts &= REGR(npu_dev, NPU_MASTERn_ERROR_IRQ_ENABLE(0));
|
||||
if (error_irq_sts != 0) {
|
||||
REGW(npu_dev, NPU_MASTERn_ERROR_IRQ_CLEAR(0), error_irq_sts);
|
||||
pr_err("error irq %x\n", error_irq_sts);
|
||||
host_ctx->err_irq_sts |= error_irq_sts;
|
||||
host_ctx->fw_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t npu_interrupt_raise_m0(struct npu_device *npu_dev)
|
||||
{
|
||||
/* Bit 4 is setting IRQ_SOURCE_SELECT to local
|
||||
* and we're triggering a pulse to NPU_MASTER0_IPC_IN_IRQ0
|
||||
*/
|
||||
npu_core_reg_write(npu_dev, NPU_MASTERn_IPC_IRQ_IN_CTRL(0), 0x1
|
||||
<< NPU_MASTER0_IPC_IRQ_IN_CTRL__IRQ_SOURCE_SELECT___S | 0x1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t npu_interrupt_raise_dsp(struct npu_device *npu_dev)
|
||||
{
|
||||
npu_core_reg_write(npu_dev, NPU_MASTERn_IPC_IRQ_OUT_CTRL(1), 0x8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Functions - ION Memory
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
static struct npu_ion_buf *npu_alloc_npu_ion_buffer(struct npu_client
|
||||
*client, int buf_hdl, uint32_t size)
|
||||
{
|
||||
struct npu_ion_buf *ret_val = NULL, *tmp;
|
||||
struct list_head *pos = NULL;
|
||||
|
||||
mutex_lock(&client->list_lock);
|
||||
list_for_each(pos, &(client->mapped_buffer_list)) {
|
||||
tmp = list_entry(pos, struct npu_ion_buf, list);
|
||||
if (tmp->fd == buf_hdl) {
|
||||
ret_val = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_val) {
|
||||
/* mapped already, treat as invalid request */
|
||||
pr_err("ion buf has been mapped\n");
|
||||
ret_val = NULL;
|
||||
} else {
|
||||
ret_val = kzalloc(sizeof(*ret_val), GFP_KERNEL);
|
||||
if (ret_val) {
|
||||
ret_val->fd = buf_hdl;
|
||||
ret_val->size = size;
|
||||
ret_val->iova = 0;
|
||||
list_add(&(ret_val->list),
|
||||
&(client->mapped_buffer_list));
|
||||
}
|
||||
}
|
||||
mutex_unlock(&client->list_lock);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static struct npu_ion_buf *npu_get_npu_ion_buffer(struct npu_client
|
||||
*client, int buf_hdl)
|
||||
{
|
||||
struct list_head *pos = NULL;
|
||||
struct npu_ion_buf *ret_val = NULL, *tmp;
|
||||
|
||||
mutex_lock(&client->list_lock);
|
||||
list_for_each(pos, &(client->mapped_buffer_list)) {
|
||||
tmp = list_entry(pos, struct npu_ion_buf, list);
|
||||
if (tmp->fd == buf_hdl) {
|
||||
ret_val = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&client->list_lock);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static void npu_free_npu_ion_buffer(struct npu_client
|
||||
*client, int buf_hdl)
|
||||
{
|
||||
struct list_head *pos = NULL;
|
||||
struct npu_ion_buf *npu_ion_buf = NULL;
|
||||
|
||||
mutex_lock(&client->list_lock);
|
||||
list_for_each(pos, &(client->mapped_buffer_list)) {
|
||||
npu_ion_buf = list_entry(pos, struct npu_ion_buf, list);
|
||||
if (npu_ion_buf->fd == buf_hdl) {
|
||||
list_del(&npu_ion_buf->list);
|
||||
kfree(npu_ion_buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&client->list_lock);
|
||||
}
|
||||
|
||||
int npu_mem_map(struct npu_client *client, int buf_hdl, uint32_t size,
|
||||
uint64_t *addr)
|
||||
{
|
||||
MODULE_IMPORT_NS(DMA_BUF);
|
||||
int ret = 0;
|
||||
struct npu_device *npu_dev = client->npu_dev;
|
||||
struct npu_ion_buf *ion_buf = NULL;
|
||||
struct npu_smmu_ctx *smmu_ctx = &npu_dev->smmu_ctx;
|
||||
|
||||
if (buf_hdl == 0)
|
||||
return -EINVAL;
|
||||
|
||||
ion_buf = npu_alloc_npu_ion_buffer(client, buf_hdl, size);
|
||||
if (!ion_buf) {
|
||||
pr_err("%s fail to alloc npu_ion_buffer\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
smmu_ctx->attach_cnt++;
|
||||
|
||||
ion_buf->dma_buf = dma_buf_get(ion_buf->fd);
|
||||
if (IS_ERR_OR_NULL(ion_buf->dma_buf)) {
|
||||
pr_err("dma_buf_get failed %d\n", ion_buf->fd);
|
||||
ret = -ENOMEM;
|
||||
ion_buf->dma_buf = NULL;
|
||||
goto map_end;
|
||||
}
|
||||
|
||||
ion_buf->attachment = dma_buf_attach(ion_buf->dma_buf,
|
||||
&(npu_dev->pdev->dev));
|
||||
if (IS_ERR(ion_buf->attachment)) {
|
||||
ret = -ENOMEM;
|
||||
ion_buf->attachment = NULL;
|
||||
goto map_end;
|
||||
}
|
||||
|
||||
ion_buf->attachment->dma_map_attrs = DMA_ATTR_IOMMU_USE_UPSTREAM_HINT;
|
||||
|
||||
ion_buf->table = dma_buf_map_attachment(ion_buf->attachment,
|
||||
DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR(ion_buf->table)) {
|
||||
pr_err("npu dma_buf_map_attachment failed\n");
|
||||
ret = -ENOMEM;
|
||||
ion_buf->table = NULL;
|
||||
goto map_end;
|
||||
}
|
||||
|
||||
ion_buf->iova = ion_buf->table->sgl->dma_address;
|
||||
ion_buf->size = ion_buf->dma_buf->size;
|
||||
*addr = ion_buf->iova;
|
||||
pr_debug("mapped mem addr:0x%llx size:0x%x\n", ion_buf->iova,
|
||||
ion_buf->size);
|
||||
map_end:
|
||||
if (ret)
|
||||
npu_mem_unmap(client, buf_hdl, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void npu_mem_invalidate(struct npu_client *client, int buf_hdl)
|
||||
{
|
||||
struct npu_device *npu_dev = client->npu_dev;
|
||||
struct npu_ion_buf *ion_buf = npu_get_npu_ion_buffer(client,
|
||||
buf_hdl);
|
||||
|
||||
if (!ion_buf)
|
||||
pr_err("%s can't find ion buf\n", __func__);
|
||||
else
|
||||
dma_sync_sg_for_cpu(&(npu_dev->pdev->dev), ion_buf->table->sgl,
|
||||
ion_buf->table->nents, DMA_BIDIRECTIONAL);
|
||||
}
|
||||
|
||||
bool npu_mem_verify_addr(struct npu_client *client, uint64_t addr)
|
||||
{
|
||||
struct npu_ion_buf *ion_buf = NULL;
|
||||
struct list_head *pos = NULL;
|
||||
bool valid = false;
|
||||
|
||||
mutex_lock(&client->list_lock);
|
||||
list_for_each(pos, &(client->mapped_buffer_list)) {
|
||||
ion_buf = list_entry(pos, struct npu_ion_buf, list);
|
||||
if (ion_buf->iova == addr) {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&client->list_lock);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
void npu_mem_unmap(struct npu_client *client, int buf_hdl, uint64_t addr)
|
||||
{
|
||||
MODULE_IMPORT_NS(DMA_BUF);
|
||||
struct npu_device *npu_dev = client->npu_dev;
|
||||
struct npu_ion_buf *ion_buf = NULL;
|
||||
|
||||
/* clear entry and retrieve the corresponding buffer */
|
||||
ion_buf = npu_get_npu_ion_buffer(client, buf_hdl);
|
||||
if (!ion_buf) {
|
||||
pr_err("%s could not find buffer\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ion_buf->iova != addr)
|
||||
pr_warn("unmap address %llu doesn't match %llu\n", addr,
|
||||
ion_buf->iova);
|
||||
|
||||
if (ion_buf->table)
|
||||
dma_buf_unmap_attachment(ion_buf->attachment, ion_buf->table,
|
||||
DMA_BIDIRECTIONAL);
|
||||
if (ion_buf->dma_buf && ion_buf->attachment)
|
||||
dma_buf_detach(ion_buf->dma_buf, ion_buf->attachment);
|
||||
if (ion_buf->dma_buf)
|
||||
dma_buf_put(ion_buf->dma_buf);
|
||||
npu_dev->smmu_ctx.attach_cnt--;
|
||||
|
||||
pr_debug("unmapped mem addr:0x%llx size:0x%x\n", ion_buf->iova,
|
||||
ion_buf->size);
|
||||
npu_free_npu_ion_buffer(client, buf_hdl);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Functions - Features
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
uint8_t npu_hw_clk_gating_enabled(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t npu_hw_log_enabled(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Functions - Subsystem/PIL
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#define NPU_PAS_ID (23)
|
||||
|
||||
int npu_subsystem_get(struct npu_device *npu_dev, const char *fw_name)
|
||||
{
|
||||
struct device *dev = npu_dev->device;
|
||||
const struct firmware *firmware_p;
|
||||
ssize_t fw_size;
|
||||
/* load firmware */
|
||||
int ret = request_firmware(&firmware_p, fw_name, dev);
|
||||
|
||||
if (ret < 0) {
|
||||
pr_err("request_firmware %s failed: %d\n", fw_name, ret);
|
||||
return ret;
|
||||
}
|
||||
fw_size = qcom_mdt_get_size(firmware_p);
|
||||
if (fw_size < 0 || fw_size > npu_dev->fw_io.mem_size) {
|
||||
pr_err("npu fw size invalid, %lld\n", fw_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* load the ELF segments to memory */
|
||||
ret = qcom_mdt_load(dev, firmware_p, fw_name, NPU_PAS_ID,
|
||||
npu_dev->fw_io.mem_region, npu_dev->fw_io.mem_phys,
|
||||
npu_dev->fw_io.mem_size, &npu_dev->fw_io.mem_reloc);
|
||||
release_firmware(firmware_p);
|
||||
if (ret) {
|
||||
pr_err("qcom_mdt_load failure, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = qcom_scm_pas_auth_and_reset(NPU_PAS_ID);
|
||||
if (ret) {
|
||||
pr_err("failed to authenticate image and release reset\n");
|
||||
return -2;
|
||||
}
|
||||
pr_debug("done pas auth\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void npu_subsystem_put(struct npu_device *npu_dev)
|
||||
{
|
||||
int ret = qcom_scm_pas_shutdown(NPU_PAS_ID);
|
||||
|
||||
if (ret)
|
||||
pr_err("failed to shutdown: %d\n", ret);
|
||||
|
||||
}
|
87
drivers/media/platform/msm/npu/npu_hw_access.h
Normal file
87
drivers/media/platform/msm/npu/npu_hw_access.h
Normal file
@ -0,0 +1,87 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _NPU_HW_ACCESS_H
|
||||
#define _NPU_HW_ACCESS_H
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Includes
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#include "npu_common.h"
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Defines
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#define IPC_MEM_OFFSET_FROM_SSTCM 0x00010000
|
||||
#define SYS_CACHE_SCID 23
|
||||
|
||||
#define QFPROM_FMAX_REG_OFFSET 0x000001C8
|
||||
#define QFPROM_FMAX_BITS_MASK 0x0000000C
|
||||
#define QFPROM_FMAX_BITS_SHIFT 2
|
||||
|
||||
#define REGW(npu_dev, off, val) npu_core_reg_write(npu_dev, off, val)
|
||||
#define REGR(npu_dev, off) npu_core_reg_read(npu_dev, off)
|
||||
#define MEMW(npu_dev, dst, src, size) npu_mem_write(npu_dev, (void *)(dst),\
|
||||
(void *)(src), size)
|
||||
#define MEMR(npu_dev, src, dst, size) npu_mem_read(npu_dev, (void *)(src),\
|
||||
(void *)(dst), size)
|
||||
#define IPC_ADDR npu_ipc_addr()
|
||||
#define INTERRUPT_ACK(npu_dev, num) npu_interrupt_ack(npu_dev, num)
|
||||
#define INTERRUPT_RAISE_NPU(npu_dev) npu_interrupt_raise_m0(npu_dev)
|
||||
#define INTERRUPT_RAISE_DSP(npu_dev) npu_interrupt_raise_dsp(npu_dev)
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Data Structures
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
struct npu_device;
|
||||
struct npu_ion_buf_t;
|
||||
struct npu_host_ctx;
|
||||
struct npu_client;
|
||||
typedef irqreturn_t (*intr_hdlr_fn)(int32_t irq, void *ptr);
|
||||
typedef void (*wq_hdlr_fn) (struct work_struct *work);
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Function Prototypes
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
uint32_t npu_core_reg_read(struct npu_device *npu_dev, uint32_t off);
|
||||
void npu_core_reg_write(struct npu_device *npu_dev, uint32_t off, uint32_t val);
|
||||
uint32_t npu_bwmon_reg_read(struct npu_device *npu_dev, uint32_t off);
|
||||
void npu_bwmon_reg_write(struct npu_device *npu_dev, uint32_t off,
|
||||
uint32_t val);
|
||||
void npu_mem_write(struct npu_device *npu_dev, void *dst, void *src,
|
||||
uint32_t size);
|
||||
int32_t npu_mem_read(struct npu_device *npu_dev, void *src, void *dst,
|
||||
uint32_t size);
|
||||
uint32_t npu_qfprom_reg_read(struct npu_device *npu_dev, uint32_t off);
|
||||
|
||||
int npu_mem_map(struct npu_client *client, int buf_hdl, uint32_t size,
|
||||
uint64_t *addr);
|
||||
void npu_mem_unmap(struct npu_client *client, int buf_hdl, uint64_t addr);
|
||||
void npu_mem_invalidate(struct npu_client *client, int buf_hdl);
|
||||
bool npu_mem_verify_addr(struct npu_client *client, uint64_t addr);
|
||||
|
||||
void *npu_ipc_addr(void);
|
||||
void npu_interrupt_ack(struct npu_device *npu_dev, uint32_t intr_num);
|
||||
int32_t npu_interrupt_raise_m0(struct npu_device *npu_dev);
|
||||
int32_t npu_interrupt_raise_dsp(struct npu_device *npu_dev);
|
||||
|
||||
uint8_t npu_hw_clk_gating_enabled(void);
|
||||
uint8_t npu_hw_log_enabled(void);
|
||||
|
||||
int npu_enable_irq(struct npu_device *npu_dev);
|
||||
void npu_disable_irq(struct npu_device *npu_dev);
|
||||
|
||||
int npu_enable_sys_cache(struct npu_device *npu_dev);
|
||||
void npu_disable_sys_cache(struct npu_device *npu_dev);
|
||||
|
||||
int npu_subsystem_get(struct npu_device *npu_dev, const char *fw_name);
|
||||
void npu_subsystem_put(struct npu_device *npu_dev);
|
||||
|
||||
#endif /* _NPU_HW_ACCESS_H*/
|
2112
drivers/media/platform/msm/npu/npu_mgr.c
Normal file
2112
drivers/media/platform/msm/npu/npu_mgr.c
Normal file
File diff suppressed because it is too large
Load Diff
147
drivers/media/platform/msm/npu/npu_mgr.h
Normal file
147
drivers/media/platform/msm/npu/npu_mgr.h
Normal file
@ -0,0 +1,147 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _NPU_MGR_H
|
||||
#define _NPU_MGR_H
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Includes
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#include <linux/spinlock.h>
|
||||
#include "npu_hw_access.h"
|
||||
#include "npu_common.h"
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Defines
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#define NW_CMD_TIMEOUT_MS (1000 * 60 * 5) /* set for 5 minutes */
|
||||
#define NW_CMD_TIMEOUT msecs_to_jiffies(NW_CMD_TIMEOUT_MS)
|
||||
#define NW_DEBUG_TIMEOUT_MS (1000 * 60 * 30) /* set for 30 minutes */
|
||||
#define NW_DEBUG_TIMEOUT msecs_to_jiffies(NW_DEBUG_TIMEOUT_MS)
|
||||
#define FIRMWARE_VERSION 0x00001000
|
||||
#define MAX_LOADED_NETWORK 32
|
||||
#define NPU_IPC_BUF_LENGTH 512
|
||||
|
||||
#define FW_DBG_MODE_PAUSE (1 << 0)
|
||||
#define FW_DBG_MODE_INC_TIMEOUT (1 << 1)
|
||||
#define FW_DBG_DISABLE_WDOG (1 << 2)
|
||||
#define FW_DBG_ENABLE_LOGGING (1 << 3)
|
||||
/* -------------------------------------------------------------------------
|
||||
* Data Structures
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
struct npu_network {
|
||||
uint64_t id;
|
||||
int buf_hdl;
|
||||
uint64_t phy_add;
|
||||
uint32_t size;
|
||||
uint32_t first_block_size;
|
||||
uint32_t network_hdl;
|
||||
uint32_t priority;
|
||||
uint32_t cur_perf_mode;
|
||||
uint32_t init_perf_mode;
|
||||
uint32_t num_layers;
|
||||
void *stats_buf;
|
||||
void __user *stats_buf_u;
|
||||
uint32_t stats_buf_size;
|
||||
uint32_t trans_id;
|
||||
atomic_t ref_cnt;
|
||||
bool is_valid;
|
||||
bool is_active;
|
||||
bool fw_error;
|
||||
bool cmd_pending;
|
||||
bool cmd_async;
|
||||
int cmd_ret_status;
|
||||
struct completion cmd_done;
|
||||
struct npu_client *client;
|
||||
};
|
||||
|
||||
enum fw_state {
|
||||
FW_DISABLED = 0,
|
||||
FW_ENABLED = 1,
|
||||
};
|
||||
|
||||
struct npu_host_ctx {
|
||||
struct mutex lock;
|
||||
void *subsystem_handle;
|
||||
struct npu_device *npu_dev;
|
||||
enum fw_state fw_state;
|
||||
int32_t fw_ref_cnt;
|
||||
int32_t npu_init_cnt;
|
||||
int32_t power_vote_num;
|
||||
struct work_struct irq_work;
|
||||
struct delayed_work fw_deinit_work;
|
||||
atomic_t fw_deinit_work_cnt;
|
||||
struct workqueue_struct *wq;
|
||||
struct completion misc_done;
|
||||
struct completion fw_deinit_done;
|
||||
bool misc_pending;
|
||||
void *prop_buf;
|
||||
int32_t network_num;
|
||||
struct npu_network networks[MAX_LOADED_NETWORK];
|
||||
bool sys_cache_disable;
|
||||
uint32_t fw_dbg_mode;
|
||||
uint32_t exec_flags_override;
|
||||
uint32_t fw_unload_delay_ms;
|
||||
atomic_t ipc_trans_id;
|
||||
atomic_t network_execute_cnt;
|
||||
int cmd_ret_status;
|
||||
|
||||
uint32_t err_irq_sts;
|
||||
uint32_t wdg_irq_sts;
|
||||
bool fw_error;
|
||||
};
|
||||
|
||||
struct npu_device;
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Function Prototypes
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
int npu_host_init(struct npu_device *npu_dev);
|
||||
void npu_host_deinit(struct npu_device *npu_dev);
|
||||
|
||||
/* Host Driver IPC Interface */
|
||||
int npu_host_ipc_pre_init(struct npu_device *npu_dev);
|
||||
int npu_host_ipc_post_init(struct npu_device *npu_dev);
|
||||
void npu_host_ipc_deinit(struct npu_device *npu_dev);
|
||||
int npu_host_ipc_send_cmd(struct npu_device *npu_dev, uint32_t queueIndex,
|
||||
void *pCmd);
|
||||
int npu_host_ipc_read_msg(struct npu_device *npu_dev, uint32_t queueIndex,
|
||||
uint32_t *pMsg);
|
||||
|
||||
int32_t npu_host_get_info(struct npu_device *npu_dev,
|
||||
struct msm_npu_get_info_ioctl *get_info_ioctl);
|
||||
int32_t npu_host_map_buf(struct npu_client *client,
|
||||
struct msm_npu_map_buf_ioctl *map_ioctl);
|
||||
int32_t npu_host_unmap_buf(struct npu_client *client,
|
||||
struct msm_npu_unmap_buf_ioctl *unmap_ioctl);
|
||||
int32_t npu_host_load_network(struct npu_client *client,
|
||||
struct msm_npu_load_network_ioctl *load_ioctl);
|
||||
int32_t npu_host_load_network_v2(struct npu_client *client,
|
||||
struct msm_npu_load_network_ioctl_v2 *load_ioctl,
|
||||
struct msm_npu_patch_info_v2 *patch_info);
|
||||
int32_t npu_host_unload_network(struct npu_client *client,
|
||||
struct msm_npu_unload_network_ioctl *unload);
|
||||
int32_t npu_host_exec_network(struct npu_client *client,
|
||||
struct msm_npu_exec_network_ioctl *exec_ioctl);
|
||||
int32_t npu_host_exec_network_v2(struct npu_client *client,
|
||||
struct msm_npu_exec_network_ioctl_v2 *exec_ioctl,
|
||||
struct msm_npu_patch_buf_info *patch_buf_info);
|
||||
int32_t npu_host_loopback_test(struct npu_device *npu_dev);
|
||||
int32_t npu_host_set_fw_property(struct npu_device *npu_dev,
|
||||
struct msm_npu_property *property);
|
||||
int32_t npu_host_get_fw_property(struct npu_device *npu_dev,
|
||||
struct msm_npu_property *property);
|
||||
void npu_host_cleanup_networks(struct npu_client *client);
|
||||
int32_t npu_host_set_perf_mode(struct npu_client *client, uint32_t network_hdl,
|
||||
uint32_t perf_mode);
|
||||
int32_t npu_host_get_perf_mode(struct npu_client *client, uint32_t network_hdl);
|
||||
void npu_dump_debug_timeout_stats(struct npu_device *npu_dev);
|
||||
|
||||
#endif /* _NPU_MGR_H */
|
279
include/soc/qcom/subsystem_restart.h
Normal file
279
include/soc/qcom/subsystem_restart.h
Normal file
@ -0,0 +1,279 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2014-2019 2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __SUBSYS_RESTART_H
|
||||
#define __SUBSYS_RESTART_H
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
struct subsys_device;
|
||||
extern struct bus_type subsys_bus_type;
|
||||
|
||||
enum {
|
||||
RESET_SOC = 0,
|
||||
RESET_SUBSYS_COUPLED,
|
||||
RESET_LEVEL_MAX
|
||||
};
|
||||
|
||||
enum crash_status {
|
||||
CRASH_STATUS_NO_CRASH = 0,
|
||||
CRASH_STATUS_ERR_FATAL,
|
||||
CRASH_STATUS_WDOG_BITE,
|
||||
};
|
||||
|
||||
struct device;
|
||||
struct module;
|
||||
|
||||
enum ssr_comm {
|
||||
SUBSYS_TO_SUBSYS_SYSMON,
|
||||
SUBSYS_TO_HLOS,
|
||||
HLOS_TO_SUBSYS_SYSMON_SHUTDOWN,
|
||||
HLOS_TO_SUBSYS_SYSMON_DSENTER,
|
||||
NUM_SSR_COMMS,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct subsys_notif_timeout - timeout data used by notification timeout hdlr
|
||||
* @comm_type: Specifies if the type of communication being tracked is
|
||||
* through sysmon between two subsystems, subsystem notifier call chain, or
|
||||
* sysmon shutdown.
|
||||
* @dest_name: subsystem to which sysmon notification is being sent to
|
||||
* @source_name: subsystem which generated event that notification is being sent
|
||||
* for
|
||||
* @timer: timer for scheduling timeout
|
||||
*/
|
||||
struct subsys_notif_timeout {
|
||||
enum ssr_comm comm_type;
|
||||
const char *dest_name;
|
||||
const char *source_name;
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct subsys_desc - subsystem descriptor
|
||||
* @name: name of subsystem
|
||||
* @fw_name: firmware name
|
||||
* @pon_depends_on: subsystem this subsystem wants to power-on first. If the
|
||||
* dependednt subsystem is already powered-on, the framework won't try to power
|
||||
* it back up again.
|
||||
* @poff_depends_on: subsystem this subsystem wants to power-off first. If the
|
||||
* dependednt subsystem is already powered-off, the framework won't try to power
|
||||
* it off again.
|
||||
* @dev: parent device
|
||||
* @owner: module the descriptor belongs to
|
||||
* @shutdown: Stop a subsystem
|
||||
* @powerup_notify: Notify about start of a subsystem
|
||||
* @powerup: Start a subsystem
|
||||
* @crash_shutdown: Shutdown a subsystem when the system crashes (can't sleep)
|
||||
* @ramdump: Collect a ramdump of the subsystem
|
||||
* @free_memory: Free the memory associated with this subsystem
|
||||
* @no_auth: Set if subsystem does not rely on PIL to authenticate and bring
|
||||
* it out of reset
|
||||
* @ssctl_instance_id: Instance id used to connect with SSCTL service
|
||||
* @sysmon_pid: pdev id that sysmon is probed with for the subsystem
|
||||
* @sysmon_shutdown_ret: Return value for the call to sysmon_send_shutdown
|
||||
* @system_debug: If "set", triggers a device restart when the
|
||||
* subsystem's wdog bite handler is invoked.
|
||||
* @ignore_ssr_failure: SSR failures are usually fatal and results in panic. If
|
||||
* set will ignore failure.
|
||||
* @edge: GLINK logical name of the subsystem
|
||||
*/
|
||||
struct subsys_desc {
|
||||
const char *name;
|
||||
char fw_name[256];
|
||||
const char *pon_depends_on;
|
||||
const char *poff_depends_on;
|
||||
struct device *dev;
|
||||
struct module *owner;
|
||||
|
||||
int (*shutdown)(const struct subsys_desc *desc, bool force_stop);
|
||||
int (*enter_ds)(const struct subsys_desc *desc);
|
||||
int (*powerup_notify)(const struct subsys_desc *desc);
|
||||
int (*powerup)(const struct subsys_desc *desc);
|
||||
void (*crash_shutdown)(const struct subsys_desc *desc);
|
||||
int (*ramdump)(int need_dumps, const struct subsys_desc *desc);
|
||||
void (*free_memory)(const struct subsys_desc *desc);
|
||||
struct completion shutdown_ack;
|
||||
struct completion dsentry_ack;
|
||||
int err_fatal_gpio;
|
||||
int force_stop_bit;
|
||||
int ramdump_disable_irq;
|
||||
int shutdown_ack_irq;
|
||||
int dsentry_ack_irq;
|
||||
int ramdump_disable;
|
||||
bool no_auth;
|
||||
bool pil_mss_memsetup;
|
||||
int ssctl_instance_id;
|
||||
u32 sysmon_pid;
|
||||
int sysmon_shutdown_ret;
|
||||
int sysmon_dsentry_ret;
|
||||
bool system_debug;
|
||||
bool ignore_ssr_failure;
|
||||
const char *edge;
|
||||
struct qcom_smem_state *state;
|
||||
#ifdef CONFIG_SETUP_SSR_NOTIF_TIMEOUTS
|
||||
struct subsys_notif_timeout timeout_data;
|
||||
#endif /* CONFIG_SETUP_SSR_NOTIF_TIMEOUTS */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct notif_data - additional notif information
|
||||
* @crashed: indicates if subsystem has crashed due to wdog bite or err fatal
|
||||
* @enable_ramdump: ramdumps disabled if set to 0
|
||||
* @enable_mini_ramdumps: enable flag for minimized critical-memory-only
|
||||
* ramdumps
|
||||
* @no_auth: set if subsystem does not use PIL to bring it out of reset
|
||||
* @pdev: subsystem platform device pointer
|
||||
*/
|
||||
struct notif_data {
|
||||
enum crash_status crashed;
|
||||
int enable_ramdump;
|
||||
int enable_mini_ramdumps;
|
||||
bool no_auth;
|
||||
struct platform_device *pdev;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART)
|
||||
|
||||
extern int subsys_get_restart_level(struct subsys_device *dev);
|
||||
extern int subsystem_restart_dev(struct subsys_device *dev);
|
||||
extern int subsystem_restart(const char *name);
|
||||
extern int subsystem_crashed(const char *name);
|
||||
extern int subsystem_start_notify(const char *name);
|
||||
extern int subsystem_stop_notify(const char *subsystem);
|
||||
extern int subsystem_ds_entry(const char *subsystem);
|
||||
extern int subsystem_ds_exit(const char *name);
|
||||
extern int subsystem_s2d_entry(const char *subsystem);
|
||||
extern int subsystem_s2d_exit(const char *name);
|
||||
|
||||
extern void *subsystem_get(const char *name);
|
||||
extern void *subsystem_get_with_fwname(const char *name, const char *fw_name);
|
||||
extern int subsystem_set_fwname(const char *name, const char *fw_name);
|
||||
extern void subsystem_put(void *subsystem);
|
||||
|
||||
extern struct subsys_device *subsys_register(struct subsys_desc *desc);
|
||||
extern void subsys_unregister(struct subsys_device *dev);
|
||||
|
||||
extern void subsys_set_crash_status(struct subsys_device *dev,
|
||||
enum crash_status crashed);
|
||||
extern enum crash_status subsys_get_crash_status(struct subsys_device *dev);
|
||||
void notify_proxy_vote(struct device *device);
|
||||
void notify_proxy_unvote(struct device *device);
|
||||
void notify_before_auth_and_reset(struct device *device);
|
||||
static inline void complete_shutdown_ack(struct subsys_desc *desc)
|
||||
{
|
||||
complete(&desc->shutdown_ack);
|
||||
}
|
||||
static inline void complete_dsentry_ack(struct subsys_desc *desc)
|
||||
{
|
||||
complete(&desc->dsentry_ack);
|
||||
}
|
||||
struct subsys_device *find_subsys_device(const char *str);
|
||||
#else
|
||||
|
||||
static inline int subsys_get_restart_level(struct subsys_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int subsystem_restart_dev(struct subsys_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int subsystem_restart(const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int subsystem_crashed(const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int subsystem_start_notify(const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int subsystem_stop_notify(const char *subsystem)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* static int subsystem_ds_entry(const char *subsystem)
|
||||
* {
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* static int subsystem_ds_exit(const char *name)
|
||||
* {
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* static int subsystem_s2d_exit(const char *name)
|
||||
* {
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* static int subsystem_s2d_entry(const char *name)
|
||||
* {
|
||||
* return 0;
|
||||
* }
|
||||
*/
|
||||
|
||||
static inline void *subsystem_get(const char *name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void *subsystem_get_with_fwname(const char *name,
|
||||
const char *fw_name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int subsystem_set_fwname(const char *name,
|
||||
const char *fw_name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void subsystem_put(void *subsystem) { }
|
||||
|
||||
static inline
|
||||
struct subsys_device *subsys_register(struct subsys_desc *desc)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void subsys_unregister(struct subsys_device *dev) { }
|
||||
|
||||
static inline void subsys_set_crash_status(struct subsys_device *dev,
|
||||
enum crash_status crashed) { }
|
||||
static inline
|
||||
enum crash_status subsys_get_crash_status(struct subsys_device *dev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline void notify_proxy_vote(struct device *device) { }
|
||||
static inline void notify_proxy_unvote(struct device *device) { }
|
||||
static inline void notify_before_auth_and_reset(struct device *device) { }
|
||||
#endif
|
||||
/* CONFIG_MSM_SUBSYSTEM_RESTART */
|
||||
|
||||
/* Helper wrappers */
|
||||
static inline void wakeup_source_trash(struct wakeup_source *ws)
|
||||
{
|
||||
if (!ws)
|
||||
return;
|
||||
|
||||
wakeup_source_remove(ws);
|
||||
__pm_relax(ws);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user