diff --git a/drivers/video/rockchip/mpp/Kconfig b/drivers/video/rockchip/mpp/Kconfig index 53342703a6ee..92dfe93e7eaf 100644 --- a/drivers/video/rockchip/mpp/Kconfig +++ b/drivers/video/rockchip/mpp/Kconfig @@ -65,6 +65,11 @@ config ROCKCHIP_MPP_JPGDEC help rockchip mpp rkv jpeg decoder. +config ROCKCHIP_MPP_JPGENC + bool "RKV jpeg encoder v1 device driver" + help + rockchip mpp rkv jpeg encoder. + config ROCKCHIP_MPP_AV1DEC bool "AV1 decoder device driver" help diff --git a/drivers/video/rockchip/mpp/Makefile b/drivers/video/rockchip/mpp/Makefile index e227f0e4a038..0be859eb1ae0 100644 --- a/drivers/video/rockchip/mpp/Makefile +++ b/drivers/video/rockchip/mpp/Makefile @@ -21,6 +21,7 @@ rk_vcodec-$(CONFIG_ROCKCHIP_MPP_VDPU2) += mpp_vdpu2.o rk_vcodec-$(CONFIG_ROCKCHIP_MPP_VEPU2) += mpp_vepu2.o rk_vcodec-$(CONFIG_ROCKCHIP_MPP_IEP2) += mpp_iep2.o rk_vcodec-$(CONFIG_ROCKCHIP_MPP_JPGDEC) += mpp_jpgdec.o +rk_vcodec-$(CONFIG_ROCKCHIP_MPP_JPGENC) += mpp_jpgenc.o rk_vcodec-$(CONFIG_ROCKCHIP_MPP_AV1DEC) += mpp_av1dec.o rk_vcodec-$(CONFIG_ROCKCHIP_MPP_VDPP) += mpp_vdpp.o diff --git a/drivers/video/rockchip/mpp/mpp_common.c b/drivers/video/rockchip/mpp/mpp_common.c index f80087d11170..84c3502f9103 100644 --- a/drivers/video/rockchip/mpp/mpp_common.c +++ b/drivers/video/rockchip/mpp/mpp_common.c @@ -60,6 +60,7 @@ const char *mpp_device_name[MPP_DEVICE_BUTT] = { [MPP_DEVICE_VEPU1] = "VEPU1", [MPP_DEVICE_VEPU2] = "VEPU2", [MPP_DEVICE_VEPU2_JPEG] = "VEPU2", + [MPP_DEVICE_RKJPEGE] = "RKJPEGE", [MPP_DEVICE_VEPU22] = "VEPU22", [MPP_DEVICE_IEP2] = "IEP2", [MPP_DEVICE_VDPP] = "VDPP", diff --git a/drivers/video/rockchip/mpp/mpp_common.h b/drivers/video/rockchip/mpp/mpp_common.h index 5232f2919e0d..795f48afa105 100644 --- a/drivers/video/rockchip/mpp/mpp_common.h +++ b/drivers/video/rockchip/mpp/mpp_common.h @@ -58,6 +58,7 @@ enum MPP_DEVICE_TYPE { MPP_DEVICE_VEPU1 = 17, /* 0x00020000 */ MPP_DEVICE_VEPU2 = 18, /* 0x00040000 */ MPP_DEVICE_VEPU2_JPEG = 19, /* 0x00080000 */ + MPP_DEVICE_RKJPEGE = 20, /* 0x00100000 */ MPP_DEVICE_VEPU22 = 24, /* 0x01000000 */ MPP_DEVICE_IEP2 = 28, /* 0x10000000 */ @@ -84,6 +85,7 @@ enum MPP_DRIVER_TYPE { MPP_DRIVER_RKVENC2, MPP_DRIVER_AV1DEC, MPP_DRIVER_VDPP, + MPP_DRIVER_JPGENC, MPP_DRIVER_BUTT, }; @@ -847,6 +849,7 @@ extern struct platform_driver rockchip_jpgdec_driver; extern struct platform_driver rockchip_rkvdec2_driver; extern struct platform_driver rockchip_rkvenc2_driver; extern struct platform_driver rockchip_av1dec_driver; +extern struct platform_driver rockchip_jpgenc_driver; extern struct platform_driver rockchip_vdpp_driver; #endif diff --git a/drivers/video/rockchip/mpp/mpp_jpgdec.c b/drivers/video/rockchip/mpp/mpp_jpgdec.c index 753b061f22ea..b88daee1c7e5 100644 --- a/drivers/video/rockchip/mpp/mpp_jpgdec.c +++ b/drivers/video/rockchip/mpp/mpp_jpgdec.c @@ -27,6 +27,8 @@ #define JPGDEC_DRIVER_NAME "mpp_jpgdec" +#define JPGDEC_HWID_VPU720 0xdb1f0006 + #define JPGDEC_SESSION_MAX_BUFFERS 40 /* The maximum registers number of all the version */ #define JPGDEC_REG_NUM 42 @@ -69,6 +71,8 @@ #define JPGDEC_REG_STREAM_RLC_BASE 0x030 #define JPGDEC_REG_STREAM_RLC_BASE_INDEX (12) +#define JPGDEC_REG_PERF_WORKING_CNT 0x9c + #define to_jpgdec_task(task) \ container_of(task, struct jpgdec_task, mpp_task) #define to_jpgdec_dev(dev) \ @@ -315,6 +319,7 @@ static int jpgdec_finish(struct mpp_dev *mpp, * has not been completed.We have to manually trigger to do soft-reset. */ if (!(task->irq_status & JPGDEC_SOFT_RSET_READY) && + (mpp->var->hw_info->hw_id < JPGDEC_HWID_VPU720) && !atomic_read(&mpp->reset_request)) jpgdec_soft_reset(mpp); @@ -411,8 +416,6 @@ static int jpgdec_init(struct mpp_dev *mpp) int ret; struct jpgdec_dev *dec = to_jpgdec_dev(mpp); - mpp->grf_info = &mpp->srv->grf_infos[MPP_DRIVER_VDPU1]; - /* Get clock info from dtsi */ ret = mpp_get_clk_info(mpp, &dec->aclk_info, "aclk_vcodec"); if (ret) @@ -476,7 +479,17 @@ static int jpgdec_reduce_freq(struct mpp_dev *mpp) static int jpgdec_irq(struct mpp_dev *mpp) { + u32 clr_mask = 0; + mpp->irq_status = mpp_read(mpp, JPGDEC_REG_INT_EN_BASE); + + if (mpp->var->hw_info->hw_id == JPGDEC_HWID_VPU720) { + clr_mask = (~(0x00fe7f40 & mpp->irq_status)) & (0xff0180bf & mpp->irq_status); + mpp_debug(DEBUG_IRQ_STATUS, "irq status 0x%08x, mask 0x%08x\n", + mpp->irq_status, clr_mask); + mpp_write(mpp, JPGDEC_REG_INT_EN_BASE, clr_mask); + } + if (!(mpp->irq_status & JPGDEC_IRQ_RAW)) return IRQ_NONE; mpp_write(mpp, JPGDEC_REG_INT_EN_BASE, 0); @@ -489,13 +502,15 @@ static int jpgdec_isr(struct mpp_dev *mpp) int error_mask; struct jpgdec_task *task = NULL; struct mpp_task *mpp_task = mpp->cur_task; + struct jpgdec_dev *dec = to_jpgdec_dev(mpp); /* FIXME use a spin lock here */ if (!mpp_task) { dev_err(mpp->dev, "no current task\n"); return IRQ_HANDLED; } - mpp_time_diff(mpp_task); + mpp_task->hw_cycles = mpp_read(mpp, JPGDEC_REG_PERF_WORKING_CNT); + mpp_time_diff_with_hw_time(mpp_task, dec->aclk_info.real_rate_hz); mpp->cur_task = NULL; task = to_jpgdec_task(mpp_task); task->irq_status = mpp->irq_status; @@ -611,6 +626,7 @@ static int jpgdec_probe(struct platform_device *pdev) } mpp->session_max_buffers = JPGDEC_SESSION_MAX_BUFFERS; + jpgdec_procfs_init(mpp); /* register current device to mpp service */ mpp_dev_register_srv(mpp, mpp->srv); diff --git a/drivers/video/rockchip/mpp/mpp_jpgenc.c b/drivers/video/rockchip/mpp/mpp_jpgenc.c new file mode 100644 index 000000000000..a7e3dbbb1175 --- /dev/null +++ b/drivers/video/rockchip/mpp/mpp_jpgenc.c @@ -0,0 +1,651 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Rockchip Electronics Co., Ltd + * + * author: + * Johnson.Ding, johnson.ding@rock-chips.com + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mpp_debug.h" +#include "mpp_common.h" +#include "mpp_iommu.h" + +#define JPGENC_DRIVER_NAME "mpp_jpgenc" + +#define JPGENC_SESSION_MAX_BUFFERS 40 +#define JPGENC_REG_NUM 79 + +#define JPGENC_REG_HW_ID_INDEX 0 +#define JPGENC_REG_START_INDEX 0 +#define JPGENC_REG_END_INDEX 78 +#define JPGENC_REG_START_EN_BASE 0x4 +#define JPGENC_REG_START_EN_INDEX 1 +#define JPGENC_REG_INT_EN_BASE 0x10 +#define JPGENC_REG_INT_EN_INDEX 4 +#define JPGENC_REG_INT_MASK_BASE 0x14 +#define JPGENC_REG_INT_MASK_INDEX 5 +#define JPGENC_REG_INT_CLR_BASE 0x18 +#define JPGENC_REG_INT_CLR_INDEX 6 +#define JPGENC_REG_INT_STATUS_BASE 0x1c +#define JPGENC_REG_INT_STATUS_INDEX 7 +#define JPGENC_REG_PERF_WORKING_CNT 0xe4 + +#define JPGENC_REG_ENC_RSL_INDEX (29) +#define JPGENC_GET_WIDTH(x) ((((x) & 0x1fff) + 1) << 3) +#define JPGENC_GET_HEIGHT(x) (((((x) >> 16) & 0x1fff) + 1) << 3) + +#define JPGENC_START_EN BIT(8) +#define JPGENC_INT_ST_ENC_DONE BIT(0) + +#define to_jpgenc_task(task) \ + container_of(task, struct jpgenc_task, mpp_task) +#define to_jpgenc_dev(dev) \ + container_of(dev, struct jpgenc_dev, mpp) + +enum VEPU_CMD { + VEPU_CMD_NONE = 0, + VEPU_CMD_ONE_FRAME, + VEPU_CMD_MULTI_FRAME_START, + VEPU_CMD_MULTI_FRAME_UPDATE, + VEPU_CMD_LINK_TABLE_FORCE_PAUSE, + VEPU_CMD_LINK_TABLE_RESUME, + VEPU_CMD_SAFE_CLR, + VEPU_CMD_FORCE_CLR, +}; + +enum JPGENC_MODE { + JPGENC_MODE_ONEFRAME = 0, + JPGENC_MODE_LINK_ADD = 1, + JPGENC_MODE_LINK_ONEFRAME = 2, + JPGENC_MODE_BUTT, +}; + +struct jpgenc_reg_msg { + u32 base_s; + u32 base_e; + /* class base for link */ + u32 link_s; + /* class end for link */ + u32 link_e; + /* class bytes for link */ + u32 link_len; +}; + +struct jpgenc_task { + struct mpp_task mpp_task; + enum MPP_CLOCK_MODE clk_mode; + u32 reg[JPGENC_REG_NUM]; + + struct reg_offset_info off_inf; + u32 irq_status; + /* req for current task */ + u32 w_req_cnt; + struct mpp_request w_reqs[MPP_MAX_MSG_NUM]; + u32 r_req_cnt; + struct mpp_request r_reqs[MPP_MAX_MSG_NUM]; + /* image info */ + u32 width; + u32 height; + u32 pixels; + struct mpp_dma_buffer *bs_buf; + u32 offset_bs; +}; + +struct jpgenc_dev { + struct mpp_dev mpp; + + struct mpp_clk_info aclk_info; + struct mpp_clk_info hclk_info; + struct mpp_clk_info core_clk_info; +#ifdef CONFIG_ROCKCHIP_MPP_PROC_FS + struct proc_dir_entry *procfs; +#endif + struct reset_control *rst_a; + struct reset_control *rst_h; + + // /* for link mode */ + enum JPGENC_MODE link_mode; + // atomic_t link_task_cnt; + // u32 link_run; + // u32 jpeg_wr_addr; +}; + +static struct mpp_hw_info jpgenc_v1_hw_info = { + .reg_num = JPGENC_REG_NUM, + .reg_id = JPGENC_REG_HW_ID_INDEX, + .reg_start = JPGENC_REG_START_INDEX, + .reg_end = JPGENC_REG_END_INDEX, + .reg_en = JPGENC_REG_START_EN_INDEX, +}; + +static const u16 trans_tbl_jpgenc[] = { + 9, // link table base + 16, // address of JPEG Q table + 17, // top address of JPEG bitstream + 18, // bottom address of JPEG bitstream + 19, // read address of JPEG bitstream + 20, // start address of JPEG bitstream + 21, // base address of ECS length buffer + 22, // base address of the 1st storage area for video source buffer + 23, // base address of the 2nd storage area for video source buffer + 24 // base address of the 3rd storage area for video source buffer +}; + +#define JPGENC_FMT_DEFAULT 0 +static struct mpp_trans_info jpgenc_v1_trans[] = { + [JPGENC_FMT_DEFAULT] = { + .count = ARRAY_SIZE(trans_tbl_jpgenc), + .table = trans_tbl_jpgenc, + }, +}; + +static int jpgenc_process_reg_fd(struct mpp_session *session, struct jpgenc_task *task) +{ + int ret = 0; + + ret = mpp_translate_reg_address(session, &task->mpp_task, + JPGENC_FMT_DEFAULT, task->reg, &task->off_inf); + + if (ret) + return ret; + + mpp_translate_reg_offset_info(&task->mpp_task, &task->off_inf, task->reg); + return 0; +} + +static int jpgenc_extract_task_msg(struct jpgenc_task *task, struct mpp_task_msgs *msgs) +{ + u32 i; + int ret; + struct mpp_request *req; + struct mpp_hw_info *hw_info = task->mpp_task.hw_info; + + for (i = 0; i < msgs->req_cnt; i++) { + u32 off_s, off_e; + + req = &msgs->reqs[i]; + if (!req->size) + continue; + + switch (req->cmd) { + case MPP_CMD_SET_REG_WRITE: { + off_s = hw_info->reg_start * sizeof(u32); + off_e = hw_info->reg_end * sizeof(u32); + ret = mpp_check_req(req, 0, sizeof(task->reg), off_s, off_e); + + if (ret) + continue; + + if (copy_from_user((u8 *)task->reg + req->offset, req->data, req->size)) { + mpp_err("copy_from_user reg failed\n"); + return -EIO; + } + + memcpy(&task->w_reqs[task->w_req_cnt++], req, sizeof(*req)); + } break; + case MPP_CMD_SET_REG_READ: { + off_s = hw_info->reg_start * sizeof(u32); + off_e = hw_info->reg_end * sizeof(u32); + ret = mpp_check_req(req, 0, sizeof(task->reg), off_s, off_e); + + if (ret) + continue; + + memcpy(&task->r_reqs[task->r_req_cnt++], req, sizeof(*req)); + } break; + case MPP_CMD_SET_REG_ADDR_OFFSET: { + mpp_extract_reg_offset_info(&task->off_inf, req); + } break; + default: + break; + } + } + mpp_debug(DEBUG_TASK_INFO, "w_req_cnt %d, r_req_cnt %d\n", + task->w_req_cnt, task->r_req_cnt); + + return 0; +} + +static void *jpgenc_alloc_task(struct mpp_session *session, struct mpp_task_msgs *msgs) +{ + int ret; + struct mpp_task *mpp_task = NULL; + struct jpgenc_task *task = NULL; + struct mpp_dev *mpp = session->mpp; + + mpp_debug_enter(); + + task = kzalloc(sizeof(*task), GFP_KERNEL); + if (!task) + return NULL; + + mpp_task = &task->mpp_task; + mpp_task_init(session, mpp_task); + mpp_task->hw_info = mpp->var->hw_info; + mpp_task->reg = task->reg; + /* process fd in register */ + ret = jpgenc_extract_task_msg(task, msgs); + if (ret) + goto fail; + + if (!(msgs->flags & MPP_FLAGS_REG_FD_NO_TRANS)) { + ret = jpgenc_process_reg_fd(session, task); + if (ret) + goto fail; + + } + task->clk_mode = CLK_MODE_NORMAL; + task->width = JPGENC_GET_WIDTH(task->reg[JPGENC_REG_ENC_RSL_INDEX]); + task->height = JPGENC_GET_HEIGHT(task->reg[JPGENC_REG_ENC_RSL_INDEX]); + task->pixels = task->width * task->height; + mpp_debug(DEBUG_TASK_INFO, "width=%d, height=%d\n", task->width, task->height); + + mpp_debug_leave(); + return mpp_task; +fail: + mpp_task_dump_mem_region(mpp, mpp_task); + mpp_task_dump_reg(mpp, mpp_task); + mpp_task_finalize(session, mpp_task); + kfree(task); + return NULL; +} + +static int jpgenc_run(struct mpp_dev *mpp, struct mpp_task *mpp_task) +{ + u32 i; + u32 reg_en; + struct jpgenc_task *task = to_jpgenc_task(mpp_task); + u32 timing_en = mpp->srv->timing_en; + + mpp_debug_enter(); + + /* set registers for hardware */ + reg_en = mpp_task->hw_info->reg_en; + task->reg[JPGENC_REG_INT_EN_INDEX] = 0xff; + task->reg[JPGENC_REG_INT_MASK_INDEX] = 0xff; + + for (i = 0; i < task->w_req_cnt; i++) { + struct mpp_request *req = &task->w_reqs[i]; + u32 s = req->offset / sizeof(u32); + u32 e = s + req->size / sizeof(u32); + + mpp_write_req(mpp, task->reg, s, e, reg_en); + } + + /* flush tlb before starting hardware */ + mpp_iommu_flush_tlb(mpp->iommu_info); + + /* init current task */ + mpp->cur_task = mpp_task; + + mpp_task_run_begin(mpp_task, timing_en, MPP_WORK_TIMEOUT_DELAY); + + /* Flush the register before starting device */ + wmb(); + mpp_write(mpp, JPGENC_REG_START_EN_BASE, task->reg[reg_en] | JPGENC_START_EN); + + mpp_task_run_end(mpp_task, timing_en); + + mpp_debug_leave(); + return 0; +} + +static int jpgenc_finish(struct mpp_dev *mpp, struct mpp_task *mpp_task) +{ + u32 i; + u32 s, e; + struct mpp_request *req; + struct jpgenc_task *task = to_jpgenc_task(mpp_task); + + mpp_debug_enter(); + + for (i = 0; i < task->r_req_cnt; i++) { + req = &task->r_reqs[i]; + s = req->offset / sizeof(u32); + e = s + req->size / sizeof(u32); + mpp_read_req(mpp, task->reg, s, e); + } + + task->reg[JPGENC_REG_INT_STATUS_INDEX] = task->irq_status; + + mpp_debug_leave(); + return 0; +} + +static int jpgenc_result(struct mpp_dev *mpp, struct mpp_task *mpp_task, struct mpp_task_msgs *msgs) +{ + u32 i; + struct mpp_request *req; + struct jpgenc_task *task = to_jpgenc_task(mpp_task); + + mpp_debug_enter(); + + for (i = 0; i < task->r_req_cnt; i++) { + req = &task->r_reqs[i]; + if (copy_to_user(req->data, + (u8 *)task->reg + req->offset, + req->size)) { + mpp_err("copy_to_user reg fail\n"); + mpp_debug_leave(); + return -EIO; + } + } + + mpp_debug_leave(); + return 0; +} + +static int jpgenc_free_task(struct mpp_session *session, struct mpp_task *mpp_task) +{ + struct jpgenc_task *task = to_jpgenc_task(mpp_task); + + mpp_debug_enter(); + + mpp_task_finalize(session, mpp_task); + kfree(task); + + mpp_debug_leave(); + return 0; +} + +#ifdef CONFIG_ROCKCHIP_MPP_PROC_FS +static int jpgenc_procfs_remove(struct mpp_dev *mpp) +{ + struct jpgenc_dev *enc = to_jpgenc_dev(mpp); + + mpp_debug_enter(); + + if (enc->procfs) { + proc_remove(enc->procfs); + enc->procfs = NULL; + } + + mpp_debug_leave(); + return 0; +} + +static int jpgenc_show_session_info(struct seq_file *seq, void *offset) +{ + return 0; +} + +static int jpgenc_procfs_init(struct mpp_dev *mpp) +{ + struct jpgenc_dev *enc = to_jpgenc_dev(mpp); + + mpp_debug_enter(); + + enc->procfs = proc_mkdir(mpp->dev->of_node->name, mpp->srv->procfs); + + if (IS_ERR_OR_NULL(enc->procfs)) { + mpp_err("failed on open procfs\n"); + enc->procfs = NULL; + return -EIO; + } + + mpp_procfs_create_common(enc->procfs, mpp); + mpp_procfs_create_u32("aclk", 0644, enc->procfs, &enc->aclk_info.debug_rate_hz); + mpp_procfs_create_u32("hclk", 0644, enc->procfs, &enc->hclk_info.debug_rate_hz); + mpp_procfs_create_u32("session_buffers", 0644, enc->procfs, &mpp->session_max_buffers); + mpp_procfs_create_u32("link_mode", 0644, enc->procfs, &enc->link_mode); + proc_create_single_data("sessions-info", 0444, enc->procfs, jpgenc_show_session_info, mpp); + + mpp_debug_leave(); + return 0; +} +#else +static inline int jpgenc_procfs_remove(struct mpp_dev *mpp) +{ + return 0; +} + +static inline int jpgenc_procfs_init(struct mpp_dev *mpp) +{ + return 0; +} +#endif + +static int jpgenc_init(struct mpp_dev *mpp) +{ + int ret; + struct jpgenc_dev *enc = to_jpgenc_dev(mpp); + + mpp_debug_enter(); + + ret = mpp_get_clk_info(mpp, &enc->aclk_info, "aclk_vcodec"); + if (ret) + mpp_err("failed on clk_get aclk_vcodec\n"); + + ret = mpp_get_clk_info(mpp, &enc->hclk_info, "hclk_vcodec"); + if (ret) + mpp_err("failed on clk_get hclk_vcodec\n"); + + mpp_set_clk_info_rate_hz(&enc->aclk_info, CLK_MODE_DEFAULT, 700 * MHZ); + + enc->rst_a = mpp_reset_control_get(mpp, RST_TYPE_A, "video_a"); + if (!enc->rst_a) + mpp_err("No aclk reset resource define\n"); + + enc->rst_h = mpp_reset_control_get(mpp, RST_TYPE_H, "video_h"); + if (!enc->rst_h) + mpp_err("No hclk reset resource define\n"); + + mpp_debug_leave(); + return 0; +} + +static int jpgenc_clk_on(struct mpp_dev *mpp) +{ + struct jpgenc_dev *enc = to_jpgenc_dev(mpp); + + mpp_clk_safe_enable(enc->aclk_info.clk); + mpp_clk_safe_enable(enc->hclk_info.clk); + + return 0; +} + +static int jpgenc_clk_off(struct mpp_dev *mpp) +{ + struct jpgenc_dev *enc = to_jpgenc_dev(mpp); + + mpp_clk_safe_disable(enc->aclk_info.clk); + mpp_clk_safe_disable(enc->hclk_info.clk); + + return 0; +} + +static int jpgenc_set_freq(struct mpp_dev *mpp, struct mpp_task *mpp_task) +{ + struct jpgenc_dev *enc = to_jpgenc_dev(mpp); + struct jpgenc_task *task = to_jpgenc_task(mpp_task); + + mpp_clk_set_rate(&enc->aclk_info, task->clk_mode); + + return 0; +} + +static int jpgenc_irq(struct mpp_dev *mpp) +{ + mpp->irq_status = mpp_read(mpp, JPGENC_REG_INT_STATUS_BASE); + mpp_write(mpp, JPGENC_REG_INT_CLR_BASE, mpp->irq_status); + if (!(mpp->irq_status & JPGENC_INT_ST_ENC_DONE)) + return IRQ_NONE; + + mpp_write(mpp, JPGENC_REG_START_EN_BASE, 0); + return IRQ_WAKE_THREAD; +} + +static int jpgenc_isr(struct mpp_dev *mpp) +{ + int err_mask = 0x340; + struct jpgenc_task *task = NULL; + struct mpp_task *mpp_task = mpp->cur_task; + struct jpgenc_dev *enc = to_jpgenc_dev(mpp); + + mpp_debug_enter(); + + if (!mpp_task) { + dev_err(mpp->dev, "no current task\n"); + return IRQ_HANDLED; + } + + mpp_task->hw_cycles = mpp_read(mpp, JPGENC_REG_PERF_WORKING_CNT); + mpp_time_diff_with_hw_time(mpp_task, enc->aclk_info.real_rate_hz); + mpp->cur_task = NULL; + task = to_jpgenc_task(mpp_task); + task->irq_status = mpp->irq_status; + mpp_debug(DEBUG_IRQ_STATUS, "irq_status: %08x\n", task->irq_status); + + if (err_mask & task->irq_status) + atomic_inc(&mpp->reset_request); + + mpp_task_finish(mpp_task->session, mpp_task); + + mpp_debug_leave(); + + return 0; +} + +static int jpgenc_reset(struct mpp_dev *mpp) +{ + struct jpgenc_dev *enc = to_jpgenc_dev(mpp); + + mpp_debug_enter(); + + if (enc->rst_a && enc->rst_h) { + mpp_debug(DEBUG_RESET, "reset n\n"); + + mpp_pmu_idle_request(mpp, true); + mpp_safe_reset(enc->rst_a); + mpp_safe_reset(enc->rst_h); + udelay(5); + mpp_safe_unreset(enc->rst_a); + mpp_safe_unreset(enc->rst_h); + mpp_pmu_idle_request(mpp, false); + + mpp_debug(DEBUG_RESET, "reset out\n"); + } + mpp_write(mpp, JPGENC_REG_INT_EN_BASE, 0); + + mpp_debug_leave(); + return 0; +} + +static struct mpp_hw_ops jpgenc_v1_hw_ops = { + .init = jpgenc_init, + .clk_on = jpgenc_clk_on, + .clk_off = jpgenc_clk_off, + .set_freq = jpgenc_set_freq, + .reset = jpgenc_reset, +}; + +static struct mpp_dev_ops jpgenc_v1_dev_ops = { + .alloc_task = jpgenc_alloc_task, + .prepare = NULL, + .run = jpgenc_run, + .irq = jpgenc_irq, + .isr = jpgenc_isr, + .finish = jpgenc_finish, + .result = jpgenc_result, + .free_task = jpgenc_free_task, + .ioctl = NULL, + .init_session = NULL, + .free_session = NULL, + .dump_session = NULL, +}; + +static const struct mpp_dev_var jpgenc_v1_data = { + .device_type = MPP_DEVICE_RKJPEGE, + .hw_info = &jpgenc_v1_hw_info, + .trans_info = jpgenc_v1_trans, + .hw_ops = &jpgenc_v1_hw_ops, + .dev_ops = &jpgenc_v1_dev_ops, +}; + +static const struct of_device_id mpp_jpgenc_dt_match[] = { + { + .compatible = "rockchip,rkv-jpeg-encoder-v1", + .data = &jpgenc_v1_data, + }, + {}, +}; + +static int jpgenc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct jpgenc_dev *enc = NULL; + struct mpp_dev *mpp = NULL; + const struct of_device_id *match = NULL; + int ret = 0; + + dev_info(dev, "probe device\n"); + enc = devm_kzalloc(dev, sizeof(struct jpgenc_dev), GFP_KERNEL); + if (!enc) + return -ENOMEM; + + mpp = &enc->mpp; + platform_set_drvdata(pdev, mpp); + + if (pdev->dev.of_node) { + match = of_match_node(mpp_jpgenc_dt_match, pdev->dev.of_node); + if (match) + mpp->var = (struct mpp_dev_var *) match->data; + } + + ret = mpp_dev_probe(mpp, pdev); + + if (ret) { + dev_err(dev, "probe sub driver failed\n"); + return -EINVAL; + } + + ret = devm_request_threaded_irq(dev, mpp->irq, mpp_dev_irq, mpp_dev_isr_sched, + IRQF_SHARED, dev_name(dev), mpp); + + if (ret) { + dev_err(dev, "register interrupt runtime failed\n"); + return -EINVAL; + } + + mpp->session_max_buffers = JPGENC_SESSION_MAX_BUFFERS; + jpgenc_procfs_init(mpp); + /* register current device to mpp service */ + mpp_dev_register_srv(mpp, mpp->srv); + dev_info(dev, "probe finish"); + return 0; +} + +static int jpgenc_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mpp_dev *mpp = dev_get_drvdata(dev); + + dev_info(dev, "remove device\n"); + mpp_dev_remove(mpp); + jpgenc_procfs_remove(mpp); + return 0; +} + +struct platform_driver rockchip_jpgenc_driver = { + .probe = jpgenc_probe, + .remove = jpgenc_remove, + .shutdown = mpp_dev_shutdown, + .driver = { + .name = JPGENC_DRIVER_NAME, + .of_match_table = of_match_ptr(mpp_jpgenc_dt_match), + }, +}; +EXPORT_SYMBOL(rockchip_jpgenc_driver); diff --git a/drivers/video/rockchip/mpp/mpp_service.c b/drivers/video/rockchip/mpp/mpp_service.c index 52ae0ad766f1..cc5968e1689e 100644 --- a/drivers/video/rockchip/mpp/mpp_service.c +++ b/drivers/video/rockchip/mpp/mpp_service.c @@ -36,6 +36,7 @@ #define HAS_VEPU22 IS_ENABLED(CONFIG_ROCKCHIP_MPP_VEPU22) #define HAS_IEP2 IS_ENABLED(CONFIG_ROCKCHIP_MPP_IEP2) #define HAS_JPGDEC IS_ENABLED(CONFIG_ROCKCHIP_MPP_JPGDEC) +#define HAS_JPGENC IS_ENABLED(CONFIG_ROCKCHIP_MPP_JPGENC) #define HAS_RKVDEC2 IS_ENABLED(CONFIG_ROCKCHIP_MPP_RKVDEC2) #define HAS_RKVENC2 IS_ENABLED(CONFIG_ROCKCHIP_MPP_RKVENC2) #define HAS_AV1DEC IS_ENABLED(CONFIG_ROCKCHIP_MPP_AV1DEC) @@ -424,6 +425,7 @@ static int mpp_service_probe(struct platform_device *pdev) MPP_REGISTER_DRIVER(srv, HAS_VEPU22, VEPU22, vepu22); MPP_REGISTER_DRIVER(srv, HAS_IEP2, IEP2, iep2); MPP_REGISTER_DRIVER(srv, HAS_JPGDEC, JPGDEC, jpgdec); + MPP_REGISTER_DRIVER(srv, HAS_JPGENC, JPGENC, jpgenc); MPP_REGISTER_DRIVER(srv, HAS_RKVDEC2, RKVDEC2, rkvdec2); MPP_REGISTER_DRIVER(srv, HAS_RKVENC2, RKVENC2, rkvenc2); MPP_REGISTER_DRIVER(srv, HAS_AV1DEC, AV1DEC, av1dec);