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