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