techpack: video: add video driver

Add initial video driver files.

Change-Id: Icd48bbf31e435cf36f149d6c3267cf3a4d7913b3
Signed-off-by: Maheshwar Ajja <majja@codeaurora.org>
此提交包含在:
Maheshwar Ajja
2020-08-05 14:29:29 -07:00
父節點 7eb9a06ef5
當前提交 6f107f7e35
共有 39 個檔案被更改,包括 9337 行新增0 行删除

查看文件

@@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include "hfi_packet.h"
#include "msm_vidc_core.h"
#include "msm_vidc_inst.h"
#include "msm_vidc_debug.h"
int hfi_packet_sys_init(struct msm_vidc_core *core, void *pkt, u32 pkt_size)
{
d_vpr_h("%s()\n", __func__);
return 0;
}
int hfi_packet_sys_pc_prep(struct msm_vidc_core *core, void *pkt, u32 pkt_size)
{
d_vpr_h("%s()\n", __func__);
return 0;
}

108
driver/vidc/src/msm_vdec.c 一般檔案
查看文件

@@ -0,0 +1,108 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include <media/msm_vidc_utils.h>
#include <media/msm_media_info.h>
#include "msm_vdec.h"
#include "msm_vidc_core.h"
#include "msm_vidc_inst.h"
#include "msm_vidc_driver.h"
#include "msm_vidc_internal.h"
#include "msm_vidc_platform.h"
#include "msm_vidc_debug.h"
int msm_vdec_inst_init(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_vidc_core *core;
struct v4l2_format *f;
d_vpr_h("%s()\n", __func__);
if (!inst || !inst->core) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
core = inst->core;
INIT_DELAYED_WORK(&inst->decode_batch.work, msm_vidc_batch_handler);
f = &inst->fmts[INPUT_PORT];
f->type = INPUT_PLANE;
f->fmt.pix.width = DEFAULT_WIDTH;
f->fmt.pix.height = DEFAULT_HEIGHT;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
f->fmt.pix.bytesperline = 0;
f->fmt.pix.sizeimage = call_session_op(core, buffer_size,
inst, MSM_VIDC_INPUT);
inst->buffers.input.min_count =
call_session_op(core, min_count, inst, MSM_VIDC_INPUT);
inst->buffers.input.extra_count =
call_session_op(core, extra_count, inst, MSM_VIDC_INPUT);
inst->buffers.input.actual_count =
inst->buffers.input.min_count +
inst->buffers.input.extra_count;
inst->buffers.input.size = f->fmt.pix.sizeimage;
f = &inst->fmts[INPUT_META_PORT];
f->type = INPUT_META_PLANE;
f->fmt.meta.dataformat = V4L2_PIX_FMT_VIDC_META;
f->fmt.meta.buffersize = call_session_op(core, buffer_size,
inst, MSM_VIDC_INPUT_META);
inst->buffers.input_meta.min_count = inst->buffers.input.min_count;
inst->buffers.input_meta.extra_count = inst->buffers.input.extra_count;
inst->buffers.input_meta.actual_count = inst->buffers.input.actual_count;
inst->buffers.input_meta.size = f->fmt.meta.buffersize;
f = &inst->fmts[OUTPUT_PORT];
f->type = OUTPUT_PLANE;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12_UBWC;
f->fmt.pix.width = VENUS_Y_STRIDE(
msm_vidc_convert_color_fmt(f->fmt.pix.pixelformat), DEFAULT_WIDTH);
f->fmt.pix.height = VENUS_Y_SCANLINES(
msm_vidc_convert_color_fmt(f->fmt.pix.pixelformat), DEFAULT_HEIGHT);
f->fmt.pix.bytesperline = f->fmt.pix.width;
f->fmt.pix.sizeimage = call_session_op(core, buffer_size,
inst, MSM_VIDC_OUTPUT);
inst->buffers.output.min_count =
call_session_op(core, min_count, inst, MSM_VIDC_OUTPUT);
inst->buffers.output.extra_count =
call_session_op(core, extra_count, inst, MSM_VIDC_OUTPUT);
inst->buffers.output.actual_count =
inst->buffers.output.min_count +
inst->buffers.output.extra_count;
inst->buffers.output.size = f->fmt.pix.sizeimage;
f = &inst->fmts[OUTPUT_META_PORT];
f->type = OUTPUT_META_PLANE;
f->fmt.meta.dataformat = V4L2_PIX_FMT_VIDC_META;
f->fmt.meta.buffersize = call_session_op(core, buffer_size,
inst, MSM_VIDC_OUTPUT_META);
inst->buffers.output_meta.min_count = inst->buffers.output.min_count;
inst->buffers.output_meta.extra_count = inst->buffers.output.extra_count;
inst->buffers.output_meta.actual_count = inst->buffers.output.actual_count;
inst->buffers.output_meta.size = f->fmt.meta.buffersize;
inst->prop.frame_rate = DEFAULT_FPS << 16;
inst->prop.operating_rate = DEFAULT_FPS << 16;
return rc;
}
int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_vidc_core *core;
d_vpr_h("%s()\n", __func__);
if (!inst || !inst->core) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
core = inst->core;
return rc;
}

106
driver/vidc/src/msm_venc.c 一般檔案
查看文件

@@ -0,0 +1,106 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include <media/msm_vidc_utils.h>
#include <media/msm_media_info.h>
#include "msm_venc.h"
#include "msm_vidc_core.h"
#include "msm_vidc_inst.h"
#include "msm_vidc_driver.h"
#include "msm_vidc_internal.h"
#include "msm_vidc_platform.h"
#include "msm_vidc_debug.h"
int msm_venc_inst_init(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_vidc_core *core;
struct v4l2_format *f;
d_vpr_h("%s()\n", __func__);
if (!inst || !inst->core) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
core = inst->core;
f = &inst->fmts[OUTPUT_PORT];
f->type = OUTPUT_PLANE;
f->fmt.pix.width = DEFAULT_WIDTH;
f->fmt.pix.height = DEFAULT_HEIGHT;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
f->fmt.pix.bytesperline = 0;
f->fmt.pix.sizeimage = call_session_op(core, buffer_size,
inst, MSM_VIDC_OUTPUT);
inst->buffers.output.min_count =
call_session_op(core, min_count, inst, MSM_VIDC_OUTPUT);
inst->buffers.output.extra_count =
call_session_op(core, extra_count, inst, MSM_VIDC_OUTPUT);
inst->buffers.output.actual_count =
inst->buffers.output.min_count +
inst->buffers.output.extra_count;
inst->buffers.output.size = f->fmt.pix.sizeimage;
f = &inst->fmts[OUTPUT_META_PORT];
f->type = OUTPUT_META_PLANE;
f->fmt.meta.dataformat = V4L2_PIX_FMT_VIDC_META;
f->fmt.meta.buffersize = call_session_op(core, buffer_size,
inst, MSM_VIDC_OUTPUT_META);
inst->buffers.output_meta.min_count = inst->buffers.output.min_count;
inst->buffers.output_meta.extra_count = inst->buffers.output.extra_count;
inst->buffers.output_meta.actual_count = inst->buffers.output.actual_count;
inst->buffers.output_meta.size = f->fmt.meta.buffersize;
f = &inst->fmts[INPUT_PORT];
f->type = INPUT_PLANE;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12_UBWC;
f->fmt.pix.width = VENUS_Y_STRIDE(
msm_vidc_convert_color_fmt(f->fmt.pix.pixelformat), DEFAULT_WIDTH);
f->fmt.pix.height = VENUS_Y_SCANLINES(
msm_vidc_convert_color_fmt(f->fmt.pix.pixelformat), DEFAULT_HEIGHT);
f->fmt.pix.bytesperline = f->fmt.pix.width;
f->fmt.pix.sizeimage = call_session_op(core, buffer_size,
inst, MSM_VIDC_INPUT);
inst->buffers.input.min_count =
call_session_op(core, min_count, inst, MSM_VIDC_INPUT);
inst->buffers.input.extra_count =
call_session_op(core, extra_count, inst, MSM_VIDC_INPUT);
inst->buffers.input.actual_count =
inst->buffers.input.min_count +
inst->buffers.input.extra_count;
inst->buffers.input.size = f->fmt.pix.sizeimage;
f = &inst->fmts[INPUT_META_PORT];
f->type = INPUT_META_PLANE;
f->fmt.meta.dataformat = V4L2_PIX_FMT_VIDC_META;
f->fmt.meta.buffersize = call_session_op(core, buffer_size,
inst, MSM_VIDC_INPUT_META);
inst->buffers.input_meta.min_count = inst->buffers.input.min_count;
inst->buffers.input_meta.extra_count = inst->buffers.input.extra_count;
inst->buffers.input_meta.actual_count = inst->buffers.input.actual_count;
inst->buffers.input_meta.size = f->fmt.meta.buffersize;
inst->prop.frame_rate = DEFAULT_FPS << 16;
inst->prop.operating_rate = DEFAULT_FPS << 16;
return rc;
}
int msm_venc_ctrl_init(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_vidc_core *core;
d_vpr_h("%s()\n", __func__);
if (!inst || !inst->core) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
core = inst->core;
return rc;
}

457
driver/vidc/src/msm_vidc.c 一般檔案
查看文件

@@ -0,0 +1,457 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include "msm_vidc.h"
#include "msm_vidc_core.h"
#include "msm_vidc_inst.h"
#include "msm_vdec.h"
#include "msm_venc.h"
#include "msm_vidc_internal.h"
#include "msm_vidc_driver.h"
#include "msm_vidc_vb2.h"
#include "msm_vidc_v4l2.h"
#include "msm_vidc_debug.h"
#define MSM_VIDC_DRV_NAME "msm_vidc_driver"
/* kernel/msm-4.19 */
#define MSM_VIDC_VERSION ((0 << 16) + (4 << 8) + 19)
#define MAX_EVENTS 30
bool valid_v4l2_buffer(struct v4l2_buffer *b,
struct msm_vidc_inst *inst)
{
return true;
}
/*
static int get_poll_flags(struct msm_vidc_inst *inst)
{
int rc = 0;
struct vb2_queue *outq = &inst->bufq[PORT_INPUT].vb2_bufq;
struct vb2_queue *capq = &inst->bufq[PORT_OUTPUT].vb2_bufq;
struct vb2_buffer *out_vb = NULL;
struct vb2_buffer *cap_vb = NULL;
unsigned long flags = 0;
if (v4l2_event_pending(&inst->event_handler))
rc |= POLLPRI;
spin_lock_irqsave(&capq->done_lock, flags);
if (!list_empty(&capq->done_list))
cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer,
done_entry);
if (cap_vb && (cap_vb->state == VB2_BUF_STATE_DONE
|| cap_vb->state == VB2_BUF_STATE_ERROR))
rc |= POLLIN | POLLRDNORM;
spin_unlock_irqrestore(&capq->done_lock, flags);
spin_lock_irqsave(&outq->done_lock, flags);
if (!list_empty(&outq->done_list))
out_vb = list_first_entry(&outq->done_list, struct vb2_buffer,
done_entry);
if (out_vb && (out_vb->state == VB2_BUF_STATE_DONE
|| out_vb->state == VB2_BUF_STATE_ERROR))
rc |= POLLOUT | POLLWRNORM;
spin_unlock_irqrestore(&outq->done_lock, flags);
return rc;
}
*/
int msm_vidc_poll(void *instance, struct file *filp,
struct poll_table_struct *wait)
{
/*
struct msm_vidc_inst *inst = instance;
struct vb2_queue *outq = NULL;
struct vb2_queue *capq = NULL;
if (!inst)
return -EINVAL;
outq = &inst->bufq[PORT_INPUT].vb2_bufq;
capq = &inst->bufq[PORT_OUTPUT].vb2_bufq;
poll_wait(filp, &inst->event_handler.wait, wait);
poll_wait(filp, &capq->done_wq, wait);
poll_wait(filp, &outq->done_wq, wait);
return get_poll_flags(inst);
*/
return 0;
}
EXPORT_SYMBOL(msm_vidc_poll);
int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
{
struct msm_vidc_inst *inst = instance;
if (!inst || !cap)
return -EINVAL;
strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
cap->bus_info[0] = 0;
cap->version = MSM_VIDC_VERSION;
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
V4L2_CAP_VIDEO_OUTPUT_MPLANE |
V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
memset(cap->reserved, 0, sizeof(cap->reserved));
if (inst->domain == MSM_VIDC_DECODER)
strlcpy(cap->card, "msm_vidc_decoder", sizeof(cap->card));
else if (inst->domain == MSM_VIDC_ENCODER)
strlcpy(cap->card, "msm_vidc_encoder", sizeof(cap->card));
else
return -EINVAL;
return 0;
}
EXPORT_SYMBOL(msm_vidc_querycap);
int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f)
{
struct msm_vidc_inst *inst = instance;
if (!inst || !f)
return -EINVAL;
if (inst->domain == MSM_VIDC_DECODER)
return 0;//msm_vdec_enum_fmt(instance, f);
else if (inst->domain == MSM_VIDC_ENCODER)
return 0;//msm_venc_enum_fmt(instance, f);
return -EINVAL;
}
EXPORT_SYMBOL(msm_vidc_enum_fmt);
int msm_vidc_query_ctrl(void *instance, struct v4l2_queryctrl *q_ctrl)
{
int rc = 0;
struct msm_vidc_inst *inst = instance;
struct v4l2_ctrl *ctrl;
if (!inst || !q_ctrl) {
d_vpr_e("%s: invalid params %pK %pK\n",
__func__, inst, q_ctrl);
return -EINVAL;
}
ctrl = v4l2_ctrl_find(&inst->ctrl_handler, q_ctrl->id);
if (!ctrl) {
s_vpr_e(inst->sid, "%s: get_ctrl failed for id %d\n",
__func__, q_ctrl->id);
return -EINVAL;
}
q_ctrl->minimum = ctrl->minimum;
q_ctrl->maximum = ctrl->maximum;
q_ctrl->default_value = ctrl->default_value;
/* remove tier info for HEVC level */
if (q_ctrl->id == V4L2_CID_MPEG_VIDEO_HEVC_LEVEL) {
q_ctrl->minimum &= ~(0xF << 28);
q_ctrl->maximum &= ~(0xF << 28);
}
if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
q_ctrl->flags = ~(ctrl->menu_skip_mask);
} else {
q_ctrl->flags = 0;
q_ctrl->step = ctrl->step;
}
s_vpr_h(inst->sid,
"query ctrl: %s: min %d, max %d, default %d step %d flags %#x\n",
ctrl->name, q_ctrl->minimum, q_ctrl->maximum,
q_ctrl->default_value, q_ctrl->step, q_ctrl->flags);
return rc;
}
EXPORT_SYMBOL(msm_vidc_query_ctrl);
int msm_vidc_query_menu(void *instance, struct v4l2_querymenu *qmenu)
{
int rc = 0;
struct msm_vidc_inst *inst = instance;
struct v4l2_ctrl *ctrl;
if (!inst || !qmenu) {
d_vpr_e("%s: invalid params %pK %pK\n",
__func__, inst, qmenu);
return -EINVAL;
}
ctrl = v4l2_ctrl_find(&inst->ctrl_handler, qmenu->id);
if (!ctrl) {
s_vpr_e(inst->sid, "%s: get_ctrl failed for id %d\n",
__func__, qmenu->id);
return -EINVAL;
}
if (ctrl->type != V4L2_CTRL_TYPE_MENU) {
s_vpr_e(inst->sid, "%s: ctrl: %s: type (%d) is not MENU type\n",
__func__, ctrl->name, ctrl->type);
return -EINVAL;
}
if (qmenu->index < ctrl->minimum || qmenu->index > ctrl->maximum)
return -EINVAL;
if (ctrl->menu_skip_mask & (1 << qmenu->index))
rc = -EINVAL;
s_vpr_h(inst->sid,
"%s: ctrl: %s: min %d, max %d, menu_skip_mask %#x, qmenu: id %d, index %d, %s\n",
__func__, ctrl->name, ctrl->minimum, ctrl->maximum,
ctrl->menu_skip_mask, qmenu->id, qmenu->index,
rc ? "not supported" : "supported");
return rc;
}
EXPORT_SYMBOL(msm_vidc_query_menu);
int msm_vidc_s_fmt(void *instance, struct v4l2_format *f)
{
int rc = 0;
struct msm_vidc_inst *inst = instance;
if (!inst || !f)
return -EINVAL;
if (inst->domain == MSM_VIDC_DECODER)
rc = 0;//msm_vdec_s_fmt(instance, f);
if (inst->domain == MSM_VIDC_ENCODER)
rc = 0;//msm_venc_s_fmt(instance, f);
return rc;
}
EXPORT_SYMBOL(msm_vidc_s_fmt);
int msm_vidc_g_fmt(void *instance, struct v4l2_format *f)
{
int rc = 0;
struct msm_vidc_inst *inst = instance;
if (!inst || !f)
return -EINVAL;
if (inst->domain == MSM_VIDC_DECODER)
rc = 0;//msm_vdec_g_fmt(instance, f);
if (inst->domain == MSM_VIDC_ENCODER)
rc = 0;//msm_venc_g_fmt(instance, f);
return rc;
}
EXPORT_SYMBOL(msm_vidc_g_fmt);
int msm_vidc_s_ctrl(void *instance, struct v4l2_control *control)
{
struct msm_vidc_inst *inst = instance;
if (!inst || !control)
return -EINVAL;
return 0;//msm_comm_s_ctrl(instance, control);
}
EXPORT_SYMBOL(msm_vidc_s_ctrl);
int msm_vidc_g_ctrl(void *instance, struct v4l2_control *control)
{
struct msm_vidc_inst *inst = instance;
struct v4l2_ctrl *ctrl = NULL;
int rc = 0;
if (!inst || !control)
return -EINVAL;
ctrl = v4l2_ctrl_find(&inst->ctrl_handler, control->id);
if (ctrl) {
rc = 0;//try_get_ctrl_for_instance(inst, ctrl);
if (!rc)
control->value = ctrl->val;
}
return rc;
}
EXPORT_SYMBOL(msm_vidc_g_ctrl);
int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b)
{
return 0;
}
EXPORT_SYMBOL(msm_vidc_reqbufs);
int msm_vidc_qbuf(void *instance, struct media_device *mdev,
struct v4l2_buffer *b)
{
return 0;
}
EXPORT_SYMBOL(msm_vidc_qbuf);
int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
{
return 0;
}
EXPORT_SYMBOL(msm_vidc_dqbuf);
int msm_vidc_streamon(void *instance, enum v4l2_buf_type i)
{
return 0;
}
EXPORT_SYMBOL(msm_vidc_streamon);
int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i)
{
return 0;
}
EXPORT_SYMBOL(msm_vidc_streamoff);
int msm_vidc_cmd(void *instance, union msm_v4l2_cmd *cmd)
{
return 0;
}
EXPORT_SYMBOL(msm_vidc_cmd);
int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize)
{
return 0;
}
EXPORT_SYMBOL(msm_vidc_enum_framesizes);
int msm_vidc_subscribe_event(void *inst,
const struct v4l2_event_subscription *sub)
{
int rc = 0;
struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
if (!inst || !sub)
return -EINVAL;
rc = v4l2_event_subscribe(&vidc_inst->event_handler,
sub, MAX_EVENTS, NULL);
return rc;
}
EXPORT_SYMBOL(msm_vidc_subscribe_event);
int msm_vidc_unsubscribe_event(void *inst,
const struct v4l2_event_subscription *sub)
{
int rc = 0;
struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
if (!inst || !sub)
return -EINVAL;
rc = v4l2_event_unsubscribe(&vidc_inst->event_handler, sub);
return rc;
}
EXPORT_SYMBOL(msm_vidc_unsubscribe_event);
int msm_vidc_dqevent(void *inst, struct v4l2_event *event)
{
int rc = 0;
struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
if (!inst || !event)
return -EINVAL;
rc = v4l2_event_dequeue(&vidc_inst->event_handler, event, false);
return rc;
}
EXPORT_SYMBOL(msm_vidc_dqevent);
void *msm_vidc_open(void *vidc_core, u32 session_type)
{
int rc = 0;
struct msm_vidc_inst *inst;
struct msm_vidc_core *core;
d_vpr_h("%s()\n", __func__);
core = vidc_core;
if (!core) {
d_vpr_e("%s: invalid params\n", __func__);
return NULL;
}
if (session_type != MSM_VIDC_DECODER &&
session_type != MSM_VIDC_ENCODER) {
d_vpr_e("%s: invalid session_type %d\n",
__func__, session_type);
return NULL;
}
if (core->state == MSM_VIDC_CORE_ERROR) {
d_vpr_e("%s: core invalid state\n", __func__);
return NULL;
}
if (core->state == MSM_VIDC_CORE_DEINIT) {
rc = msm_vidc_core_init(core);
if (rc)
return NULL;
}
inst = kzalloc(sizeof(*inst), GFP_KERNEL);
if (!inst) {
d_vpr_e("%s: failed to allocate inst memory\n", __func__);
return NULL;
}
inst->core = core;
rc = msm_vidc_add_session(inst);
if (rc) {
d_vpr_e("%s: failed to get session id\n", __func__);
return NULL;
}
s_vpr_i(inst->sid, "Opening video instance: %d\n", session_type);
kref_init(&inst->kref);
INIT_LIST_HEAD(&inst->buffers.input.list);
INIT_LIST_HEAD(&inst->buffers.input_meta.list);
INIT_LIST_HEAD(&inst->buffers.output.list);
INIT_LIST_HEAD(&inst->buffers.output_meta.list);
INIT_LIST_HEAD(&inst->buffers.scratch.list);
INIT_LIST_HEAD(&inst->buffers.scratch_1.list);
INIT_LIST_HEAD(&inst->buffers.scratch_2.list);
INIT_LIST_HEAD(&inst->buffers.persist.list);
INIT_LIST_HEAD(&inst->buffers.persist_1.list);
inst->domain = session_type;
inst->state = MSM_VIDC_OPEN;
//inst->debugfs_root =
// msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
if (is_decode_session(inst)) {
rc = msm_vdec_inst_init(inst);
if (rc)
goto error;
rc = msm_vdec_ctrl_init(inst);
if (rc)
goto error;
} else if (is_encode_session(inst)) {
rc = msm_venc_inst_init(inst);
if (rc)
goto error;
rc = msm_venc_ctrl_init(inst);
if (rc)
goto error;
}
rc = msm_vidc_queue_init(inst);
if (rc)
goto error;
rc = msm_vidc_setup_event_queue(inst);
if (rc)
goto error;
//msm_power_setup(inst);
// send cmd to firmware here
return inst;
error:
msm_vidc_close(inst);
return NULL;
}
EXPORT_SYMBOL(msm_vidc_open);
int msm_vidc_close(void *instance)
{
return 0;
}
EXPORT_SYMBOL(msm_vidc_close);

查看文件

@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include "msm_vidc_debug.h"
int msm_vidc_debug = VIDC_HIGH | VIDC_LOW | VIDC_PKT | VIDC_ERR | VIDC_PRINTK |
FW_ERROR | FW_FATAL | FW_FTRACE;
EXPORT_SYMBOL(msm_vidc_debug);
bool msm_vidc_lossless_encode = !true;
EXPORT_SYMBOL(msm_vidc_lossless_encode);
bool msm_vidc_syscache_disable = !true;
EXPORT_SYMBOL(msm_vidc_syscache_disable);

查看文件

@@ -0,0 +1,151 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include <linux/iommu.h>
#include <linux/workqueue.h>
#include <media/msm_vidc_utils.h>
#include <media/msm_media_info.h>
#include "msm_vidc_driver.h"
#include "msm_vidc_internal.h"
#include "msm_vidc_debug.h"
#include "venus_hfi.h"
u32 msm_vidc_convert_color_fmt(u32 v4l2_fmt)
{
switch (v4l2_fmt) {
case V4L2_PIX_FMT_NV12:
return COLOR_FMT_NV12;
case V4L2_PIX_FMT_NV21:
return COLOR_FMT_NV21;
case V4L2_PIX_FMT_NV12_512:
return COLOR_FMT_NV12_512;
case V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS:
return COLOR_FMT_P010;
case V4L2_PIX_FMT_NV12_UBWC:
return COLOR_FMT_NV12_UBWC;
case V4L2_PIX_FMT_NV12_TP10_UBWC:
return COLOR_FMT_NV12_BPP10_UBWC;
case V4L2_PIX_FMT_RGBA8888_UBWC:
return COLOR_FMT_RGBA8888_UBWC;
default:
d_vpr_e(
"Invalid v4l2 color fmt FMT : %x, Set default(NV12)",
v4l2_fmt);
return COLOR_FMT_NV12;
}
}
int msm_vidc_setup_event_queue(struct msm_vidc_inst *inst)
{
int rc = 0;
return rc;
}
int msm_vidc_queue_init(struct msm_vidc_inst *inst)
{
int rc = 0;
return rc;
}
int msm_vidc_add_session(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_vidc_inst *i;
struct msm_vidc_core *core;
u32 count = 0;
if (!inst || !inst->core) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
core = inst->core;
mutex_lock(&core->lock);
list_for_each_entry(i, &core->instances, list)
count++;
if (count < MAX_SUPPORTED_INSTANCES) {
list_add_tail(&inst->list, &core->instances);
} else {
d_vpr_e("%s: total sessions %d reached max limit %d\n",
__func__, count, MAX_SUPPORTED_INSTANCES);
rc = -EINVAL;
}
mutex_unlock(&core->lock);
/* assign session_id */
inst->session_id = count + 1;
inst->sid = inst->session_id;
return rc;
}
int msm_vidc_core_init(struct msm_vidc_core *core)
{
int rc;
d_vpr_h("%s()\n", __func__);
if (!core) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
mutex_lock(&core->lock);
if (core->state == MSM_VIDC_CORE_ERROR) {
d_vpr_e("%s: core invalid state\n", __func__);
rc = -EINVAL;
goto unlock;
}
if (core->state == MSM_VIDC_CORE_INIT) {
rc = 0;
goto unlock;
}
rc = venus_hfi_core_init(core);
if (rc) {
d_vpr_e("%s: core init failed\n", __func__);
core->state = MSM_VIDC_CORE_DEINIT;
goto unlock;
}
core->state = MSM_VIDC_CORE_INIT;
core->smmu_fault_handled = false;
core->ssr.trigger = false;
unlock:
mutex_unlock(&core->lock);
return rc;
}
int msm_vidc_smmu_fault_handler(struct iommu_domain *domain,
struct device *dev, unsigned long iova, int flags, void *data)
{
return -EINVAL;
}
int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
enum msm_vidc_ssr_trigger_type type)
{
return 0;
}
void msm_vidc_ssr_handler(struct work_struct *work)
{
}
void msm_vidc_pm_work_handler(struct work_struct *work)
{
}
void msm_vidc_fw_unload_handler(struct work_struct *work)
{
}
void msm_vidc_batch_handler(struct work_struct *work)
{
}

查看文件

@@ -0,0 +1,970 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include <linux/iommu.h>
#include <linux/of.h>
#include <linux/sort.h>
#include "msm_vidc_dt.h"
#include "msm_vidc_internal.h"
#include "msm_vidc_core.h"
#include "msm_vidc_debug.h"
#include "msm_vidc_driver.h"
static size_t get_u32_array_num_elements(struct device_node *np,
char *name)
{
int len;
size_t num_elements = 0;
if (!of_get_property(np, name, &len)) {
d_vpr_e("Failed to read %s from device tree\n", name);
goto fail_read;
}
num_elements = len / sizeof(u32);
if (num_elements <= 0) {
d_vpr_e("%s not specified in device tree\n", name);
goto fail_read;
}
return num_elements;
fail_read:
return 0;
}
/**
* msm_vidc_load_u32_table() - load dtsi table entries
* @pdev: A pointer to the platform device.
* @of_node: A pointer to the device node.
* @table_name: A pointer to the dtsi table entry name.
* @struct_size: The size of the structure which is nothing but
* a single entry in the dtsi table.
* @table: A pointer to the table pointer which needs to be
* filled by the dtsi table entries.
* @num_elements: Number of elements pointer which needs to be filled
* with the number of elements in the table.
*
* This is a generic implementation to load single or multiple array
* table from dtsi. The array elements should be of size equal to u32.
*
* Return: Return '0' for success else appropriate error value.
*/
static int msm_vidc_load_u32_table(struct platform_device *pdev,
struct device_node *of_node, char *table_name, int struct_size,
u32 **table, u32 *num_elements)
{
int rc = 0, num_elemts = 0;
u32 *ptbl = NULL;
if (!of_find_property(of_node, table_name, NULL)) {
d_vpr_h("%s not found\n", table_name);
return 0;
}
num_elemts = get_u32_array_num_elements(of_node, table_name);
if (!num_elemts) {
d_vpr_e("no elements in %s\n", table_name);
return 0;
}
num_elemts /= struct_size / sizeof(u32);
ptbl = devm_kzalloc(&pdev->dev, num_elemts * struct_size, GFP_KERNEL);
if (!ptbl) {
d_vpr_e("Failed to alloc table %s\n", table_name);
return -ENOMEM;
}
if (of_property_read_u32_array(of_node, table_name, ptbl,
num_elemts * struct_size / sizeof(u32))) {
d_vpr_e("Failed to read %s\n", table_name);
return -EINVAL;
}
*table = ptbl;
if (num_elements)
*num_elements = num_elemts;
return rc;
}
/* A comparator to compare loads (needed later on) */
static int cmp(const void *a, const void *b)
{
/* want to sort in reverse so flip the comparison */
return ((struct allowed_clock_rates_table *)b)->clock_rate -
((struct allowed_clock_rates_table *)a)->clock_rate;
}
static void msm_vidc_free_allowed_clocks_table(struct msm_vidc_dt *dt)
{
dt->allowed_clks_tbl = NULL;
}
static void msm_vidc_free_reg_table(struct msm_vidc_dt *dt)
{
dt->reg_set.reg_tbl = NULL;
}
static void msm_vidc_free_qdss_addr_table(struct msm_vidc_dt *dt)
{
dt->qdss_addr_set.addr_tbl = NULL;
}
static void msm_vidc_free_bus_table(struct msm_vidc_dt *dt)
{
dt->bus_set.bus_tbl = NULL;
dt->bus_set.count = 0;
}
static void msm_vidc_free_buffer_usage_table(struct msm_vidc_dt *dt)
{
dt->buffer_usage_set.buffer_usage_tbl = NULL;
}
static void msm_vidc_free_regulator_table(struct msm_vidc_dt *dt)
{
int c = 0;
for (c = 0; c < dt->regulator_set.count; ++c) {
struct regulator_info *rinfo =
&dt->regulator_set.regulator_tbl[c];
rinfo->name = NULL;
}
dt->regulator_set.regulator_tbl = NULL;
dt->regulator_set.count = 0;
}
static void msm_vidc_free_clock_table(struct msm_vidc_dt *dt)
{
dt->clock_set.clock_tbl = NULL;
dt->clock_set.count = 0;
}
static int msm_vidc_load_fw_name(struct msm_vidc_core *core)
{
struct platform_device *pdev = core->pdev;
return of_property_read_string_index(pdev->dev.of_node,
"vidc,firmware-name", 0, &core->dt->fw_name);
}
static int msm_vidc_load_reg_table(struct msm_vidc_core *core)
{
struct reg_set *reg_set;
struct platform_device *pdev = core->pdev;
struct msm_vidc_dt *dt = core->dt;
int i;
int rc = 0;
if (!of_find_property(pdev->dev.of_node, "qcom,reg-presets", NULL)) {
/*
* qcom,reg-presets is an optional property. It likely won't be
* present if we don't have any register settings to program
*/
d_vpr_h("reg-presets not found\n");
return 0;
}
reg_set = &dt->reg_set;
reg_set->count = get_u32_array_num_elements(pdev->dev.of_node,
"qcom,reg-presets");
reg_set->count /= sizeof(*reg_set->reg_tbl) / sizeof(u32);
if (!reg_set->count) {
d_vpr_h("no elements in reg set\n");
return rc;
}
reg_set->reg_tbl = devm_kzalloc(&pdev->dev, reg_set->count *
sizeof(*(reg_set->reg_tbl)), GFP_KERNEL);
if (!reg_set->reg_tbl) {
d_vpr_e("%s: Failed to alloc register table\n", __func__);
return -ENOMEM;
}
if (of_property_read_u32_array(pdev->dev.of_node, "qcom,reg-presets",
(u32 *)reg_set->reg_tbl, reg_set->count * 3)) {
d_vpr_e("Failed to read register table\n");
msm_vidc_free_reg_table(core->dt);
return -EINVAL;
}
for (i = 0; i < reg_set->count; i++) {
d_vpr_h("reg = %#x, value = %#x, mask = %#x\n",
reg_set->reg_tbl[i].reg, reg_set->reg_tbl[i].value,
reg_set->reg_tbl[i].mask);
}
return rc;
}
static int msm_vidc_load_qdss_table(struct msm_vidc_core *core)
{
struct addr_set *qdss_addr_set;
struct platform_device *pdev = core->pdev;
struct msm_vidc_dt *dt = core->dt;
int i;
int rc = 0;
if (!of_find_property(pdev->dev.of_node, "qcom,qdss-presets", NULL)) {
/*
* qcom,qdss-presets is an optional property. It likely won't be
* present if we don't have any register settings to program
*/
d_vpr_h("qdss-presets not found\n");
return rc;
}
qdss_addr_set = &dt->qdss_addr_set;
qdss_addr_set->count = get_u32_array_num_elements(pdev->dev.of_node,
"qcom,qdss-presets");
qdss_addr_set->count /= sizeof(*qdss_addr_set->addr_tbl) / sizeof(u32);
if (!qdss_addr_set->count) {
d_vpr_h("no elements in qdss reg set\n");
return rc;
}
qdss_addr_set->addr_tbl = devm_kzalloc(&pdev->dev,
qdss_addr_set->count * sizeof(*qdss_addr_set->addr_tbl),
GFP_KERNEL);
if (!qdss_addr_set->addr_tbl) {
d_vpr_e("%s: Failed to alloc register table\n", __func__);
rc = -ENOMEM;
goto err_qdss_addr_tbl;
}
rc = of_property_read_u32_array(pdev->dev.of_node, "qcom,qdss-presets",
(u32 *)qdss_addr_set->addr_tbl, qdss_addr_set->count * 2);
if (rc) {
d_vpr_e("Failed to read qdss address table\n");
msm_vidc_free_qdss_addr_table(core->dt);
rc = -EINVAL;
goto err_qdss_addr_tbl;
}
for (i = 0; i < qdss_addr_set->count; i++) {
d_vpr_h("qdss addr = %x, value = %x\n",
qdss_addr_set->addr_tbl[i].start,
qdss_addr_set->addr_tbl[i].size);
}
err_qdss_addr_tbl:
return rc;
}
static int msm_vidc_load_subcache_info(struct msm_vidc_core *core)
{
int rc = 0, num_subcaches = 0, c;
struct platform_device *pdev = core->pdev;
struct msm_vidc_dt *dt = core->dt;
struct subcache_set *subcaches = &dt->subcache_set;
num_subcaches = of_property_count_strings(pdev->dev.of_node,
"cache-slice-names");
if (num_subcaches <= 0) {
d_vpr_h("No subcaches found\n");
goto err_load_subcache_table_fail;
}
subcaches->subcache_tbl = devm_kzalloc(&pdev->dev,
sizeof(*subcaches->subcache_tbl) * num_subcaches, GFP_KERNEL);
if (!subcaches->subcache_tbl) {
d_vpr_e("Failed to allocate memory for subcache tbl\n");
rc = -ENOMEM;
goto err_load_subcache_table_fail;
}
subcaches->count = num_subcaches;
d_vpr_h("Found %d subcaches\n", num_subcaches);
for (c = 0; c < num_subcaches; ++c) {
struct subcache_info *vsc = &dt->subcache_set.subcache_tbl[c];
of_property_read_string_index(pdev->dev.of_node,
"cache-slice-names", c, &vsc->name);
}
dt->sys_cache_present = true;
return 0;
err_load_subcache_table_fail:
dt->sys_cache_present = false;
subcaches->count = 0;
subcaches->subcache_tbl = NULL;
return rc;
}
static int msm_vidc_load_allowed_clocks_table(
struct msm_vidc_core *core)
{
int rc = 0;
struct platform_device *pdev = core->pdev;
struct msm_vidc_dt *dt = core->dt;
if (!of_find_property(pdev->dev.of_node,
"qcom,allowed-clock-rates", NULL)) {
d_vpr_h("allowed-clock-rates not found\n");
return 0;
}
rc = msm_vidc_load_u32_table(pdev, pdev->dev.of_node,
"qcom,allowed-clock-rates",
sizeof(*dt->allowed_clks_tbl),
(u32 **)&dt->allowed_clks_tbl,
&dt->allowed_clks_tbl_size);
if (rc) {
d_vpr_e("%s: failed to read allowed clocks table\n", __func__);
return rc;
}
sort(dt->allowed_clks_tbl, dt->allowed_clks_tbl_size,
sizeof(*dt->allowed_clks_tbl), cmp, NULL);
return 0;
}
static int msm_vidc_load_bus_table(struct msm_vidc_core *core)
{
struct platform_device *pdev = core->pdev;
struct msm_vidc_dt *dt = core->dt;
struct bus_set *buses = &dt->bus_set;
int c = 0, num_buses = 0, rc = 0;
u32 *bus_ranges = NULL;
num_buses = of_property_count_strings(pdev->dev.of_node,
"interconnect-names");
if (num_buses <= 0) {
d_vpr_e("No buses found\n");
return -EINVAL;
}
buses->count = num_buses;
d_vpr_h("Found %d bus interconnects\n", num_buses);
bus_ranges = kzalloc(2 * num_buses * sizeof(*bus_ranges), GFP_KERNEL);
if (!bus_ranges) {
d_vpr_e("No memory to read bus ranges\n");
return -ENOMEM;
}
rc = of_property_read_u32_array(pdev->dev.of_node,
"qcom,bus-range-kbps", bus_ranges,
num_buses * 2);
if (rc) {
d_vpr_e(
"Failed to read bus ranges: defaulting to <0 INT_MAX>\n");
for (c = 0; c < num_buses; c++) {
bus_ranges[c * 2] = 0;
bus_ranges[c * 2 + 1] = INT_MAX;
}
}
buses->bus_tbl = devm_kzalloc(&pdev->dev, num_buses *
sizeof(*buses->bus_tbl), GFP_KERNEL);
if (!buses->bus_tbl) {
d_vpr_e("No memory for bus table\n");
rc = -ENOMEM;
goto exit;
}
for (c = 0; c < num_buses; c++) {
struct bus_info *bus = &dt->bus_set.bus_tbl[c];
of_property_read_string_index(pdev->dev.of_node,
"interconnect-names", c, &bus->name);
bus->dev = &pdev->dev;
bus->range[0] = bus_ranges[c * 2];
bus->range[1] = bus_ranges[c * 2 + 1];
d_vpr_h("Found bus %s\n", bus->name);
}
exit:
kfree(bus_ranges);
return rc;
}
/* TODO: move this to platform data */
static int msm_vidc_load_buffer_usage_table(struct msm_vidc_core *core)
{
int rc = 0;
struct platform_device *pdev = core->pdev;
struct msm_vidc_dt *dt = core->dt;
struct buffer_usage_set *buffer_usage_set = &dt->buffer_usage_set;
if (!of_find_property(pdev->dev.of_node,
"qcom,buffer-type-tz-usage-table", NULL)) {
/*
* qcom,buffer-type-tz-usage-table is an optional property. It
* likely won't be present if the core doesn't support content
* protection
*/
d_vpr_h("buffer-type-tz-usage-table not found\n");
return 0;
}
buffer_usage_set->count = get_u32_array_num_elements(
pdev->dev.of_node, "qcom,buffer-type-tz-usage-table");
buffer_usage_set->count /=
sizeof(*buffer_usage_set->buffer_usage_tbl) / sizeof(u32);
if (!buffer_usage_set->count) {
d_vpr_h("no elements in buffer usage set\n");
return 0;
}
buffer_usage_set->buffer_usage_tbl = devm_kzalloc(&pdev->dev,
buffer_usage_set->count *
sizeof(*buffer_usage_set->buffer_usage_tbl),
GFP_KERNEL);
if (!buffer_usage_set->buffer_usage_tbl) {
d_vpr_e("%s: Failed to alloc buffer usage table\n",
__func__);
rc = -ENOMEM;
goto err_load_buf_usage;
}
rc = of_property_read_u32_array(pdev->dev.of_node,
"qcom,buffer-type-tz-usage-table",
(u32 *)buffer_usage_set->buffer_usage_tbl,
buffer_usage_set->count *
sizeof(*buffer_usage_set->buffer_usage_tbl) / sizeof(u32));
if (rc) {
d_vpr_e("Failed to read buffer usage table\n");
goto err_load_buf_usage;
}
return 0;
err_load_buf_usage:
msm_vidc_free_buffer_usage_table(core->dt);
return rc;
}
static int msm_vidc_load_regulator_table(struct msm_vidc_core *core)
{
int rc = 0;
struct platform_device *pdev = core->pdev;
struct msm_vidc_dt *dt = core->dt;
struct regulator_set *regulators = &dt->regulator_set;
struct device_node *domains_parent_node = NULL;
struct property *domains_property = NULL;
int reg_count = 0;
regulators->count = 0;
regulators->regulator_tbl = NULL;
domains_parent_node = pdev->dev.of_node;
for_each_property_of_node(domains_parent_node, domains_property) {
const char *search_string = "-supply";
char *supply;
bool matched = false;
/* check if current property is possibly a regulator */
supply = strnstr(domains_property->name, search_string,
strlen(domains_property->name) + 1);
matched = supply && (*(supply + strlen(search_string)) == '\0');
if (!matched)
continue;
reg_count++;
}
regulators->regulator_tbl = devm_kzalloc(&pdev->dev,
sizeof(*regulators->regulator_tbl) *
reg_count, GFP_KERNEL);
if (!regulators->regulator_tbl) {
rc = -ENOMEM;
d_vpr_e("Failed to alloc memory for regulator table\n");
goto err_reg_tbl_alloc;
}
for_each_property_of_node(domains_parent_node, domains_property) {
const char *search_string = "-supply";
char *supply;
bool matched = false;
struct device_node *regulator_node = NULL;
struct regulator_info *rinfo = NULL;
/* check if current property is possibly a regulator */
supply = strnstr(domains_property->name, search_string,
strlen(domains_property->name) + 1);
matched = supply && (supply[strlen(search_string)] == '\0');
if (!matched)
continue;
/* make sure prop isn't being misused */
regulator_node = of_parse_phandle(domains_parent_node,
domains_property->name, 0);
if (IS_ERR(regulator_node)) {
d_vpr_e("%s is not a phandle\n",
domains_property->name);
continue;
}
regulators->count++;
/* populate regulator info */
rinfo = &regulators->regulator_tbl[regulators->count - 1];
rinfo->name = devm_kzalloc(&pdev->dev,
(supply - domains_property->name) + 1, GFP_KERNEL);
if (!rinfo->name) {
rc = -ENOMEM;
d_vpr_e("Failed to alloc memory for regulator name\n");
goto err_reg_name_alloc;
}
strlcpy(rinfo->name, domains_property->name,
(supply - domains_property->name) + 1);
rinfo->has_hw_power_collapse = of_property_read_bool(
regulator_node, "qcom,support-hw-trigger");
d_vpr_h("Found regulator %s: h/w collapse = %s\n",
rinfo->name,
rinfo->has_hw_power_collapse ? "yes" : "no");
}
if (!regulators->count)
d_vpr_h("No regulators found");
return 0;
err_reg_name_alloc:
err_reg_tbl_alloc:
msm_vidc_free_regulator_table(core->dt);
return rc;
}
static int msm_vidc_load_clock_table(struct msm_vidc_core *core)
{
int rc = 0, num_clocks = 0, c = 0;
struct platform_device *pdev = core->pdev;
struct msm_vidc_dt *dt = core->dt;
int *clock_props = NULL;
struct clock_set *clocks = &dt->clock_set;
num_clocks = of_property_count_strings(pdev->dev.of_node,
"clock-names");
if (num_clocks <= 0) {
d_vpr_h("No clocks found\n");
clocks->count = 0;
rc = 0;
goto err_load_clk_table_fail;
}
clock_props = devm_kzalloc(&pdev->dev, num_clocks *
sizeof(*clock_props), GFP_KERNEL);
if (!clock_props) {
d_vpr_e("No memory to read clock properties\n");
rc = -ENOMEM;
goto err_load_clk_table_fail;
}
rc = of_property_read_u32_array(pdev->dev.of_node,
"qcom,clock-configs", clock_props,
num_clocks);
if (rc) {
d_vpr_e("Failed to read clock properties: %d\n", rc);
goto err_load_clk_prop_fail;
}
clocks->clock_tbl = devm_kzalloc(&pdev->dev, sizeof(*clocks->clock_tbl)
* num_clocks, GFP_KERNEL);
if (!clocks->clock_tbl) {
d_vpr_e("Failed to allocate memory for clock tbl\n");
rc = -ENOMEM;
goto err_load_clk_prop_fail;
}
clocks->count = num_clocks;
d_vpr_h("Found %d clocks\n", num_clocks);
for (c = 0; c < num_clocks; ++c) {
struct clock_info *vc = &dt->clock_set.clock_tbl[c];
of_property_read_string_index(pdev->dev.of_node,
"clock-names", c, &vc->name);
if (clock_props[c] & CLOCK_PROP_HAS_SCALING) {
vc->has_scaling = true;
} else {
vc->has_scaling = false;
}
if (clock_props[c] & CLOCK_PROP_HAS_MEM_RETENTION)
vc->has_mem_retention = true;
else
vc->has_mem_retention = false;
d_vpr_h("Found clock %s: scale-able = %s\n", vc->name,
vc->has_scaling ? "yes" : "no");
}
return 0;
err_load_clk_prop_fail:
err_load_clk_table_fail:
return rc;
}
static int msm_vidc_load_reset_table(struct msm_vidc_core *core)
{
struct platform_device *pdev = core->pdev;
struct msm_vidc_dt *dt = core->dt;
struct reset_set *rst = &dt->reset_set;
int num_clocks = 0, c = 0;
num_clocks = of_property_count_strings(pdev->dev.of_node,
"reset-names");
if (num_clocks <= 0) {
d_vpr_h("No reset clocks found\n");
rst->count = 0;
return 0;
}
rst->reset_tbl = devm_kcalloc(&pdev->dev, num_clocks,
sizeof(*rst->reset_tbl), GFP_KERNEL);
if (!rst->reset_tbl)
return -ENOMEM;
rst->count = num_clocks;
d_vpr_h("Found %d reset clocks\n", num_clocks);
for (c = 0; c < num_clocks; ++c) {
struct reset_info *rc = &dt->reset_set.reset_tbl[c];
of_property_read_string_index(pdev->dev.of_node,
"reset-names", c, &rc->name);
}
return 0;
}
static int msm_decide_dt_node(struct msm_vidc_core *core)
{
int rc = 0;
struct platform_device *pdev = core->pdev;
u32 sku_index = 0;
rc = of_property_read_u32(pdev->dev.of_node, "sku-index",
&sku_index);
if (rc) {
d_vpr_h("'sku_index' not found in node\n");
return 0;
}
return 0;
}
static int msm_vidc_read_resources_from_dt(struct platform_device *pdev)
{
int rc = 0;
struct msm_vidc_core *core;
struct msm_vidc_dt *dt;
struct resource *kres;
if (!pdev) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
core = dev_get_drvdata(&pdev->dev);
if (!core || !core->dt) {
d_vpr_e("%s: core not found in device %s",
dev_name(&pdev->dev));
return -EINVAL;
}
dt = core->dt;
rc = msm_decide_dt_node(core);
if (rc)
return rc;
INIT_LIST_HEAD(&dt->context_banks);
kres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dt->register_base = kres ? kres->start : -1;
dt->register_size = kres ? (kres->end + 1 - kres->start) : -1;
kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
dt->irq = kres ? kres->start : -1;
rc = msm_vidc_load_fw_name(core);
if (rc)
d_vpr_e("%s: failed to load fw name, rc %d, using default fw\n",
__func__, rc);
rc = msm_vidc_load_subcache_info(core);
if (rc)
d_vpr_e("Failed to load subcache info: %d\n", rc);
rc = msm_vidc_load_qdss_table(core);
if (rc)
d_vpr_e("Failed to load qdss reg table: %d\n", rc);
rc = msm_vidc_load_reg_table(core);
if (rc) {
d_vpr_e("Failed to load reg table: %d\n", rc);
goto err_load_reg_table;
}
// TODO: move this table to platform
rc = msm_vidc_load_buffer_usage_table(core);
if (rc) {
d_vpr_e("Failed to load buffer usage table: %d\n", rc);
goto err_load_buffer_usage_table;
}
rc = msm_vidc_load_regulator_table(core);
if (rc) {
d_vpr_e("Failed to load list of regulators %d\n", rc);
goto err_load_regulator_table;
}
rc = msm_vidc_load_bus_table(core);
if (rc) {
d_vpr_e("Failed to load bus table: %d\n", rc);
goto err_load_bus_table;
}
rc = msm_vidc_load_clock_table(core);
if (rc) {
d_vpr_e("Failed to load clock table: %d\n", rc);
goto err_load_clock_table;
}
// TODO: move this table to platform
rc = msm_vidc_load_allowed_clocks_table(core);
if (rc) {
d_vpr_e("Failed to load allowed clocks table: %d\n", rc);
goto err_load_allowed_clocks_table;
}
rc = msm_vidc_load_reset_table(core);
if (rc) {
d_vpr_e("Failed to load reset table: %d\n", rc);
goto err_load_reset_table;
}
return rc;
err_load_reset_table:
msm_vidc_free_allowed_clocks_table(core->dt);
err_load_allowed_clocks_table:
msm_vidc_free_clock_table(core->dt);
err_load_clock_table:
msm_vidc_free_bus_table(core->dt);
err_load_bus_table:
msm_vidc_free_regulator_table(core->dt);
err_load_regulator_table:
msm_vidc_free_buffer_usage_table(core->dt);
err_load_buffer_usage_table:
msm_vidc_free_reg_table(core->dt);
err_load_reg_table:
return rc;
}
static int msm_vidc_setup_context_bank(struct msm_vidc_core *core,
struct context_bank_info *cb, struct device *dev)
{
int rc = 0;
struct bus_type *bus;
if (!core || !dev || !cb) {
d_vpr_e("%s: Invalid Input params\n", __func__);
return -EINVAL;
}
cb->dev = dev;
bus = cb->dev->bus;
if (IS_ERR_OR_NULL(bus)) {
d_vpr_e("%s: failed to get bus type\n", __func__);
rc = PTR_ERR(bus) ? PTR_ERR(bus) : -ENODEV;
goto remove_cb;
}
cb->domain = iommu_get_domain_for_dev(cb->dev);
/*
* configure device segment size and segment boundary to ensure
* iommu mapping returns one mapping (which is required for partial
* cache operations)
*/
if (!dev->dma_parms)
dev->dma_parms =
devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
dma_set_max_seg_size(dev, (unsigned int)DMA_BIT_MASK(32));
dma_set_seg_boundary(dev, (unsigned long)DMA_BIT_MASK(64));
d_vpr_h("Attached %s and created mapping\n", dev_name(dev));
d_vpr_h(
"Context bank: %s, buffer_type: %#x, is_secure: %d, address range start: %#x, size: %#x, dev: %pK, domain: %pK",
cb->name, cb->buffer_type, cb->is_secure, cb->addr_range.start,
cb->addr_range.size, cb->dev, cb->domain);
remove_cb:
return rc;
}
static int msm_vidc_populate_context_bank(struct device *dev,
struct msm_vidc_core *core)
{
int rc = 0;
struct context_bank_info *cb = NULL;
struct device_node *np = NULL;
if (!dev || !core || !core->dt) {
d_vpr_e("%s: invalid inputs\n", __func__);
return -EINVAL;
}
np = dev->of_node;
cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL);
if (!cb) {
d_vpr_e("%s: Failed to allocate cb\n", __func__);
return -ENOMEM;
}
INIT_LIST_HEAD(&cb->list);
list_add_tail(&cb->list, &core->dt->context_banks);
rc = of_property_read_string(np, "label", &cb->name);
if (rc) {
d_vpr_h("Failed to read cb label from device tree\n");
rc = 0;
}
d_vpr_h("%s: context bank has name %s\n", __func__, cb->name);
rc = of_property_read_u32_array(np, "virtual-addr-pool",
(u32 *)&cb->addr_range, 2);
if (rc) {
d_vpr_e("Could not read addr pool: context bank: %s %d\n",
cb->name, rc);
goto err_setup_cb;
}
cb->is_secure = of_property_read_bool(np, "qcom,secure-context-bank");
d_vpr_h("context bank %s: secure = %d\n",
cb->name, cb->is_secure);
/* setup buffer type for each sub device*/
rc = of_property_read_u32(np, "buffer-types", &cb->buffer_type);
if (rc) {
d_vpr_e("failed to load buffer_type info %d\n", rc);
rc = -ENOENT;
goto err_setup_cb;
}
d_vpr_h("context bank %s address start %x size %x buffer_type %x\n",
cb->name, cb->addr_range.start,
cb->addr_range.size, cb->buffer_type);
rc = msm_vidc_setup_context_bank(core, cb, dev);
if (rc) {
d_vpr_e("Cannot setup context bank %d\n", rc);
goto err_setup_cb;
}
iommu_set_fault_handler(cb->domain,
msm_vidc_smmu_fault_handler, (void *)core);
return 0;
err_setup_cb:
list_del(&cb->list);
return rc;
}
int msm_vidc_read_context_bank_resources_from_dt(struct platform_device *pdev)
{
struct msm_vidc_core *core;
int rc = 0;
if (!pdev) {
d_vpr_e("Invalid platform device\n");
return -EINVAL;
} else if (!pdev->dev.parent) {
d_vpr_e("Failed to find a parent for %s\n",
dev_name(&pdev->dev));
return -ENODEV;
}
core = dev_get_drvdata(pdev->dev.parent);
if (!core) {
d_vpr_e("Failed to find cookie in parent device %s",
dev_name(pdev->dev.parent));
return -EINVAL;
}
rc = msm_vidc_populate_context_bank(&pdev->dev, core);
if (rc)
d_vpr_e("Failed to probe context bank\n");
else
d_vpr_h("Successfully probed context bank\n");
return rc;
}
void msm_vidc_deinit_dt(struct platform_device *pdev)
{
struct msm_vidc_core *core;
if (!pdev) {
d_vpr_e("%s: invalid params\n", __func__);
return;
}
core = dev_get_drvdata(&pdev->dev);
if (!core) {
d_vpr_e("%s: core not found in device %s",
dev_name(&pdev->dev));
return;
} else if (!core->dt) {
d_vpr_e("%s: invalid dt in device %s",
dev_name(&pdev->dev));
return;
}
msm_vidc_free_clock_table(core->dt);
msm_vidc_free_regulator_table(core->dt);
msm_vidc_free_allowed_clocks_table(core->dt);
msm_vidc_free_reg_table(core->dt);
msm_vidc_free_qdss_addr_table(core->dt);
msm_vidc_free_bus_table(core->dt);
msm_vidc_free_buffer_usage_table(core->dt);
}
int msm_vidc_init_dt(struct platform_device *pdev)
{
int rc = 0;
struct msm_vidc_dt *dt;
struct msm_vidc_core *core;
if (!pdev) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
core = dev_get_drvdata(&pdev->dev);
if (!core) {
d_vpr_e("%s: core not found in device %s",
dev_name(&pdev->dev));
return -EINVAL;
}
dt = kzalloc(sizeof(struct msm_vidc_dt), GFP_KERNEL);
if (!dt)
return -ENOMEM;
core->dt = dt;
dt->core = core;
rc = msm_vidc_read_resources_from_dt(pdev);
if (rc)
return rc;
return 0;
}

查看文件

@@ -0,0 +1,407 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include <linux/dma-buf.h>
#include <linux/msm_ion.h>
#include <linux/ion.h>
#include "msm_vidc_memory.h"
#include "msm_vidc_debug.h"
#include "msm_vidc_internal.h"
#include "msm_vidc_dt.h"
#include "msm_vidc_core.h"
static int get_ion_secure_flag(enum msm_vidc_buffer_region region)
{
u32 ion_flag = 0;
switch (region) {
case MSM_VIDC_SECURE_PIXEL:
ion_flag = ION_FLAG_CP_PIXEL;
break;
case MSM_VIDC_SECURE_NONPIXEL:
ion_flag = ION_FLAG_CP_NON_PIXEL;
break;
case MSM_VIDC_SECURE_BITSTREAM:
ion_flag = ION_FLAG_CP_BITSTREAM;
break;
default:
d_vpr_e("invalid secure region : %#x\n", region);
}
return ion_flag;
}
struct context_bank_info *get_context_bank(struct msm_vidc_core *core,
enum msm_vidc_buffer_region region)
{
char *name;
struct context_bank_info *cb = NULL, *match = NULL;
switch (region) {
case MSM_VIDC_NON_SECURE:
name = "venus_ns";
break;
case MSM_VIDC_SECURE_PIXEL:
name = "venus_sec_pixel";
break;
case MSM_VIDC_SECURE_NONPIXEL:
name = "venus_sec_non_pixel";
break;
case MSM_VIDC_SECURE_BITSTREAM:
name = "venus_sec_bitstream";
break;
default:
d_vpr_e("invalid region : %#x\n", region);
return NULL;
}
list_for_each_entry(cb, &core->dt->context_banks, list) {
if (!strcmp(cb->name, name)) {
match = cb;
break;
}
}
if (!match)
d_vpr_e("cb not found for region %#x\n", region);
return match;
}
struct dma_buf *msm_vidc_memory_get_dmabuf(int fd)
{
struct dma_buf *dmabuf;
dmabuf = dma_buf_get(fd);
if (IS_ERR_OR_NULL(dmabuf)) {
d_vpr_e("Failed to get dmabuf for %d, error %ld\n",
fd, PTR_ERR(dmabuf));
dmabuf = NULL;
}
return dmabuf;
}
void msm_vidc_memory_put_dmabuf(void *dmabuf)
{
if (!dmabuf) {
d_vpr_e("%s: NULL dmabuf\n", __func__);
return;
}
dma_buf_put((struct dma_buf *)dmabuf);
}
int msm_vidc_memory_map(struct msm_vidc_core *core, struct msm_vidc_map *map)
{
int rc = 0;
struct dma_buf_attachment *attach = NULL;
struct sg_table *table = NULL;
struct context_bank_info *cb = NULL;
if (!core || !map) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
if (map->refcount) {
map->refcount++;
return 0;
}
cb = get_context_bank(core, map->region);
if (!cb) {
d_vpr_e("%s: Failed to get context bank device\n",
__func__);
rc = -EIO;
goto error_cb;
}
/* Prepare a dma buf for dma on the given device */
attach = dma_buf_attach(map->dmabuf, cb->dev);
if (IS_ERR_OR_NULL(attach)) {
rc = PTR_ERR(attach) ? PTR_ERR(attach) : -ENOMEM;
d_vpr_e("Failed to attach dmabuf\n");
goto error_attach;
}
/*
* Get the scatterlist for the given attachment
* Mapping of sg is taken care by map attachment
*/
attach->dma_map_attrs = DMA_ATTR_DELAYED_UNMAP;
/*
* We do not need dma_map function to perform cache operations
* on the whole buffer size and hence pass skip sync flag.
* We do the required cache operations separately for the
* required buffer size
*/
attach->dma_map_attrs |= DMA_ATTR_SKIP_CPU_SYNC;
if (core->dt->sys_cache_present)
attach->dma_map_attrs |=
DMA_ATTR_IOMMU_USE_UPSTREAM_HINT;
table = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
if (IS_ERR_OR_NULL(table)) {
rc = PTR_ERR(table) ? PTR_ERR(table) : -ENOMEM;
d_vpr_e("Failed to map table\n");
goto error_table;
}
if (!table->sgl) {
d_vpr_e("sgl is NULL\n");
rc = -ENOMEM;
goto error_sg;
}
map->device_addr = table->sgl->dma_address;
map->table = table;
map->attach = attach;
map->refcount++;
return 0;
error_sg:
dma_buf_unmap_attachment(attach, table, DMA_BIDIRECTIONAL);
error_table:
dma_buf_detach(map->dmabuf, attach);
error_attach:
error_cb:
return rc;
}
int msm_vidc_memory_unmap(struct msm_vidc_core *core, struct msm_vidc_map *map)
{
int rc = 0;
if (!core || !map) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
if (map->refcount) {
map->refcount--;
} else {
d_vpr_e("unmap called while refcount is zero already\n");
return -EINVAL;
}
if (map->refcount)
goto exit;
dma_buf_unmap_attachment(map->attach, map->table, DMA_BIDIRECTIONAL);
dma_buf_detach(map->dmabuf, map->attach);
map->device_addr = 0x0;
map->dmabuf = NULL;
map->attach = NULL;
map->table = NULL;
exit:
return rc;
}
int msm_vidc_memory_alloc(struct msm_vidc_core *core, struct msm_vidc_alloc *mem)
{
int rc = 0;
int ion_flags = 0;
int ion_secure_flag = 0;
unsigned long heap_mask = 0;
int size = 0;
if (!mem) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
size = ALIGN(mem->size, SZ_4K);
if (mem->cached)
ion_flags |= ION_FLAG_CACHED;
if (mem->secure) {
ion_secure_flag = get_ion_secure_flag(mem->region);
ion_flags |= ION_FLAG_SECURE | ion_secure_flag;
heap_mask = ION_HEAP(ION_SECURE_HEAP_ID);
} else {
heap_mask = ION_HEAP(ION_SYSTEM_HEAP_ID);
}
mem->dmabuf = ion_alloc(size, heap_mask, ion_flags);
if (IS_ERR_OR_NULL(mem->dmabuf)) {
d_vpr_e("%s: ion alloc failed\n", __func__);
mem->dmabuf = NULL;
rc = -ENOMEM;
goto error;
}
if (mem->map_kernel) {
dma_buf_begin_cpu_access(mem->dmabuf, DMA_BIDIRECTIONAL);
mem->kvaddr = dma_buf_vmap(mem->dmabuf);
if (!mem->kvaddr) {
d_vpr_e("%s: kernel map failed\n", __func__);
rc = -EIO;
goto error;
}
}
d_vpr_h(
"%s: dmabuf = %pK, size = %d, kvaddr = %pK, buffer_type = %#x\n",
__func__, mem->dmabuf, mem->size,
mem->kvaddr, mem->buffer_type);
return 0;
error:
msm_vidc_memory_free(core, mem);
return rc;
}
int msm_vidc_memory_free(struct msm_vidc_core *core, struct msm_vidc_alloc *mem)
{
int rc = 0;
if (!mem || !mem->dmabuf) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
d_vpr_h(
"%s: dmabuf = %pK, size = %d, kvaddr = %pK, buffer_type = %#x\n",
__func__, mem->dmabuf, mem->size,
mem->kvaddr, mem->buffer_type);
if (mem->kvaddr) {
dma_buf_vunmap(mem->dmabuf, mem->kvaddr);
mem->kvaddr = NULL;
dma_buf_end_cpu_access(mem->dmabuf, DMA_BIDIRECTIONAL);
}
if (mem->dmabuf) {
dma_buf_put(mem->dmabuf);
mem->dmabuf = NULL;
}
return rc;
};
/*
int msm_memory_cache_operations(struct dma_buf *dbuf,
enum smem_cache_ops cache_op, unsigned long offset,
unsigned long size, u32 sid)
{
int rc = 0;
unsigned long flags = 0;
if (!dbuf) {
s_vpr_e(sid, "%s: invalid params\n", __func__);
return -EINVAL;
}
rc = dma_buf_get_flags(dbuf, &flags);
if (rc) {
s_vpr_e(sid, "%s: dma_buf_get_flags failed, err %d\n",
__func__, rc);
return rc;
} else if (!(flags & ION_FLAG_CACHED)) {
return rc;
}
switch (cache_op) {
case SMEM_CACHE_CLEAN:
case SMEM_CACHE_CLEAN_INVALIDATE:
rc = dma_buf_begin_cpu_access_partial(dbuf, DMA_TO_DEVICE,
offset, size);
if (rc)
break;
rc = dma_buf_end_cpu_access_partial(dbuf, DMA_TO_DEVICE,
offset, size);
break;
case SMEM_CACHE_INVALIDATE:
rc = dma_buf_begin_cpu_access_partial(dbuf, DMA_TO_DEVICE,
offset, size);
if (rc)
break;
rc = dma_buf_end_cpu_access_partial(dbuf, DMA_FROM_DEVICE,
offset, size);
break;
default:
s_vpr_e(sid, "%s: cache (%d) operation not supported\n",
__func__, cache_op);
rc = -EINVAL;
break;
}
return rc;
}
int msm_smem_memory_prefetch(struct msm_vidc_inst *inst)
{
int i, rc = 0;
struct memory_regions *vidc_regions = NULL;
struct ion_prefetch_region ion_region[MEMORY_REGIONS_MAX];
if (!inst) {
d_vpr_e("%s: invalid parameters\n", __func__);
return -EINVAL;
}
vidc_regions = &inst->regions;
if (vidc_regions->num_regions > MEMORY_REGIONS_MAX) {
s_vpr_e(inst->sid, "%s: invalid num_regions %d, max %d\n",
__func__, vidc_regions->num_regions,
MEMORY_REGIONS_MAX);
return -EINVAL;
}
memset(ion_region, 0, sizeof(ion_region));
for (i = 0; i < vidc_regions->num_regions; i++) {
ion_region[i].size = vidc_regions->region[i].size;
ion_region[i].vmid = vidc_regions->region[i].vmid;
}
rc = msm_ion_heap_prefetch(ION_SECURE_HEAP_ID, ion_region,
vidc_regions->num_regions);
if (rc)
s_vpr_e(inst->sid, "%s: prefetch failed, ret: %d\n",
__func__, rc);
else
s_vpr_l(inst->sid, "%s: prefetch succeeded\n", __func__);
return rc;
}
int msm_smem_memory_drain(struct msm_vidc_inst *inst)
{
int i, rc = 0;
struct memory_regions *vidc_regions = NULL;
struct ion_prefetch_region ion_region[MEMORY_REGIONS_MAX];
if (!inst) {
d_vpr_e("%s: invalid parameters\n", __func__);
return -EINVAL;
}
vidc_regions = &inst->regions;
if (vidc_regions->num_regions > MEMORY_REGIONS_MAX) {
s_vpr_e(inst->sid, "%s: invalid num_regions %d, max %d\n",
__func__, vidc_regions->num_regions,
MEMORY_REGIONS_MAX);
return -EINVAL;
}
memset(ion_region, 0, sizeof(ion_region));
for (i = 0; i < vidc_regions->num_regions; i++) {
ion_region[i].size = vidc_regions->region[i].size;
ion_region[i].vmid = vidc_regions->region[i].vmid;
}
rc = msm_ion_heap_drain(ION_SECURE_HEAP_ID, ion_region,
vidc_regions->num_regions);
if (rc)
s_vpr_e(inst->sid, "%s: drain failed, ret: %d\n", __func__, rc);
else
s_vpr_l(inst->sid, "%s: drain succeeded\n", __func__);
return rc;
}
*/

查看文件

@@ -0,0 +1,133 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include <linux/of_platform.h>
#include "msm_vidc_waipio.h"
#include "msm_vidc_platform.h"
#include "msm_vidc_iris2.h"
#include "msm_vidc_debug.h"
#include "msm_vidc_v4l2.h"
#include "msm_vidc_vb2.h"
static struct v4l2_file_operations msm_v4l2_file_operations = {
.owner = THIS_MODULE,
.open = msm_v4l2_open,
.release = msm_v4l2_close,
.unlocked_ioctl = video_ioctl2,
.poll = msm_v4l2_poll,
};
static struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
.vidioc_querycap = msm_v4l2_querycap,
.vidioc_enum_fmt_vid_cap = msm_v4l2_enum_fmt,
.vidioc_enum_fmt_vid_out = msm_v4l2_enum_fmt,
.vidioc_enum_framesizes = msm_v4l2_enum_framesizes,
.vidioc_s_fmt_vid_cap_mplane = msm_v4l2_s_fmt,
.vidioc_s_fmt_vid_out_mplane = msm_v4l2_s_fmt,
.vidioc_g_fmt_vid_cap_mplane = msm_v4l2_g_fmt,
.vidioc_g_fmt_vid_out_mplane = msm_v4l2_g_fmt,
.vidioc_reqbufs = msm_v4l2_reqbufs,
.vidioc_qbuf = msm_v4l2_qbuf,
.vidioc_dqbuf = msm_v4l2_dqbuf,
.vidioc_streamon = msm_v4l2_streamon,
.vidioc_streamoff = msm_v4l2_streamoff,
.vidioc_s_ctrl = msm_v4l2_s_ctrl,
.vidioc_g_ctrl = msm_v4l2_g_ctrl,
.vidioc_queryctrl = msm_v4l2_queryctrl,
.vidioc_querymenu = msm_v4l2_querymenu,
.vidioc_subscribe_event = msm_v4l2_subscribe_event,
.vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
.vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
};
static struct v4l2_ctrl_ops msm_v4l2_ctrl_ops = {
//.s_ctrl = msm_vidc_s_ctrl,
};
static struct vb2_ops msm_vb2_ops = {
.queue_setup = msm_vidc_queue_setup,
.start_streaming = msm_vidc_start_streaming,
.buf_queue = msm_vidc_buf_queue,
.buf_cleanup = msm_vidc_buf_cleanup,
.stop_streaming = msm_vidc_stop_streaming,
};
static struct vb2_mem_ops msm_vb2_mem_ops = {
.get_userptr = msm_vb2_get_userptr,
.put_userptr = msm_vb2_put_userptr,
};
static int msm_vidc_init_ops(struct msm_vidc_core *core)
{
if (!core) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
d_vpr_h("%s: initialize ops\n", __func__);
core->v4l2_file_ops = &msm_v4l2_file_operations;
core->v4l2_ioctl_ops = &msm_v4l2_ioctl_ops;
core->v4l2_ctrl_ops = &msm_v4l2_ctrl_ops;
core->vb2_ops = &msm_vb2_ops;
core->vb2_mem_ops = &msm_vb2_mem_ops;
return 0;
}
int msm_vidc_init_platform(struct platform_device *pdev)
{
int rc = 0;
struct msm_vidc_platform *platform;
struct msm_vidc_core *core;
if (!pdev) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
d_vpr_h("%s()\n", __func__);
core = dev_get_drvdata(&pdev->dev);
if (!core) {
d_vpr_e("%s: core not found in device %s",
dev_name(&pdev->dev));
return -EINVAL;
}
platform = kzalloc(sizeof(struct msm_vidc_platform), GFP_KERNEL);
if (!platform)
return -ENOMEM;
core->platform = platform;
platform->core = core;
/* selected ops can be re-assigned in platform specific file */
rc = msm_vidc_init_ops(core);
if (rc)
return rc;
if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-vidc")) { // "qcom,msm-vidc-waipio"
rc = msm_vidc_init_platform_waipio(core);
if (rc)
return rc;
}
if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-vidc")) { // "qcom,msm-vidc-iris2"
rc = msm_vidc_init_iris2(core);
if (rc)
return rc;
}
return rc;
}
int msm_vidc_deinit_platform(struct platform_device *pdev)
{
return 0;
}

查看文件

@@ -0,0 +1,367 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include <linux/workqueue.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include "msm_vidc_internal.h"
#include "msm_vidc_debug.h"
#include "msm_vidc_driver.h"
#include "msm_vidc_dt.h"
#include "msm_vidc_platform.h"
#include "msm_vidc_core.h"
#include "venus_hfi.h"
#define BASE_DEVICE_NUMBER 32
static irqreturn_t msm_vidc_isr(int irq, void *data)
{
struct msm_vidc_core *core = data;
d_vpr_e("%s()\n", __func__);
disable_irq_nosync(irq);
queue_work(core->device_workq, &core->device_work);
return IRQ_HANDLED;
}
static int msm_vidc_init_irq(struct msm_vidc_core *core)
{
int rc = 0;
struct msm_vidc_dt *dt;
d_vpr_e("%s()\n", __func__);
if (!core || !core->pdev || !core->dt) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
dt = core->dt;
core->register_base_addr = devm_ioremap_nocache(&core->pdev->dev,
dt->register_base, dt->register_size);
if (!core->register_base_addr) {
d_vpr_e("could not map reg addr %pa of size %d\n",
&dt->register_base, dt->register_size);
goto exit;
}
rc = request_irq(dt->irq, msm_vidc_isr, IRQF_TRIGGER_HIGH,
"msm_vidc", core);
if (unlikely(rc)) {
d_vpr_e("%s: request_irq failed\n", __func__);
goto exit;
}
disable_irq_nosync(dt->irq);
d_vpr_h("%s: reg_base = %pa, reg_size = %d\n",
__func__, &dt->register_base, dt->register_size);
return 0;
exit:
if (core->device_workq)
destroy_workqueue(core->device_workq);
return rc;
}
static struct attribute *msm_vidc_core_attrs[] = {
NULL
};
static struct attribute_group msm_vidc_core_attr_group = {
.attrs = msm_vidc_core_attrs,
};
static const struct of_device_id msm_vidc_dt_match[] = {
{.compatible = "qcom,msm-vidc"},
{.compatible = "qcom,msm-vidc,context-bank"},
{}
};
MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
void msm_vidc_release_video_device(struct video_device *vdev)
{
d_vpr_e("%s:\n", __func__);
}
static int msm_vidc_register_video_device(struct msm_vidc_core *core,
enum msm_vidc_domain_type type, int nr)
{
int rc = 0;
int index;
d_vpr_h("%s()\n", __func__);
if (type == MSM_VIDC_DECODER)
index = 0;
else if (type == MSM_VIDC_ENCODER)
index = 1;
else
return -EINVAL;
core->vdev[index].vdev.release =
msm_vidc_release_video_device;
core->vdev[index].vdev.fops = core->v4l2_file_ops;
core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops;
core->vdev[index].vdev.vfl_dir = VFL_DIR_M2M;
core->vdev[index].type = type;
core->vdev[index].vdev.v4l2_dev = &core->v4l2_dev;
core->vdev[index].vdev.device_caps =
V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE |
V4L2_CAP_STREAMING;
rc = video_register_device(&core->vdev[index].vdev,
VFL_TYPE_GRABBER, nr);
if (rc) {
d_vpr_e("Failed to register the video device\n");
return rc;
}
video_set_drvdata(&core->vdev[index].vdev, core);
//rc = device_create_file(&core->vdev[index].vdev.dev, &dev_attr_link_name);
if (rc) {
d_vpr_e("Failed to create video device file\n");
video_unregister_device(&core->vdev[index].vdev);
return rc;
}
return 0;
}
static int msm_vidc_initialize_core(struct msm_vidc_core *core)
{
int rc = 0;
if (!core) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
d_vpr_h("%s()\n", __func__);
core->state = MSM_VIDC_CORE_DEINIT;
core->device_workq = create_singlethread_workqueue("device_workq");
if (!core->device_workq) {
d_vpr_e("%s: create device workq failed\n", __func__);
rc = -EINVAL;
goto exit;
}
core->pm_workq = create_singlethread_workqueue("pm_workq");
if (!core->pm_workq) {
d_vpr_e("%s: create pm workq failed\n", __func__);
destroy_workqueue(core->device_workq);
rc = -EINVAL;
goto exit;
}
mutex_init(&core->lock);
INIT_LIST_HEAD(&core->instances);
INIT_LIST_HEAD(&core->dangling_instances);
INIT_WORK(&core->device_work, venus_hfi_work_handler);
INIT_DELAYED_WORK(&core->pm_work, venus_hfi_pm_work_handler);
INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
INIT_DELAYED_WORK(&core->batch_work, msm_vidc_batch_handler);
INIT_WORK(&core->ssr_work, msm_vidc_ssr_handler);
exit:
return rc;
}
static int msm_vidc_probe_video_device(struct platform_device *pdev)
{
int rc = 0;
struct msm_vidc_core *core;
int nr = BASE_DEVICE_NUMBER;
d_vpr_h("%s()\n", __func__);
core = kzalloc(sizeof(*core), GFP_KERNEL);
if (!core)
return -ENOMEM;
core->pdev = pdev;
dev_set_drvdata(&pdev->dev, core);
rc = msm_vidc_initialize_core(core);
if (rc) {
d_vpr_e("%s: init core failed with %d\n", __func__, rc);
goto exit;
}
rc = msm_vidc_init_dt(pdev);
if (rc) {
d_vpr_e("%s: init dt failed with %d\n", __func__, rc);
return -EINVAL;
}
rc = msm_vidc_init_platform(pdev);
if (rc) {
d_vpr_e("%s: init platform failed with %d\n", __func__, rc);
return -EINVAL;
}
rc = msm_vidc_init_irq(core);
if (rc)
return rc;
rc = sysfs_create_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
if (rc) {
d_vpr_e("Failed to create attributes\n");
goto exit;
}
rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
if (rc) {
d_vpr_e("Failed to register v4l2 device\n");
goto exit;
}
/* setup the decoder device */
rc = msm_vidc_register_video_device(core, MSM_VIDC_DECODER, nr);
if (rc) {
d_vpr_e("Failed to register video decoder\n");
goto exit;
}
/* setup the encoder device */
rc = msm_vidc_register_video_device(core, MSM_VIDC_ENCODER, nr + 1);
if (rc) {
d_vpr_e("Failed to register video encoder\n");
goto exit;
}
//rc = msm_vidc_debugfs_init_core(core);
d_vpr_h("populating sub devices\n");
/*
* Trigger probe for each sub-device i.e. qcom,msm-vidc,context-bank.
* When msm_vidc_probe is called for each sub-device, parse the
* context-bank details and store it in core->resources.context_banks
* list.
*/
rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL,
&pdev->dev);
if (rc) {
d_vpr_e("Failed to trigger probe for sub-devices\n");
goto exit;
}
exit:
return rc;
}
static int msm_vidc_probe_context_bank(struct platform_device *pdev)
{
d_vpr_h("%s()\n", __func__);
return msm_vidc_read_context_bank_resources_from_dt(pdev);
}
static int msm_vidc_probe(struct platform_device *pdev)
{
d_vpr_h("%s()\n", __func__);
/*
* Sub devices probe will be triggered by of_platform_populate() towards
* the end of the probe function after msm-vidc device probe is
* completed. Return immediately after completing sub-device probe.
*/
if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-vidc")) {
return msm_vidc_probe_video_device(pdev);
} else if (of_device_is_compatible(pdev->dev.of_node,
"qcom,msm-vidc,context-bank")) {
return msm_vidc_probe_context_bank(pdev);
}
/* How did we end up here? */
MSM_VIDC_ERROR(1);
return -EINVAL;
}
static int msm_vidc_remove(struct platform_device *pdev)
{
int rc = 0;
d_vpr_h("%s()\n", __func__);
/*
struct msm_vidc_core *core;
if (!pdev) {
d_vpr_e("%s: invalid input %pK", __func__, pdev);
return -EINVAL;
}
core = dev_get_drvdata(&pdev->dev);
if (!core) {
d_vpr_e("%s: invalid core", __func__);
return -EINVAL;
}
if (core->vidc_core_workq)
destroy_workqueue(core->vidc_core_workq);
vidc_hfi_deinitialize(core->hfi_type, core->device);
device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev,
&dev_attr_link_name);
video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
device_remove_file(&core->vdev[MSM_VIDC_DECODER].vdev.dev,
&dev_attr_link_name);
video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
v4l2_device_unregister(&core->v4l2_dev);
//msm_vidc_free_platform_resources(&core->resources);
sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
dev_set_drvdata(&pdev->dev, NULL);
mutex_destroy(&core->lock);
kfree(core);
*/
return rc;
}
static struct platform_driver msm_vidc_driver = {
.probe = msm_vidc_probe,
.remove = msm_vidc_remove,
.driver = {
.name = "msm_vidc_v4l2",
.of_match_table = msm_vidc_dt_match,
},
};
static int __init msm_vidc_init(void)
{
int rc = 0;
d_vpr_h("%s()\n", __func__);
rc = platform_driver_register(&msm_vidc_driver);
if (rc) {
d_vpr_e("Failed to register platform driver\n");
return rc;
}
return 0;
}
static void __exit msm_vidc_exit(void)
{
d_vpr_h("%s()\n", __func__);
platform_driver_unregister(&msm_vidc_driver);
}
module_init(msm_vidc_init);
module_exit(msm_vidc_exit);
MODULE_SOFTDEP("pre: subsys-pil-tz");
MODULE_LICENSE("GPL v2");

查看文件

@@ -0,0 +1,200 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include "msm_vidc_v4l2.h"
#include "msm_vidc_internal.h"
#include "msm_vidc_core.h"
#include "msm_vidc_inst.h"
#include "msm_vidc_debug.h"
#include "msm_vidc.h"
static struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
{
if (!filp->private_data)
return NULL;
return container_of(filp->private_data,
struct msm_vidc_inst, event_handler);
}
unsigned int msm_v4l2_poll(struct file *filp, struct poll_table_struct *pt)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, NULL);
return msm_vidc_poll((void *)vidc_inst, filp, pt);
}
int msm_v4l2_open(struct file *filp)
{
struct video_device *vdev = video_devdata(filp);
struct msm_video_device *vid_dev =
container_of(vdev, struct msm_video_device, vdev);
struct msm_vidc_core *core = video_drvdata(filp);
struct msm_vidc_inst *vidc_inst;
vidc_inst = msm_vidc_open(core, vid_dev->type);
if (!vidc_inst) {
d_vpr_e("Failed to create instance, type = %d\n",
vid_dev->type);
return -ENOMEM;
}
clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags);
filp->private_data = &(vidc_inst->event_handler);
return 0;
}
int msm_v4l2_close(struct file *filp)
{
int rc = 0;
struct msm_vidc_inst *vidc_inst;
vidc_inst = get_vidc_inst(filp, NULL);
rc = msm_vidc_close(vidc_inst);
filp->private_data = NULL;
return rc;
}
int msm_v4l2_querycap(struct file *filp, void *fh,
struct v4l2_capability *cap)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, fh);
return msm_vidc_querycap((void *)vidc_inst, cap);
}
int msm_v4l2_enum_fmt(struct file *file, void *fh,
struct v4l2_fmtdesc *f)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_enum_fmt((void *)vidc_inst, f);
}
int msm_v4l2_s_fmt(struct file *file, void *fh,
struct v4l2_format *f)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_s_fmt((void *)vidc_inst, f);
}
int msm_v4l2_g_fmt(struct file *file, void *fh,
struct v4l2_format *f)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_g_fmt((void *)vidc_inst, f);
}
int msm_v4l2_s_ctrl(struct file *file, void *fh,
struct v4l2_control *a)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_s_ctrl((void *)vidc_inst, a);
}
int msm_v4l2_g_ctrl(struct file *file, void *fh,
struct v4l2_control *a)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_g_ctrl((void *)vidc_inst, a);
}
int msm_v4l2_reqbufs(struct file *file, void *fh,
struct v4l2_requestbuffers *b)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_reqbufs((void *)vidc_inst, b);
}
int msm_v4l2_qbuf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
struct video_device *vdev = video_devdata(file);
return msm_vidc_qbuf(get_vidc_inst(file, fh), vdev->v4l2_dev->mdev, b);
}
int msm_v4l2_dqbuf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
return msm_vidc_dqbuf(get_vidc_inst(file, fh), b);
}
int msm_v4l2_streamon(struct file *file, void *fh,
enum v4l2_buf_type i)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_streamon((void *)vidc_inst, i);
}
int msm_v4l2_streamoff(struct file *file, void *fh,
enum v4l2_buf_type i)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_streamoff((void *)vidc_inst, i);
}
int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
const struct v4l2_event_subscription *sub)
{
struct msm_vidc_inst *vidc_inst = container_of(fh,
struct msm_vidc_inst, event_handler);
return msm_vidc_subscribe_event((void *)vidc_inst, sub);
}
int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
const struct v4l2_event_subscription *sub)
{
struct msm_vidc_inst *vidc_inst = container_of(fh,
struct msm_vidc_inst, event_handler);
return msm_vidc_unsubscribe_event((void *)vidc_inst, sub);
}
int msm_v4l2_decoder_cmd(struct file *file, void *fh,
struct v4l2_decoder_cmd *dec)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_cmd((void *)vidc_inst, (union msm_v4l2_cmd *)dec);
}
int msm_v4l2_encoder_cmd(struct file *file, void *fh,
struct v4l2_encoder_cmd *enc)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_cmd((void *)vidc_inst, (union msm_v4l2_cmd *)enc);
}
int msm_v4l2_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_enum_framesizes((void *)vidc_inst, fsize);
}
int msm_v4l2_queryctrl(struct file *file, void *fh,
struct v4l2_queryctrl *ctrl)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_query_ctrl((void *)vidc_inst, ctrl);
}
int msm_v4l2_querymenu(struct file *file, void *fh,
struct v4l2_querymenu *qmenu)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_query_menu((void *)vidc_inst, qmenu);
}

查看文件

@@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include "msm_vidc_vb2.h"
#include "msm_vidc_core.h"
#include "msm_vidc_inst.h"
#include "msm_vidc_internal.h"
#include "msm_vidc_debug.h"
void *msm_vb2_get_userptr(struct device *dev, unsigned long vaddr,
unsigned long size, enum dma_data_direction dma_dir)
{
return (void *)0xdeadbeef;
}
void msm_vb2_put_userptr(void *buf_priv)
{
}
int msm_vidc_queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], struct device *alloc_devs[])
{
return 0;
}
int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count)
{
return 0;
}
void msm_vidc_stop_streaming(struct vb2_queue *q)
{
}
void msm_vidc_buf_queue(struct vb2_buffer *vb2)
{
}
void msm_vidc_buf_cleanup(struct vb2_buffer *vb)
{
}

2351
driver/vidc/src/venus_hfi.c 一般檔案

檔案差異因為檔案過大而無法顯示 載入差異