xref: /OK3568_Linux_fs/kernel/drivers/video/rockchip/mpp/mpp_vepu1.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * author:
6*4882a593Smuzhiyun  *	Alpha Lin, alpha.lin@rock-chips.com
7*4882a593Smuzhiyun  *	Randy Li, randy.li@rock-chips.com
8*4882a593Smuzhiyun  *	Ding Wei, leo.ding@rock-chips.com
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun #include <asm/cacheflush.h>
12*4882a593Smuzhiyun #include <linux/delay.h>
13*4882a593Smuzhiyun #include <linux/iopoll.h>
14*4882a593Smuzhiyun #include <linux/interrupt.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/types.h>
17*4882a593Smuzhiyun #include <linux/of_platform.h>
18*4882a593Smuzhiyun #include <linux/slab.h>
19*4882a593Smuzhiyun #include <linux/seq_file.h>
20*4882a593Smuzhiyun #include <linux/uaccess.h>
21*4882a593Smuzhiyun #include <linux/regmap.h>
22*4882a593Smuzhiyun #include <linux/proc_fs.h>
23*4882a593Smuzhiyun #include <linux/nospec.h>
24*4882a593Smuzhiyun #include <soc/rockchip/pm_domains.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include "mpp_debug.h"
27*4882a593Smuzhiyun #include "mpp_common.h"
28*4882a593Smuzhiyun #include "mpp_iommu.h"
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #define VEPU1_DRIVER_NAME		"mpp_vepu1"
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #define	VEPU1_SESSION_MAX_BUFFERS	20
33*4882a593Smuzhiyun /* The maximum registers number of all the version */
34*4882a593Smuzhiyun #define VEPU1_REG_NUM			164
35*4882a593Smuzhiyun #define VEPU1_REG_HW_ID_INDEX		0
36*4882a593Smuzhiyun #define VEPU1_REG_START_INDEX		0
37*4882a593Smuzhiyun #define VEPU1_REG_END_INDEX		163
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define VEPU1_REG_INT			0x004
40*4882a593Smuzhiyun #define VEPU1_REG_INT_INDEX		(1)
41*4882a593Smuzhiyun #define VEPU1_INT_SLICE			BIT(8)
42*4882a593Smuzhiyun #define VEPU1_INT_TIMEOUT		BIT(6)
43*4882a593Smuzhiyun #define VEPU1_INT_BUF_FULL		BIT(5)
44*4882a593Smuzhiyun #define VEPU1_INT_RESET			BIT(4)
45*4882a593Smuzhiyun #define VEPU1_INT_BUS_ERROR		BIT(3)
46*4882a593Smuzhiyun #define VEPU1_INT_RDY			BIT(2)
47*4882a593Smuzhiyun #define VEPU1_IRQ_DIS			BIT(1)
48*4882a593Smuzhiyun #define VEPU1_INT_RAW			BIT(0)
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define VEPU1_REG_ENC_EN		0x038
51*4882a593Smuzhiyun #define VEPU1_REG_ENC_EN_INDEX		(14)
52*4882a593Smuzhiyun #define VEPU1_INT_TIMEOUT_EN		BIT(31)
53*4882a593Smuzhiyun #define VEPU1_INT_SLICE_EN		BIT(28)
54*4882a593Smuzhiyun #define VEPU1_ENC_START			BIT(0)
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #define VEPU1_GET_FORMAT(x)		(((x) >> 1) & 0x3)
57*4882a593Smuzhiyun #define VEPU1_FORMAT_MASK		(0x06)
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define VEPU1_FMT_RESERVED		(0)
60*4882a593Smuzhiyun #define VEPU1_FMT_VP8E			(1)
61*4882a593Smuzhiyun #define VEPU1_FMT_JPEGE			(2)
62*4882a593Smuzhiyun #define VEPU1_FMT_H264E			(3)
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun #define VEPU1_REG_CLR_CACHE_BASE	0xc10
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define to_vepu_task(task)		\
67*4882a593Smuzhiyun 		container_of(task, struct vepu_task, mpp_task)
68*4882a593Smuzhiyun #define to_vepu_dev(dev)		\
69*4882a593Smuzhiyun 		container_of(dev, struct vepu_dev, mpp)
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun struct vepu_task {
72*4882a593Smuzhiyun 	struct mpp_task mpp_task;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	enum MPP_CLOCK_MODE clk_mode;
75*4882a593Smuzhiyun 	u32 reg[VEPU1_REG_NUM];
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	struct reg_offset_info off_inf;
78*4882a593Smuzhiyun 	u32 irq_status;
79*4882a593Smuzhiyun 	/* req for current task */
80*4882a593Smuzhiyun 	u32 w_req_cnt;
81*4882a593Smuzhiyun 	struct mpp_request w_reqs[MPP_MAX_MSG_NUM];
82*4882a593Smuzhiyun 	u32 r_req_cnt;
83*4882a593Smuzhiyun 	struct mpp_request r_reqs[MPP_MAX_MSG_NUM];
84*4882a593Smuzhiyun };
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun struct vepu_session_priv {
87*4882a593Smuzhiyun 	struct rw_semaphore rw_sem;
88*4882a593Smuzhiyun 	/* codec info from user */
89*4882a593Smuzhiyun 	struct {
90*4882a593Smuzhiyun 		/* show mode */
91*4882a593Smuzhiyun 		u32 flag;
92*4882a593Smuzhiyun 		/* item data */
93*4882a593Smuzhiyun 		u64 val;
94*4882a593Smuzhiyun 	} codec_info[ENC_INFO_BUTT];
95*4882a593Smuzhiyun };
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun struct vepu_dev {
98*4882a593Smuzhiyun 	struct mpp_dev mpp;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	struct mpp_clk_info aclk_info;
101*4882a593Smuzhiyun 	struct mpp_clk_info hclk_info;
102*4882a593Smuzhiyun #ifdef CONFIG_ROCKCHIP_MPP_PROC_FS
103*4882a593Smuzhiyun 	struct proc_dir_entry *procfs;
104*4882a593Smuzhiyun #endif
105*4882a593Smuzhiyun 	struct reset_control *rst_a;
106*4882a593Smuzhiyun 	struct reset_control *rst_h;
107*4882a593Smuzhiyun };
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun static struct mpp_hw_info vepu_v1_hw_info = {
110*4882a593Smuzhiyun 	.reg_num = VEPU1_REG_NUM,
111*4882a593Smuzhiyun 	.reg_id = VEPU1_REG_HW_ID_INDEX,
112*4882a593Smuzhiyun 	.reg_start = VEPU1_REG_START_INDEX,
113*4882a593Smuzhiyun 	.reg_end = VEPU1_REG_END_INDEX,
114*4882a593Smuzhiyun 	.reg_en = VEPU1_REG_ENC_EN_INDEX,
115*4882a593Smuzhiyun };
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun /*
118*4882a593Smuzhiyun  * file handle translate information
119*4882a593Smuzhiyun  */
120*4882a593Smuzhiyun static const u16 trans_tbl_default[] = {
121*4882a593Smuzhiyun 	5, 6, 7, 8, 9, 10, 11, 12, 13, 51
122*4882a593Smuzhiyun };
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun static const u16 trans_tbl_vp8e[] = {
125*4882a593Smuzhiyun 	5, 6, 7, 8, 9, 10, 11, 12, 13, 16, 17, 26, 51, 52, 58, 59, 71
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun static struct mpp_trans_info trans_rk_vepu1[] = {
129*4882a593Smuzhiyun 	[VEPU1_FMT_RESERVED] = {
130*4882a593Smuzhiyun 		.count = 0,
131*4882a593Smuzhiyun 		.table = NULL,
132*4882a593Smuzhiyun 	},
133*4882a593Smuzhiyun 	[VEPU1_FMT_VP8E] = {
134*4882a593Smuzhiyun 		.count = ARRAY_SIZE(trans_tbl_vp8e),
135*4882a593Smuzhiyun 		.table = trans_tbl_vp8e,
136*4882a593Smuzhiyun 	},
137*4882a593Smuzhiyun 	[VEPU1_FMT_JPEGE] = {
138*4882a593Smuzhiyun 		.count = ARRAY_SIZE(trans_tbl_default),
139*4882a593Smuzhiyun 		.table = trans_tbl_default,
140*4882a593Smuzhiyun 	},
141*4882a593Smuzhiyun 	[VEPU1_FMT_H264E] = {
142*4882a593Smuzhiyun 		.count = ARRAY_SIZE(trans_tbl_default),
143*4882a593Smuzhiyun 		.table = trans_tbl_default,
144*4882a593Smuzhiyun 	},
145*4882a593Smuzhiyun };
146*4882a593Smuzhiyun 
vepu_process_reg_fd(struct mpp_session * session,struct vepu_task * task,struct mpp_task_msgs * msgs)147*4882a593Smuzhiyun static int vepu_process_reg_fd(struct mpp_session *session,
148*4882a593Smuzhiyun 			       struct vepu_task *task,
149*4882a593Smuzhiyun 			       struct mpp_task_msgs *msgs)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	int ret = 0;
152*4882a593Smuzhiyun 	int fmt = VEPU1_GET_FORMAT(task->reg[VEPU1_REG_ENC_EN_INDEX]);
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	ret = mpp_translate_reg_address(session, &task->mpp_task,
155*4882a593Smuzhiyun 					fmt, task->reg, &task->off_inf);
156*4882a593Smuzhiyun 	if (ret)
157*4882a593Smuzhiyun 		return ret;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	mpp_translate_reg_offset_info(&task->mpp_task,
160*4882a593Smuzhiyun 				      &task->off_inf, task->reg);
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	return 0;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun 
vepu_extract_task_msg(struct vepu_task * task,struct mpp_task_msgs * msgs)165*4882a593Smuzhiyun static int vepu_extract_task_msg(struct vepu_task *task,
166*4882a593Smuzhiyun 				 struct mpp_task_msgs *msgs)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun 	u32 i;
169*4882a593Smuzhiyun 	int ret;
170*4882a593Smuzhiyun 	struct mpp_request *req;
171*4882a593Smuzhiyun 	struct mpp_hw_info *hw_info = task->mpp_task.hw_info;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	for (i = 0; i < msgs->req_cnt; i++) {
174*4882a593Smuzhiyun 		u32 off_s, off_e;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 		req = &msgs->reqs[i];
177*4882a593Smuzhiyun 		if (!req->size)
178*4882a593Smuzhiyun 			continue;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 		switch (req->cmd) {
181*4882a593Smuzhiyun 		case MPP_CMD_SET_REG_WRITE: {
182*4882a593Smuzhiyun 			off_s = hw_info->reg_start * sizeof(u32);
183*4882a593Smuzhiyun 			off_e = hw_info->reg_end * sizeof(u32);
184*4882a593Smuzhiyun 			ret = mpp_check_req(req, 0, sizeof(task->reg),
185*4882a593Smuzhiyun 					    off_s, off_e);
186*4882a593Smuzhiyun 			if (ret)
187*4882a593Smuzhiyun 				continue;
188*4882a593Smuzhiyun 			if (copy_from_user((u8 *)task->reg + req->offset,
189*4882a593Smuzhiyun 					   req->data, req->size)) {
190*4882a593Smuzhiyun 				mpp_err("copy_from_user reg failed\n");
191*4882a593Smuzhiyun 				return -EIO;
192*4882a593Smuzhiyun 			}
193*4882a593Smuzhiyun 			memcpy(&task->w_reqs[task->w_req_cnt++],
194*4882a593Smuzhiyun 			       req, sizeof(*req));
195*4882a593Smuzhiyun 		} break;
196*4882a593Smuzhiyun 		case MPP_CMD_SET_REG_READ: {
197*4882a593Smuzhiyun 			off_s = hw_info->reg_start * sizeof(u32);
198*4882a593Smuzhiyun 			off_e = hw_info->reg_end * sizeof(u32);
199*4882a593Smuzhiyun 			ret = mpp_check_req(req, 0, sizeof(task->reg),
200*4882a593Smuzhiyun 					    off_s, off_e);
201*4882a593Smuzhiyun 			if (ret)
202*4882a593Smuzhiyun 				continue;
203*4882a593Smuzhiyun 			memcpy(&task->r_reqs[task->r_req_cnt++],
204*4882a593Smuzhiyun 			       req, sizeof(*req));
205*4882a593Smuzhiyun 		} break;
206*4882a593Smuzhiyun 		case MPP_CMD_SET_REG_ADDR_OFFSET: {
207*4882a593Smuzhiyun 			mpp_extract_reg_offset_info(&task->off_inf, req);
208*4882a593Smuzhiyun 		} break;
209*4882a593Smuzhiyun 		default:
210*4882a593Smuzhiyun 			break;
211*4882a593Smuzhiyun 		}
212*4882a593Smuzhiyun 	}
213*4882a593Smuzhiyun 	mpp_debug(DEBUG_TASK_INFO, "w_req_cnt %d, r_req_cnt %d\n",
214*4882a593Smuzhiyun 		  task->w_req_cnt, task->r_req_cnt);
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	return 0;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
vepu_alloc_task(struct mpp_session * session,struct mpp_task_msgs * msgs)219*4882a593Smuzhiyun static void *vepu_alloc_task(struct mpp_session *session,
220*4882a593Smuzhiyun 			     struct mpp_task_msgs *msgs)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	int ret;
223*4882a593Smuzhiyun 	struct mpp_task *mpp_task = NULL;
224*4882a593Smuzhiyun 	struct vepu_task *task = NULL;
225*4882a593Smuzhiyun 	struct mpp_dev *mpp = session->mpp;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	mpp_debug_enter();
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	task = kzalloc(sizeof(*task), GFP_KERNEL);
230*4882a593Smuzhiyun 	if (!task)
231*4882a593Smuzhiyun 		return NULL;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	mpp_task = &task->mpp_task;
234*4882a593Smuzhiyun 	mpp_task_init(session, mpp_task);
235*4882a593Smuzhiyun 	mpp_task->hw_info = mpp->var->hw_info;
236*4882a593Smuzhiyun 	mpp_task->reg = task->reg;
237*4882a593Smuzhiyun 	/* extract reqs for current task */
238*4882a593Smuzhiyun 	ret = vepu_extract_task_msg(task, msgs);
239*4882a593Smuzhiyun 	if (ret)
240*4882a593Smuzhiyun 		goto fail;
241*4882a593Smuzhiyun 	/* process fd in register */
242*4882a593Smuzhiyun 	if (!(msgs->flags & MPP_FLAGS_REG_FD_NO_TRANS)) {
243*4882a593Smuzhiyun 		ret = vepu_process_reg_fd(session, task, msgs);
244*4882a593Smuzhiyun 		if (ret)
245*4882a593Smuzhiyun 			goto fail;
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 	task->clk_mode = CLK_MODE_NORMAL;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	mpp_debug_leave();
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	return mpp_task;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun fail:
254*4882a593Smuzhiyun 	mpp_task_dump_mem_region(mpp, mpp_task);
255*4882a593Smuzhiyun 	mpp_task_dump_reg(mpp, mpp_task);
256*4882a593Smuzhiyun 	mpp_task_finalize(session, mpp_task);
257*4882a593Smuzhiyun 	kfree(task);
258*4882a593Smuzhiyun 	return NULL;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun 
vepu_run(struct mpp_dev * mpp,struct mpp_task * mpp_task)261*4882a593Smuzhiyun static int vepu_run(struct mpp_dev *mpp,
262*4882a593Smuzhiyun 		    struct mpp_task *mpp_task)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	u32 i;
265*4882a593Smuzhiyun 	u32 reg_en;
266*4882a593Smuzhiyun 	struct vepu_task *task = to_vepu_task(mpp_task);
267*4882a593Smuzhiyun 	u32 timing_en = mpp->srv->timing_en;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	mpp_debug_enter();
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	/* clear cache */
272*4882a593Smuzhiyun 	mpp_write_relaxed(mpp, VEPU1_REG_CLR_CACHE_BASE, 1);
273*4882a593Smuzhiyun 	/* set registers for hardware */
274*4882a593Smuzhiyun 	reg_en = mpp_task->hw_info->reg_en;
275*4882a593Smuzhiyun 	/* First, flush correct encoder format */
276*4882a593Smuzhiyun 	mpp_write_relaxed(mpp, VEPU1_REG_ENC_EN,
277*4882a593Smuzhiyun 			  task->reg[reg_en] & VEPU1_FORMAT_MASK);
278*4882a593Smuzhiyun 	/* Second, flush others register */
279*4882a593Smuzhiyun 	for (i = 0; i < task->w_req_cnt; i++) {
280*4882a593Smuzhiyun 		struct mpp_request *req = &task->w_reqs[i];
281*4882a593Smuzhiyun 		int s = req->offset / sizeof(u32);
282*4882a593Smuzhiyun 		int e = s + req->size / sizeof(u32);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 		mpp_write_req(mpp, task->reg, s, e, reg_en);
285*4882a593Smuzhiyun 	}
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	/* flush tlb before starting hardware */
288*4882a593Smuzhiyun 	mpp_iommu_flush_tlb(mpp->iommu_info);
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	/* init current task */
291*4882a593Smuzhiyun 	mpp->cur_task = mpp_task;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	mpp_task_run_begin(mpp_task, timing_en, MPP_WORK_TIMEOUT_DELAY);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	/* Last, flush start registers */
296*4882a593Smuzhiyun 	wmb();
297*4882a593Smuzhiyun 	mpp_write(mpp, VEPU1_REG_ENC_EN,
298*4882a593Smuzhiyun 		  task->reg[reg_en] | VEPU1_ENC_START);
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	mpp_task_run_end(mpp_task, timing_en);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	mpp_debug_leave();
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	return 0;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
vepu_irq(struct mpp_dev * mpp)307*4882a593Smuzhiyun static int vepu_irq(struct mpp_dev *mpp)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	mpp->irq_status = mpp_read(mpp, VEPU1_REG_INT);
310*4882a593Smuzhiyun 	if (!(mpp->irq_status & VEPU1_INT_RAW))
311*4882a593Smuzhiyun 		return IRQ_NONE;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	mpp_write(mpp, VEPU1_REG_INT, 0);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	return IRQ_WAKE_THREAD;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
vepu_isr(struct mpp_dev * mpp)318*4882a593Smuzhiyun static int vepu_isr(struct mpp_dev *mpp)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun 	u32 err_mask;
321*4882a593Smuzhiyun 	struct vepu_task *task = NULL;
322*4882a593Smuzhiyun 	struct mpp_task *mpp_task = mpp->cur_task;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	/* FIXME use a spin lock here */
325*4882a593Smuzhiyun 	if (!mpp_task) {
326*4882a593Smuzhiyun 		dev_err(mpp->dev, "no current task\n");
327*4882a593Smuzhiyun 		return IRQ_HANDLED;
328*4882a593Smuzhiyun 	}
329*4882a593Smuzhiyun 	mpp_time_diff(mpp_task);
330*4882a593Smuzhiyun 	mpp->cur_task = NULL;
331*4882a593Smuzhiyun 	task = to_vepu_task(mpp_task);
332*4882a593Smuzhiyun 	task->irq_status = mpp->irq_status;
333*4882a593Smuzhiyun 	mpp_debug(DEBUG_IRQ_STATUS, "irq_status: %08x\n",
334*4882a593Smuzhiyun 		  task->irq_status);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	err_mask = VEPU1_INT_TIMEOUT
337*4882a593Smuzhiyun 		| VEPU1_INT_BUF_FULL
338*4882a593Smuzhiyun 		| VEPU1_INT_BUS_ERROR;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	if (err_mask & task->irq_status)
341*4882a593Smuzhiyun 		atomic_inc(&mpp->reset_request);
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	mpp_task_finish(mpp_task->session, mpp_task);
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	mpp_debug_leave();
346*4882a593Smuzhiyun 	return IRQ_HANDLED;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun 
vepu_finish(struct mpp_dev * mpp,struct mpp_task * mpp_task)349*4882a593Smuzhiyun static int vepu_finish(struct mpp_dev *mpp,
350*4882a593Smuzhiyun 		       struct mpp_task *mpp_task)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun 	u32 i;
353*4882a593Smuzhiyun 	u32 s, e;
354*4882a593Smuzhiyun 	struct mpp_request *req;
355*4882a593Smuzhiyun 	struct vepu_task *task = to_vepu_task(mpp_task);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	mpp_debug_enter();
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	/* read register after running */
360*4882a593Smuzhiyun 	for (i = 0; i < task->r_req_cnt; i++) {
361*4882a593Smuzhiyun 		req = &task->r_reqs[i];
362*4882a593Smuzhiyun 		s = req->offset / sizeof(u32);
363*4882a593Smuzhiyun 		e = s + req->size / sizeof(u32);
364*4882a593Smuzhiyun 		mpp_read_req(mpp, task->reg, s, e);
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 	/* revert hack for irq status */
367*4882a593Smuzhiyun 	task->reg[VEPU1_REG_INT_INDEX] = task->irq_status;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	mpp_debug_leave();
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	return 0;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun 
vepu_result(struct mpp_dev * mpp,struct mpp_task * mpp_task,struct mpp_task_msgs * msgs)374*4882a593Smuzhiyun static int vepu_result(struct mpp_dev *mpp,
375*4882a593Smuzhiyun 		       struct mpp_task *mpp_task,
376*4882a593Smuzhiyun 		       struct mpp_task_msgs *msgs)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun 	u32 i;
379*4882a593Smuzhiyun 	struct mpp_request *req;
380*4882a593Smuzhiyun 	struct vepu_task *task = to_vepu_task(mpp_task);
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	/* FIXME may overflow the kernel */
383*4882a593Smuzhiyun 	for (i = 0; i < task->r_req_cnt; i++) {
384*4882a593Smuzhiyun 		req = &task->r_reqs[i];
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 		if (copy_to_user(req->data,
387*4882a593Smuzhiyun 				 (u8 *)task->reg + req->offset,
388*4882a593Smuzhiyun 				 req->size)) {
389*4882a593Smuzhiyun 			mpp_err("copy_to_user reg fail\n");
390*4882a593Smuzhiyun 			return -EIO;
391*4882a593Smuzhiyun 		}
392*4882a593Smuzhiyun 	}
393*4882a593Smuzhiyun 	return 0;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun 
vepu_free_task(struct mpp_session * session,struct mpp_task * mpp_task)396*4882a593Smuzhiyun static int vepu_free_task(struct mpp_session *session,
397*4882a593Smuzhiyun 			  struct mpp_task *mpp_task)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun 	struct vepu_task *task = to_vepu_task(mpp_task);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	mpp_task_finalize(session, mpp_task);
402*4882a593Smuzhiyun 	kfree(task);
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	return 0;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun 
vepu_control(struct mpp_session * session,struct mpp_request * req)407*4882a593Smuzhiyun static int vepu_control(struct mpp_session *session, struct mpp_request *req)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	switch (req->cmd) {
410*4882a593Smuzhiyun 	case MPP_CMD_SEND_CODEC_INFO: {
411*4882a593Smuzhiyun 		int i;
412*4882a593Smuzhiyun 		int cnt;
413*4882a593Smuzhiyun 		struct codec_info_elem elem;
414*4882a593Smuzhiyun 		struct vepu_session_priv *priv;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 		if (!session || !session->priv) {
417*4882a593Smuzhiyun 			mpp_err("session info null\n");
418*4882a593Smuzhiyun 			return -EINVAL;
419*4882a593Smuzhiyun 		}
420*4882a593Smuzhiyun 		priv = session->priv;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 		cnt = req->size / sizeof(elem);
423*4882a593Smuzhiyun 		cnt = (cnt > ENC_INFO_BUTT) ? ENC_INFO_BUTT : cnt;
424*4882a593Smuzhiyun 		mpp_debug(DEBUG_IOCTL, "codec info count %d\n", cnt);
425*4882a593Smuzhiyun 		down_write(&priv->rw_sem);
426*4882a593Smuzhiyun 		for (i = 0; i < cnt; i++) {
427*4882a593Smuzhiyun 			if (copy_from_user(&elem, req->data + i * sizeof(elem), sizeof(elem))) {
428*4882a593Smuzhiyun 				mpp_err("copy_from_user failed\n");
429*4882a593Smuzhiyun 				continue;
430*4882a593Smuzhiyun 			}
431*4882a593Smuzhiyun 			if (elem.type > ENC_INFO_BASE && elem.type < ENC_INFO_BUTT &&
432*4882a593Smuzhiyun 			    elem.flag > CODEC_INFO_FLAG_NULL && elem.flag < CODEC_INFO_FLAG_BUTT) {
433*4882a593Smuzhiyun 				elem.type = array_index_nospec(elem.type, ENC_INFO_BUTT);
434*4882a593Smuzhiyun 				priv->codec_info[elem.type].flag = elem.flag;
435*4882a593Smuzhiyun 				priv->codec_info[elem.type].val = elem.data;
436*4882a593Smuzhiyun 			} else {
437*4882a593Smuzhiyun 				mpp_err("codec info invalid, type %d, flag %d\n",
438*4882a593Smuzhiyun 					elem.type, elem.flag);
439*4882a593Smuzhiyun 			}
440*4882a593Smuzhiyun 		}
441*4882a593Smuzhiyun 		up_write(&priv->rw_sem);
442*4882a593Smuzhiyun 	} break;
443*4882a593Smuzhiyun 	default: {
444*4882a593Smuzhiyun 		mpp_err("unknown mpp ioctl cmd %x\n", req->cmd);
445*4882a593Smuzhiyun 	} break;
446*4882a593Smuzhiyun 	}
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	return 0;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun 
vepu_free_session(struct mpp_session * session)451*4882a593Smuzhiyun static int vepu_free_session(struct mpp_session *session)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun 	if (session && session->priv) {
454*4882a593Smuzhiyun 		kfree(session->priv);
455*4882a593Smuzhiyun 		session->priv = NULL;
456*4882a593Smuzhiyun 	}
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	return 0;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun 
vepu_init_session(struct mpp_session * session)461*4882a593Smuzhiyun static int vepu_init_session(struct mpp_session *session)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun 	struct vepu_session_priv *priv;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	if (!session) {
466*4882a593Smuzhiyun 		mpp_err("session is null\n");
467*4882a593Smuzhiyun 		return -EINVAL;
468*4882a593Smuzhiyun 	}
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
471*4882a593Smuzhiyun 	if (!priv)
472*4882a593Smuzhiyun 		return -ENOMEM;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	init_rwsem(&priv->rw_sem);
475*4882a593Smuzhiyun 	session->priv = priv;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	return 0;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun #ifdef CONFIG_ROCKCHIP_MPP_PROC_FS
vepu_procfs_remove(struct mpp_dev * mpp)481*4882a593Smuzhiyun static int vepu_procfs_remove(struct mpp_dev *mpp)
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun 	struct vepu_dev *enc = to_vepu_dev(mpp);
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	if (enc->procfs) {
486*4882a593Smuzhiyun 		proc_remove(enc->procfs);
487*4882a593Smuzhiyun 		enc->procfs = NULL;
488*4882a593Smuzhiyun 	}
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	return 0;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun 
vepu_dump_session(struct mpp_session * session,struct seq_file * seq)493*4882a593Smuzhiyun static int vepu_dump_session(struct mpp_session *session, struct seq_file *seq)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun 	int i;
496*4882a593Smuzhiyun 	struct vepu_session_priv *priv = session->priv;
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	down_read(&priv->rw_sem);
499*4882a593Smuzhiyun 	/* item name */
500*4882a593Smuzhiyun 	seq_puts(seq, "------------------------------------------------------");
501*4882a593Smuzhiyun 	seq_puts(seq, "------------------------------------------------------\n");
502*4882a593Smuzhiyun 	seq_printf(seq, "|%8s|", (const char *)"session");
503*4882a593Smuzhiyun 	seq_printf(seq, "%8s|", (const char *)"device");
504*4882a593Smuzhiyun 	for (i = ENC_INFO_BASE; i < ENC_INFO_BUTT; i++) {
505*4882a593Smuzhiyun 		bool show = priv->codec_info[i].flag;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 		if (show)
508*4882a593Smuzhiyun 			seq_printf(seq, "%8s|", enc_info_item_name[i]);
509*4882a593Smuzhiyun 	}
510*4882a593Smuzhiyun 	seq_puts(seq, "\n");
511*4882a593Smuzhiyun 	/* item data*/
512*4882a593Smuzhiyun 	seq_printf(seq, "|%8d|", session->index);
513*4882a593Smuzhiyun 	seq_printf(seq, "%8s|", mpp_device_name[session->device_type]);
514*4882a593Smuzhiyun 	for (i = ENC_INFO_BASE; i < ENC_INFO_BUTT; i++) {
515*4882a593Smuzhiyun 		u32 flag = priv->codec_info[i].flag;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 		if (!flag)
518*4882a593Smuzhiyun 			continue;
519*4882a593Smuzhiyun 		if (flag == CODEC_INFO_FLAG_NUMBER) {
520*4882a593Smuzhiyun 			u32 data = priv->codec_info[i].val;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 			seq_printf(seq, "%8d|", data);
523*4882a593Smuzhiyun 		} else if (flag == CODEC_INFO_FLAG_STRING) {
524*4882a593Smuzhiyun 			const char *name = (const char *)&priv->codec_info[i].val;
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 			seq_printf(seq, "%8s|", name);
527*4882a593Smuzhiyun 		} else {
528*4882a593Smuzhiyun 			seq_printf(seq, "%8s|", (const char *)"null");
529*4882a593Smuzhiyun 		}
530*4882a593Smuzhiyun 	}
531*4882a593Smuzhiyun 	seq_puts(seq, "\n");
532*4882a593Smuzhiyun 	up_read(&priv->rw_sem);
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	return 0;
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun 
vepu_show_session_info(struct seq_file * seq,void * offset)537*4882a593Smuzhiyun static int vepu_show_session_info(struct seq_file *seq, void *offset)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun 	struct mpp_session *session = NULL, *n;
540*4882a593Smuzhiyun 	struct mpp_dev *mpp = seq->private;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	mutex_lock(&mpp->srv->session_lock);
543*4882a593Smuzhiyun 	list_for_each_entry_safe(session, n,
544*4882a593Smuzhiyun 				 &mpp->srv->session_list,
545*4882a593Smuzhiyun 				 service_link) {
546*4882a593Smuzhiyun 		if (session->device_type != MPP_DEVICE_VEPU1)
547*4882a593Smuzhiyun 			continue;
548*4882a593Smuzhiyun 		if (!session->priv)
549*4882a593Smuzhiyun 			continue;
550*4882a593Smuzhiyun 		if (mpp->dev_ops->dump_session)
551*4882a593Smuzhiyun 			mpp->dev_ops->dump_session(session, seq);
552*4882a593Smuzhiyun 	}
553*4882a593Smuzhiyun 	mutex_unlock(&mpp->srv->session_lock);
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	return 0;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun 
vepu_procfs_init(struct mpp_dev * mpp)558*4882a593Smuzhiyun static int vepu_procfs_init(struct mpp_dev *mpp)
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun 	struct vepu_dev *enc = to_vepu_dev(mpp);
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	enc->procfs = proc_mkdir(mpp->dev->of_node->name, mpp->srv->procfs);
563*4882a593Smuzhiyun 	if (IS_ERR_OR_NULL(enc->procfs)) {
564*4882a593Smuzhiyun 		mpp_err("failed on open procfs\n");
565*4882a593Smuzhiyun 		enc->procfs = NULL;
566*4882a593Smuzhiyun 		return -EIO;
567*4882a593Smuzhiyun 	}
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	/* for common mpp_dev options */
570*4882a593Smuzhiyun 	mpp_procfs_create_common(enc->procfs, mpp);
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	mpp_procfs_create_u32("aclk", 0644,
573*4882a593Smuzhiyun 			      enc->procfs, &enc->aclk_info.debug_rate_hz);
574*4882a593Smuzhiyun 	mpp_procfs_create_u32("session_buffers", 0644,
575*4882a593Smuzhiyun 			      enc->procfs, &mpp->session_max_buffers);
576*4882a593Smuzhiyun 	/* for show session info */
577*4882a593Smuzhiyun 	proc_create_single_data("sessions-info", 0444,
578*4882a593Smuzhiyun 				enc->procfs, vepu_show_session_info, mpp);
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	return 0;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun #else
vepu_procfs_remove(struct mpp_dev * mpp)583*4882a593Smuzhiyun static inline int vepu_procfs_remove(struct mpp_dev *mpp)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun 	return 0;
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun 
vepu_procfs_init(struct mpp_dev * mpp)588*4882a593Smuzhiyun static inline int vepu_procfs_init(struct mpp_dev *mpp)
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun 	return 0;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun 
vepu_dump_session(struct mpp_session * session,struct seq_file * seq)593*4882a593Smuzhiyun static inline int vepu_dump_session(struct mpp_session *session, struct seq_file *seq)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun 	return 0;
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun #endif
598*4882a593Smuzhiyun 
vepu_init(struct mpp_dev * mpp)599*4882a593Smuzhiyun static int vepu_init(struct mpp_dev *mpp)
600*4882a593Smuzhiyun {
601*4882a593Smuzhiyun 	int ret;
602*4882a593Smuzhiyun 	struct vepu_dev *enc = to_vepu_dev(mpp);
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	mpp->grf_info = &mpp->srv->grf_infos[MPP_DRIVER_VEPU1];
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	/* Get clock info from dtsi */
607*4882a593Smuzhiyun 	ret = mpp_get_clk_info(mpp, &enc->aclk_info, "aclk_vcodec");
608*4882a593Smuzhiyun 	if (ret)
609*4882a593Smuzhiyun 		mpp_err("failed on clk_get aclk_vcodec\n");
610*4882a593Smuzhiyun 	ret = mpp_get_clk_info(mpp, &enc->hclk_info, "hclk_vcodec");
611*4882a593Smuzhiyun 	if (ret)
612*4882a593Smuzhiyun 		mpp_err("failed on clk_get hclk_vcodec\n");
613*4882a593Smuzhiyun 	/* Set default rates */
614*4882a593Smuzhiyun 	mpp_set_clk_info_rate_hz(&enc->aclk_info, CLK_MODE_DEFAULT, 300 * MHZ);
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	/* Get reset control from dtsi */
617*4882a593Smuzhiyun 	enc->rst_a = mpp_reset_control_get(mpp, RST_TYPE_A, "video_a");
618*4882a593Smuzhiyun 	if (!enc->rst_a)
619*4882a593Smuzhiyun 		mpp_err("No aclk reset resource define\n");
620*4882a593Smuzhiyun 	enc->rst_h = mpp_reset_control_get(mpp, RST_TYPE_H, "video_h");
621*4882a593Smuzhiyun 	if (!enc->rst_h)
622*4882a593Smuzhiyun 		mpp_err("No hclk reset resource define\n");
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	return 0;
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun 
vepu_clk_on(struct mpp_dev * mpp)627*4882a593Smuzhiyun static int vepu_clk_on(struct mpp_dev *mpp)
628*4882a593Smuzhiyun {
629*4882a593Smuzhiyun 	struct vepu_dev *enc = to_vepu_dev(mpp);
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	mpp_clk_safe_enable(enc->aclk_info.clk);
632*4882a593Smuzhiyun 	mpp_clk_safe_enable(enc->hclk_info.clk);
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	return 0;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun 
vepu_clk_off(struct mpp_dev * mpp)637*4882a593Smuzhiyun static int vepu_clk_off(struct mpp_dev *mpp)
638*4882a593Smuzhiyun {
639*4882a593Smuzhiyun 	struct vepu_dev *enc = to_vepu_dev(mpp);
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	mpp_clk_safe_disable(enc->aclk_info.clk);
642*4882a593Smuzhiyun 	mpp_clk_safe_disable(enc->hclk_info.clk);
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun 	return 0;
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun 
vepu_set_freq(struct mpp_dev * mpp,struct mpp_task * mpp_task)647*4882a593Smuzhiyun static int vepu_set_freq(struct mpp_dev *mpp,
648*4882a593Smuzhiyun 			 struct mpp_task *mpp_task)
649*4882a593Smuzhiyun {
650*4882a593Smuzhiyun 	struct vepu_dev *enc = to_vepu_dev(mpp);
651*4882a593Smuzhiyun 	struct vepu_task *task = to_vepu_task(mpp_task);
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	mpp_clk_set_rate(&enc->aclk_info, task->clk_mode);
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	return 0;
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun 
vepu_reduce_freq(struct mpp_dev * mpp)658*4882a593Smuzhiyun static int vepu_reduce_freq(struct mpp_dev *mpp)
659*4882a593Smuzhiyun {
660*4882a593Smuzhiyun 	struct vepu_dev *enc = to_vepu_dev(mpp);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	mpp_clk_set_rate(&enc->aclk_info, CLK_MODE_REDUCE);
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	return 0;
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun 
vepu_reset(struct mpp_dev * mpp)667*4882a593Smuzhiyun static int vepu_reset(struct mpp_dev *mpp)
668*4882a593Smuzhiyun {
669*4882a593Smuzhiyun 	struct vepu_dev *enc = to_vepu_dev(mpp);
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	if (enc->rst_a && enc->rst_h) {
672*4882a593Smuzhiyun 		/* Don't skip this or iommu won't work after reset */
673*4882a593Smuzhiyun 		mpp_pmu_idle_request(mpp, true);
674*4882a593Smuzhiyun 		mpp_safe_reset(enc->rst_a);
675*4882a593Smuzhiyun 		mpp_safe_reset(enc->rst_h);
676*4882a593Smuzhiyun 		udelay(5);
677*4882a593Smuzhiyun 		mpp_safe_unreset(enc->rst_a);
678*4882a593Smuzhiyun 		mpp_safe_unreset(enc->rst_h);
679*4882a593Smuzhiyun 		mpp_pmu_idle_request(mpp, false);
680*4882a593Smuzhiyun 	}
681*4882a593Smuzhiyun 	mpp_write(mpp, VEPU1_REG_ENC_EN, 0);
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	return 0;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun static struct mpp_hw_ops vepu_v1_hw_ops = {
687*4882a593Smuzhiyun 	.init = vepu_init,
688*4882a593Smuzhiyun 	.clk_on = vepu_clk_on,
689*4882a593Smuzhiyun 	.clk_off = vepu_clk_off,
690*4882a593Smuzhiyun 	.set_freq = vepu_set_freq,
691*4882a593Smuzhiyun 	.reduce_freq = vepu_reduce_freq,
692*4882a593Smuzhiyun 	.reset = vepu_reset,
693*4882a593Smuzhiyun };
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun static struct mpp_dev_ops vepu_v1_dev_ops = {
696*4882a593Smuzhiyun 	.alloc_task = vepu_alloc_task,
697*4882a593Smuzhiyun 	.run = vepu_run,
698*4882a593Smuzhiyun 	.irq = vepu_irq,
699*4882a593Smuzhiyun 	.isr = vepu_isr,
700*4882a593Smuzhiyun 	.finish = vepu_finish,
701*4882a593Smuzhiyun 	.result = vepu_result,
702*4882a593Smuzhiyun 	.free_task = vepu_free_task,
703*4882a593Smuzhiyun 	.ioctl = vepu_control,
704*4882a593Smuzhiyun 	.init_session = vepu_init_session,
705*4882a593Smuzhiyun 	.free_session = vepu_free_session,
706*4882a593Smuzhiyun 	.dump_session = vepu_dump_session,
707*4882a593Smuzhiyun };
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun static const struct mpp_dev_var vepu_v1_data = {
710*4882a593Smuzhiyun 	.device_type = MPP_DEVICE_VEPU1,
711*4882a593Smuzhiyun 	.hw_info = &vepu_v1_hw_info,
712*4882a593Smuzhiyun 	.trans_info = trans_rk_vepu1,
713*4882a593Smuzhiyun 	.hw_ops = &vepu_v1_hw_ops,
714*4882a593Smuzhiyun 	.dev_ops = &vepu_v1_dev_ops,
715*4882a593Smuzhiyun };
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun static const struct of_device_id mpp_vepu1_dt_match[] = {
718*4882a593Smuzhiyun 	{
719*4882a593Smuzhiyun 		.compatible = "rockchip,vpu-encoder-v1",
720*4882a593Smuzhiyun 		.data = &vepu_v1_data,
721*4882a593Smuzhiyun 	},
722*4882a593Smuzhiyun 	{},
723*4882a593Smuzhiyun };
724*4882a593Smuzhiyun 
vepu_probe(struct platform_device * pdev)725*4882a593Smuzhiyun static int vepu_probe(struct platform_device *pdev)
726*4882a593Smuzhiyun {
727*4882a593Smuzhiyun 	int ret = 0;
728*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
729*4882a593Smuzhiyun 	struct vepu_dev *enc = NULL;
730*4882a593Smuzhiyun 	struct mpp_dev *mpp = NULL;
731*4882a593Smuzhiyun 	const struct of_device_id *match = NULL;
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	dev_info(dev, "probe device\n");
734*4882a593Smuzhiyun 	enc = devm_kzalloc(dev, sizeof(struct vepu_dev), GFP_KERNEL);
735*4882a593Smuzhiyun 	if (!enc)
736*4882a593Smuzhiyun 		return -ENOMEM;
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	mpp = &enc->mpp;
739*4882a593Smuzhiyun 	platform_set_drvdata(pdev, mpp);
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	if (pdev->dev.of_node) {
742*4882a593Smuzhiyun 		match = of_match_node(mpp_vepu1_dt_match, pdev->dev.of_node);
743*4882a593Smuzhiyun 		if (match)
744*4882a593Smuzhiyun 			mpp->var = (struct mpp_dev_var *)match->data;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 		mpp->core_id = of_alias_get_id(pdev->dev.of_node, "vepu");
747*4882a593Smuzhiyun 	}
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	ret = mpp_dev_probe(mpp, pdev);
750*4882a593Smuzhiyun 	if (ret) {
751*4882a593Smuzhiyun 		dev_err(dev, "probe sub driver failed\n");
752*4882a593Smuzhiyun 		return -EINVAL;
753*4882a593Smuzhiyun 	}
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	ret = devm_request_threaded_irq(dev, mpp->irq,
756*4882a593Smuzhiyun 					mpp_dev_irq,
757*4882a593Smuzhiyun 					mpp_dev_isr_sched,
758*4882a593Smuzhiyun 					IRQF_SHARED,
759*4882a593Smuzhiyun 					dev_name(dev), mpp);
760*4882a593Smuzhiyun 	if (ret) {
761*4882a593Smuzhiyun 		dev_err(dev, "register interrupter runtime failed\n");
762*4882a593Smuzhiyun 		return -EINVAL;
763*4882a593Smuzhiyun 	}
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 	mpp->session_max_buffers = VEPU1_SESSION_MAX_BUFFERS;
766*4882a593Smuzhiyun 	vepu_procfs_init(mpp);
767*4882a593Smuzhiyun 	/* register current device to mpp service */
768*4882a593Smuzhiyun 	mpp_dev_register_srv(mpp, mpp->srv);
769*4882a593Smuzhiyun 	dev_info(dev, "probing finish\n");
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun 	return 0;
772*4882a593Smuzhiyun }
773*4882a593Smuzhiyun 
vepu_remove(struct platform_device * pdev)774*4882a593Smuzhiyun static int vepu_remove(struct platform_device *pdev)
775*4882a593Smuzhiyun {
776*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
777*4882a593Smuzhiyun 	struct mpp_dev *mpp = dev_get_drvdata(dev);
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	dev_info(dev, "remove device\n");
780*4882a593Smuzhiyun 	mpp_dev_remove(mpp);
781*4882a593Smuzhiyun 	vepu_procfs_remove(mpp);
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	return 0;
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun struct platform_driver rockchip_vepu1_driver = {
787*4882a593Smuzhiyun 	.probe = vepu_probe,
788*4882a593Smuzhiyun 	.remove = vepu_remove,
789*4882a593Smuzhiyun 	.shutdown = mpp_dev_shutdown,
790*4882a593Smuzhiyun 	.driver = {
791*4882a593Smuzhiyun 		.name = VEPU1_DRIVER_NAME,
792*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(mpp_vepu1_dt_match),
793*4882a593Smuzhiyun 	},
794*4882a593Smuzhiyun };
795*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_vepu1_driver);
796