xref: /OK3568_Linux_fs/kernel/drivers/media/platform/davinci/vpss.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2009 Texas Instruments.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * common vpss system module platform driver for all video drivers.
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun #include <linux/module.h>
8*4882a593Smuzhiyun #include <linux/platform_device.h>
9*4882a593Smuzhiyun #include <linux/io.h>
10*4882a593Smuzhiyun #include <linux/pm_runtime.h>
11*4882a593Smuzhiyun #include <linux/err.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <media/davinci/vpss.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun MODULE_LICENSE("GPL");
16*4882a593Smuzhiyun MODULE_DESCRIPTION("VPSS Driver");
17*4882a593Smuzhiyun MODULE_AUTHOR("Texas Instruments");
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun /* DM644x defines */
20*4882a593Smuzhiyun #define DM644X_SBL_PCR_VPSS		(4)
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define DM355_VPSSBL_INTSEL		0x10
23*4882a593Smuzhiyun #define DM355_VPSSBL_EVTSEL		0x14
24*4882a593Smuzhiyun /* vpss BL register offsets */
25*4882a593Smuzhiyun #define DM355_VPSSBL_CCDCMUX		0x1c
26*4882a593Smuzhiyun /* vpss CLK register offsets */
27*4882a593Smuzhiyun #define DM355_VPSSCLK_CLKCTRL		0x04
28*4882a593Smuzhiyun /* masks and shifts */
29*4882a593Smuzhiyun #define VPSS_HSSISEL_SHIFT		4
30*4882a593Smuzhiyun /*
31*4882a593Smuzhiyun  * VDINT0 - vpss_int0, VDINT1 - vpss_int1, H3A - vpss_int4,
32*4882a593Smuzhiyun  * IPIPE_INT1_SDR - vpss_int5
33*4882a593Smuzhiyun  */
34*4882a593Smuzhiyun #define DM355_VPSSBL_INTSEL_DEFAULT	0xff83ff10
35*4882a593Smuzhiyun /* VENCINT - vpss_int8 */
36*4882a593Smuzhiyun #define DM355_VPSSBL_EVTSEL_DEFAULT	0x4
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define DM365_ISP5_PCCR				0x04
39*4882a593Smuzhiyun #define DM365_ISP5_PCCR_BL_CLK_ENABLE		BIT(0)
40*4882a593Smuzhiyun #define DM365_ISP5_PCCR_ISIF_CLK_ENABLE		BIT(1)
41*4882a593Smuzhiyun #define DM365_ISP5_PCCR_H3A_CLK_ENABLE		BIT(2)
42*4882a593Smuzhiyun #define DM365_ISP5_PCCR_RSZ_CLK_ENABLE		BIT(3)
43*4882a593Smuzhiyun #define DM365_ISP5_PCCR_IPIPE_CLK_ENABLE	BIT(4)
44*4882a593Smuzhiyun #define DM365_ISP5_PCCR_IPIPEIF_CLK_ENABLE	BIT(5)
45*4882a593Smuzhiyun #define DM365_ISP5_PCCR_RSV			BIT(6)
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #define DM365_ISP5_BCR			0x08
48*4882a593Smuzhiyun #define DM365_ISP5_BCR_ISIF_OUT_ENABLE	BIT(1)
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define DM365_ISP5_INTSEL1		0x10
51*4882a593Smuzhiyun #define DM365_ISP5_INTSEL2		0x14
52*4882a593Smuzhiyun #define DM365_ISP5_INTSEL3		0x18
53*4882a593Smuzhiyun #define DM365_ISP5_CCDCMUX		0x20
54*4882a593Smuzhiyun #define DM365_ISP5_PG_FRAME_SIZE	0x28
55*4882a593Smuzhiyun #define DM365_VPBE_CLK_CTRL		0x00
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun #define VPSS_CLK_CTRL			0x01c40044
58*4882a593Smuzhiyun #define VPSS_CLK_CTRL_VENCCLKEN		BIT(3)
59*4882a593Smuzhiyun #define VPSS_CLK_CTRL_DACCLKEN		BIT(4)
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun /*
62*4882a593Smuzhiyun  * vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1,
63*4882a593Smuzhiyun  * AF - vpss_int3
64*4882a593Smuzhiyun  */
65*4882a593Smuzhiyun #define DM365_ISP5_INTSEL1_DEFAULT	0x0b1f0100
66*4882a593Smuzhiyun /* AEW - vpss_int6, RSZ_INT_DMA - vpss_int5 */
67*4882a593Smuzhiyun #define DM365_ISP5_INTSEL2_DEFAULT	0x1f0a0f1f
68*4882a593Smuzhiyun /* VENC - vpss_int8 */
69*4882a593Smuzhiyun #define DM365_ISP5_INTSEL3_DEFAULT	0x00000015
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun /* masks and shifts for DM365*/
72*4882a593Smuzhiyun #define DM365_CCDC_PG_VD_POL_SHIFT	0
73*4882a593Smuzhiyun #define DM365_CCDC_PG_HD_POL_SHIFT	1
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun #define CCD_SRC_SEL_MASK		(BIT_MASK(5) | BIT_MASK(4))
76*4882a593Smuzhiyun #define CCD_SRC_SEL_SHIFT		4
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun /* Different SoC platforms supported by this driver */
79*4882a593Smuzhiyun enum vpss_platform_type {
80*4882a593Smuzhiyun 	DM644X,
81*4882a593Smuzhiyun 	DM355,
82*4882a593Smuzhiyun 	DM365,
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun /*
86*4882a593Smuzhiyun  * vpss operations. Depends on platform. Not all functions are available
87*4882a593Smuzhiyun  * on all platforms. The api, first check if a function is available before
88*4882a593Smuzhiyun  * invoking it. In the probe, the function ptrs are initialized based on
89*4882a593Smuzhiyun  * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc.
90*4882a593Smuzhiyun  */
91*4882a593Smuzhiyun struct vpss_hw_ops {
92*4882a593Smuzhiyun 	/* enable clock */
93*4882a593Smuzhiyun 	int (*enable_clock)(enum vpss_clock_sel clock_sel, int en);
94*4882a593Smuzhiyun 	/* select input to ccdc */
95*4882a593Smuzhiyun 	void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel);
96*4882a593Smuzhiyun 	/* clear wbl overflow bit */
97*4882a593Smuzhiyun 	int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel);
98*4882a593Smuzhiyun 	/* set sync polarity */
99*4882a593Smuzhiyun 	void (*set_sync_pol)(struct vpss_sync_pol);
100*4882a593Smuzhiyun 	/* set the PG_FRAME_SIZE register*/
101*4882a593Smuzhiyun 	void (*set_pg_frame_size)(struct vpss_pg_frame_size);
102*4882a593Smuzhiyun 	/* check and clear interrupt if occurred */
103*4882a593Smuzhiyun 	int (*dma_complete_interrupt)(void);
104*4882a593Smuzhiyun };
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun /* vpss configuration */
107*4882a593Smuzhiyun struct vpss_oper_config {
108*4882a593Smuzhiyun 	__iomem void *vpss_regs_base0;
109*4882a593Smuzhiyun 	__iomem void *vpss_regs_base1;
110*4882a593Smuzhiyun 	__iomem void *vpss_regs_base2;
111*4882a593Smuzhiyun 	enum vpss_platform_type platform;
112*4882a593Smuzhiyun 	spinlock_t vpss_lock;
113*4882a593Smuzhiyun 	struct vpss_hw_ops hw_ops;
114*4882a593Smuzhiyun };
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun static struct vpss_oper_config oper_cfg;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun /* register access routines */
bl_regr(u32 offset)119*4882a593Smuzhiyun static inline u32 bl_regr(u32 offset)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	return __raw_readl(oper_cfg.vpss_regs_base0 + offset);
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
bl_regw(u32 val,u32 offset)124*4882a593Smuzhiyun static inline void bl_regw(u32 val, u32 offset)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	__raw_writel(val, oper_cfg.vpss_regs_base0 + offset);
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun 
vpss_regr(u32 offset)129*4882a593Smuzhiyun static inline u32 vpss_regr(u32 offset)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	return __raw_readl(oper_cfg.vpss_regs_base1 + offset);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun 
vpss_regw(u32 val,u32 offset)134*4882a593Smuzhiyun static inline void vpss_regw(u32 val, u32 offset)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	__raw_writel(val, oper_cfg.vpss_regs_base1 + offset);
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun /* For DM365 only */
isp5_read(u32 offset)140*4882a593Smuzhiyun static inline u32 isp5_read(u32 offset)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	return __raw_readl(oper_cfg.vpss_regs_base0 + offset);
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun /* For DM365 only */
isp5_write(u32 val,u32 offset)146*4882a593Smuzhiyun static inline void isp5_write(u32 val, u32 offset)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	__raw_writel(val, oper_cfg.vpss_regs_base0 + offset);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)151*4882a593Smuzhiyun static void dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	u32 temp = isp5_read(DM365_ISP5_CCDCMUX) & ~CCD_SRC_SEL_MASK;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	/* if we are using pattern generator, enable it */
156*4882a593Smuzhiyun 	if (src_sel == VPSS_PGLPBK || src_sel == VPSS_CCDCPG)
157*4882a593Smuzhiyun 		temp |= 0x08;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	temp |= (src_sel << CCD_SRC_SEL_SHIFT);
160*4882a593Smuzhiyun 	isp5_write(temp, DM365_ISP5_CCDCMUX);
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun 
dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)163*4882a593Smuzhiyun static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun 	bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun 
vpss_dma_complete_interrupt(void)168*4882a593Smuzhiyun int vpss_dma_complete_interrupt(void)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun 	if (!oper_cfg.hw_ops.dma_complete_interrupt)
171*4882a593Smuzhiyun 		return 2;
172*4882a593Smuzhiyun 	return oper_cfg.hw_ops.dma_complete_interrupt();
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun EXPORT_SYMBOL(vpss_dma_complete_interrupt);
175*4882a593Smuzhiyun 
vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)176*4882a593Smuzhiyun int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	if (!oper_cfg.hw_ops.select_ccdc_source)
179*4882a593Smuzhiyun 		return -EINVAL;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	oper_cfg.hw_ops.select_ccdc_source(src_sel);
182*4882a593Smuzhiyun 	return 0;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun EXPORT_SYMBOL(vpss_select_ccdc_source);
185*4882a593Smuzhiyun 
dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)186*4882a593Smuzhiyun static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	u32 mask = 1, val;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	if (wbl_sel < VPSS_PCR_AEW_WBL_0 ||
191*4882a593Smuzhiyun 	    wbl_sel > VPSS_PCR_CCDC_WBL_O)
192*4882a593Smuzhiyun 		return -EINVAL;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	/* writing a 0 clear the overflow */
195*4882a593Smuzhiyun 	mask = ~(mask << wbl_sel);
196*4882a593Smuzhiyun 	val = bl_regr(DM644X_SBL_PCR_VPSS) & mask;
197*4882a593Smuzhiyun 	bl_regw(val, DM644X_SBL_PCR_VPSS);
198*4882a593Smuzhiyun 	return 0;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
vpss_set_sync_pol(struct vpss_sync_pol sync)201*4882a593Smuzhiyun void vpss_set_sync_pol(struct vpss_sync_pol sync)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	if (!oper_cfg.hw_ops.set_sync_pol)
204*4882a593Smuzhiyun 		return;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	oper_cfg.hw_ops.set_sync_pol(sync);
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun EXPORT_SYMBOL(vpss_set_sync_pol);
209*4882a593Smuzhiyun 
vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)210*4882a593Smuzhiyun int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	if (!oper_cfg.hw_ops.clear_wbl_overflow)
213*4882a593Smuzhiyun 		return -EINVAL;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun EXPORT_SYMBOL(vpss_clear_wbl_overflow);
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun /*
220*4882a593Smuzhiyun  *  dm355_enable_clock - Enable VPSS Clock
221*4882a593Smuzhiyun  *  @clock_sel: Clock to be enabled/disabled
222*4882a593Smuzhiyun  *  @en: enable/disable flag
223*4882a593Smuzhiyun  *
224*4882a593Smuzhiyun  *  This is called to enable or disable a vpss clock
225*4882a593Smuzhiyun  */
dm355_enable_clock(enum vpss_clock_sel clock_sel,int en)226*4882a593Smuzhiyun static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun 	unsigned long flags;
229*4882a593Smuzhiyun 	u32 utemp, mask = 0x1, shift = 0;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	switch (clock_sel) {
232*4882a593Smuzhiyun 	case VPSS_VPBE_CLOCK:
233*4882a593Smuzhiyun 		/* nothing since lsb */
234*4882a593Smuzhiyun 		break;
235*4882a593Smuzhiyun 	case VPSS_VENC_CLOCK_SEL:
236*4882a593Smuzhiyun 		shift = 2;
237*4882a593Smuzhiyun 		break;
238*4882a593Smuzhiyun 	case VPSS_CFALD_CLOCK:
239*4882a593Smuzhiyun 		shift = 3;
240*4882a593Smuzhiyun 		break;
241*4882a593Smuzhiyun 	case VPSS_H3A_CLOCK:
242*4882a593Smuzhiyun 		shift = 4;
243*4882a593Smuzhiyun 		break;
244*4882a593Smuzhiyun 	case VPSS_IPIPE_CLOCK:
245*4882a593Smuzhiyun 		shift = 5;
246*4882a593Smuzhiyun 		break;
247*4882a593Smuzhiyun 	case VPSS_CCDC_CLOCK:
248*4882a593Smuzhiyun 		shift = 6;
249*4882a593Smuzhiyun 		break;
250*4882a593Smuzhiyun 	default:
251*4882a593Smuzhiyun 		printk(KERN_ERR "dm355_enable_clock: Invalid selector: %d\n",
252*4882a593Smuzhiyun 		       clock_sel);
253*4882a593Smuzhiyun 		return -EINVAL;
254*4882a593Smuzhiyun 	}
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	spin_lock_irqsave(&oper_cfg.vpss_lock, flags);
257*4882a593Smuzhiyun 	utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL);
258*4882a593Smuzhiyun 	if (!en)
259*4882a593Smuzhiyun 		utemp &= ~(mask << shift);
260*4882a593Smuzhiyun 	else
261*4882a593Smuzhiyun 		utemp |= (mask << shift);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL);
264*4882a593Smuzhiyun 	spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags);
265*4882a593Smuzhiyun 	return 0;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
dm365_enable_clock(enum vpss_clock_sel clock_sel,int en)268*4882a593Smuzhiyun static int dm365_enable_clock(enum vpss_clock_sel clock_sel, int en)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun 	unsigned long flags;
271*4882a593Smuzhiyun 	u32 utemp, mask = 0x1, shift = 0, offset = DM365_ISP5_PCCR;
272*4882a593Smuzhiyun 	u32 (*read)(u32 offset) = isp5_read;
273*4882a593Smuzhiyun 	void(*write)(u32 val, u32 offset) = isp5_write;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	switch (clock_sel) {
276*4882a593Smuzhiyun 	case VPSS_BL_CLOCK:
277*4882a593Smuzhiyun 		break;
278*4882a593Smuzhiyun 	case VPSS_CCDC_CLOCK:
279*4882a593Smuzhiyun 		shift = 1;
280*4882a593Smuzhiyun 		break;
281*4882a593Smuzhiyun 	case VPSS_H3A_CLOCK:
282*4882a593Smuzhiyun 		shift = 2;
283*4882a593Smuzhiyun 		break;
284*4882a593Smuzhiyun 	case VPSS_RSZ_CLOCK:
285*4882a593Smuzhiyun 		shift = 3;
286*4882a593Smuzhiyun 		break;
287*4882a593Smuzhiyun 	case VPSS_IPIPE_CLOCK:
288*4882a593Smuzhiyun 		shift = 4;
289*4882a593Smuzhiyun 		break;
290*4882a593Smuzhiyun 	case VPSS_IPIPEIF_CLOCK:
291*4882a593Smuzhiyun 		shift = 5;
292*4882a593Smuzhiyun 		break;
293*4882a593Smuzhiyun 	case VPSS_PCLK_INTERNAL:
294*4882a593Smuzhiyun 		shift = 6;
295*4882a593Smuzhiyun 		break;
296*4882a593Smuzhiyun 	case VPSS_PSYNC_CLOCK_SEL:
297*4882a593Smuzhiyun 		shift = 7;
298*4882a593Smuzhiyun 		break;
299*4882a593Smuzhiyun 	case VPSS_VPBE_CLOCK:
300*4882a593Smuzhiyun 		read = vpss_regr;
301*4882a593Smuzhiyun 		write = vpss_regw;
302*4882a593Smuzhiyun 		offset = DM365_VPBE_CLK_CTRL;
303*4882a593Smuzhiyun 		break;
304*4882a593Smuzhiyun 	case VPSS_VENC_CLOCK_SEL:
305*4882a593Smuzhiyun 		shift = 2;
306*4882a593Smuzhiyun 		read = vpss_regr;
307*4882a593Smuzhiyun 		write = vpss_regw;
308*4882a593Smuzhiyun 		offset = DM365_VPBE_CLK_CTRL;
309*4882a593Smuzhiyun 		break;
310*4882a593Smuzhiyun 	case VPSS_LDC_CLOCK:
311*4882a593Smuzhiyun 		shift = 3;
312*4882a593Smuzhiyun 		read = vpss_regr;
313*4882a593Smuzhiyun 		write = vpss_regw;
314*4882a593Smuzhiyun 		offset = DM365_VPBE_CLK_CTRL;
315*4882a593Smuzhiyun 		break;
316*4882a593Smuzhiyun 	case VPSS_FDIF_CLOCK:
317*4882a593Smuzhiyun 		shift = 4;
318*4882a593Smuzhiyun 		read = vpss_regr;
319*4882a593Smuzhiyun 		write = vpss_regw;
320*4882a593Smuzhiyun 		offset = DM365_VPBE_CLK_CTRL;
321*4882a593Smuzhiyun 		break;
322*4882a593Smuzhiyun 	case VPSS_OSD_CLOCK_SEL:
323*4882a593Smuzhiyun 		shift = 6;
324*4882a593Smuzhiyun 		read = vpss_regr;
325*4882a593Smuzhiyun 		write = vpss_regw;
326*4882a593Smuzhiyun 		offset = DM365_VPBE_CLK_CTRL;
327*4882a593Smuzhiyun 		break;
328*4882a593Smuzhiyun 	case VPSS_LDC_CLOCK_SEL:
329*4882a593Smuzhiyun 		shift = 7;
330*4882a593Smuzhiyun 		read = vpss_regr;
331*4882a593Smuzhiyun 		write = vpss_regw;
332*4882a593Smuzhiyun 		offset = DM365_VPBE_CLK_CTRL;
333*4882a593Smuzhiyun 		break;
334*4882a593Smuzhiyun 	default:
335*4882a593Smuzhiyun 		printk(KERN_ERR "dm365_enable_clock: Invalid selector: %d\n",
336*4882a593Smuzhiyun 		       clock_sel);
337*4882a593Smuzhiyun 		return -1;
338*4882a593Smuzhiyun 	}
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	spin_lock_irqsave(&oper_cfg.vpss_lock, flags);
341*4882a593Smuzhiyun 	utemp = read(offset);
342*4882a593Smuzhiyun 	if (!en) {
343*4882a593Smuzhiyun 		mask = ~mask;
344*4882a593Smuzhiyun 		utemp &= (mask << shift);
345*4882a593Smuzhiyun 	} else
346*4882a593Smuzhiyun 		utemp |= (mask << shift);
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	write(utemp, offset);
349*4882a593Smuzhiyun 	spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	return 0;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun 
vpss_enable_clock(enum vpss_clock_sel clock_sel,int en)354*4882a593Smuzhiyun int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun 	if (!oper_cfg.hw_ops.enable_clock)
357*4882a593Smuzhiyun 		return -EINVAL;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	return oper_cfg.hw_ops.enable_clock(clock_sel, en);
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun EXPORT_SYMBOL(vpss_enable_clock);
362*4882a593Smuzhiyun 
dm365_vpss_set_sync_pol(struct vpss_sync_pol sync)363*4882a593Smuzhiyun void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun 	int val = 0;
366*4882a593Smuzhiyun 	val = isp5_read(DM365_ISP5_CCDCMUX);
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	val |= (sync.ccdpg_hdpol << DM365_CCDC_PG_HD_POL_SHIFT);
369*4882a593Smuzhiyun 	val |= (sync.ccdpg_vdpol << DM365_CCDC_PG_VD_POL_SHIFT);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	isp5_write(val, DM365_ISP5_CCDCMUX);
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun EXPORT_SYMBOL(dm365_vpss_set_sync_pol);
374*4882a593Smuzhiyun 
vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size)375*4882a593Smuzhiyun void vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun 	if (!oper_cfg.hw_ops.set_pg_frame_size)
378*4882a593Smuzhiyun 		return;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	oper_cfg.hw_ops.set_pg_frame_size(frame_size);
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun EXPORT_SYMBOL(vpss_set_pg_frame_size);
383*4882a593Smuzhiyun 
dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size)384*4882a593Smuzhiyun void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun 	int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	current_reg |= (frame_size.pplen - 1);
389*4882a593Smuzhiyun 	isp5_write(current_reg, DM365_ISP5_PG_FRAME_SIZE);
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size);
392*4882a593Smuzhiyun 
vpss_probe(struct platform_device * pdev)393*4882a593Smuzhiyun static int vpss_probe(struct platform_device *pdev)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun 	struct resource *res;
396*4882a593Smuzhiyun 	char *platform_name;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	if (!pdev->dev.platform_data) {
399*4882a593Smuzhiyun 		dev_err(&pdev->dev, "no platform data\n");
400*4882a593Smuzhiyun 		return -ENOENT;
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	platform_name = pdev->dev.platform_data;
404*4882a593Smuzhiyun 	if (!strcmp(platform_name, "dm355_vpss"))
405*4882a593Smuzhiyun 		oper_cfg.platform = DM355;
406*4882a593Smuzhiyun 	else if (!strcmp(platform_name, "dm365_vpss"))
407*4882a593Smuzhiyun 		oper_cfg.platform = DM365;
408*4882a593Smuzhiyun 	else if (!strcmp(platform_name, "dm644x_vpss"))
409*4882a593Smuzhiyun 		oper_cfg.platform = DM644X;
410*4882a593Smuzhiyun 	else {
411*4882a593Smuzhiyun 		dev_err(&pdev->dev, "vpss driver not supported on this platform\n");
412*4882a593Smuzhiyun 		return -ENODEV;
413*4882a593Smuzhiyun 	}
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	dev_info(&pdev->dev, "%s vpss probed\n", platform_name);
416*4882a593Smuzhiyun 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	oper_cfg.vpss_regs_base0 = devm_ioremap_resource(&pdev->dev, res);
419*4882a593Smuzhiyun 	if (IS_ERR(oper_cfg.vpss_regs_base0))
420*4882a593Smuzhiyun 		return PTR_ERR(oper_cfg.vpss_regs_base0);
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) {
423*4882a593Smuzhiyun 		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 		oper_cfg.vpss_regs_base1 = devm_ioremap_resource(&pdev->dev,
426*4882a593Smuzhiyun 								 res);
427*4882a593Smuzhiyun 		if (IS_ERR(oper_cfg.vpss_regs_base1))
428*4882a593Smuzhiyun 			return PTR_ERR(oper_cfg.vpss_regs_base1);
429*4882a593Smuzhiyun 	}
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	if (oper_cfg.platform == DM355) {
432*4882a593Smuzhiyun 		oper_cfg.hw_ops.enable_clock = dm355_enable_clock;
433*4882a593Smuzhiyun 		oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source;
434*4882a593Smuzhiyun 		/* Setup vpss interrupts */
435*4882a593Smuzhiyun 		bl_regw(DM355_VPSSBL_INTSEL_DEFAULT, DM355_VPSSBL_INTSEL);
436*4882a593Smuzhiyun 		bl_regw(DM355_VPSSBL_EVTSEL_DEFAULT, DM355_VPSSBL_EVTSEL);
437*4882a593Smuzhiyun 	} else if (oper_cfg.platform == DM365) {
438*4882a593Smuzhiyun 		oper_cfg.hw_ops.enable_clock = dm365_enable_clock;
439*4882a593Smuzhiyun 		oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source;
440*4882a593Smuzhiyun 		/* Setup vpss interrupts */
441*4882a593Smuzhiyun 		isp5_write((isp5_read(DM365_ISP5_PCCR) |
442*4882a593Smuzhiyun 				      DM365_ISP5_PCCR_BL_CLK_ENABLE |
443*4882a593Smuzhiyun 				      DM365_ISP5_PCCR_ISIF_CLK_ENABLE |
444*4882a593Smuzhiyun 				      DM365_ISP5_PCCR_H3A_CLK_ENABLE |
445*4882a593Smuzhiyun 				      DM365_ISP5_PCCR_RSZ_CLK_ENABLE |
446*4882a593Smuzhiyun 				      DM365_ISP5_PCCR_IPIPE_CLK_ENABLE |
447*4882a593Smuzhiyun 				      DM365_ISP5_PCCR_IPIPEIF_CLK_ENABLE |
448*4882a593Smuzhiyun 				      DM365_ISP5_PCCR_RSV), DM365_ISP5_PCCR);
449*4882a593Smuzhiyun 		isp5_write((isp5_read(DM365_ISP5_BCR) |
450*4882a593Smuzhiyun 			    DM365_ISP5_BCR_ISIF_OUT_ENABLE), DM365_ISP5_BCR);
451*4882a593Smuzhiyun 		isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1);
452*4882a593Smuzhiyun 		isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2);
453*4882a593Smuzhiyun 		isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3);
454*4882a593Smuzhiyun 	} else
455*4882a593Smuzhiyun 		oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	pm_runtime_enable(&pdev->dev);
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	pm_runtime_get(&pdev->dev);
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	spin_lock_init(&oper_cfg.vpss_lock);
462*4882a593Smuzhiyun 	dev_info(&pdev->dev, "%s vpss probe success\n", platform_name);
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	return 0;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun 
vpss_remove(struct platform_device * pdev)467*4882a593Smuzhiyun static int vpss_remove(struct platform_device *pdev)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun 	pm_runtime_disable(&pdev->dev);
470*4882a593Smuzhiyun 	return 0;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun 
vpss_suspend(struct device * dev)473*4882a593Smuzhiyun static int vpss_suspend(struct device *dev)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	pm_runtime_put(dev);
476*4882a593Smuzhiyun 	return 0;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun 
vpss_resume(struct device * dev)479*4882a593Smuzhiyun static int vpss_resume(struct device *dev)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun 	pm_runtime_get(dev);
482*4882a593Smuzhiyun 	return 0;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun static const struct dev_pm_ops vpss_pm_ops = {
486*4882a593Smuzhiyun 	.suspend = vpss_suspend,
487*4882a593Smuzhiyun 	.resume = vpss_resume,
488*4882a593Smuzhiyun };
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun static struct platform_driver vpss_driver = {
491*4882a593Smuzhiyun 	.driver = {
492*4882a593Smuzhiyun 		.name	= "vpss",
493*4882a593Smuzhiyun 		.pm = &vpss_pm_ops,
494*4882a593Smuzhiyun 	},
495*4882a593Smuzhiyun 	.remove = vpss_remove,
496*4882a593Smuzhiyun 	.probe = vpss_probe,
497*4882a593Smuzhiyun };
498*4882a593Smuzhiyun 
vpss_exit(void)499*4882a593Smuzhiyun static void vpss_exit(void)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun 	platform_driver_unregister(&vpss_driver);
502*4882a593Smuzhiyun 	iounmap(oper_cfg.vpss_regs_base2);
503*4882a593Smuzhiyun 	release_mem_region(VPSS_CLK_CTRL, 4);
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun 
vpss_init(void)506*4882a593Smuzhiyun static int __init vpss_init(void)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun 	int ret;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	if (!request_mem_region(VPSS_CLK_CTRL, 4, "vpss_clock_control"))
511*4882a593Smuzhiyun 		return -EBUSY;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	oper_cfg.vpss_regs_base2 = ioremap(VPSS_CLK_CTRL, 4);
514*4882a593Smuzhiyun 	if (unlikely(!oper_cfg.vpss_regs_base2)) {
515*4882a593Smuzhiyun 		ret = -ENOMEM;
516*4882a593Smuzhiyun 		goto err_ioremap;
517*4882a593Smuzhiyun 	}
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	writel(VPSS_CLK_CTRL_VENCCLKEN |
520*4882a593Smuzhiyun 	       VPSS_CLK_CTRL_DACCLKEN, oper_cfg.vpss_regs_base2);
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	ret = platform_driver_register(&vpss_driver);
523*4882a593Smuzhiyun 	if (ret)
524*4882a593Smuzhiyun 		goto err_pd_register;
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	return 0;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun err_pd_register:
529*4882a593Smuzhiyun 	iounmap(oper_cfg.vpss_regs_base2);
530*4882a593Smuzhiyun err_ioremap:
531*4882a593Smuzhiyun 	release_mem_region(VPSS_CLK_CTRL, 4);
532*4882a593Smuzhiyun 	return ret;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun subsys_initcall(vpss_init);
535*4882a593Smuzhiyun module_exit(vpss_exit);
536