summaryrefslogtreecommitdiff
path: root/drivers/mxc
diff options
context:
space:
mode:
authorShijie Qin <shijie.qin@nxp.com>2019-10-29 13:14:32 +0800
committerShijie Qin <shijie.qin@nxp.com>2019-10-31 17:34:17 +0800
commitb136114daf197fdf90f19d67b38f588622d58100 (patch)
tree052147ab392106d3390c35ba494031ef2f5786ba /drivers/mxc
parente8e726b7ac2e8cdc126b0115135777770207a000 (diff)
MLK-22769 VPU Encoder: unify code between 4.19 and 5.x
- Separate sc and mu contents to vpu_encoder_mu.h/.c - Separate pm_domain contents to vpu_encoder_pm.h/.c It unnecessary on 4.19, just create API for unify 5.4 - Add kfifo for better hold received mu message - Sync v4l2 change Remove vidioc_enum_fmt_vid_cap_mplane from 5.3.0 Remove v4l2_ioctl_g_crop(), v4l2_ioctl_g_selection could compatible with it from 4.14 or earlier vb2_qbuf() api changed from 4.20.0 vb2_buffer_state type changed from 4.20.0 Need set devices_caps when create video_device Signed-off-by: Shijie Qin <shijie.qin@nxp.com> Reviewed-by: Zhou Peng <eagle.zhou@nxp.com> Reviewed-by: ming_qian <ming.qian@nxp.com> (cherry picked from commit 4110874eb1aa2b31e5834537c0aba2ce67109212)
Diffstat (limited to 'drivers/mxc')
-rw-r--r--drivers/mxc/vpu_windsor/Makefile4
-rw-r--r--drivers/mxc/vpu_windsor/mediasys_types.h4
-rw-r--r--drivers/mxc/vpu_windsor/vpu_encoder_b0.c380
-rw-r--r--drivers/mxc/vpu_windsor/vpu_encoder_b0.h43
-rw-r--r--drivers/mxc/vpu_windsor/vpu_encoder_mu.c153
-rw-r--r--drivers/mxc/vpu_windsor/vpu_encoder_mu.h42
-rw-r--r--drivers/mxc/vpu_windsor/vpu_encoder_pm.c30
-rw-r--r--drivers/mxc/vpu_windsor/vpu_encoder_pm.h32
8 files changed, 459 insertions, 229 deletions
diff --git a/drivers/mxc/vpu_windsor/Makefile b/drivers/mxc/vpu_windsor/Makefile
index 14bbfe66cb55..5d315aa30712 100644
--- a/drivers/mxc/vpu_windsor/Makefile
+++ b/drivers/mxc/vpu_windsor/Makefile
@@ -9,7 +9,9 @@ vpu-windsor-objs = vpu_encoder_b0.o \
vpu_encoder_ctrl.o \
vpu_event_msg.o \
vpu_encoder_mem.o \
- vpu_encoder_rpc.o
+ vpu_encoder_rpc.o \
+ vpu_encoder_mu.o \
+ vpu_encoder_pm.o
clean:
rm -rf $(vpu-windsor-objs)
diff --git a/drivers/mxc/vpu_windsor/mediasys_types.h b/drivers/mxc/vpu_windsor/mediasys_types.h
index 62a187ae1dd7..a47ca84299c3 100644
--- a/drivers/mxc/vpu_windsor/mediasys_types.h
+++ b/drivers/mxc/vpu_windsor/mediasys_types.h
@@ -60,8 +60,12 @@ typedef unsigned char u_int8;
typedef unsigned long u_int64;
typedef unsigned int BOOL;
typedef int int32;
+#ifndef FALSE
#define FALSE 0
+#endif
+#ifndef TRUE
#define TRUE 1
+#endif
#define VID_API_NUM_STREAMS 8
#define VID_API_MAX_BUF_PER_STR 3
#define VID_API_MAX_NUM_MVC_VIEWS 4
diff --git a/drivers/mxc/vpu_windsor/vpu_encoder_b0.c b/drivers/mxc/vpu_windsor/vpu_encoder_b0.c
index 3f8732464bfd..c595a643d9cf 100644
--- a/drivers/mxc/vpu_windsor/vpu_encoder_b0.c
+++ b/drivers/mxc/vpu_windsor/vpu_encoder_b0.c
@@ -48,12 +48,13 @@
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-vmalloc.h>
-#include <soc/imx8/sc/ipc.h>
#include "vpu_encoder_b0.h"
#include "vpu_encoder_ctrl.h"
#include "vpu_encoder_config.h"
#include "vpu_event_msg.h"
#include "vpu_encoder_mem.h"
+#include "vpu_encoder_mu.h"
+#include "vpu_encoder_pm.h"
#define VPU_ENC_DRIVER_VERSION "1.0.1"
@@ -281,12 +282,6 @@ static struct vpu_v4l2_fmt formats_yuv_enc[] = {
static void vpu_ctx_send_cmd(struct vpu_ctx *ctx, uint32_t cmdid,
uint32_t cmdnum, uint32_t *local_cmddata);
-static void MU_sendMesgToFW(void __iomem *base, MSG_Type type, uint32_t value)
-{
- MU_SendMessage(base, 1, value);
- MU_SendMessage(base, 0, type);
-}
-
#define GET_CTX_RPC(ctx, func) \
func(&ctx->core_dev->shared_mem, ctx->str_index)
@@ -346,13 +341,17 @@ static int vpu_enc_v4l2_ioctl_querycap(struct file *file,
return 0;
}
-static int vpu_enc_v4l2_ioctl_enum_fmt_vid_cap_mplane(struct file *file,
+static int vpu_enc_v4l2_ioctl_enum_fmt_vid_cap(struct file *file,
void *fh,
struct v4l2_fmtdesc *f)
{
struct vpu_v4l2_fmt *fmt;
vpu_log_func();
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
if (f->index >= ARRAY_SIZE(formats_compressed_enc))
return -EINVAL;
@@ -362,13 +361,17 @@ static int vpu_enc_v4l2_ioctl_enum_fmt_vid_cap_mplane(struct file *file,
f->flags |= V4L2_FMT_FLAG_COMPRESSED;
return 0;
}
-static int vpu_enc_v4l2_ioctl_enum_fmt_vid_out_mplane(struct file *file,
+static int vpu_enc_v4l2_ioctl_enum_fmt_vid_out(struct file *file,
void *fh,
struct v4l2_fmtdesc *f)
{
struct vpu_v4l2_fmt *fmt;
vpu_log_func();
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return -EINVAL;
+
if (f->index >= ARRAY_SIZE(formats_yuv_enc))
return -EINVAL;
@@ -892,8 +895,13 @@ static int vpu_enc_queue_qbuf(struct queue_data *queue,
int ret = -EINVAL;
down(&queue->drv_q_lock);
- if (queue->vb2_q_inited)
+ if (queue->vb2_q_inited) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+ ret = vb2_qbuf(&queue->vb2_q, queue->ctx->dev->v4l2_dev.mdev, buf);
+#else
ret = vb2_qbuf(&queue->vb2_q, buf);
+#endif
+ }
up(&queue->drv_q_lock);
return ret;
@@ -1339,42 +1347,6 @@ static int vpu_enc_v4l2_ioctl_s_selection(struct file *file, void *fh,
return 0;
}
-static int vpu_enc_v4l2_ioctl_g_crop(struct file *file, void *fh,
- struct v4l2_crop *cr)
-{
- struct v4l2_selection s;
- int ret;
-
- if (!cr)
- return -EINVAL;
-
- s.type = cr->type;
- s.target = V4L2_SEL_TGT_CROP;
-
- vpu_log_func();
- ret = vpu_enc_v4l2_ioctl_g_selection(file, fh, &s);
- if (!ret)
- cr->c = s.r;
-
- return ret;
-}
-
-static int vpu_enc_v4l2_ioctl_s_crop(struct file *file, void *fh,
- const struct v4l2_crop *cr)
-{
- struct v4l2_selection s;
-
- if (!cr)
- return -EINVAL;
-
- s.type = cr->type;
- s.target = V4L2_SEL_TGT_CROP;
- s.r = cr->c;
-
- vpu_log_func();
- return vpu_enc_v4l2_ioctl_s_selection(file, fh, &s);
-}
-
static int response_stop_stream(struct vpu_ctx *ctx)
{
struct queue_data *queue;
@@ -1581,8 +1553,13 @@ static int vpu_enc_v4l2_ioctl_streamoff(struct file *file,
static const struct v4l2_ioctl_ops vpu_enc_v4l2_ioctl_ops = {
.vidioc_querycap = vpu_enc_v4l2_ioctl_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = vpu_enc_v4l2_ioctl_enum_fmt_vid_cap_mplane,
- .vidioc_enum_fmt_vid_out_mplane = vpu_enc_v4l2_ioctl_enum_fmt_vid_out_mplane,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
+ .vidioc_enum_fmt_vid_cap = vpu_enc_v4l2_ioctl_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_out = vpu_enc_v4l2_ioctl_enum_fmt_vid_out,
+#else
+ .vidioc_enum_fmt_vid_cap_mplane = vpu_enc_v4l2_ioctl_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_out_mplane = vpu_enc_v4l2_ioctl_enum_fmt_vid_out,
+#endif
.vidioc_enum_framesizes = vpu_enc_v4l2_ioctl_enum_framesizes,
.vidioc_enum_frameintervals = vpu_enc_v4l2_ioctl_enum_frameintervals,
.vidioc_g_fmt_vid_cap_mplane = vpu_enc_v4l2_ioctl_g_fmt,
@@ -1594,8 +1571,6 @@ static const struct v4l2_ioctl_ops vpu_enc_v4l2_ioctl_ops = {
.vidioc_g_parm = vpu_enc_v4l2_ioctl_g_parm,
.vidioc_s_parm = vpu_enc_v4l2_ioctl_s_parm,
.vidioc_expbuf = vpu_enc_v4l2_ioctl_expbuf,
- .vidioc_g_crop = vpu_enc_v4l2_ioctl_g_crop,
- .vidioc_s_crop = vpu_enc_v4l2_ioctl_s_crop,
.vidioc_g_selection = vpu_enc_v4l2_ioctl_g_selection,
.vidioc_s_selection = vpu_enc_v4l2_ioctl_s_selection,
.vidioc_encoder_cmd = vpu_enc_v4l2_ioctl_encoder_cmd,
@@ -1617,12 +1592,12 @@ static void vpu_core_send_cmd(struct core_device *core, u32 idx,
vpu_log_cmd(cmdid, idx);
count_cmd(&core->attr[idx], cmdid);
- spin_lock(&core->cmd_spinlock);
- rpc_send_cmd_buf_encoder(&core->shared_mem, idx,
- cmdid, cmdnum, local_cmddata);
+ mutex_lock(&core->cmd_mutex);
+ rpc_send_cmd_buf_encoder(&core->shared_mem, idx, cmdid, cmdnum,
+ local_cmddata);
mb();
- MU_SendMessage(core->mu_base_virtaddr, 0, COMMAND);
- spin_unlock(&core->cmd_spinlock);
+ vpu_enc_mu_send_msg(core, COMMAND, 0xffff);
+ mutex_unlock(&core->cmd_mutex);
}
static void vpu_ctx_send_cmd(struct vpu_ctx *ctx, uint32_t cmdid,
@@ -1656,6 +1631,8 @@ static int sw_reset_firmware(struct core_device *core, int resume)
vpu_dbg(LVL_INFO, "core[%d] sw reset firmware\n", core->id);
+ kfifo_free(&core->mu_msg_fifo);
+
init_completion(&core->start_cmp);
vpu_core_send_cmd(core, 0, GTB_ENC_CMD_FIRM_RESET, 0, NULL);
ret = wait_for_start_done(core, resume);
@@ -2882,36 +2859,6 @@ static void vpu_enc_event_handler(struct vpu_ctx *ctx,
}
}
-static void enable_mu(struct core_device *dev)
-{
- u32 mu_addr;
-
- vpu_dbg(LVL_ALL, "enable mu for core[%d]\n", dev->id);
-
- rpc_init_shared_memory_encoder(&dev->shared_mem,
- cpu_phy_to_mu(dev, dev->m0_rpc_phy),
- dev->m0_rpc_virt, dev->rpc_buf_size,
- &dev->rpc_actual_size);
- rpc_set_system_cfg_value_encoder(dev->shared_mem.pSharedInterface,
- dev->vdev->reg_rpc_system, dev->id);
-
- if (dev->rpc_actual_size > dev->rpc_buf_size)
- vpu_err("rpc actual size(0x%x) > (0x%x), may occur overlay\n",
- dev->rpc_actual_size, dev->rpc_buf_size);
-
- mu_addr = cpu_phy_to_mu(dev, dev->m0_rpc_phy + dev->rpc_buf_size);
- rpc_set_print_buffer(&dev->shared_mem, mu_addr, dev->print_buf_size);
- dev->print_buf = dev->m0_rpc_virt + dev->rpc_buf_size;
-
- mu_addr = cpu_phy_to_mu(dev, dev->m0_rpc_phy);
- spin_lock(&dev->cmd_spinlock);
- MU_sendMesgToFW(dev->mu_base_virtaddr, RPC_BUF_OFFSET, mu_addr);
- MU_sendMesgToFW(dev->mu_base_virtaddr, BOOT_ADDRESS,
- dev->m0_p_fw_space_phy);
- MU_sendMesgToFW(dev->mu_base_virtaddr, INIT_DONE, 2);
- spin_unlock(&dev->cmd_spinlock);
-}
-
static void get_core_supported_instance_count(struct core_device *core)
{
pENC_RPC_HOST_IFACE iface;
@@ -2979,57 +2926,6 @@ static void vpu_core_start_done(struct core_device *core)
show_firmware_version(core, LVL_ALL);
}
-//This code is added for MU
-static irqreturn_t fsl_vpu_enc_mu_isr(int irq, void *This)
-{
- struct core_device *dev = This;
- u32 msg;
-
- MU_ReceiveMsg(dev->mu_base_virtaddr, 0, &msg);
- if (msg == 0xaa) {
- enable_mu(dev);
- } else if (msg == 0x55) {
- vpu_core_start_done(dev);
- } else if (msg == 0xA5) {
- /*receive snapshot done msg and wakeup complete to suspend*/
- complete(&dev->snap_done_cmp);
- } else
- queue_work(dev->workqueue, &dev->msg_work);
-
- return IRQ_HANDLED;
-}
-
-/* Initialization of the MU code. */
-static int vpu_enc_mu_init(struct core_device *core_dev)
-{
- int ret = 0;
-
- core_dev->mu_base_virtaddr =
- core_dev->vdev->regs_base + core_dev->reg_base;
- WARN_ON(!core_dev->mu_base_virtaddr);
-
- vpu_dbg(LVL_INFO, "core[%d] irq : %d\n", core_dev->id, core_dev->irq);
-
- ret = devm_request_irq(core_dev->generic_dev, core_dev->irq,
- fsl_vpu_enc_mu_isr,
- IRQF_EARLY_RESUME,
- "vpu_mu_isr",
- (void *)core_dev);
- if (ret) {
- vpu_err("request_irq failed %d, error = %d\n",
- core_dev->irq, ret);
- return -EINVAL;
- }
-
- if (!core_dev->vpu_mu_init) {
- MU_Init(core_dev->mu_base_virtaddr);
- MU_EnableRxFullInt(core_dev->mu_base_virtaddr, 0);
- core_dev->vpu_mu_init = 1;
- }
-
- return ret;
-}
-
static struct vpu_ctx *get_ctx_by_index(struct core_device *core, int index)
{
struct vpu_ctx *ctx = NULL;
@@ -3127,19 +3023,65 @@ static int process_msg(struct core_device *core)
return 0;
}
+static void vpu_enc_fw_init(struct core_device *core_dev)
+{
+ u32 mu_addr;
+
+ vpu_dbg(LVL_ALL, "enable mu for core[%d]\n", core_dev->id);
+
+ rpc_init_shared_memory_encoder(&core_dev->shared_mem,
+ cpu_phy_to_mu(core_dev, core_dev->m0_rpc_phy),
+ core_dev->m0_rpc_virt, core_dev->rpc_buf_size,
+ &core_dev->rpc_actual_size);
+ rpc_set_system_cfg_value_encoder(core_dev->shared_mem.pSharedInterface,
+ core_dev->vdev->reg_rpc_system, core_dev->id);
+
+ if (core_dev->rpc_actual_size > core_dev->rpc_buf_size)
+ vpu_err("rpc actual size(0x%x) > (0x%x), may occur overlay\n",
+ core_dev->rpc_actual_size, core_dev->rpc_buf_size);
+
+ mu_addr = cpu_phy_to_mu(core_dev, core_dev->m0_rpc_phy + core_dev->rpc_buf_size);
+ rpc_set_print_buffer(&core_dev->shared_mem, mu_addr, core_dev->print_buf_size);
+ core_dev->print_buf = core_dev->m0_rpc_virt + core_dev->rpc_buf_size;
+
+ mu_addr = cpu_phy_to_mu(core_dev, core_dev->m0_rpc_phy);
+ vpu_enc_mu_send_msg(core_dev, RPC_BUF_OFFSET, mu_addr);
+ vpu_enc_mu_send_msg(core_dev, BOOT_ADDRESS, core_dev->m0_p_fw_space_phy);
+ vpu_enc_mu_send_msg(core_dev, INIT_DONE, 2);
+}
+
extern u_int32 rpc_MediaIPFW_Video_message_check_encoder(struct shared_addr *This);
+
+static void vpu_enc_receive_msg_event(struct core_device *core_dev)
+{
+ struct shared_addr *This = &core_dev->shared_mem;
+
+ while (rpc_MediaIPFW_Video_message_check_encoder(This) == API_MSG_AVAILABLE)
+ process_msg(core_dev);
+
+ if (rpc_MediaIPFW_Video_message_check_encoder(This) == API_MSG_BUFFER_ERROR)
+ vpu_err("MSG num is too big to handle\n");
+}
+
+static void vpu_enc_handle_msg_data(struct core_device *core_dev, u_int32 data)
+{
+ if (data == 0xaa)
+ vpu_enc_fw_init(core_dev);
+ else if (data == 0x55)
+ vpu_core_start_done(core_dev);
+ else if (data == 0xA5)
+ complete(&core_dev->snap_done_cmp);
+ else
+ vpu_enc_receive_msg_event(core_dev);
+}
+
static void vpu_enc_msg_run_work(struct work_struct *work)
{
struct core_device *dev = container_of(work, struct core_device, msg_work);
- /*struct vpu_ctx *ctx;*/
- /*struct event_msg msg;*/
- struct shared_addr *This = &dev->shared_mem;
+ u_int32 data;
- while (rpc_MediaIPFW_Video_message_check_encoder(This) == API_MSG_AVAILABLE) {
- process_msg(dev);
- }
- if (rpc_MediaIPFW_Video_message_check_encoder(This) == API_MSG_BUFFER_ERROR)
- vpu_err("MSG num is too big to handle");
+ while (vpu_enc_mu_receive_msg(dev, &data) >= sizeof(u_int32))
+ vpu_enc_handle_msg_data(dev, data);
}
static void vpu_enc_msg_instance_work(struct work_struct *work)
@@ -3456,9 +3398,6 @@ static int set_vpu_fw_addr(struct vpu_dev *dev, struct core_device *core_dev)
if (!dev || !core_dev)
return -EINVAL;
- MU_Init(core_dev->mu_base_virtaddr);
- MU_EnableRxFullInt(core_dev->mu_base_virtaddr, 0);
-
reg_fw_base = core_dev->reg_csr_base;
write_vpu_reg(dev, core_dev->m0_p_fw_space_phy, reg_fw_base);
write_vpu_reg(dev, 0x0, reg_fw_base + 4);
@@ -3983,24 +3922,16 @@ static int show_v4l2_buf_status(struct vpu_ctx *ctx, char *buf, u32 size)
int num = 0;
num += scnprintf(buf + num, size - num, "V4L2 Buffer Status: ");
- num += scnprintf(buf + num, PAGE_SIZE - num, "(");
- num += scnprintf(buf + num, PAGE_SIZE - num,
+ num += scnprintf(buf + num, size - num, "(");
+ num += scnprintf(buf + num, size - num,
" %d:dequeued,", VB2_BUF_STATE_DEQUEUED);
- num += scnprintf(buf + num, PAGE_SIZE - num,
- " %d:preparing,", VB2_BUF_STATE_PREPARING);
- num += scnprintf(buf + num, PAGE_SIZE - num,
- " %d:prepared,", VB2_BUF_STATE_PREPARED);
- num += scnprintf(buf + num, PAGE_SIZE - num,
- " %d:queued,", VB2_BUF_STATE_QUEUED);
- num += scnprintf(buf + num, PAGE_SIZE - num,
- " %d:requeueing,", VB2_BUF_STATE_REQUEUEING);
- num += scnprintf(buf + num, PAGE_SIZE - num,
+ num += scnprintf(buf + num, size - num,
" %d:active,", VB2_BUF_STATE_ACTIVE);
- num += scnprintf(buf + num, PAGE_SIZE - num,
+ num += scnprintf(buf + num, size - num,
" %d:done,", VB2_BUF_STATE_DONE);
- num += scnprintf(buf + num, PAGE_SIZE - num,
+ num += scnprintf(buf + num, size - num,
" %d:error", VB2_BUF_STATE_ERROR);
- num += scnprintf(buf + num, PAGE_SIZE - num, ")\n");
+ num += scnprintf(buf + num, size - num - num, ")\n");
num += scnprintf(buf + num, size - num, "\tOUTPUT:");
num += show_queue_buffer_info(&ctx->q_data[V4L2_SRC],
buf + num,
@@ -4362,14 +4293,6 @@ static ssize_t show_buffer_info(struct device *dev,
num += scnprintf(buf + num, PAGE_SIZE - num,
" %d:dequeued,", VB2_BUF_STATE_DEQUEUED);
num += scnprintf(buf + num, PAGE_SIZE - num,
- " %d:preparing,", VB2_BUF_STATE_PREPARING);
- num += scnprintf(buf + num, PAGE_SIZE - num,
- " %d:prepared,", VB2_BUF_STATE_PREPARED);
- num += scnprintf(buf + num, PAGE_SIZE - num,
- " %d:queued,", VB2_BUF_STATE_QUEUED);
- num += scnprintf(buf + num, PAGE_SIZE - num,
- " %d:requeueing,", VB2_BUF_STATE_REQUEUEING);
- num += scnprintf(buf + num, PAGE_SIZE - num,
" %d:active,", VB2_BUF_STATE_ACTIVE);
num += scnprintf(buf + num, PAGE_SIZE - num,
" %d:done,", VB2_BUF_STATE_DONE);
@@ -5043,6 +4966,11 @@ static int create_vpu_video_device(struct vpu_dev *dev)
dev->pvpu_encoder_dev->release = video_device_release;
dev->pvpu_encoder_dev->vfl_dir = vpu_enc_v4l2_videodevice.vfl_dir;
dev->pvpu_encoder_dev->v4l2_dev = &dev->v4l2_dev;
+ dev->pvpu_encoder_dev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
video_set_drvdata(dev->pvpu_encoder_dev, dev);
ret = video_register_device(dev->pvpu_encoder_dev,
@@ -5246,8 +5174,6 @@ static void print_firmware_debug(char *ptr, u32 size)
while (total < size) {
len = min_t(u32, size - total, 256);
-
- pr_info("%.*s", len, ptr + total);
total += len;
}
}
@@ -5270,7 +5196,6 @@ static void handle_core_firmware_debug(struct core_device *core)
return;
ptr = core->print_buf->buffer;
- pr_info("----mem_printf for VPU Encoder core %d----\n", core->id);
if (rptr > wptr) {
print_firmware_debug(ptr + rptr, core->print_buf->bytes - rptr);
rptr = 0;
@@ -5321,12 +5246,12 @@ static void vpu_enc_watchdog_handler(struct work_struct *work)
static int init_vpu_core_dev(struct core_device *core_dev)
{
- int ret;
+ int ret = 0;
if (!core_dev)
return -EINVAL;
- spin_lock_init(&core_dev->cmd_spinlock);
+ mutex_init(&core_dev->cmd_mutex);
init_completion(&core_dev->start_cmp);
init_completion(&core_dev->snap_done_cmp);
@@ -5340,24 +5265,37 @@ static int init_vpu_core_dev(struct core_device *core_dev)
INIT_WORK(&core_dev->msg_work, vpu_enc_msg_run_work);
- ret = vpu_enc_mu_init(core_dev);
+ ret = vpu_enc_mu_request(core_dev);
+ if (ret)
+ goto err_des_work;
+
+ ret = kfifo_alloc(&core_dev->mu_msg_fifo,
+ sizeof(u32) * VID_API_NUM_STREAMS * VID_API_MESSAGE_LIMIT,
+ GFP_KERNEL);
if (ret) {
- vpu_err("%s vpu mu init failed\n", __func__);
- goto error;
+ vpu_err("error: fail to alloc mu msg fifo\n");
+ goto err_free_mu;
}
+
//firmware space for M0
core_dev->m0_p_fw_space_vir =
ioremap_wc(core_dev->m0_p_fw_space_phy, core_dev->fw_buf_size);
- if (!core_dev->m0_p_fw_space_vir)
+ if (!core_dev->m0_p_fw_space_vir) {
vpu_err("failed to remap space for M0 firmware\n");
+ ret = -EINVAL;
+ goto err_free_fifo;
+ }
cleanup_firmware_memory(core_dev);
core_dev->m0_rpc_virt =
ioremap_wc(core_dev->m0_rpc_phy,
core_dev->rpc_buf_size + core_dev->print_buf_size);
- if (!core_dev->m0_rpc_virt)
+ if (!core_dev->m0_rpc_virt) {
vpu_err("failed to remap space for shared memory\n");
+ ret = -EINVAL;
+ goto err_free_fifo;
+ }
memset_io(core_dev->m0_rpc_virt, 0, core_dev->rpc_buf_size);
@@ -5373,8 +5311,13 @@ static int init_vpu_core_dev(struct core_device *core_dev)
core_dev->core_attr.show = show_core_info;
device_create_file(core_dev->generic_dev, &core_dev->core_attr);
- return 0;
-error:
+ return ret;
+
+err_free_fifo:
+ kfifo_free(&core_dev->mu_msg_fifo);
+err_free_mu:
+ vpu_enc_mu_free(core_dev);
+err_des_work:
if (core_dev->workqueue) {
destroy_workqueue(core_dev->workqueue);
core_dev->workqueue = NULL;
@@ -5387,6 +5330,9 @@ static int uninit_vpu_core_dev(struct core_device *core_dev)
if (!core_dev)
return -EINVAL;
+ vpu_enc_mu_free(core_dev);
+ kfifo_free(&core_dev->mu_msg_fifo);
+
if (core_dev->core_attr.attr.name)
device_remove_file(core_dev->generic_dev, &core_dev->core_attr);
release_vpu_attrs(core_dev);
@@ -5429,43 +5375,6 @@ static void init_vpu_enc_watchdog(struct vpu_dev *vdev)
msecs_to_jiffies(VPU_WATCHDOG_INTERVAL_MS));
}
-static int check_vpu_encoder_is_available(void)
-{
- sc_ipc_t mu_ipc;
- sc_ipc_id_t mu_id;
- uint32_t fuse = 0xffff;
- int ret;
-
- ret = sc_ipc_getMuID(&mu_id);
- if (ret) {
- vpu_err("sc_ipc_getMuID() can't obtain mu id SCI! %d\n",
- ret);
- return -EINVAL;
- }
-
- ret = sc_ipc_open(&mu_ipc, mu_id);
- if (ret) {
- vpu_err("sc_ipc_getMuID() can't open MU channel to SCU! %d\n",
- ret);
- return -EINVAL;
- }
-
- ret = sc_misc_otp_fuse_read(mu_ipc, VPU_DISABLE_BITS, &fuse);
- sc_ipc_close(mu_ipc);
- if (ret) {
- vpu_err("sc_misc_otp_fuse_read fail! %d\n", ret);
- return -EINVAL;
- }
-
- vpu_dbg(LVL_INFO, "mu_id = %d, fuse[7] = 0x%x\n", mu_id, fuse);
- if (fuse & VPU_ENCODER_MASK) {
- vpu_err("----Error, VPU Encoder is disabled\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
static const struct of_device_id vpu_enc_of_match[];
static int vpu_enc_probe(struct platform_device *pdev)
{
@@ -5488,7 +5397,7 @@ static int vpu_enc_probe(struct platform_device *pdev)
}
vpu_dbg(LVL_INFO, "probe %s\n", dev_id->compatible);
- if (check_vpu_encoder_is_available())
+ if (vpu_enc_sc_check_fuse())
return -EINVAL;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
@@ -5498,24 +5407,30 @@ static int vpu_enc_probe(struct platform_device *pdev)
dev->plat_dev = pdev;
dev->generic_dev = get_device(&pdev->dev);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!res)
+ ret = vpu_enc_attach_pm_domains(dev);
+ if (ret)
goto error_put_dev;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ ret = -EINVAL;
+ goto error_det_pm;
+ }
+
dev->reg_vpu_base = res->start;
dev->reg_vpu_size = resource_size(res);
ret = parse_dt_info(dev, np);
if (ret) {
vpu_err("parse device tree fail\n");
- goto error_put_dev;
+ goto error_det_pm;
}
dev->regs_base = ioremap(dev->reg_vpu_base, dev->reg_vpu_size);
if (!dev->regs_base) {
vpu_err("%s could not map regs_base\n", __func__);
ret = PTR_ERR(dev->regs_base);
- goto error_put_dev;
+ goto error_det_pm;
}
ret = vpu_enc_init_reserved_memory(&dev->reserved_mem);
@@ -5552,8 +5467,14 @@ static int vpu_enc_probe(struct platform_device *pdev)
if (ret)
break;
}
- if (i == 0)
- goto error_init_core;
+
+ if (i < dev->core_num) {
+ if (i == 0)
+ goto error_init_core;
+ else
+ vpu_err("error: core[%d] init failed\n", i);
+ }
+
dev->core_num = i;
pm_runtime_put_sync(&pdev->dev);
@@ -5588,12 +5509,16 @@ error_iounmap:
iounmap(dev->regs_base);
dev->regs_base = NULL;
}
+error_det_pm:
+ vpu_enc_detach_pm_domains(dev);
error_put_dev:
if (dev->generic_dev) {
put_device(dev->generic_dev);
dev->generic_dev = NULL;
}
- return -EINVAL;
+ devm_kfree(&pdev->dev, dev);
+
+ return ret;
}
static int vpu_enc_remove(struct platform_device *pdev)
@@ -5619,6 +5544,7 @@ static int vpu_enc_remove(struct platform_device *pdev)
video_unregister_device(dev->pvpu_encoder_dev);
v4l2_device_unregister(&dev->v4l2_dev);
+ vpu_enc_detach_pm_domains(dev);
vpu_enc_release_reserved_memory(&dev->reserved_mem);
if (dev->regs_base) {
iounmap(dev->regs_base);
@@ -5629,7 +5555,7 @@ static int vpu_enc_remove(struct platform_device *pdev)
dev->generic_dev = NULL;
}
- vpu_dbg(LVL_INFO, "VPU Encoder removed\n");
+ devm_kfree(&pdev->dev, dev);
return 0;
}
diff --git a/drivers/mxc/vpu_windsor/vpu_encoder_b0.h b/drivers/mxc/vpu_windsor/vpu_encoder_b0.h
index a9ad783461b1..26ee2f6659fe 100644
--- a/drivers/mxc/vpu_windsor/vpu_encoder_b0.h
+++ b/drivers/mxc/vpu_windsor/vpu_encoder_b0.h
@@ -27,11 +27,19 @@
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/videobuf2-v4l2.h>
+#ifdef CONFIG_IMX_SCU
+#include <linux/firmware/imx/ipc.h>
+#include <linux/firmware/imx/svc/misc.h>
+#else
#include <soc/imx8/sc/svc/irq/api.h>
#include <soc/imx8/sc/ipc.h>
#include <soc/imx8/sc/sci.h>
+#endif
#include <linux/mx8_mu.h>
#include <media/v4l2-event.h>
+#include <linux/mailbox_client.h>
+#include <linux/kfifo.h>
+
#include "vpu_encoder_rpc.h"
#include "vpu_encoder_config.h"
@@ -271,6 +279,20 @@ struct print_buf_desc {
char buffer[0];
};
+#ifdef CONFIG_IMX_SCU
+struct vpu_sc_msg_misc {
+ struct imx_sc_rpc_msg hdr;
+ u32 word;
+} __packed;
+#endif
+
+struct vpu_sc_chan {
+ struct core_device *dev;
+ char name[20];
+ struct mbox_client cl;
+ struct mbox_chan *ch;
+};
+
struct core_device {
void *m0_p_fw_space_vir;
u_int32 m0_p_fw_space_phy;
@@ -283,7 +305,7 @@ struct core_device {
u32 rpc_actual_size;
struct print_buf_desc *print_buf;
- spinlock_t cmd_spinlock;
+ struct mutex cmd_mutex;
bool fw_is_ready;
bool firmware_started;
struct completion start_cmp;
@@ -312,6 +334,13 @@ struct core_device {
struct device_attribute core_attr;
char name[64];
unsigned long reset_times;
+
+ struct kfifo mu_msg_fifo;
+
+ /* reserve for kernel version 5.4 or later */
+ struct vpu_sc_chan sc_chan_tx0;
+ struct vpu_sc_chan sc_chan_tx1;
+ struct vpu_sc_chan sc_chan_rx;
};
struct vpu_enc_mem_item {
@@ -364,6 +393,18 @@ struct vpu_dev {
u32 step;
} supported_fps;
struct vpu_enc_mem_info reserved_mem;
+
+ /* reserve for kernel version 5.4 or later */
+ struct device *pd_vpu;
+ struct device *pd_enc1;
+ struct device *pd_enc2;
+ struct device *pd_mu1;
+ struct device *pd_mu2;
+ struct device_link *pd_vpu_link;
+ struct device_link *pd_enc1_link;
+ struct device_link *pd_enc2_link;
+ struct device_link *pd_mu1_link;
+ struct device_link *pd_mu2_link;
};
struct buffer_addr {
diff --git a/drivers/mxc/vpu_windsor/vpu_encoder_mu.c b/drivers/mxc/vpu_windsor/vpu_encoder_mu.c
new file mode 100644
index 000000000000..05c6ce169b3d
--- /dev/null
+++ b/drivers/mxc/vpu_windsor/vpu_encoder_mu.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file vpu_encoder_mu.h
+ *
+ */
+
+#include "vpu_encoder_mu.h"
+
+static void vpu_enc_mu_inq_msg(struct core_device *core_dev, void *msg)
+{
+ if (&core_dev->mu_msg_fifo == NULL) {
+ vpu_err("mu_msg_fifo is NULL\n");
+ return;
+ }
+
+ if (kfifo_in(&core_dev->mu_msg_fifo, msg, sizeof(u_int32)) != sizeof(u_int32)) {
+ vpu_err("No memory for mu msg fifo\n");
+ return;
+ }
+
+ queue_work(core_dev->workqueue, &core_dev->msg_work);
+}
+
+static irqreturn_t vpu_enc_mu_irq_handle(int irq, void *This)
+{
+ struct core_device *dev = This;
+ u32 msg;
+
+ MU_ReceiveMsg(dev->mu_base_virtaddr, 0, &msg);
+ vpu_enc_mu_inq_msg(dev, &msg);
+
+ return IRQ_HANDLED;
+}
+
+static int vpu_enc_mu_init(struct core_device *core_dev)
+{
+ int ret = 0;
+
+ core_dev->mu_base_virtaddr =
+ core_dev->vdev->regs_base + core_dev->reg_base;
+ WARN_ON(!core_dev->mu_base_virtaddr);
+
+ vpu_dbg(LVL_INFO, "core[%d] irq : %d\n", core_dev->id, core_dev->irq);
+
+ ret = devm_request_irq(core_dev->generic_dev, core_dev->irq,
+ vpu_enc_mu_irq_handle,
+ IRQF_EARLY_RESUME,
+ "vpu_mu_isr",
+ (void *)core_dev);
+ if (ret) {
+ vpu_err("request_irq failed %d, error = %d\n",
+ core_dev->irq, ret);
+ return -EINVAL;
+ }
+
+ if (!core_dev->vpu_mu_init) {
+ MU_Init(core_dev->mu_base_virtaddr);
+ MU_EnableRxFullInt(core_dev->mu_base_virtaddr, 0);
+ core_dev->vpu_mu_init = 1;
+ }
+
+ return ret;
+}
+
+int vpu_enc_mu_request(struct core_device *core_dev)
+{
+ int ret = 0;
+
+ ret = vpu_enc_mu_init(core_dev);
+ if (ret)
+ vpu_err("error: vpu mu init failed\n");
+
+ return ret;
+}
+
+void vpu_enc_mu_free(struct core_device *core_dev)
+{
+ devm_free_irq(core_dev->generic_dev, core_dev->irq, (void *)core_dev);
+}
+
+void vpu_enc_mu_send_msg(struct core_device *core_dev, MSG_Type type, uint32_t value)
+{
+ if (value != 0xffff)
+ MU_SendMessage(core_dev->mu_base_virtaddr, 1, value);
+ if (type != 0xffff)
+ MU_SendMessage(core_dev->mu_base_virtaddr, 0, type);
+}
+
+u_int32 vpu_enc_mu_receive_msg(struct core_device *core_dev, void *msg)
+{
+ int ret = 0;
+
+ if (kfifo_len(&core_dev->mu_msg_fifo) >= sizeof(u_int32)) {
+ ret = kfifo_out(&core_dev->mu_msg_fifo, msg, sizeof(u_int32));
+ if (ret != sizeof(u_int32))
+ vpu_err("error: kfifo_out mu msg failed\n, ret=%d\n",
+ ret);
+ } else {
+ ret = kfifo_len(&core_dev->mu_msg_fifo);
+ }
+
+ return ret;
+}
+
+int vpu_enc_sc_check_fuse(void)
+{
+ sc_ipc_t mu_ipc;
+ sc_ipc_id_t mu_id;
+ uint32_t fuse = 0xffff;
+ int ret;
+
+ ret = sc_ipc_getMuID(&mu_id);
+ if (ret) {
+ vpu_err("error: can't obtain mu id SCI! ret=%d\n",
+ ret);
+ return -EINVAL;
+ }
+
+ ret = sc_ipc_open(&mu_ipc, mu_id);
+ if (ret) {
+ vpu_err("error: can't open MU channel to SCU! ret=%d\n",
+ ret);
+ return -EINVAL;
+ }
+
+ ret = sc_misc_otp_fuse_read(mu_ipc, VPU_DISABLE_BITS, &fuse);
+ sc_ipc_close(mu_ipc);
+ if (ret) {
+ vpu_err("error: sc_misc_otp_fuse_read fail! ret=%d\n", ret);
+ return -EINVAL;
+ }
+
+ vpu_dbg(LVL_INFO, "mu_id = %d, fuse[7] = 0x%x\n", mu_id, fuse);
+ if (fuse & VPU_ENCODER_MASK) {
+ vpu_err("error, VPU Encoder is disabled\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
diff --git a/drivers/mxc/vpu_windsor/vpu_encoder_mu.h b/drivers/mxc/vpu_windsor/vpu_encoder_mu.h
new file mode 100644
index 000000000000..1632b61a22e2
--- /dev/null
+++ b/drivers/mxc/vpu_windsor/vpu_encoder_mu.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file vpu_encoder_mu.h
+ *
+ */
+
+#ifndef _VPU_ENCODER_MU_H_
+#define _VPU_ENCODER_MU_H_
+
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/mx8_mu.h>
+#include <linux/workqueue.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/mailbox_client.h>
+#include <linux/pm_domain.h>
+#include <linux/kfifo.h>
+
+#include "vpu_encoder_b0.h"
+
+int vpu_enc_mu_request(struct core_device *core_dev);
+void vpu_enc_mu_free(struct core_device *core_dev);
+void vpu_enc_mu_send_msg(struct core_device *core_dev, MSG_Type type, u_int32 value);
+u_int32 vpu_enc_mu_receive_msg(struct core_device *core_dev, void *msg);
+int vpu_enc_sc_check_fuse(void);
+
+#endif
diff --git a/drivers/mxc/vpu_windsor/vpu_encoder_pm.c b/drivers/mxc/vpu_windsor/vpu_encoder_pm.c
new file mode 100644
index 000000000000..0e7413d78ed5
--- /dev/null
+++ b/drivers/mxc/vpu_windsor/vpu_encoder_pm.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file vpu_encoder_pm.c
+ *
+ */
+
+#include "vpu_encoder_pm.h"
+
+int vpu_enc_attach_pm_domains(struct vpu_dev *dev)
+{
+ return 0;
+}
+
+void vpu_enc_detach_pm_domains(struct vpu_dev *dev)
+{
+
+}
diff --git a/drivers/mxc/vpu_windsor/vpu_encoder_pm.h b/drivers/mxc/vpu_windsor/vpu_encoder_pm.h
new file mode 100644
index 000000000000..5e08adc8799e
--- /dev/null
+++ b/drivers/mxc/vpu_windsor/vpu_encoder_pm.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file vpu_encoder_pm.h
+ *
+ */
+
+#ifndef _VPU_ENCODER_PM_H_
+#define _VPU_ENCODER_PM_H_
+
+#include <linux/version.h>
+#include <linux/pm_domain.h>
+#include <linux/platform_device.h>
+
+#include "vpu_encoder_b0.h"
+
+int vpu_enc_attach_pm_domains(struct vpu_dev *dev);
+void vpu_enc_detach_pm_domains(struct vpu_dev *dev);
+
+#endif