xref: /OK3568_Linux_fs/kernel/drivers/video/rockchip/dvbm/rockchip_dvbm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2 /*
3  * Copyright (c) 2022 Rockchip Electronics Co., Ltd
4  *
5  * author:
6  *	Yandong Lin, yandong.lin@rock-chips.com
7  */
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9 
10 #include <linux/delay.h>
11 #include <linux/module.h>
12 #include <linux/of_platform.h>
13 #include <linux/proc_fs.h>
14 #include <linux/pm_runtime.h>
15 #include <linux/regmap.h>
16 #include <linux/interrupt.h>
17 #include <soc/rockchip/rockchip_dvbm.h>
18 
19 #include "rockchip_dvbm.h"
20 
21 #define RK_DVBM		"rk_dvbm"
22 
23 unsigned int dvbm_debug;
24 module_param(dvbm_debug, uint, 0644);
25 MODULE_PARM_DESC(dvbm_debug, "bit switch for dvbm debug information");
26 
27 static struct dvbm_ctx *g_ctx;
28 
29 #define DVBM_DEBUG	0x00000001
30 #define DVBM_DEBUG_IRQ	0x00000002
31 #define DVBM_DEBUG_REG	0x00000004
32 #define DVBM_DEBUG_DUMP	0x00000008
33 #define DVBM_DEBUG_FRM	0x00000010
34 
35 #define dvbm_debug(fmt, args...)				\
36 	do {							\
37 		if (unlikely(dvbm_debug & (DVBM_DEBUG)))	\
38 			pr_info(fmt, ##args);			\
39 	} while (0)
40 
41 #define dvbm_debug_reg(fmt, args...)				\
42 	do {							\
43 		if (unlikely(dvbm_debug & (DVBM_DEBUG_REG)))	\
44 			pr_info(fmt, ##args);			\
45 	} while (0)
46 
47 #define dvbm_debug_irq(fmt, args...)				\
48 	do {							\
49 		if (unlikely(dvbm_debug & (DVBM_DEBUG_IRQ)))	\
50 			pr_info(fmt, ##args);			\
51 	} while (0)
52 
53 #define dvbm_debug_dump(fmt, args...)				\
54 	do {							\
55 		if (unlikely(dvbm_debug & (DVBM_DEBUG_DUMP)))	\
56 			pr_info(fmt, ##args);			\
57 	} while (0)
58 
59 #define dvbm_debug_frm(fmt, args...)				\
60 	do {							\
61 		if (unlikely(dvbm_debug & (DVBM_DEBUG_FRM)))	\
62 			pr_info(fmt, ##args);			\
63 	} while (0)
64 
65 #define dvbm_err(fmt, args...)	\
66 	pr_err(fmt, ##args)
67 
68 enum dvbm_flow {
69 	ISP_CFG		= 1,
70 	ISP_CONNECT	= 2,
71 	VEPU_CFG	= 3,
72 	VEPU_CONNECT	= 4,
73 };
74 /* dvbm status reg bit value define */
75 #define BUF_OVERFLOW		BIT(0)
76 #define RESYNC_FINISH		BIT(1)
77 #define ISP_CNCT_TIMEOUT	BIT(2)
78 #define VEPU_CNCT_TIMEOUT	BIT(3)
79 #define VEPU_HANDSHAKE_TIMEOUT	BIT(4)
80 #define ISP_CNCT		BIT(5)
81 #define ISP_DISCNCT		BIT(6)
82 #define VEPU_CNCT		BIT(7)
83 #define VEPU_DISCNCT		BIT(8)
84 
85 /* dvbm reg addr define */
86 #define DVBM_VERSION	0x0
87 #define DVBM_ISP_CNCT	0x4
88 #define DVBM_VEPU_CNCT	0x8
89 /* cfg regs */
90 #define DVBM_CFG	0xC
91 #define DVBM_WDG_CFG0	0x10
92 #define DVBM_WDG_CFG1	0x14
93 #define DVBM_WDG_CFG2	0x18
94 /* interrupt regs */
95 #define DVBM_INT_EN	0x1c
96 #define DVBM_INT_MSK	0x20
97 #define DVBM_INT_CLR	0x24
98 #define DVBM_INT_ST	0x28
99 /* addr regs */
100 #define DVBM_YBUF_BOT	0x2c
101 #define DVBM_YBUF_TOP	0x30
102 #define DVBM_YBUF_SADR	0x34
103 #define DVBM_YBUF_LSTD	0x38
104 #define DVBM_YBUF_FSTD	0x3c
105 #define DVBM_CBUF_BOT	0x40
106 #define DVBM_CBUF_TOP	0x44
107 #define DVBM_CBUF_SADR	0x48
108 #define DVBM_CBUF_LSTD	0x4c
109 #define DVBM_CBUF_FSTD	0x50
110 #define DVBM_AFUL_THDY	0x54
111 #define DVBM_AFUL_THDC	0x58
112 #define DVBM_OVFL_THDY	0x5c
113 #define DVBM_OVFL_THDC	0x60
114 /* status regs */
115 #define DVBM_ST		0x80
116 #define DVBM_OVFL_ST	0x84
117 
118 #define DVBM_REG_OFFSET 0x2c
119 
120 #define SOFT_DVBM 1
121 #define UPDATE_LINE_CNT 0
122 
rk_dvbm_set_reg(struct dvbm_ctx * ctx,u32 offset,u32 val)123 static void rk_dvbm_set_reg(struct dvbm_ctx *ctx, u32 offset, u32 val)
124 {
125 	if (!SOFT_DVBM) {
126 		dvbm_debug_reg("write reg[%d] 0x%x = 0x%08x\n", offset >> 2, offset, val);
127 		writel(val, ctx->reg_base + offset);
128 	}
129 }
130 
rk_dvbm_read_reg(struct dvbm_ctx * ctx,u32 offset)131 static u32 rk_dvbm_read_reg(struct dvbm_ctx *ctx, u32 offset)
132 {
133 	u32 val = 0;
134 
135 	if (!SOFT_DVBM) {
136 		val = readl(ctx->reg_base + offset);
137 		dvbm_debug_reg("read reg[%d] 0x%x = 0x%08x\n", offset >> 2, offset, val);
138 	}
139 	return val;
140 }
141 
port_to_ctx(struct dvbm_port * port)142 static struct dvbm_ctx *port_to_ctx(struct dvbm_port *port)
143 {
144 	struct dvbm_ctx *ctx = NULL;
145 
146 	if (IS_ERR_OR_NULL(port))
147 		return g_ctx;
148 	if (port->dir == DVBM_ISP_PORT)
149 		ctx = container_of(port, struct dvbm_ctx, port_isp);
150 	else if (port->dir == DVBM_VEPU_PORT)
151 		ctx = container_of(port, struct dvbm_ctx, port_vepu);
152 
153 	return ctx;
154 }
155 
dvbm2enc_callback(struct dvbm_ctx * ctx,enum dvbm_cb_event event,void * arg)156 static void dvbm2enc_callback(struct dvbm_ctx *ctx, enum dvbm_cb_event event, void *arg)
157 {
158 	struct dvbm_cb *callback = &ctx->vepu_cb;
159 	dvbm_callback cb = callback->cb;
160 
161 	if (!ctx->port_vepu.linked)
162 		return;
163 	if (cb)
164 		cb(callback->ctx, event, arg);
165 }
166 
rk_dvbm_dump_regs(struct dvbm_ctx * ctx)167 static void rk_dvbm_dump_regs(struct dvbm_ctx *ctx)
168 {
169 	u32 start = ctx->dump_s;//0x80;
170 	u32 end = ctx->dump_e;//0xb8;
171 	u32 i;
172 	dvbm_debug_dump("=== %s ===\n", __func__);
173 	for (i = start; i <= end; i += 4)
174 		dvbm_debug_dump("reg[0x%0x] = 0x%08x\n", i, readl(ctx->reg_base + i));
175 	dvbm_debug_dump("=== %s ===\n", __func__);
176 }
177 
rk_dvbm_clk_on(struct dvbm_ctx * ctx)178 static int rk_dvbm_clk_on(struct dvbm_ctx *ctx)
179 {
180 	int ret = 0;
181 
182 	if (ctx->clk)
183 		ret = clk_prepare_enable(ctx->clk);
184 	if (ret)
185 		dev_err(ctx->dev, "clk on failed\n");
186 	return ret;
187 }
188 
rk_dvbm_clk_off(struct dvbm_ctx * ctx)189 static int rk_dvbm_clk_off(struct dvbm_ctx *ctx)
190 {
191 	if (ctx->clk)
192 		clk_disable_unprepare(ctx->clk);
193 	return 0;
194 }
195 
init_isp_infos(struct dvbm_ctx * ctx)196 static void init_isp_infos(struct dvbm_ctx *ctx)
197 {
198 	ctx->isp_frm_start = 0;
199 	ctx->isp_frm_end = 0;
200 	ctx->isp_frm_time = 0;
201 }
202 
rk_dvbm_show_time(struct dvbm_ctx * ctx)203 static void rk_dvbm_show_time(struct dvbm_ctx *ctx)
204 {
205 	ktime_t time = ktime_get();
206 
207 	if (ctx->isp_frm_time)
208 		dvbm_debug("isp frame start[%d : %d] times %lld us\n",
209 			   ctx->isp_frm_start, ctx->isp_frm_end,
210 			   ktime_us_delta(time, ctx->isp_frm_time));
211 	ctx->isp_frm_time = time;
212 }
213 
rk_dvbm_update_isp_frm_info(struct dvbm_ctx * ctx,u32 line_cnt)214 static void rk_dvbm_update_isp_frm_info(struct dvbm_ctx *ctx, u32 line_cnt)
215 {
216 #if UPDATE_LINE_CNT
217 	struct dvbm_isp_frm_info *frm_info = &ctx->isp_frm_info;
218 
219 	frm_info->line_cnt = ALIGN(line_cnt, 32);
220 	dvbm_debug_frm("dvbm frame %d line %d\n", frm_info->frame_cnt, frm_info->line_cnt);
221 	dvbm2enc_callback(ctx, DVBM_VEPU_NOTIFY_FRM_INFO, frm_info);
222 #endif
223 }
224 
rk_dvbm_setup_iobuf(struct dvbm_ctx * ctx)225 static int rk_dvbm_setup_iobuf(struct dvbm_ctx *ctx)
226 {
227 	u32 *data;
228 	u32 i;
229 	struct rk_dvbm_base *addr_base = &ctx->regs.addr_base;
230 	struct dvbm_isp_cfg_t *cfg = &ctx->isp_cfg;
231 
232 	addr_base->ybuf_bot = cfg->dma_addr + cfg->ybuf_bot;
233 	addr_base->ybuf_top = cfg->dma_addr + cfg->ybuf_top;
234 	addr_base->ybuf_sadr = cfg->dma_addr + cfg->ybuf_bot;
235 	addr_base->ybuf_fstd = cfg->ybuf_fstd;
236 	addr_base->ybuf_lstd = cfg->ybuf_lstd;
237 
238 	addr_base->cbuf_bot = cfg->dma_addr + cfg->cbuf_bot;
239 	addr_base->cbuf_top = cfg->dma_addr + cfg->cbuf_top;
240 	addr_base->cbuf_sadr = cfg->dma_addr + cfg->cbuf_bot;
241 	addr_base->cbuf_fstd = cfg->cbuf_fstd;
242 	addr_base->cbuf_lstd = cfg->cbuf_lstd;
243 
244 	addr_base->aful_thdy = cfg->ybuf_lstd;
245 	addr_base->aful_thdc = cfg->ybuf_lstd;
246 	addr_base->oful_thdy = cfg->ybuf_lstd;
247 	addr_base->oful_thdc = cfg->ybuf_lstd;
248 
249 	ctx->isp_max_lcnt = cfg->ybuf_fstd / cfg->ybuf_lstd;
250 	ctx->wrap_line = (cfg->ybuf_top - cfg->ybuf_bot) / cfg->ybuf_lstd;
251 	ctx->isp_frm_info.frame_cnt = 0;
252 	ctx->isp_frm_info.line_cnt = 0;
253 	ctx->isp_frm_info.max_line_cnt = ALIGN(ctx->isp_max_lcnt, 32);
254 	ctx->isp_frm_info.wrap_line = ctx->wrap_line;
255 	dvbm_debug("dma_addr %pad y_lstd %d y_fstd %d\n",
256 		   &cfg->dma_addr, cfg->ybuf_lstd, cfg->ybuf_fstd);
257 	dvbm_debug("ybot 0x%x top 0x%x cbuf bot 0x%x top 0x%x\n",
258 		   addr_base->ybuf_bot, addr_base->ybuf_top,
259 		   addr_base->cbuf_bot, addr_base->cbuf_top);
260 
261 	data = (u32 *)addr_base;
262 	for (i = 0; i < sizeof(struct rk_dvbm_base) / sizeof(u32); i++)
263 		rk_dvbm_set_reg(ctx, i * sizeof(u32) + DVBM_REG_OFFSET, data[i]);
264 
265 	for (i = 1; i < 65536; i++)
266 		if (!((addr_base->ybuf_fstd * i) % (cfg->ybuf_top - cfg->ybuf_bot)))
267 			break;
268 	ctx->loopcnt = i;
269 	return 0;
270 }
271 
rk_dvbm_reg_init(struct dvbm_ctx * ctx)272 static void rk_dvbm_reg_init(struct dvbm_ctx *ctx)
273 {
274 	struct rk_dvbm_regs *reg = &ctx->regs;
275 	u32 *val = (u32 *)reg;
276 
277 	reg->int_en.buf_ovfl               = 1;
278 	reg->int_en.isp_cnct               = 1;
279 	reg->int_en.vepu_cnct              = 1;
280 	reg->int_en.vepu_discnct           = 1;
281 	reg->int_en.isp_discnct            = 1;
282 	reg->int_en.resync_finish          = 1;
283 	reg->int_en.isp_cnct_timeout       = 1;
284 	reg->int_en.vepu_cnct_timeout      = 1;
285 	reg->int_en.vepu_handshake_timeout = 1;
286 
287 	reg->dvbm_cfg.fmt                         = 0;
288 	reg->dvbm_cfg.auto_resyn                  = 0;
289 	reg->dvbm_cfg.ignore_vepu_cnct_ack        = 0;
290 	reg->dvbm_cfg.start_point_after_vepu_cnct = 0;
291 
292 	reg->wdg_cfg0.wdg_isp_cnct_timeout       = 0xfffff;
293 	reg->wdg_cfg1.wdg_vepu_cnct_timeout      = 0xfffff;
294 	reg->wdg_cfg2.wdg_vepu_handshake_timeout = 0xfffff;
295 
296 	rk_dvbm_set_reg(ctx, DVBM_WDG_CFG0, val[DVBM_WDG_CFG0 >> 2]);
297 	rk_dvbm_set_reg(ctx, DVBM_WDG_CFG1, val[DVBM_WDG_CFG1 >> 2]);
298 	rk_dvbm_set_reg(ctx, DVBM_WDG_CFG2, val[DVBM_WDG_CFG2 >> 2]);
299 	rk_dvbm_set_reg(ctx, DVBM_CFG, val[DVBM_CFG >> 2]);
300 	rk_dvbm_set_reg(ctx, DVBM_INT_EN, val[DVBM_INT_EN >> 2]);
301 }
302 
rk_dvbm_get_port(struct platform_device * pdev,enum dvbm_port_dir dir)303 struct dvbm_port *rk_dvbm_get_port(struct platform_device *pdev,
304 				   enum dvbm_port_dir dir)
305 {
306 	struct dvbm_ctx *ctx = NULL;
307 	struct dvbm_port *port = NULL;
308 
309 	if (WARN_ON(!pdev))
310 		return NULL;
311 
312 	ctx = (struct dvbm_ctx *)platform_get_drvdata(pdev);
313 	WARN_ON(!ctx);
314 	dvbm_debug("%s dir %d\n", __func__, dir);
315 	if (dir == DVBM_ISP_PORT)
316 		port = &ctx->port_isp;
317 	else if (dir == DVBM_VEPU_PORT)
318 		port = &ctx->port_vepu;
319 
320 	return port;
321 }
322 EXPORT_SYMBOL(rk_dvbm_get_port);
323 
rk_dvbm_put(struct dvbm_port * port)324 int rk_dvbm_put(struct dvbm_port *port)
325 {
326 	struct dvbm_ctx *ctx = NULL;
327 
328 	if (WARN_ON(!port))
329 		return -EINVAL;
330 
331 	ctx = port_to_ctx(port);
332 
333 	if (!ctx)
334 		return -EINVAL;
335 	return 0;
336 }
337 EXPORT_SYMBOL(rk_dvbm_put);
338 
rk_dvbm_link(struct dvbm_port * port)339 int rk_dvbm_link(struct dvbm_port *port)
340 {
341 	struct dvbm_ctx *ctx;
342 	enum dvbm_port_dir dir;
343 	struct rk_dvbm_regs *reg;
344 	int ret = 0;
345 
346 	if (WARN_ON(!port))
347 		return -EINVAL;
348 
349 	ctx = port_to_ctx(port);
350 	dir = port->dir;
351 	reg = &ctx->regs;
352 
353 	if (dir == DVBM_ISP_PORT) {
354 		if (port->linked) {
355 			rk_dvbm_unlink(port);
356 			udelay(5);
357 		}
358 		reg->isp_cnct.isp_cnct = 1;
359 		rk_dvbm_set_reg(ctx, DVBM_ISP_CNCT, 0x1);
360 	} else if (dir == DVBM_VEPU_PORT) {
361 		if (!port->linked) {
362 			reg->vepu_cnct.vepu_cnct = 1;
363 			rk_dvbm_set_reg(ctx, DVBM_VEPU_CNCT, 0x1);
364 		}
365 		port->linked = 1;
366 		dvbm_debug_dump("=== vepu link ===\n");
367 		rk_dvbm_dump_regs(ctx);
368 		dvbm_debug_dump("=== vepu link ===\n");
369 	}
370 
371 	dvbm_debug("%s connect frm_cnt[%d : %d]\n",
372 		   dir == DVBM_ISP_PORT ? "isp" : "vepu",
373 		   ctx->isp_frm_start, ctx->isp_frm_end);
374 
375 	return ret;
376 }
377 EXPORT_SYMBOL(rk_dvbm_link);
378 
rk_dvbm_unlink(struct dvbm_port * port)379 int rk_dvbm_unlink(struct dvbm_port *port)
380 {
381 	struct dvbm_ctx *ctx;
382 	enum dvbm_port_dir dir;
383 	struct rk_dvbm_regs *reg;
384 
385 	if (WARN_ON(!port))
386 		return -EINVAL;
387 
388 	ctx = port_to_ctx(port);
389 	dir = port->dir;
390 	reg = &ctx->regs;
391 
392 	if (dir == DVBM_ISP_PORT) {
393 		reg->isp_cnct.isp_cnct = 0;
394 		rk_dvbm_set_reg(ctx, DVBM_ISP_CNCT, 0);
395 	} else if (dir == DVBM_VEPU_PORT) {
396 		reg->vepu_cnct.vepu_cnct = 0;
397 		port->linked = 0;
398 		rk_dvbm_set_reg(ctx, DVBM_VEPU_CNCT, 0);
399 		if (!ctx->regs.dvbm_cfg.auto_resyn) {
400 			u32 connect = 0;
401 
402 			dvbm2enc_callback(ctx, DVBM_VEPU_REQ_CONNECT, &connect);
403 		}
404 	}
405 	dvbm_debug("%s disconnect\n", dir == DVBM_ISP_PORT ? "isp" : "vepu");
406 
407 	return 0;
408 }
409 EXPORT_SYMBOL(rk_dvbm_unlink);
410 
rk_dvbm_set_cb(struct dvbm_port * port,struct dvbm_cb * cb)411 int rk_dvbm_set_cb(struct dvbm_port *port, struct dvbm_cb *cb)
412 {
413 	struct dvbm_ctx *ctx;
414 	enum dvbm_port_dir dir;
415 
416 	if (WARN_ON(!port) || WARN_ON(!cb))
417 		return -EINVAL;
418 
419 	ctx = port_to_ctx(port);
420 	dir = port->dir;
421 
422 	if (dir == DVBM_ISP_PORT) {
423 
424 	} else if (dir == DVBM_VEPU_PORT) {
425 		ctx->vepu_cb.cb = cb->cb;
426 		ctx->vepu_cb.ctx = cb->ctx;
427 	}
428 
429 	return 0;
430 }
431 EXPORT_SYMBOL(rk_dvbm_set_cb);
432 
rk_dvbm_update_next_adr(struct dvbm_ctx * ctx)433 static void rk_dvbm_update_next_adr(struct dvbm_ctx *ctx)
434 {
435 	u32 frame_cnt = ctx->isp_frm_start;
436 	struct dvbm_isp_cfg_t *isp_cfg = &ctx->isp_cfg;
437 	struct dvbm_addr_cfg *vepu_cfg = &ctx->vepu_cfg;
438 	u32 y_wrap_size = isp_cfg->ybuf_top - isp_cfg->ybuf_bot;
439 	u32 c_wrap_size = isp_cfg->cbuf_top - isp_cfg->cbuf_bot;
440 	u32 s_off;
441 
442 	frame_cnt = (frame_cnt + 1) % (ctx->loopcnt);
443 	s_off = (frame_cnt * isp_cfg->ybuf_fstd) % y_wrap_size;
444 	vepu_cfg->ybuf_sadr = isp_cfg->dma_addr + isp_cfg->ybuf_bot + s_off;
445 
446 	s_off = (frame_cnt * isp_cfg->cbuf_fstd) % c_wrap_size;
447 	vepu_cfg->cbuf_sadr = isp_cfg->dma_addr + isp_cfg->cbuf_bot + s_off;
448 }
449 
rk_dvbm_ctrl(struct dvbm_port * port,enum dvbm_cmd cmd,void * arg)450 int rk_dvbm_ctrl(struct dvbm_port *port, enum dvbm_cmd cmd, void *arg)
451 {
452 	struct dvbm_ctx *ctx;
453 	struct rk_dvbm_regs *reg;
454 
455 	if ((cmd < DVBM_ISP_CMD_BASE) || (cmd > DVBM_VEPU_CMD_BUTT)) {
456 		dvbm_err("%s input cmd invalid\n", __func__);
457 		return -EINVAL;
458 	}
459 
460 	ctx = port_to_ctx(port);
461 	reg = &ctx->regs;
462 
463 	switch (cmd) {
464 	case DVBM_ISP_SET_CFG: {
465 		struct dvbm_isp_cfg_t *cfg = (struct dvbm_isp_cfg_t *)arg;
466 
467 		memcpy(&ctx->isp_cfg, cfg, sizeof(struct dvbm_isp_cfg_t));
468 		rk_dvbm_setup_iobuf(ctx);
469 		init_isp_infos(ctx);
470 		rk_dvbm_update_next_adr(ctx);
471 	} break;
472 	case DVBM_ISP_FRM_START: {
473 		rk_dvbm_update_isp_frm_info(ctx, 0);
474 		rk_dvbm_show_time(ctx);
475 	} break;
476 	case DVBM_ISP_FRM_END: {
477 		u32 line_cnt = ctx->isp_max_lcnt;
478 
479 		ctx->isp_frm_end = *(u32 *)arg;
480 		/* wrap frame_cnt 0 - 255 */
481 		ctx->isp_frm_info.frame_cnt = (ctx->isp_frm_start + 1) % 256;
482 		rk_dvbm_update_next_adr(ctx);
483 		rk_dvbm_update_isp_frm_info(ctx, line_cnt);
484 		ctx->isp_frm_start++;
485 		dvbm_debug("isp frame end[%d : %d]\n", ctx->isp_frm_start, ctx->isp_frm_end);
486 	} break;
487 	case DVBM_ISP_FRM_QUARTER: {
488 		u32 line_cnt;
489 
490 		line_cnt = ctx->isp_max_lcnt >> 2;
491 		rk_dvbm_update_isp_frm_info(ctx, line_cnt);
492 	} break;
493 	case DVBM_ISP_FRM_HALF: {
494 		u32 line_cnt;
495 
496 		line_cnt = ctx->isp_max_lcnt >> 1;
497 		rk_dvbm_update_isp_frm_info(ctx, line_cnt);
498 	} break;
499 	case DVBM_ISP_FRM_THREE_QUARTERS: {
500 		u32 line_cnt;
501 
502 		line_cnt = (ctx->isp_max_lcnt >> 2) * 3;
503 		rk_dvbm_update_isp_frm_info(ctx, line_cnt);
504 	} break;
505 	case DVBM_VEPU_GET_ADR: {
506 		struct dvbm_addr_cfg *dvbm_adr = (struct dvbm_addr_cfg *)arg;
507 		struct rk_dvbm_base *addr_base = &reg->addr_base;
508 
509 		dvbm_adr->ybuf_top = addr_base->ybuf_top;
510 		dvbm_adr->ybuf_bot = addr_base->ybuf_bot;
511 		dvbm_adr->cbuf_top = addr_base->cbuf_top;
512 		dvbm_adr->cbuf_bot = addr_base->cbuf_bot;
513 		dvbm_adr->cbuf_sadr = ctx->vepu_cfg.cbuf_sadr;
514 		dvbm_adr->ybuf_sadr = ctx->vepu_cfg.ybuf_sadr;
515 		dvbm_adr->overflow = ctx->isp_frm_info.line_cnt >= ctx->wrap_line;
516 		dvbm_adr->frame_id = ctx->isp_frm_info.frame_cnt;
517 		dvbm_adr->line_cnt = ctx->isp_frm_info.line_cnt;
518 	} break;
519 	case DVBM_VEPU_GET_FRAME_INFO: {
520 		memcpy(arg, &ctx->isp_frm_info, sizeof(struct dvbm_isp_frm_info));
521 	} break;
522 	case DVBM_VEPU_SET_RESYNC: {
523 		reg->dvbm_cfg.auto_resyn = *(u32 *)arg;
524 		dev_info(ctx->dev, "change resync %s\n",
525 			 reg->dvbm_cfg.auto_resyn ? "auto" : "soft");
526 		rk_dvbm_set_reg(ctx, DVBM_CFG, ((u32 *)&reg->dvbm_cfg)[0]);
527 	} break;
528 	case DVBM_VEPU_SET_CFG: {
529 		struct dvbm_vepu_cfg *cfg = (struct dvbm_vepu_cfg *)arg;
530 
531 		reg->dvbm_cfg.auto_resyn = cfg->auto_resyn;
532 		reg->dvbm_cfg.ignore_vepu_cnct_ack = cfg->ignore_vepu_cnct_ack;
533 		reg->dvbm_cfg.start_point_after_vepu_cnct = cfg->start_point_after_vepu_cnct;
534 
535 		rk_dvbm_set_reg(ctx, DVBM_CFG, ((u32 *)&reg->dvbm_cfg)[0]);
536 	} break;
537 	case DVBM_VEPU_DUMP_REGS: {
538 		rk_dvbm_dump_regs(ctx);
539 	} break;
540 	default: {
541 	} break;
542 	}
543 
544 	return 0;
545 }
546 EXPORT_SYMBOL(rk_dvbm_ctrl);
547 
dvbm_check_irq(struct dvbm_ctx * ctx)548 static void dvbm_check_irq(struct dvbm_ctx *ctx)
549 {
550 	u32 irq_st = ctx->irq_status;
551 	u32 cur_st = ctx->dvbm_status;
552 
553 	if (irq_st & ISP_CNCT) {
554 		dvbm_debug_irq("%s isp connect success! st 0x%08x\n",
555 			       __func__, cur_st);
556 		ctx->port_isp.linked = 1;
557 	}
558 	if (irq_st & ISP_DISCNCT) {
559 		dvbm_debug_irq("%s isp disconnect success!\n", __func__);
560 		ctx->port_isp.linked = 0;
561 	}
562 	if (irq_st & VEPU_CNCT) {
563 		dvbm_debug_irq("%s vepu connect success! st 0x%08x\n",
564 			       __func__, cur_st);
565 		ctx->port_vepu.linked = 1;
566 	}
567 	if (irq_st & VEPU_DISCNCT) {
568 		dvbm_debug_irq("%s vepu disconnect success! st 0x%08x\n", __func__, cur_st);
569 		ctx->port_vepu.linked = 0;
570 	}
571 	if (irq_st & BUF_OVERFLOW) {
572 		dvbm_debug_irq("%s buf overflow st 0x%08x auto_resync %d ignore %d\n",
573 			       __func__, cur_st, ctx->regs.dvbm_cfg.auto_resyn, ctx->ignore_ovfl);
574 
575 		if (!ctx->regs.dvbm_cfg.auto_resyn && !ctx->ignore_ovfl)
576 			rk_dvbm_unlink(&ctx->port_vepu);
577 	}
578 	if (irq_st & (ISP_CNCT_TIMEOUT | VEPU_CNCT_TIMEOUT))
579 		rk_dvbm_dump_regs(ctx);
580 }
581 
rk_dvbm_irq(int irq,void * param)582 static irqreturn_t rk_dvbm_irq(int irq, void *param)
583 {
584 	struct dvbm_ctx *ctx = param;
585 	u32 irq_st = 0;
586 	u32 cur_st = 0;
587 
588 	if (ctx->reg_base) {
589 		/* read irq st */
590 		irq_st = rk_dvbm_read_reg(ctx, DVBM_INT_ST);
591 		cur_st = rk_dvbm_read_reg(ctx, DVBM_ST);
592 		if (irq_st & BUF_OVERFLOW) {
593 			dvbm_debug_dump("=== dvbm overflow! dump reg st: 0x%08x===\n", irq_st);
594 			rk_dvbm_dump_regs(ctx);
595 			dvbm2enc_callback(ctx, DVBM_VEPU_NOTIFY_DUMP, NULL);
596 			dvbm_debug_dump("=== dvbm overflow! dump reg end===\n");
597 		}
598 		/* clr irq */
599 		rk_dvbm_set_reg(ctx, DVBM_INT_CLR, irq_st);
600 		rk_dvbm_set_reg(ctx, DVBM_INT_ST, 0);
601 	}
602 	ctx->irq_status = irq_st;
603 	ctx->dvbm_status = cur_st;
604 
605 	dvbm_debug_irq("%s irq status 0x%08x\n", __func__, irq_st);
606 
607 	return IRQ_WAKE_THREAD;
608 }
609 
rk_dvbm_isr(int irq,void * param)610 static irqreturn_t rk_dvbm_isr(int irq, void *param)
611 {
612 	struct dvbm_ctx *ctx = param;
613 
614 	dvbm_check_irq(ctx);
615 
616 	return IRQ_HANDLED;
617 }
618 
rk_dvbm_probe(struct platform_device * pdev)619 static int rk_dvbm_probe(struct platform_device *pdev)
620 {
621 	int ret;
622 	struct dvbm_ctx *ctx = NULL;
623 	struct device *dev = &pdev->dev;
624 	struct resource *res = NULL;
625 
626 	dev_info(dev, "probe start\n");
627 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
628 	if (!ctx)
629 		return -ENOMEM;
630 	dev_info(dev, "dvbm ctx %p\n", ctx);
631 
632 	ctx->dev = dev;
633 
634 	atomic_set(&ctx->isp_ref, 0);
635 	atomic_set(&ctx->vepu_ref, 0);
636 	ctx->port_isp.dir = DVBM_ISP_PORT;
637 	ctx->port_vepu.dir = DVBM_VEPU_PORT;
638 
639 	platform_set_drvdata(pdev, ctx);
640 
641 	pm_runtime_enable(dev);
642 
643 	/* get irq */
644 	ctx->irq = platform_get_irq(pdev, 0);
645 	if (ctx->irq < 0) {
646 		dev_err(&pdev->dev, "no interrupt resource found\n");
647 		ret = -ENODEV;
648 		goto failed;
649 	}
650 	/* get mem resource */
651 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
652 	if (!res) {
653 		dev_err(&pdev->dev, "no memory resource defined\n");
654 		ret = -ENODEV;
655 		goto failed;
656 	}
657 
658 	ctx->reg_base = devm_ioremap_resource(dev, res);
659 	if (IS_ERR_OR_NULL(ctx->reg_base)) {
660 		dev_err(dev, "ioremap failed for resource %pR\n", res);
661 		ret = -ENODEV;
662 		goto failed;
663 	}
664 
665 	ctx->clk = devm_clk_get(ctx->dev, "clk_core");
666 	if (IS_ERR_OR_NULL(ctx->clk)) {
667 		dev_err(dev, "clk_get failed for resource %pR\n", res);
668 		ret = -ENODEV;
669 		goto failed;
670 	}
671 	ctx->rst = devm_reset_control_get(ctx->dev, "dvbm_rst");
672 	if (IS_ERR_OR_NULL(ctx->rst)) {
673 		dev_err(dev, "clk_rst failed for resource %pR\n", res);
674 		ret = -ENODEV;
675 		goto failed;
676 	}
677 	if (!SOFT_DVBM) {
678 		ret = pm_runtime_get_sync(dev);
679 		if (ret)
680 			dev_err(dev, "pm get failed!\n");
681 		ret = rk_dvbm_clk_on(ctx);
682 		if (ret)
683 			goto failed;
684 	}
685 	g_ctx = ctx;
686 	rk_dvbm_reg_init(ctx);
687 	ctx->ignore_ovfl = 1;
688 	ctx->dump_s = 0x80;
689 	ctx->dump_e = 0xb8;
690 	ret = devm_request_threaded_irq(dev, ctx->irq,
691 					rk_dvbm_irq, rk_dvbm_isr,
692 					IRQF_ONESHOT, dev_name(dev), ctx);
693 	if (ret) {
694 		dev_err(dev, "register interrupter failed\n");
695 		goto failed;
696 	}
697 	dev_info(dev, "probe success\n");
698 
699 	return 0;
700 
701 failed:
702 	pm_runtime_disable(dev);
703 
704 	return ret;
705 }
706 
rk_dvbm_remove(struct platform_device * pdev)707 static int rk_dvbm_remove(struct platform_device *pdev)
708 {
709 	struct device *dev = &pdev->dev;
710 
711 	dev_info(dev, "remove device\n");
712 	if (!SOFT_DVBM) {
713 		rk_dvbm_clk_off(g_ctx);
714 		pm_runtime_put(dev);
715 	}
716 	pm_runtime_disable(dev);
717 
718 	return 0;
719 }
720 
721 static const struct of_device_id rk_dvbm_dt_ids[] = {
722 	{
723 		.compatible = "rockchip,rk-dvbm",
724 	},
725 	{ },
726 };
727 
728 static struct platform_driver rk_dvbm_driver = {
729 	.probe = rk_dvbm_probe,
730 	.remove = rk_dvbm_remove,
731 	.driver = {
732 		.name = "rk_dvbm",
733 		.of_match_table = of_match_ptr(rk_dvbm_dt_ids),
734 	},
735 };
736 
rk_dvbm_init(void)737 static int __init rk_dvbm_init(void)
738 {
739 	return platform_driver_register(&rk_dvbm_driver);
740 }
741 
rk_dvbm_exit(void)742 static __exit void rk_dvbm_exit(void)
743 {
744 	platform_driver_unregister(&rk_dvbm_driver);
745 }
746 
747 subsys_initcall(rk_dvbm_init);
748 module_exit(rk_dvbm_exit);
749 
750 MODULE_LICENSE("Dual MIT/GPL");
751 MODULE_AUTHOR("Yandong Lin yandong.lin@rock-chips.com");
752 MODULE_DESCRIPTION("Rockchip dvbm driver");
753