video: rockchip: mpp: add function that trans info can set by user space

priority order:
1. MPP_CMD_SET_REG_ADDR_OFFSET define the trans table each task.
2. MPP_CMD_INIT_TRANS_TABLE define once when open session.
3. use default trans table define in each device.

Change-Id: I13409fb67d58dfa53295aabe7952d044dc1637d4
Signed-off-by: Ding Wei <leo.ding@rock-chips.com>
This commit is contained in:
Ding Wei
2019-12-03 16:53:44 +08:00
parent 4a448336e4
commit d31787415c
7 changed files with 679 additions and 407 deletions

View File

@@ -154,15 +154,20 @@ static int mpp_power_off(struct mpp_dev *mpp)
}
static void *
mpp_fd_to_mem_region(struct mpp_dev *mpp,
struct mpp_dma_session *dma, int fd)
mpp_fd_to_mem_region(struct mpp_session *session, int fd)
{
struct mpp_dma_buffer *buffer = NULL;
struct mpp_mem_region *mem_region = NULL;
struct mpp_dev *mpp = session->mpp;
struct mpp_dma_session *dma = session->dma;
if (fd <= 0 || !dma || !mpp)
return ERR_PTR(-EINVAL);
mem_region = kzalloc(sizeof(*mem_region), GFP_KERNEL);
if (!mem_region)
return ERR_PTR(-ENOMEM);
down_read(&mpp->rw_sem);
buffer = mpp_dma_import_fd(mpp->iommu_info, dma, fd);
up_read(&mpp->rw_sem);
@@ -171,14 +176,6 @@ mpp_fd_to_mem_region(struct mpp_dev *mpp,
return ERR_PTR(-EINVAL);
}
mem_region = kzalloc(sizeof(*mem_region), GFP_KERNEL);
if (!mem_region) {
down_read(&mpp->rw_sem);
mpp_dma_release_fd(dma, fd);
up_read(&mpp->rw_sem);
return ERR_PTR(-ENOMEM);
}
mem_region->hdl = (void *)(long)fd;
mem_region->iova = buffer->iova;
mem_region->len = buffer->size;
@@ -224,7 +221,7 @@ mpp_session_pull_done(struct mpp_session *session)
}
static int mpp_process_task(struct mpp_session *session,
struct mpp_request *req)
struct mpp_task_msgs *msgs)
{
struct mpp_task *task = NULL;
struct mpp_dev *mpp = session->mpp;
@@ -236,7 +233,7 @@ static int mpp_process_task(struct mpp_session *session,
}
if (mpp->dev_ops->alloc_task)
task = mpp->dev_ops->alloc_task(session, req->data, req->size);
task = mpp->dev_ops->alloc_task(session, msgs);
if (!task) {
mpp_err("alloc_task failed.\n");
return -ENOMEM;
@@ -344,7 +341,7 @@ mpp_reset_control_get(struct mpp_dev *mpp, const char *name)
}
if (!clk) {
rst_clk = devm_kzalloc(dev, sizeof(*rst_clk),
GFP_KERNEL);
GFP_KERNEL);
strncpy(rst_clk->name, name, sizeof(rst_clk->name));
rst_clk->clk = devm_reset_control_get(dev,
shared_name);
@@ -542,7 +539,7 @@ static int mpp_session_clear(struct mpp_dev *mpp,
static int mpp_task_result(struct mpp_dev *mpp,
struct mpp_task *task,
u32 __user *dst, u32 size)
struct mpp_task_msgs *msgs)
{
mpp_debug_enter();
@@ -550,7 +547,7 @@ static int mpp_task_result(struct mpp_dev *mpp,
return -EINVAL;
if (mpp->dev_ops->result)
mpp->dev_ops->result(mpp, task, dst, size);
mpp->dev_ops->result(mpp, task, msgs);
mpp_free_task(task->session, task);
@@ -560,11 +557,17 @@ static int mpp_task_result(struct mpp_dev *mpp,
}
static int mpp_wait_result(struct mpp_session *session,
struct mpp_dev *mpp,
struct mpp_request *req)
struct mpp_task_msgs *msgs)
{
int ret;
struct mpp_task *task;
struct mpp_dev *mpp = session->mpp;
if (!mpp) {
mpp_err("pid %d not find clinet %d\n",
session->pid, session->device_type);
return -EINVAL;
}
ret = wait_event_timeout(session->wait,
!kfifo_is_empty(&session->done_fifo),
@@ -572,9 +575,9 @@ static int mpp_wait_result(struct mpp_session *session,
if (ret > 0) {
ret = 0;
task = mpp_session_pull_done(session);
mpp_task_result(mpp, task, req->data, req->size);
mpp_task_result(mpp, task, msgs);
} else {
mpp_err("error: pid %d wait %d task done timeout\n",
mpp_err("pid %d wait %d task done timeout.\n",
session->pid, atomic_read(&session->task_running));
ret = -ETIMEDOUT;
mpp_dev_abort(mpp);
@@ -663,7 +666,7 @@ int mpp_taskqueue_init(struct mpp_taskqueue *queue,
}
int mpp_reset_group_init(struct mpp_reset_group *group,
struct mpp_service *srv)
struct mpp_service *srv)
{
init_rwsem(&group->rw_sem);
INIT_LIST_HEAD(&group->clk);
@@ -786,17 +789,38 @@ static int mpp_process_request(struct mpp_session *session,
if (mpp->grf_info->grf)
regmap_write(mpp->grf_info->grf, 0x5d8, val);
} break;
case MPP_CMD_INIT_TRANS_TABLE: {
if (session && req->size) {
int trans_tbl_size = sizeof(session->trans_table);
if (req->size > trans_tbl_size) {
mpp_err("init table size %d more than %d\n",
req->size, trans_tbl_size);
return -ENOMEM;
}
if (copy_from_user(session->trans_table,
req->data, req->size)) {
mpp_err("copy_from_user failed\n");
return -EINVAL;
}
session->trans_count =
req->size / sizeof(session->trans_table[0]);
}
} break;
case MPP_CMD_SET_REG_ADDR_OFFSET: {
memcpy(&msgs->reg_offset, req, sizeof(*req));
if (mpp_msg_is_last(req))
return mpp_process_task(session, msgs);
} break;
case MPP_CMD_SET_REG: {
mpp = session->mpp;
if (!mpp)
return -EINVAL;
return mpp_process_task(session, req);
memcpy(&msgs->reg_in, req, sizeof(*req));
if (mpp_msg_is_last(req))
return mpp_process_task(session, msgs);
} break;
case MPP_CMD_GET_REG: {
mpp = session->mpp;
if (!mpp)
return -EINVAL;
return mpp_wait_result(session, mpp, req);
memcpy(&msgs->reg_out, req, sizeof(*req));
return mpp_wait_result(session, msgs);
} break;
default: {
mpp = session->mpp;
@@ -992,8 +1016,7 @@ mpp_task_attach_fd(struct mpp_task *task, int fd)
{
struct mpp_mem_region *mem_region = NULL;
mem_region = mpp_fd_to_mem_region(task->session->mpp,
task->session->dma, fd);
mem_region = mpp_fd_to_mem_region(task->session, fd);
if (IS_ERR(mem_region))
return mem_region;
@@ -1005,17 +1028,34 @@ mpp_task_attach_fd(struct mpp_task *task, int fd)
return mem_region;
}
int mpp_translate_reg_address(struct mpp_dev *mpp,
struct mpp_task *task,
int fmt, u32 *reg)
int mpp_translate_reg_address(struct mpp_session *session,
struct mpp_task *task, int fmt,
u32 *reg, struct reg_offset_info *off_inf)
{
struct mpp_trans_info *trans_info = mpp->var->trans_info;
const u8 *tbl = trans_info[fmt].table;
int size = trans_info[fmt].count;
int i;
int cnt;
const u16 *tbl;
u16 trans_tbl[MPP_MAX_REG_TRANS_NUM];
mpp_debug_enter();
for (i = 0; i < size; i++) {
if (off_inf->cnt > 0) {
cnt = off_inf->cnt;
for (i = 0; i < cnt; i++)
trans_tbl[i] = (u16)off_inf->elem[i].index;
tbl = trans_tbl;
} else if (session->trans_count > 0) {
cnt = session->trans_count;
tbl = session->trans_table;
} else {
struct mpp_dev *mpp = session->mpp;
struct mpp_trans_info *trans_info = mpp->var->trans_info;
cnt = trans_info[fmt].count;
tbl = trans_info[fmt].table;
}
for (i = 0; i < cnt; i++) {
struct mpp_mem_region *mem_region = NULL;
int usr_fd = reg[tbl[i]] & 0x3FF;
int offset = reg[tbl[i]] >> 10;
@@ -1041,22 +1081,70 @@ int mpp_translate_reg_address(struct mpp_dev *mpp,
return 0;
}
int mpp_translate_extra_info(struct mpp_task *task,
struct extra_info_for_iommu *ext_inf,
u32 *reg)
int mpp_extract_reg_offset_info(struct mpp_request *msg,
struct reg_offset_info *off_inf)
{
int ret = 0;
int off_inf_size = sizeof(off_inf->elem);
if (msg->size > off_inf_size) {
mpp_err("msg->size %d more than %d.\n",
msg->size, off_inf_size);
return -EINVAL;
}
if (msg->size) {
off_inf->magic = EXTRA_INFO_MAGIC;
off_inf->cnt = msg->size / sizeof(off_inf->elem[0]);
if (copy_from_user(off_inf->elem,
msg->data,
msg->size)) {
mpp_err("copy_from_user failed\n");
return -EINVAL;
}
}
return ret;
}
int mpp_query_reg_offset_info(struct reg_offset_info *off_inf,
u32 index)
{
mpp_debug_enter();
if (ext_inf) {
if (off_inf) {
int i;
if (ext_inf->magic != EXTRA_INFO_MAGIC)
return -EINVAL;
if (off_inf->magic != EXTRA_INFO_MAGIC)
return 0;
for (i = 0; i < ext_inf->cnt; i++) {
for (i = 0; i < off_inf->cnt; i++) {
if (off_inf->elem[i].index == index)
return off_inf->elem[i].offset;
}
}
mpp_debug_leave();
return 0;
}
int mpp_translate_reg_offset_info(struct mpp_task *task,
struct reg_offset_info *off_inf,
u32 *reg)
{
mpp_debug_enter();
if (off_inf) {
int i;
if (off_inf->magic != EXTRA_INFO_MAGIC)
return 0;
for (i = 0; i < off_inf->cnt; i++) {
mpp_debug(DEBUG_IOMMU, "reg[%d] + offset %d\n",
ext_inf->elem[i].index,
ext_inf->elem[i].offset);
reg[ext_inf->elem[i].index] += ext_inf->elem[i].offset;
off_inf->elem[i].index,
off_inf->elem[i].offset);
reg[off_inf->elem[i].index] += off_inf->elem[i].offset;
}
}
mpp_debug_leave();

View File

@@ -32,6 +32,8 @@
/* define flags for mpp_request */
#define MPP_FLAGS_MULTI_MSG (0x00000001)
#define MPP_FLAGS_LAST_MSG (0x00000002)
#define MPP_FLAGS_REG_FD_NO_TRANS (0x00000004)
#define MPP_FLAGS_SCL_FD_NO_TRANS (0x00000008)
#define MPP_FLAGS_SECURE_MODE (0x00010000)
/**
@@ -80,12 +82,14 @@ enum MPP_DEV_COMMAND_TYPE {
MPP_CMD_INIT_BASE = 0x100,
MPP_CMD_INIT_CLIENT_TYPE = MPP_CMD_INIT_BASE + 0,
MPP_CMD_INIT_DRIVER_DATA = MPP_CMD_INIT_BASE + 1,
MPP_CMD_INIT_TRANS_TABLE = MPP_CMD_INIT_BASE + 2,
MPP_CMD_SEND_BASE = 0x200,
MPP_CMD_SET_REG = MPP_CMD_SEND_BASE + 0,
MPP_CMD_SET_VEPU22_CFG = MPP_CMD_SEND_BASE + 1,
MPP_CMD_SET_RKVENC_OSD_PLT = MPP_CMD_SEND_BASE + 2,
MPP_CMD_SET_RKVENC_L2_REG = MPP_CMD_SEND_BASE + 3,
MPP_CMD_SET_REG_ADDR_OFFSET = MPP_CMD_SEND_BASE + 4,
MPP_CMD_POLL_BASE = 0x300,
MPP_CMD_GET_REG = MPP_CMD_POLL_BASE + 0,
@@ -138,18 +142,18 @@ struct mpp_hw_info {
struct mpp_trans_info {
const int count;
const char * const table;
const u16 * const table;
};
struct extra_info_elem {
struct reg_offset_elem {
u32 index;
u32 offset;
};
struct extra_info_for_iommu {
struct reg_offset_info {
u32 magic;
u32 cnt;
struct extra_info_elem elem[20];
struct reg_offset_elem elem[MPP_MAX_REG_TRANS_NUM];
};
struct mpp_dev_var {
@@ -222,6 +226,9 @@ struct mpp_session {
wait_queue_head_t wait;
pid_t pid;
atomic_t task_running;
/* trans info set by user */
int trans_count;
u16 trans_table[MPP_MAX_REG_TRANS_NUM];
};
/* The context for the a task */
@@ -328,14 +335,14 @@ struct mpp_hw_ops {
*/
struct mpp_dev_ops {
void *(*alloc_task)(struct mpp_session *session,
void __user *src, u32 size);
struct mpp_task_msgs *msgs);
int (*prepare)(struct mpp_dev *mpp, struct mpp_task *task);
int (*run)(struct mpp_dev *mpp, struct mpp_task *task);
int (*irq)(struct mpp_dev *mpp);
int (*isr)(struct mpp_dev *mpp);
int (*finish)(struct mpp_dev *mpp, struct mpp_task *task);
int (*result)(struct mpp_dev *mpp, struct mpp_task *task,
u32 __user *dst, u32 size);
struct mpp_task_msgs *msgs);
int (*free_task)(struct mpp_session *session,
struct mpp_task *task);
long (*ioctl)(struct mpp_session *session, struct mpp_request *req);
@@ -351,13 +358,17 @@ int mpp_reset_group_init(struct mpp_reset_group *group,
struct mpp_mem_region *
mpp_task_attach_fd(struct mpp_task *task, int fd);
int mpp_translate_reg_address(struct mpp_dev *data,
struct mpp_task *task,
int fmt, u32 *reg);
int mpp_translate_extra_info(struct mpp_task *task,
struct extra_info_for_iommu *ext_inf,
u32 *reg);
int mpp_translate_reg_address(struct mpp_session *session,
struct mpp_task *task, int fmt,
u32 *reg, struct reg_offset_info *off_inf);
int mpp_extract_reg_offset_info(struct mpp_request *msg,
struct reg_offset_info *off_inf);
int mpp_query_reg_offset_info(struct reg_offset_info *off_inf,
u32 index);
int mpp_translate_reg_offset_info(struct mpp_task *task,
struct reg_offset_info *off_inf,
u32 *reg);
int mpp_task_init(struct mpp_session *session,
struct mpp_task *task);
int mpp_task_finish(struct mpp_session *session,

View File

@@ -134,6 +134,7 @@ struct rkvdec_task {
unsigned long clk_cabac_freq;
u32 reg[RKVDEC_V2_REG_NUM];
struct reg_offset_info off_inf;
u32 idx;
u32 strm_addr;
@@ -207,38 +208,38 @@ static struct mpp_hw_info rkvdec_v1_hw_info = {
/*
* file handle translate information
*/
static const char trans_tbl_h264d[] = {
static const u16 trans_tbl_h264d[] = {
4, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 41, 42, 43, 48, 75
};
static const char trans_tbl_h265d[] = {
static const u16 trans_tbl_h265d[] = {
4, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 42, 43
};
static const char trans_tbl_vp9d[] = {
static const u16 trans_tbl_vp9d[] = {
4, 6, 7, 11, 12, 13, 14, 15, 16
};
static struct mpp_trans_info rk_hevcdec_trans[] = {
[RKVDEC_FMT_H265D] = {
.count = sizeof(trans_tbl_h265d),
.count = ARRAY_SIZE(trans_tbl_h265d),
.table = trans_tbl_h265d,
},
};
static struct mpp_trans_info rkvdec_v1_trans[] = {
[RKVDEC_FMT_H265D] = {
.count = sizeof(trans_tbl_h265d),
.count = ARRAY_SIZE(trans_tbl_h265d),
.table = trans_tbl_h265d,
},
[RKVDEC_FMT_H264D] = {
.count = sizeof(trans_tbl_h264d),
.count = ARRAY_SIZE(trans_tbl_h264d),
.table = trans_tbl_h264d,
},
[RKVDEC_FMT_VP9D] = {
.count = sizeof(trans_tbl_vp9d),
.count = ARRAY_SIZE(trans_tbl_vp9d),
.table = trans_tbl_vp9d,
},
};
@@ -602,65 +603,17 @@ done:
return ret;
}
static void *rkvdec_alloc_task(struct mpp_session *session,
void __user *src, u32 size)
static int rkvdec_process_scl_fd(struct mpp_session *session,
struct rkvdec_task *task,
struct mpp_task_msgs *msgs)
{
u32 fmt;
int ret;
u32 reg_len;
int pps_fd;
u32 pps_offset;
struct rkvdec_task *task = NULL;
u32 dwsize = size / sizeof(u32);
struct mpp_dev *mpp = session->mpp;
int ret = 0;
int idx = RKVDEC_REG_PPS_BASE_INDEX;
int pps_fd = task->reg[idx] & 0x3ff;
int pps_offset = task->reg[idx] >> 10;
u32 fmt = RKVDEC_GET_FORMAT(task->reg[RKVDEC_REG_SYS_CTRL_INDEX]);
mpp_debug_enter();
task = kzalloc(sizeof(*task), GFP_KERNEL);
if (!task)
return NULL;
mpp_task_init(session, &task->mpp_task);
task->hw_info = mpp->var->hw_info;
reg_len = min(task->hw_info->reg_num, dwsize);
if (copy_from_user(task->reg, src, reg_len * 4)) {
mpp_err("error: copy_from_user failed in reg_init\n");
goto fail;
}
fmt = RKVDEC_GET_FORMAT(task->reg[RKVDEC_REG_SYS_CTRL_INDEX]);
/*
* special offset scale case
*
* This translation is for fd + offset translation.
* One register has 32bits. We need to transfer both buffer file
* handle and the start address offset so we packet file handle
* and offset together using below format.
*
* 0~9 bit for buffer file handle range 0 ~ 1023
* 10~31 bit for offset range 0 ~ 4M
*
* But on 4K case the offset can be larger the 4M
* So on VP9 4K decoder colmv base we scale the offset by 16
*/
if (fmt == RKVDEC_FMT_VP9D) {
struct mpp_mem_region *mem_region = NULL;
dma_addr_t iova = 0;
u32 offset = task->reg[RKVDEC_REG_VP9_REFCOLMV_BASE_INDEX];
int fd = task->reg[RKVDEC_REG_VP9_REFCOLMV_BASE_INDEX] & 0x3ff;
offset = offset >> 10 << 4;
mem_region = mpp_task_attach_fd(&task->mpp_task, fd);
if (IS_ERR(mem_region))
goto fail;
iova = mem_region->iova;
task->reg[RKVDEC_REG_VP9_REFCOLMV_BASE_INDEX] = iova + offset;
}
pps_fd = task->reg[RKVDEC_REG_PPS_BASE_INDEX] & 0x3ff;
pps_offset = task->reg[RKVDEC_REG_PPS_BASE_INDEX] >> 10;
pps_offset += mpp_query_reg_offset_info(&task->off_inf, idx);
if (pps_fd > 0) {
int pps_info_offset;
int pps_info_count;
@@ -713,17 +666,113 @@ static void *rkvdec_alloc_task(struct mpp_session *session,
}
}
ret = mpp_translate_reg_address(session->mpp,
&task->mpp_task,
fmt, task->reg);
fail:
return ret;
}
static int rkvdec_process_reg_fd(struct mpp_session *session,
struct rkvdec_task *task,
struct mpp_task_msgs *msgs)
{
int ret = 0;
u32 fmt = RKVDEC_GET_FORMAT(task->reg[RKVDEC_REG_SYS_CTRL_INDEX]);
/* copy reg address offset message */
ret = mpp_extract_reg_offset_info(&msgs->reg_offset,
&task->off_inf);
if (ret)
goto fail;
/*
* special offset scale case
*
* This translation is for fd + offset translation.
* One register has 32bits. We need to transfer both buffer file
* handle and the start address offset so we packet file handle
* and offset together using below format.
*
* 0~9 bit for buffer file handle range 0 ~ 1023
* 10~31 bit for offset range 0 ~ 4M
*
* But on 4K case the offset can be larger the 4M
* So on VP9 4K decoder colmv base we scale the offset by 16
*/
if (fmt == RKVDEC_FMT_VP9D) {
int fd;
int idx;
u32 offset;
dma_addr_t iova = 0;
struct mpp_mem_region *mem_region = NULL;
idx = RKVDEC_REG_VP9_REFCOLMV_BASE_INDEX;
offset = task->reg[idx];
fd = task->reg[idx] & 0x3ff;
offset = offset >> 10 << 4;
offset += mpp_query_reg_offset_info(&task->off_inf, idx);
mem_region = mpp_task_attach_fd(&task->mpp_task, fd);
if (IS_ERR(mem_region))
goto fail;
iova = mem_region->iova;
task->reg[idx] = iova + offset;
}
ret = mpp_translate_reg_address(session, &task->mpp_task,
fmt, task->reg, &task->off_inf);
if (ret) {
mpp_err("error: translate reg address failed.\n");
mpp_err("translate reg address failed.\n");
mpp_dump_reg(task->reg,
task->hw_info->regidx_start,
task->hw_info->regidx_end);
goto fail;
}
mpp_debug(DEBUG_SET_REG, "extra info cnt %u, magic %08x",
task->off_inf.cnt, task->off_inf.magic);
mpp_translate_reg_offset_info(&task->mpp_task,
&task->off_inf, task->reg);
return 0;
fail:
return -EFAULT;
}
static void *rkvdec_alloc_task(struct mpp_session *session,
struct mpp_task_msgs *msgs)
{
int ret;
u32 reg_len;
struct rkvdec_task *task = NULL;
struct mpp_dev *mpp = session->mpp;
struct mpp_request *msg_reg = &msgs->reg_in;
u32 dwsize = msg_reg->size / sizeof(u32);
mpp_debug_enter();
task = kzalloc(sizeof(*task), GFP_KERNEL);
if (!task)
return NULL;
mpp_task_init(session, &task->mpp_task);
task->hw_info = mpp->var->hw_info;
reg_len = min(task->hw_info->reg_num, dwsize);
if (copy_from_user(task->reg, msg_reg->data,
reg_len * sizeof(u32))) {
mpp_err("copy_from_user failed in reg_init\n");
goto fail;
}
/* process fd in pps for 264 and 265 */
if (!(msg_reg->flags & MPP_FLAGS_SCL_FD_NO_TRANS)) {
ret = rkvdec_process_scl_fd(session, task, msgs);
if (ret)
goto fail;
}
/* process fd in register */
if (!(msg_reg->flags & MPP_FLAGS_REG_FD_NO_TRANS)) {
ret = rkvdec_process_reg_fd(session, task, msgs);
if (ret)
goto fail;
}
task->strm_addr = task->reg[RKVDEC_REG_RLC_BASE_INDEX];
mpp_debug_leave();
@@ -929,12 +978,14 @@ static int rkvdec_finish(struct mpp_dev *mpp,
static int rkvdec_result(struct mpp_dev *mpp,
struct mpp_task *mpp_task,
u32 __user *dst, u32 size)
struct mpp_task_msgs *msgs)
{
struct mpp_request *msg_reg_out = &msgs->reg_out;
struct rkvdec_task *task = to_rkvdec_task(mpp_task);
/* FIXME may overflow the kernel */
if (copy_to_user(dst, task->reg, size)) {
if (copy_to_user(msg_reg_out->data,
task->reg, msg_reg_out->size)) {
mpp_err("copy_to_user failed\n");
return -EIO;
}
@@ -1128,6 +1179,7 @@ static int rkvdec_devfreq_remove(struct mpp_dev *mpp)
static int rkvdec_devfreq_init(struct mpp_dev *mpp)
{
int ret = 0;
struct devfreq_dev_status *stat;
struct rkvdec_dev *dec = to_rkvdec_dev(mpp);
dec->parent_devfreq = devfreq_get_devfreq_by_phandle(mpp->dev, 0);
@@ -1157,32 +1209,28 @@ static int rkvdec_devfreq_init(struct mpp_dev *mpp)
dev_warn(mpp->dev, "no regulator for vcodec\n");
return 0;
} else {
struct devfreq_dev_status *stat;
ret = rockchip_init_opp_table(mpp->dev, NULL,
"rkvdec_leakage", "vcodec");
if (ret) {
dev_err(mpp->dev, "Failed to init_opp_table\n");
goto done;
}
dec->devfreq = devm_devfreq_add_device(mpp->dev,
&devfreq_profile,
"userspace",
NULL);
if (IS_ERR(dec->devfreq)) {
ret = PTR_ERR(dec->devfreq);
goto done;
}
stat = &dec->devfreq->last_status;
stat->current_frequency = clk_get_rate(dec->aclk);
ret = devfreq_register_opp_notifier(mpp->dev, dec->devfreq);
if (ret)
goto done;
}
ret = rockchip_init_opp_table(mpp->dev, NULL,
"rkvdec_leakage", "vcodec");
if (ret) {
dev_err(mpp->dev, "Failed to init_opp_table\n");
goto done;
}
dec->devfreq = devm_devfreq_add_device(mpp->dev, &devfreq_profile,
"userspace", NULL);
if (IS_ERR(dec->devfreq)) {
ret = PTR_ERR(dec->devfreq);
goto done;
}
stat = &dec->devfreq->last_status;
stat->current_frequency = clk_get_rate(dec->aclk);
ret = devfreq_register_opp_notifier(mpp->dev, dec->devfreq);
if (ret)
goto done;
/* power simplle init */
ret = power_model_simple_init(mpp);
if (!ret && dec->devfreq) {

View File

@@ -96,7 +96,7 @@ struct vdpu_task {
unsigned long aclk_freq;
u32 reg[VDPU1_REG_PP_NUM];
u32 idx;
struct extra_info_for_iommu ext_inf;
struct reg_offset_info off_inf;
u32 strm_addr;
u32 irq_status;
};
@@ -136,66 +136,66 @@ static struct mpp_hw_info vdpu_pp_v1_hw_info = {
/*
* file handle translate information
*/
static const char trans_tbl_avsd[] = {
static const u16 trans_tbl_avsd[] = {
12, 13, 14, 15, 16, 17, 40, 41, 45
};
static const char trans_tbl_default[] = {
static const u16 trans_tbl_default[] = {
12, 13, 14, 15, 16, 17, 40, 41
};
static const char trans_tbl_jpegd[] = {
static const u16 trans_tbl_jpegd[] = {
12, 13, 14, 40, 66, 67
};
static const char trans_tbl_h264d[] = {
static const u16 trans_tbl_h264d[] = {
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 40
};
static const char trans_tbl_vc1d[] = {
static const u16 trans_tbl_vc1d[] = {
12, 13, 14, 15, 16, 17, 27, 41
};
static const char trans_tbl_vp6d[] = {
static const u16 trans_tbl_vp6d[] = {
12, 13, 14, 18, 27, 40
};
static const char trans_tbl_vp8d[] = {
static const u16 trans_tbl_vp8d[] = {
10, 12, 13, 14, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 40
};
static struct mpp_trans_info vdpu_v1_trans[] = {
[VDPU1_FMT_H264D] = {
.count = sizeof(trans_tbl_h264d),
.count = ARRAY_SIZE(trans_tbl_h264d),
.table = trans_tbl_h264d,
},
[VDPU1_FMT_H263D] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
[VDPU1_FMT_MPEG4D] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
[VDPU1_FMT_JPEGD] = {
.count = sizeof(trans_tbl_jpegd),
.count = ARRAY_SIZE(trans_tbl_jpegd),
.table = trans_tbl_jpegd,
},
[VDPU1_FMT_VC1D] = {
.count = sizeof(trans_tbl_vc1d),
.count = ARRAY_SIZE(trans_tbl_vc1d),
.table = trans_tbl_vc1d,
},
[VDPU1_FMT_MPEG2D] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
[VDPU1_FMT_MPEG1D] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
[VDPU1_FMT_VP6D] = {
.count = sizeof(trans_tbl_vp6d),
.count = ARRAY_SIZE(trans_tbl_vp6d),
.table = trans_tbl_vp6d,
},
[VDPU1_FMT_RESERVED] = {
@@ -203,79 +203,59 @@ static struct mpp_trans_info vdpu_v1_trans[] = {
.table = NULL,
},
[VDPU1_FMT_VP7D] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
[VDPU1_FMT_VP8D] = {
.count = sizeof(trans_tbl_vp8d),
.count = ARRAY_SIZE(trans_tbl_vp8d),
.table = trans_tbl_vp8d,
},
[VDPU1_FMT_AVSD] = {
.count = sizeof(trans_tbl_avsd),
.count = ARRAY_SIZE(trans_tbl_avsd),
.table = trans_tbl_avsd,
},
};
static void *vdpu_alloc_task(struct mpp_session *session,
void __user *src, u32 size)
static int vdpu_process_reg_fd(struct mpp_session *session,
struct vdpu_task *task,
struct mpp_task_msgs *msgs,
u32 extinf_len,
u32 reg_len)
{
u32 fmt;
int err;
u32 reg_len;
u32 extinf_len;
struct vdpu_task *task = NULL;
u32 dwsize = size / sizeof(u32);
struct mpp_dev *mpp = session->mpp;
int ret = 0;
struct mpp_request *msg_reg = &msgs->reg_in;
int fmt = VDPU1_GET_FORMAT(task->reg[VDPU1_REG_SYS_CTRL_INDEX]);
mpp_debug_enter();
task = kzalloc(sizeof(*task), GFP_KERNEL);
if (!task)
return NULL;
mpp_task_init(session, &task->mpp_task);
if (session->device_type == MPP_DEVICE_VDPU1_PP) {
task->pp_enable = true;
task->hw_info = &vdpu_pp_v1_hw_info;
} else {
task->hw_info = mpp->var->hw_info;
}
reg_len = min(task->hw_info->reg_num, dwsize);
extinf_len = dwsize > reg_len ? (dwsize - reg_len) * 4 : 0;
if (copy_from_user(task->reg, src, reg_len * 4)) {
mpp_err("error: copy_from_user failed in reg_init\n");
goto fail;
}
fmt = VDPU1_GET_FORMAT(task->reg[VDPU1_REG_SYS_CTRL_INDEX]);
if (extinf_len > 0) {
if (likely(fmt == VDPU1_FMT_JPEGD)) {
err = copy_from_user(&task->ext_inf,
(u8 *)src + size
ret = copy_from_user(&task->off_inf,
(u8 *)msg_reg->data
+ msg_reg->size
- JPEG_IOC_EXTRA_SIZE,
JPEG_IOC_EXTRA_SIZE);
} else {
u32 ext_cpy = min_t(size_t, extinf_len,
sizeof(task->ext_inf));
err = copy_from_user(&task->ext_inf,
(u32 *)src + reg_len,
sizeof(task->off_inf));
ret = copy_from_user(&task->off_inf,
(u32 *)msg_reg->data + reg_len,
ext_cpy);
}
if (err) {
if (ret) {
mpp_err("copy_from_user failed when extra info\n");
goto fail;
}
} else {
ret = mpp_extract_reg_offset_info(&msgs->reg_offset,
&task->off_inf);
if (ret)
goto fail;
}
err = mpp_translate_reg_address(session->mpp,
&task->mpp_task,
fmt,
task->reg);
if (err) {
mpp_err("error: translate reg address failed.\n");
ret = mpp_translate_reg_address(session, &task->mpp_task,
fmt, task->reg, &task->off_inf);
if (ret) {
mpp_err("translate reg address failed.\n");
mpp_dump_reg(task->reg,
task->hw_info->regidx_start,
task->hw_info->regidx_end);
@@ -295,28 +275,77 @@ static void *vdpu_alloc_task(struct mpp_session *session,
* But on 4K case the offset can be larger the 4M
*/
if (likely(fmt == VDPU1_FMT_H264D)) {
u32 idx = VDPU1_REG_DIR_MV_BASE_INDEX;
struct mpp_mem_region *mem_region = NULL;
dma_addr_t iova = 0;
u32 offset = task->reg[VDPU1_REG_DIR_MV_BASE_INDEX];
int fd = task->reg[VDPU1_REG_DIR_MV_BASE_INDEX] & 0x3ff;
u32 offset = task->reg[idx];
int fd = task->reg[idx] & 0x3ff;
offset = offset >> 10 << 4;
offset += mpp_query_reg_offset_info(&task->off_inf, idx);
mem_region = mpp_task_attach_fd(&task->mpp_task, fd);
if (IS_ERR(mem_region))
goto fail;
iova = mem_region->iova;
mpp_debug(DEBUG_IOMMU, "DMV[%3d]: %3d => %pad + offset %10d\n",
VDPU1_REG_DIR_MV_BASE_INDEX, fd, &iova, offset);
task->reg[VDPU1_REG_DIR_MV_BASE_INDEX] = iova + offset;
idx, fd, &iova, offset);
task->reg[idx] = iova + offset;
}
mpp_debug(DEBUG_SET_REG, "extra info cnt %u, magic %08x",
task->off_inf.cnt, task->off_inf.magic);
mpp_translate_reg_offset_info(&task->mpp_task,
&task->off_inf,
task->reg);
return 0;
fail:
return -EFAULT;
}
static void *vdpu_alloc_task(struct mpp_session *session,
struct mpp_task_msgs *msgs)
{
int ret;
u32 reg_len;
u32 extinf_len;
struct vdpu_task *task;
struct mpp_dev *mpp = session->mpp;
struct mpp_request *msg_reg = &msgs->reg_in;
u32 dwsize = msg_reg->size / sizeof(u32);
mpp_debug_enter();
task = kzalloc(sizeof(*task), GFP_KERNEL);
if (!task)
return NULL;
mpp_task_init(session, &task->mpp_task);
if (session->device_type == MPP_DEVICE_VDPU1_PP) {
task->pp_enable = true;
task->hw_info = &vdpu_pp_v1_hw_info;
} else {
task->hw_info = mpp->var->hw_info;
}
reg_len = min(task->hw_info->reg_num, dwsize);
extinf_len = dwsize > reg_len ?
(dwsize - reg_len) * sizeof(u32) : 0;
if (copy_from_user(task->reg, msg_reg->data,
reg_len * sizeof(u32))) {
mpp_err("copy_from_user failed in reg_init\n");
goto fail;
}
/* process fd in register */
if (!(msg_reg->flags & MPP_FLAGS_REG_FD_NO_TRANS)) {
ret = vdpu_process_reg_fd(session, task, msgs,
extinf_len, reg_len);
if (ret)
goto fail;
}
task->strm_addr = task->reg[VDPU1_REG_STREAM_RLC_BASE_INDEX];
mpp_debug(DEBUG_SET_REG, "extra info cnt %u, magic %08x",
task->ext_inf.cnt, task->ext_inf.magic);
mpp_translate_extra_info(&task->mpp_task, &task->ext_inf, task->reg);
mpp_debug_leave();
return &task->mpp_task;
@@ -404,12 +433,14 @@ static int vdpu_finish(struct mpp_dev *mpp,
static int vdpu_result(struct mpp_dev *mpp,
struct mpp_task *mpp_task,
u32 __user *dst, u32 size)
struct mpp_task_msgs *msgs)
{
struct mpp_request *msg_reg_out = &msgs->reg_out;
struct vdpu_task *task = to_vdpu_task(mpp_task);
/* FIXME may overflow the kernel */
if (copy_to_user(dst, task->reg, size)) {
if (copy_to_user(msg_reg_out->data,
task->reg, msg_reg_out->size)) {
mpp_err("copy_to_user failed\n");
return -EIO;
}

View File

@@ -89,7 +89,7 @@ struct vdpu_task {
unsigned long aclk_freq;
u32 reg[VDPU2_REG_NUM];
u32 idx;
struct extra_info_for_iommu ext_inf;
struct reg_offset_info off_inf;
u32 strm_addr;
u32 irq_status;
};
@@ -120,62 +120,62 @@ static struct mpp_hw_info vdpu_v2_hw_info = {
/*
* file handle translate information
*/
static const char trans_tbl_default[] = {
static const u16 trans_tbl_default[] = {
61, 62, 63, 64, 131, 134, 135, 148
};
static const char trans_tbl_jpegd[] = {
static const u16 trans_tbl_jpegd[] = {
21, 22, 61, 63, 64, 131
};
static const char trans_tbl_h264d[] = {
static const u16 trans_tbl_h264d[] = {
61, 63, 64, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
98, 99
};
static const char trans_tbl_vc1d[] = {
static const u16 trans_tbl_vc1d[] = {
62, 63, 64, 131, 134, 135, 145, 148
};
static const char trans_tbl_vp6d[] = {
static const u16 trans_tbl_vp6d[] = {
61, 63, 64, 131, 136, 145
};
static const char trans_tbl_vp8d[] = {
static const u16 trans_tbl_vp8d[] = {
61, 63, 64, 131, 136, 137, 140, 141, 142, 143, 144, 145, 146, 147, 149
};
static struct mpp_trans_info vdpu_v2_trans[] = {
[VDPU2_FMT_H264D] = {
.count = sizeof(trans_tbl_h264d),
.count = ARRAY_SIZE(trans_tbl_h264d),
.table = trans_tbl_h264d,
},
[VDPU2_FMT_H263D] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
[VDPU2_FMT_MPEG4D] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
[VDPU2_FMT_JPEGD] = {
.count = sizeof(trans_tbl_jpegd),
.count = ARRAY_SIZE(trans_tbl_jpegd),
.table = trans_tbl_jpegd,
},
[VDPU2_FMT_VC1D] = {
.count = sizeof(trans_tbl_vc1d),
.count = ARRAY_SIZE(trans_tbl_vc1d),
.table = trans_tbl_vc1d,
},
[VDPU2_FMT_MPEG2D] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
[VDPU2_FMT_MPEG1D] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
[VDPU2_FMT_VP6D] = {
.count = sizeof(trans_tbl_vp6d),
.count = ARRAY_SIZE(trans_tbl_vp6d),
.table = trans_tbl_vp6d,
},
[VDPU2_FMT_RESERVED] = {
@@ -183,29 +183,103 @@ static struct mpp_trans_info vdpu_v2_trans[] = {
.table = NULL,
},
[VDPU2_FMT_VP7D] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
[VDPU2_FMT_VP8D] = {
.count = sizeof(trans_tbl_vp8d),
.count = ARRAY_SIZE(trans_tbl_vp8d),
.table = trans_tbl_vp8d,
},
[VDPU2_FMT_AVSD] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
};
static void *vdpu_alloc_task(struct mpp_session *session,
void __user *src, u32 size)
static int vdpu_process_reg_fd(struct mpp_session *session,
struct vdpu_task *task,
struct mpp_task_msgs *msgs,
u32 extinf_len,
u32 reg_len)
{
u32 fmt;
int err;
int ret = 0;
struct mpp_request *msg_reg = &msgs->reg_in;
int fmt = VDPU2_GET_FORMAT(task->reg[VDPU2_REG_SYS_CTRL_INDEX]);
if (extinf_len > 0) {
if (likely(fmt == VDPU2_FMT_JPEGD)) {
ret = copy_from_user(&task->off_inf,
(u8 *)msg_reg->data
+ msg_reg->size
- JPEG_IOC_EXTRA_SIZE,
JPEG_IOC_EXTRA_SIZE);
} else {
u32 ext_cpy = min_t(size_t, extinf_len,
sizeof(task->off_inf));
ret = copy_from_user(&task->off_inf,
(u32 *)msg_reg->data + reg_len,
ext_cpy);
}
if (ret) {
mpp_err("copy_from_user failed when extra info\n");
goto fail;
}
} else {
ret = mpp_extract_reg_offset_info(&msgs->reg_offset,
&task->off_inf);
if (ret)
goto fail;
}
ret = mpp_translate_reg_address(session, &task->mpp_task,
fmt, task->reg, &task->off_inf);
if (ret) {
mpp_err("translate reg address failed.\n");
mpp_dump_reg(task->reg,
task->hw_info->regidx_start,
task->hw_info->regidx_end);
goto fail;
}
if (likely(fmt == VDPU2_FMT_H264D)) {
u32 idx = VDPU2_REG_DIR_MV_BASE_INDEX;
struct mpp_mem_region *mem_region = NULL;
dma_addr_t iova = 0;
u32 offset = task->reg[idx];
int fd = task->reg[idx] & 0x3ff;
offset = offset >> 10 << 4;
offset += mpp_query_reg_offset_info(&task->off_inf, idx);
mem_region = mpp_task_attach_fd(&task->mpp_task, fd);
if (IS_ERR(mem_region))
goto fail;
iova = mem_region->iova;
mpp_debug(DEBUG_IOMMU, "DMV[%3d]: %3d => %pad + offset %10d\n",
idx, fd, &iova, offset);
task->reg[idx] = iova + offset;
}
mpp_debug(DEBUG_SET_REG, "extra info cnt %u, magic %08x",
task->off_inf.cnt, task->off_inf.magic);
mpp_translate_reg_offset_info(&task->mpp_task,
&task->off_inf,
task->reg);
return 0;
fail:
return -EFAULT;
}
static void *vdpu_alloc_task(struct mpp_session *session,
struct mpp_task_msgs *msgs)
{
int ret;
u32 reg_len;
u32 extinf_len;
struct vdpu_task *task = NULL;
u32 dwsize = size / sizeof(u32);
struct mpp_dev *mpp = session->mpp;
struct mpp_request *msg_reg = &msgs->reg_in;
u32 dwsize = msg_reg->size / sizeof(u32);
mpp_debug_enter();
@@ -217,67 +291,23 @@ static void *vdpu_alloc_task(struct mpp_session *session,
task->hw_info = mpp->var->hw_info;
reg_len = min(task->hw_info->reg_num, dwsize);
extinf_len = dwsize > reg_len ? (dwsize - reg_len) * 4 : 0;
extinf_len = dwsize > reg_len ?
(dwsize - reg_len) * sizeof(u32) : 0;
if (copy_from_user(task->reg, src, reg_len * 4)) {
mpp_err("error: copy_from_user failed in reg_init\n");
if (copy_from_user(task->reg, msg_reg->data,
reg_len * sizeof(u32))) {
mpp_err("copy_from_user failed in reg_init\n");
goto fail;
}
fmt = VDPU2_GET_FORMAT(task->reg[VDPU2_REG_SYS_CTRL_INDEX]);
if (extinf_len > 0) {
if (likely(fmt == VDPU2_FMT_JPEGD)) {
err = copy_from_user(&task->ext_inf,
(u8 *)src + size
- JPEG_IOC_EXTRA_SIZE,
JPEG_IOC_EXTRA_SIZE);
} else {
u32 ext_cpy = min_t(size_t, extinf_len,
sizeof(task->ext_inf));
err = copy_from_user(&task->ext_inf,
(u32 *)src + reg_len, ext_cpy);
}
if (err) {
mpp_err("copy_from_user failed when extra info\n");
/* process fd in register */
if (!(msg_reg->flags & MPP_FLAGS_REG_FD_NO_TRANS)) {
ret = vdpu_process_reg_fd(session, task, msgs,
extinf_len, reg_len);
if (ret)
goto fail;
}
}
err = mpp_translate_reg_address(session->mpp,
&task->mpp_task,
fmt, task->reg);
if (err) {
mpp_err("error: translate reg address failed.\n");
mpp_dump_reg(task->reg,
task->hw_info->regidx_start,
task->hw_info->regidx_end);
goto fail;
}
if (likely(fmt == VDPU2_FMT_H264D)) {
struct mpp_mem_region *mem_region = NULL;
dma_addr_t iova = 0;
u32 offset = task->reg[VDPU2_REG_DIR_MV_BASE_INDEX];
int fd = task->reg[VDPU2_REG_DIR_MV_BASE_INDEX] & 0x3ff;
offset = offset >> 10 << 4;
mem_region = mpp_task_attach_fd(&task->mpp_task, fd);
if (IS_ERR(mem_region))
goto fail;
iova = mem_region->iova;
mpp_debug(DEBUG_IOMMU, "DMV[%3d]: %3d => %pad + offset %10d\n",
VDPU2_REG_DIR_MV_BASE_INDEX, fd, &iova, offset);
task->reg[VDPU2_REG_DIR_MV_BASE_INDEX] = iova + offset;
}
task->strm_addr = task->reg[VDPU2_REG_STREAM_RLC_BASE_INDEX];
mpp_debug(DEBUG_SET_REG, "extra info cnt %u, magic %08x",
task->ext_inf.cnt, task->ext_inf.magic);
mpp_translate_extra_info(&task->mpp_task, &task->ext_inf, task->reg);
mpp_debug_leave();
return &task->mpp_task;
@@ -366,12 +396,14 @@ static int vdpu_finish(struct mpp_dev *mpp,
static int vdpu_result(struct mpp_dev *mpp,
struct mpp_task *mpp_task,
u32 __user *dst, u32 size)
struct mpp_task_msgs *msgs)
{
struct mpp_request *reg_out = &msgs->reg_out;
struct vdpu_task *task = to_vdpu_task(mpp_task);
/* FIXME may overflow the kernel */
if (copy_to_user(dst, task->reg, size)) {
if (copy_to_user(reg_out->data,
task->reg, reg_out->size)) {
mpp_err("copy_to_user failed\n");
return -EIO;
}

View File

@@ -73,7 +73,7 @@ struct vepu_task {
unsigned long aclk_freq;
u32 reg[VEPU1_REG_NUM];
u32 idx;
struct extra_info_for_iommu ext_inf;
struct reg_offset_info off_inf;
u32 irq_status;
};
@@ -105,11 +105,11 @@ static struct mpp_hw_info vepu_v1_hw_info = {
/*
* file handle translate information
*/
static const char trans_tbl_default[] = {
static const u16 trans_tbl_default[] = {
5, 6, 7, 8, 9, 10, 11, 12, 13, 51
};
static const char trans_tbl_vp8e[] = {
static const u16 trans_tbl_vp8e[] = {
5, 6, 7, 8, 9, 10, 11, 12, 13, 16, 17, 26, 51, 52, 58, 59
};
@@ -119,30 +119,87 @@ static struct mpp_trans_info trans_rk_vepu1[] = {
.table = NULL,
},
[VEPU1_FMT_VP8E] = {
.count = sizeof(trans_tbl_vp8e),
.count = ARRAY_SIZE(trans_tbl_vp8e),
.table = trans_tbl_vp8e,
},
[VEPU1_FMT_JPEGE] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
[VEPU1_FMT_H264E] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
};
static void *vepu_alloc_task(struct mpp_session *session,
void __user *src, u32 size)
static int vepu_process_reg_fd(struct mpp_session *session,
struct vepu_task *task,
struct mpp_task_msgs *msgs,
u32 extinf_len,
u32 reg_len)
{
u32 fmt;
int err;
int ret = 0;
struct mpp_request *msg_reg = &msgs->reg_in;
int fmt = VEPU1_GET_FORMAT(task->reg[VEPU1_REG_ENC_EN_INDEX]);
if (extinf_len > 0) {
if (likely(fmt == VEPU1_FMT_JPEGE)) {
ret = copy_from_user(&task->off_inf,
(u8 *)msg_reg->data
+ msg_reg->size
- JPEG_IOC_EXTRA_SIZE,
JPEG_IOC_EXTRA_SIZE);
} else {
u32 ext_cpy = min_t(size_t, extinf_len,
sizeof(task->off_inf));
ret = copy_from_user(&task->off_inf,
(u32 *)msg_reg->data + reg_len,
ext_cpy);
}
if (ret) {
mpp_err("copy_from_user failed when extra info\n");
goto fail;
}
} else {
ret = mpp_extract_reg_offset_info(&msgs->reg_offset,
&task->off_inf);
if (ret)
goto fail;
}
ret = mpp_translate_reg_address(session, &task->mpp_task,
fmt, task->reg, &task->off_inf);
if (ret) {
mpp_err("translate reg address failed.\n");
mpp_dump_reg(task->reg,
task->hw_info->regidx_start,
task->hw_info->regidx_end);
goto fail;
}
mpp_debug(DEBUG_SET_REG, "extra info cnt %u, magic %08x",
task->off_inf.cnt, task->off_inf.magic);
mpp_translate_reg_offset_info(&task->mpp_task,
&task->off_inf,
task->reg);
return 0;
fail:
return -EFAULT;
}
static void *vepu_alloc_task(struct mpp_session *session,
struct mpp_task_msgs *msgs)
{
int ret;
u32 reg_len;
u32 extinf_len;
struct vepu_task *task = NULL;
u32 dwsize = size / sizeof(u32);
struct mpp_dev *mpp = session->mpp;
struct mpp_request *msg_reg = &msgs->reg_in;
u32 dwsize = msg_reg->size / sizeof(u32);
mpp_debug_enter();
@@ -154,50 +211,22 @@ static void *vepu_alloc_task(struct mpp_session *session,
task->hw_info = mpp->var->hw_info;
reg_len = min(task->hw_info->reg_num, dwsize);
extinf_len = dwsize > reg_len ? (dwsize - reg_len) * 4 : 0;
if (copy_from_user(task->reg, src, reg_len * 4)) {
mpp_err("error: copy_from_user failed in reg_init\n");
extinf_len = dwsize > reg_len ?
(dwsize - reg_len) * sizeof(u32) : 0;
if (copy_from_user(task->reg, msg_reg->data,
reg_len * sizeof(u32))) {
mpp_err("copy_from_user failed in reg_init\n");
goto fail;
}
fmt = VEPU1_GET_FORMAT(task->reg[VEPU1_REG_ENC_EN_INDEX]);
if (extinf_len > 0) {
if (likely(fmt == VEPU1_FMT_JPEGE)) {
err = copy_from_user(&task->ext_inf,
(u8 *)src + size
- JPEG_IOC_EXTRA_SIZE,
JPEG_IOC_EXTRA_SIZE);
} else {
u32 ext_cpy = min_t(size_t, extinf_len,
sizeof(task->ext_inf));
err = copy_from_user(&task->ext_inf,
(u32 *)src + reg_len, ext_cpy);
}
if (err) {
mpp_err("copy_from_user failed when extra info\n");
/* process fd in register */
if (!(msg_reg->flags & MPP_FLAGS_REG_FD_NO_TRANS)) {
ret = vepu_process_reg_fd(session, task, msgs,
extinf_len, reg_len);
if (ret)
goto fail;
}
}
err = mpp_translate_reg_address(session->mpp,
&task->mpp_task,
fmt, task->reg);
if (err) {
mpp_err("error: translate reg address failed.\n");
mpp_dump_reg(task->reg,
task->hw_info->regidx_start,
task->hw_info->regidx_end);
goto fail;
}
mpp_debug(DEBUG_SET_REG, "extra info cnt %u, magic %08x",
task->ext_inf.cnt, task->ext_inf.magic);
mpp_translate_extra_info(&task->mpp_task,
&task->ext_inf,
task->reg);
mpp_debug_leave();
return &task->mpp_task;
@@ -324,12 +353,14 @@ static int vepu_finish(struct mpp_dev *mpp,
static int vepu_result(struct mpp_dev *mpp,
struct mpp_task *mpp_task,
u32 __user *dst, u32 size)
struct mpp_task_msgs *msgs)
{
struct mpp_request *msg_reg_out = &msgs->reg_out;
struct vepu_task *task = to_vepu_task(mpp_task);
/* FIXME may overflow the kernel */
if (copy_to_user(dst, task->reg, size)) {
if (copy_to_user(msg_reg_out->data,
task->reg, msg_reg_out->size)) {
mpp_err("copy_to_user failed\n");
return -EIO;
}

View File

@@ -80,7 +80,7 @@ struct vepu_task {
unsigned long aclk_freq;
u32 reg[VEPU2_REG_NUM];
u32 idx;
struct extra_info_for_iommu ext_inf;
struct reg_offset_info off_inf;
u32 irq_status;
};
@@ -110,11 +110,11 @@ static struct mpp_hw_info vepu_v2_hw_info = {
/*
* file handle translate information
*/
static const char trans_tbl_default[] = {
static const u16 trans_tbl_default[] = {
48, 49, 50, 56, 57, 63, 64, 77, 78, 81
};
static const char trans_tbl_vp8e[] = {
static const u16 trans_tbl_vp8e[] = {
27, 44, 45, 48, 49, 50, 56, 57, 63, 64,
76, 77, 78, 80, 81, 106, 108,
};
@@ -125,30 +125,87 @@ static struct mpp_trans_info trans_rk_vepu2[] = {
.table = NULL,
},
[VEPU2_FMT_VP8E] = {
.count = sizeof(trans_tbl_vp8e),
.count = ARRAY_SIZE(trans_tbl_vp8e),
.table = trans_tbl_vp8e,
},
[VEPU2_FMT_JPEGE] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
[VEPU2_FMT_H264E] = {
.count = sizeof(trans_tbl_default),
.count = ARRAY_SIZE(trans_tbl_default),
.table = trans_tbl_default,
},
};
static void *vepu_alloc_task(struct mpp_session *session,
void __user *src, u32 size)
static int vepu_process_reg_fd(struct mpp_session *session,
struct vepu_task *task,
struct mpp_task_msgs *msgs,
u32 extinf_len,
u32 reg_len)
{
u32 fmt;
int err;
int ret = 0;
struct mpp_request *msg_reg = &msgs->reg_in;
int fmt = VEPU2_GET_FORMAT(task->reg[VEPU2_REG_ENC_EN_INDEX]);
if (extinf_len > 0) {
if (likely(fmt == VEPU2_FMT_JPEGE)) {
ret = copy_from_user(&task->off_inf,
(u8 *)msg_reg->data
+ msg_reg->size
- JPEG_IOC_EXTRA_SIZE,
JPEG_IOC_EXTRA_SIZE);
} else {
u32 ext_cpy = min_t(size_t, extinf_len,
sizeof(task->off_inf));
ret = copy_from_user(&task->off_inf,
(u32 *)msg_reg->data + reg_len,
ext_cpy);
}
if (ret) {
mpp_err("copy_from_user failed when extra info\n");
goto fail;
}
} else {
ret = mpp_extract_reg_offset_info(&msgs->reg_offset,
&task->off_inf);
if (ret)
goto fail;
}
ret = mpp_translate_reg_address(session, &task->mpp_task,
fmt, task->reg, &task->off_inf);
if (ret) {
mpp_err("translate reg address failed.\n");
mpp_dump_reg(task->reg,
task->hw_info->regidx_start,
task->hw_info->regidx_end);
goto fail;
}
mpp_debug(DEBUG_SET_REG, "extra info cnt %u, magic %08x",
task->off_inf.cnt, task->off_inf.magic);
mpp_translate_reg_offset_info(&task->mpp_task,
&task->off_inf,
task->reg);
return 0;
fail:
return -EFAULT;
}
static void *vepu_alloc_task(struct mpp_session *session,
struct mpp_task_msgs *msgs)
{
int ret;
u32 reg_len;
u32 extinf_len;
struct vepu_task *task = NULL;
u32 dwsize = size / sizeof(u32);
struct mpp_dev *mpp = session->mpp;
struct mpp_request *msg_reg = &msgs->reg_in;
u32 dwsize = msg_reg->size / sizeof(u32);
mpp_debug_enter();
@@ -159,50 +216,22 @@ static void *vepu_alloc_task(struct mpp_session *session,
mpp_task_init(session, &task->mpp_task);
task->hw_info = mpp->var->hw_info;
reg_len = min(task->hw_info->reg_num, dwsize);
extinf_len = dwsize > reg_len ? (dwsize - reg_len) * 4 : 0;
extinf_len = dwsize > reg_len ?
(dwsize - reg_len) * sizeof(u32) : 0;
if (copy_from_user(task->reg, src, reg_len * 4)) {
mpp_err("error: copy_from_user failed in reg_init\n");
if (copy_from_user(task->reg, msg_reg->data,
reg_len * sizeof(u32))) {
mpp_err("copy_from_user failed in reg_init\n");
goto fail;
}
fmt = VEPU2_GET_FORMAT(task->reg[VEPU2_REG_ENC_EN_INDEX]);
if (extinf_len > 0) {
if (likely(fmt == VEPU2_FMT_JPEGE)) {
err = copy_from_user(&task->ext_inf,
(u8 *)src + size
- JPEG_IOC_EXTRA_SIZE,
JPEG_IOC_EXTRA_SIZE);
} else {
u32 ext_cpy = min_t(size_t, extinf_len,
sizeof(task->ext_inf));
err = copy_from_user(&task->ext_inf,
(u32 *)src + reg_len,
ext_cpy);
}
if (err) {
mpp_err("copy_from_user failed when extra info\n");
/* process fd in register */
if (!(msg_reg->flags & MPP_FLAGS_REG_FD_NO_TRANS)) {
ret = vepu_process_reg_fd(session, task, msgs,
extinf_len, reg_len);
if (ret)
goto fail;
}
}
err = mpp_translate_reg_address(session->mpp,
&task->mpp_task,
fmt, task->reg);
if (err) {
mpp_err("error: translate reg address failed.\n");
mpp_dump_reg(task->reg,
task->hw_info->regidx_start,
task->hw_info->regidx_end);
goto fail;
}
mpp_debug(DEBUG_SET_REG, "extra info cnt %u, magic %08x",
task->ext_inf.cnt, task->ext_inf.magic);
mpp_translate_extra_info(&task->mpp_task,
&task->ext_inf, task->reg);
mpp_debug_leave();
return &task->mpp_task;
@@ -330,12 +359,14 @@ static int vepu_finish(struct mpp_dev *mpp,
static int vepu_result(struct mpp_dev *mpp,
struct mpp_task *mpp_task,
u32 __user *dst, u32 size)
struct mpp_task_msgs *msgs)
{
struct mpp_request *msg_reg_out = &msgs->reg_out;
struct vepu_task *task = to_vepu_task(mpp_task);
/* FIXME may overflow the kernel */
if (copy_to_user(dst, task->reg, size)) {
if (copy_to_user(msg_reg_out->data,
task->reg, msg_reg_out->size)) {
mpp_err("copy_to_user failed\n");
return -EIO;
}