diff options
author | Shijie Qin <shijie.qin@nxp.com> | 2019-10-29 13:14:32 +0800 |
---|---|---|
committer | Shijie Qin <shijie.qin@nxp.com> | 2019-10-31 17:34:17 +0800 |
commit | b136114daf197fdf90f19d67b38f588622d58100 (patch) | |
tree | 052147ab392106d3390c35ba494031ef2f5786ba /drivers/mxc | |
parent | e8e726b7ac2e8cdc126b0115135777770207a000 (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/Makefile | 4 | ||||
-rw-r--r-- | drivers/mxc/vpu_windsor/mediasys_types.h | 4 | ||||
-rw-r--r-- | drivers/mxc/vpu_windsor/vpu_encoder_b0.c | 380 | ||||
-rw-r--r-- | drivers/mxc/vpu_windsor/vpu_encoder_b0.h | 43 | ||||
-rw-r--r-- | drivers/mxc/vpu_windsor/vpu_encoder_mu.c | 153 | ||||
-rw-r--r-- | drivers/mxc/vpu_windsor/vpu_encoder_mu.h | 42 | ||||
-rw-r--r-- | drivers/mxc/vpu_windsor/vpu_encoder_pm.c | 30 | ||||
-rw-r--r-- | drivers/mxc/vpu_windsor/vpu_encoder_pm.h | 32 |
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 |