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