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