1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <common.h>
16#include <linux/types.h>
17#include <linux/err.h>
18#include <asm/io.h>
19#include <linux/errno.h>
20#include <asm/arch/imx-regs.h>
21#include <asm/arch/crm_regs.h>
22#include <asm/arch/sys_proto.h>
23#include <div64.h>
24#include "ipu.h"
25#include "ipu_regs.h"
26
27extern struct mxc_ccm_reg *mxc_ccm;
28extern u32 *ipu_cpmem_base;
29
30struct ipu_ch_param_word {
31 uint32_t data[5];
32 uint32_t res[3];
33};
34
35struct ipu_ch_param {
36 struct ipu_ch_param_word word[2];
37};
38
39#define ipu_ch_param_addr(ch) (((struct ipu_ch_param *)ipu_cpmem_base) + (ch))
40
41#define _param_word(base, w) \
42 (((struct ipu_ch_param *)(base))->word[(w)].data)
43
44#define ipu_ch_param_set_field(base, w, bit, size, v) { \
45 int i = (bit) / 32; \
46 int off = (bit) % 32; \
47 _param_word(base, w)[i] |= (v) << off; \
48 if (((bit) + (size) - 1) / 32 > i) { \
49 _param_word(base, w)[i + 1] |= (v) >> (off ? (32 - off) : 0); \
50 } \
51}
52
53#define ipu_ch_param_mod_field(base, w, bit, size, v) { \
54 int i = (bit) / 32; \
55 int off = (bit) % 32; \
56 u32 mask = (1UL << size) - 1; \
57 u32 temp = _param_word(base, w)[i]; \
58 temp &= ~(mask << off); \
59 _param_word(base, w)[i] = temp | (v) << off; \
60 if (((bit) + (size) - 1) / 32 > i) { \
61 temp = _param_word(base, w)[i + 1]; \
62 temp &= ~(mask >> (32 - off)); \
63 _param_word(base, w)[i + 1] = \
64 temp | ((v) >> (off ? (32 - off) : 0)); \
65 } \
66}
67
68#define ipu_ch_param_read_field(base, w, bit, size) ({ \
69 u32 temp2; \
70 int i = (bit) / 32; \
71 int off = (bit) % 32; \
72 u32 mask = (1UL << size) - 1; \
73 u32 temp1 = _param_word(base, w)[i]; \
74 temp1 = mask & (temp1 >> off); \
75 if (((bit)+(size) - 1) / 32 > i) { \
76 temp2 = _param_word(base, w)[i + 1]; \
77 temp2 &= mask >> (off ? (32 - off) : 0); \
78 temp1 |= temp2 << (off ? (32 - off) : 0); \
79 } \
80 temp1; \
81})
82
83#define IPU_SW_RST_TOUT_USEC (10000)
84
85#define IPUV3_CLK_MX51 133000000
86#define IPUV3_CLK_MX53 200000000
87#define IPUV3_CLK_MX6Q 264000000
88#define IPUV3_CLK_MX6DL 198000000
89
90void clk_enable(struct clk *clk)
91{
92 if (clk) {
93 if (clk->usecount++ == 0) {
94 clk->enable(clk);
95 }
96 }
97}
98
99void clk_disable(struct clk *clk)
100{
101 if (clk) {
102 if (!(--clk->usecount)) {
103 if (clk->disable)
104 clk->disable(clk);
105 }
106 }
107}
108
109int clk_get_usecount(struct clk *clk)
110{
111 if (clk == NULL)
112 return 0;
113
114 return clk->usecount;
115}
116
117u32 clk_get_rate(struct clk *clk)
118{
119 if (!clk)
120 return 0;
121
122 return clk->rate;
123}
124
125struct clk *clk_get_parent(struct clk *clk)
126{
127 if (!clk)
128 return 0;
129
130 return clk->parent;
131}
132
133int clk_set_rate(struct clk *clk, unsigned long rate)
134{
135 if (!clk)
136 return 0;
137
138 if (clk->set_rate)
139 clk->set_rate(clk, rate);
140
141 return clk->rate;
142}
143
144long clk_round_rate(struct clk *clk, unsigned long rate)
145{
146 if (clk == NULL || !clk->round_rate)
147 return 0;
148
149 return clk->round_rate(clk, rate);
150}
151
152int clk_set_parent(struct clk *clk, struct clk *parent)
153{
154 clk->parent = parent;
155 if (clk->set_parent)
156 return clk->set_parent(clk, parent);
157 return 0;
158}
159
160static int clk_ipu_enable(struct clk *clk)
161{
162 u32 reg;
163
164 reg = __raw_readl(clk->enable_reg);
165 reg |= MXC_CCM_CCGR_CG_MASK << clk->enable_shift;
166 __raw_writel(reg, clk->enable_reg);
167
168#if defined(CONFIG_MX51) || defined(CONFIG_MX53)
169
170 reg = __raw_readl(&mxc_ccm->ccdr);
171 reg &= ~MXC_CCM_CCDR_IPU_HS_MASK;
172 __raw_writel(reg, &mxc_ccm->ccdr);
173
174
175 reg = __raw_readl(&mxc_ccm->clpcr);
176 reg &= ~MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS;
177 __raw_writel(reg, &mxc_ccm->clpcr);
178#endif
179 return 0;
180}
181
182static void clk_ipu_disable(struct clk *clk)
183{
184 u32 reg;
185
186 reg = __raw_readl(clk->enable_reg);
187 reg &= ~(MXC_CCM_CCGR_CG_MASK << clk->enable_shift);
188 __raw_writel(reg, clk->enable_reg);
189
190#if defined(CONFIG_MX51) || defined(CONFIG_MX53)
191
192
193
194
195 reg = __raw_readl(&mxc_ccm->ccdr);
196 reg |= MXC_CCM_CCDR_IPU_HS_MASK;
197 __raw_writel(reg, &mxc_ccm->ccdr);
198
199
200 reg = __raw_readl(&mxc_ccm->clpcr);
201 reg |= MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS;
202 __raw_writel(reg, &mxc_ccm->clpcr);
203#endif
204}
205
206
207static struct clk ipu_clk = {
208 .name = "ipu_clk",
209#if defined(CONFIG_MX51) || defined(CONFIG_MX53)
210 .enable_reg = (u32 *)(CCM_BASE_ADDR +
211 offsetof(struct mxc_ccm_reg, CCGR5)),
212 .enable_shift = MXC_CCM_CCGR5_IPU_OFFSET,
213#else
214 .enable_reg = (u32 *)(CCM_BASE_ADDR +
215 offsetof(struct mxc_ccm_reg, CCGR3)),
216 .enable_shift = MXC_CCM_CCGR3_IPU1_IPU_DI0_OFFSET,
217#endif
218 .enable = clk_ipu_enable,
219 .disable = clk_ipu_disable,
220 .usecount = 0,
221};
222
223#if !defined CONFIG_SYS_LDB_CLOCK
224#define CONFIG_SYS_LDB_CLOCK 65000000
225#endif
226
227static struct clk ldb_clk = {
228 .name = "ldb_clk",
229 .rate = CONFIG_SYS_LDB_CLOCK,
230 .usecount = 0,
231};
232
233
234struct clk *g_ipu_clk;
235struct clk *g_ldb_clk;
236unsigned char g_ipu_clk_enabled;
237struct clk *g_di_clk[2];
238struct clk *g_pixel_clk[2];
239unsigned char g_dc_di_assignment[10];
240uint32_t g_channel_init_mask;
241uint32_t g_channel_enable_mask;
242
243static int ipu_dc_use_count;
244static int ipu_dp_use_count;
245static int ipu_dmfc_use_count;
246static int ipu_di_use_count[2];
247
248u32 *ipu_cpmem_base;
249u32 *ipu_dc_tmpl_reg;
250
251
252
253static inline void ipu_ch_param_set_high_priority(uint32_t ch)
254{
255 ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 93, 2, 1);
256};
257
258static inline uint32_t channel_2_dma(ipu_channel_t ch, ipu_buffer_t type)
259{
260 return ((uint32_t) ch >> (6 * type)) & 0x3F;
261};
262
263
264static inline int ipu_is_dp_graphic_chan(uint32_t dma_chan)
265{
266 return (dma_chan == 23 || dma_chan == 27);
267}
268
269static inline int ipu_is_dmfc_chan(uint32_t dma_chan)
270{
271 return ((dma_chan >= 23) && (dma_chan <= 29));
272}
273
274
275static inline void ipu_ch_param_set_buffer(uint32_t ch, int bufNum,
276 dma_addr_t phyaddr)
277{
278 ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 29 * bufNum, 29,
279 phyaddr / 8);
280};
281
282#define idma_is_valid(ch) (ch != NO_DMA)
283#define idma_mask(ch) (idma_is_valid(ch) ? (1UL << (ch & 0x1F)) : 0)
284#define idma_is_set(reg, dma) (__raw_readl(reg(dma)) & idma_mask(dma))
285
286static void ipu_pixel_clk_recalc(struct clk *clk)
287{
288 u32 div;
289 u64 final_rate = (unsigned long long)clk->parent->rate * 16;
290
291 div = __raw_readl(DI_BS_CLKGEN0(clk->id));
292 debug("read BS_CLKGEN0 div:%d, final_rate:%lld, prate:%ld\n",
293 div, final_rate, clk->parent->rate);
294
295 clk->rate = 0;
296 if (div != 0) {
297 do_div(final_rate, div);
298 clk->rate = final_rate;
299 }
300}
301
302static unsigned long ipu_pixel_clk_round_rate(struct clk *clk,
303 unsigned long rate)
304{
305 u64 div, final_rate;
306 u32 remainder;
307 u64 parent_rate = (unsigned long long)clk->parent->rate * 16;
308
309
310
311
312
313
314 div = parent_rate;
315 remainder = do_div(div, rate);
316
317 if (remainder > (rate / 2))
318 div++;
319 if (div < 0x10)
320 div = 0x10;
321 if (div & ~0xFEF)
322 div &= 0xFF8;
323 else {
324
325 if ((div & 0xC) == 0xC) {
326 div += 0x10;
327 div &= ~0xF;
328 }
329 }
330 final_rate = parent_rate;
331 do_div(final_rate, div);
332
333 return final_rate;
334}
335
336static int ipu_pixel_clk_set_rate(struct clk *clk, unsigned long rate)
337{
338 u64 div, parent_rate;
339 u32 remainder;
340
341 parent_rate = (unsigned long long)clk->parent->rate * 16;
342 div = parent_rate;
343 remainder = do_div(div, rate);
344
345 if (remainder > (rate / 2))
346 div++;
347
348
349 if ((div & 0xC) == 0xC) {
350 div += 0x10;
351 div &= ~0xF;
352 }
353 if (div > 0x1000)
354 debug("Overflow, DI_BS_CLKGEN0 div:0x%x\n", (u32)div);
355
356 __raw_writel(div, DI_BS_CLKGEN0(clk->id));
357
358
359
360
361
362 __raw_writel((div / 16) << 16, DI_BS_CLKGEN1(clk->id));
363
364 do_div(parent_rate, div);
365
366 clk->rate = parent_rate;
367
368 return 0;
369}
370
371static int ipu_pixel_clk_enable(struct clk *clk)
372{
373 u32 disp_gen = __raw_readl(IPU_DISP_GEN);
374 disp_gen |= clk->id ? DI1_COUNTER_RELEASE : DI0_COUNTER_RELEASE;
375 __raw_writel(disp_gen, IPU_DISP_GEN);
376
377 return 0;
378}
379
380static void ipu_pixel_clk_disable(struct clk *clk)
381{
382 u32 disp_gen = __raw_readl(IPU_DISP_GEN);
383 disp_gen &= clk->id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE;
384 __raw_writel(disp_gen, IPU_DISP_GEN);
385
386}
387
388static int ipu_pixel_clk_set_parent(struct clk *clk, struct clk *parent)
389{
390 u32 di_gen = __raw_readl(DI_GENERAL(clk->id));
391
392 if (parent == g_ipu_clk)
393 di_gen &= ~DI_GEN_DI_CLK_EXT;
394 else if (!IS_ERR(g_di_clk[clk->id]) && parent == g_ldb_clk)
395 di_gen |= DI_GEN_DI_CLK_EXT;
396 else
397 return -EINVAL;
398
399 __raw_writel(di_gen, DI_GENERAL(clk->id));
400 ipu_pixel_clk_recalc(clk);
401 return 0;
402}
403
404static struct clk pixel_clk[] = {
405 {
406 .name = "pixel_clk",
407 .id = 0,
408 .recalc = ipu_pixel_clk_recalc,
409 .set_rate = ipu_pixel_clk_set_rate,
410 .round_rate = ipu_pixel_clk_round_rate,
411 .set_parent = ipu_pixel_clk_set_parent,
412 .enable = ipu_pixel_clk_enable,
413 .disable = ipu_pixel_clk_disable,
414 .usecount = 0,
415 },
416 {
417 .name = "pixel_clk",
418 .id = 1,
419 .recalc = ipu_pixel_clk_recalc,
420 .set_rate = ipu_pixel_clk_set_rate,
421 .round_rate = ipu_pixel_clk_round_rate,
422 .set_parent = ipu_pixel_clk_set_parent,
423 .enable = ipu_pixel_clk_enable,
424 .disable = ipu_pixel_clk_disable,
425 .usecount = 0,
426 },
427};
428
429
430
431
432static void ipu_reset(void)
433{
434 u32 *reg;
435 u32 value;
436 int timeout = IPU_SW_RST_TOUT_USEC;
437
438 reg = (u32 *)SRC_BASE_ADDR;
439 value = __raw_readl(reg);
440 value = value | SW_IPU_RST;
441 __raw_writel(value, reg);
442
443 while (__raw_readl(reg) & SW_IPU_RST) {
444 udelay(1);
445 if (!(timeout--)) {
446 printf("ipu software reset timeout\n");
447 break;
448 }
449 };
450}
451
452
453
454
455
456
457
458
459
460
461int ipu_probe(void)
462{
463 unsigned long ipu_base;
464#if defined CONFIG_MX51
465 u32 temp;
466
467 u32 *reg_hsc_mcd = (u32 *)MIPI_HSC_BASE_ADDR;
468 u32 *reg_hsc_mxt_conf = (u32 *)(MIPI_HSC_BASE_ADDR + 0x800);
469
470 __raw_writel(0xF00, reg_hsc_mcd);
471
472
473 temp = __raw_readl(reg_hsc_mxt_conf);
474 __raw_writel(temp | 0x0FF, reg_hsc_mxt_conf);
475
476 temp = __raw_readl(reg_hsc_mxt_conf);
477 __raw_writel(temp | 0x10000, reg_hsc_mxt_conf);
478#endif
479
480 ipu_base = IPU_CTRL_BASE_ADDR;
481 ipu_cpmem_base = (u32 *)(ipu_base + IPU_CPMEM_REG_BASE);
482 ipu_dc_tmpl_reg = (u32 *)(ipu_base + IPU_DC_TMPL_REG_BASE);
483
484 g_pixel_clk[0] = &pixel_clk[0];
485 g_pixel_clk[1] = &pixel_clk[1];
486
487 g_ipu_clk = &ipu_clk;
488#if defined(CONFIG_MX51)
489 g_ipu_clk->rate = IPUV3_CLK_MX51;
490#elif defined(CONFIG_MX53)
491 g_ipu_clk->rate = IPUV3_CLK_MX53;
492#else
493 g_ipu_clk->rate = is_mx6sdl() ? IPUV3_CLK_MX6DL : IPUV3_CLK_MX6Q;
494#endif
495 debug("ipu_clk = %u\n", clk_get_rate(g_ipu_clk));
496 g_ldb_clk = &ldb_clk;
497 debug("ldb_clk = %u\n", clk_get_rate(g_ldb_clk));
498 ipu_reset();
499
500 clk_set_parent(g_pixel_clk[0], g_ipu_clk);
501 clk_set_parent(g_pixel_clk[1], g_ipu_clk);
502 clk_enable(g_ipu_clk);
503
504 g_di_clk[0] = NULL;
505 g_di_clk[1] = NULL;
506
507 __raw_writel(0x807FFFFF, IPU_MEM_RST);
508 while (__raw_readl(IPU_MEM_RST) & 0x80000000)
509 ;
510
511 ipu_init_dc_mappings();
512
513 __raw_writel(0, IPU_INT_CTRL(5));
514 __raw_writel(0, IPU_INT_CTRL(6));
515 __raw_writel(0, IPU_INT_CTRL(9));
516 __raw_writel(0, IPU_INT_CTRL(10));
517
518
519 ipu_dmfc_init(DMFC_NORMAL, 1);
520
521
522 __raw_writel(0x18800000L, IDMAC_CHA_PRI(0));
523
524
525 __raw_writel(0x00400000L | (IPU_MCU_T_DEFAULT << 18), IPU_DISP_GEN);
526
527 clk_disable(g_ipu_clk);
528
529 return 0;
530}
531
532void ipu_dump_registers(void)
533{
534 debug("IPU_CONF = \t0x%08X\n", __raw_readl(IPU_CONF));
535 debug("IDMAC_CONF = \t0x%08X\n", __raw_readl(IDMAC_CONF));
536 debug("IDMAC_CHA_EN1 = \t0x%08X\n",
537 __raw_readl(IDMAC_CHA_EN(0)));
538 debug("IDMAC_CHA_EN2 = \t0x%08X\n",
539 __raw_readl(IDMAC_CHA_EN(32)));
540 debug("IDMAC_CHA_PRI1 = \t0x%08X\n",
541 __raw_readl(IDMAC_CHA_PRI(0)));
542 debug("IDMAC_CHA_PRI2 = \t0x%08X\n",
543 __raw_readl(IDMAC_CHA_PRI(32)));
544 debug("IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
545 __raw_readl(IPU_CHA_DB_MODE_SEL(0)));
546 debug("IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
547 __raw_readl(IPU_CHA_DB_MODE_SEL(32)));
548 debug("DMFC_WR_CHAN = \t0x%08X\n",
549 __raw_readl(DMFC_WR_CHAN));
550 debug("DMFC_WR_CHAN_DEF = \t0x%08X\n",
551 __raw_readl(DMFC_WR_CHAN_DEF));
552 debug("DMFC_DP_CHAN = \t0x%08X\n",
553 __raw_readl(DMFC_DP_CHAN));
554 debug("DMFC_DP_CHAN_DEF = \t0x%08X\n",
555 __raw_readl(DMFC_DP_CHAN_DEF));
556 debug("DMFC_IC_CTRL = \t0x%08X\n",
557 __raw_readl(DMFC_IC_CTRL));
558 debug("IPU_FS_PROC_FLOW1 = \t0x%08X\n",
559 __raw_readl(IPU_FS_PROC_FLOW1));
560 debug("IPU_FS_PROC_FLOW2 = \t0x%08X\n",
561 __raw_readl(IPU_FS_PROC_FLOW2));
562 debug("IPU_FS_PROC_FLOW3 = \t0x%08X\n",
563 __raw_readl(IPU_FS_PROC_FLOW3));
564 debug("IPU_FS_DISP_FLOW1 = \t0x%08X\n",
565 __raw_readl(IPU_FS_DISP_FLOW1));
566}
567
568
569
570
571
572
573
574
575
576
577
578int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
579{
580 int ret = 0;
581 uint32_t ipu_conf;
582
583 debug("init channel = %d\n", IPU_CHAN_ID(channel));
584
585 if (g_ipu_clk_enabled == 0) {
586 g_ipu_clk_enabled = 1;
587 clk_enable(g_ipu_clk);
588 }
589
590
591 if (g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) {
592 printf("Warning: channel already initialized %d\n",
593 IPU_CHAN_ID(channel));
594 }
595
596 ipu_conf = __raw_readl(IPU_CONF);
597
598 switch (channel) {
599 case MEM_DC_SYNC:
600 if (params->mem_dc_sync.di > 1) {
601 ret = -EINVAL;
602 goto err;
603 }
604
605 g_dc_di_assignment[1] = params->mem_dc_sync.di;
606 ipu_dc_init(1, params->mem_dc_sync.di,
607 params->mem_dc_sync.interlaced);
608 ipu_di_use_count[params->mem_dc_sync.di]++;
609 ipu_dc_use_count++;
610 ipu_dmfc_use_count++;
611 break;
612 case MEM_BG_SYNC:
613 if (params->mem_dp_bg_sync.di > 1) {
614 ret = -EINVAL;
615 goto err;
616 }
617
618 g_dc_di_assignment[5] = params->mem_dp_bg_sync.di;
619 ipu_dp_init(channel, params->mem_dp_bg_sync.in_pixel_fmt,
620 params->mem_dp_bg_sync.out_pixel_fmt);
621 ipu_dc_init(5, params->mem_dp_bg_sync.di,
622 params->mem_dp_bg_sync.interlaced);
623 ipu_di_use_count[params->mem_dp_bg_sync.di]++;
624 ipu_dc_use_count++;
625 ipu_dp_use_count++;
626 ipu_dmfc_use_count++;
627 break;
628 case MEM_FG_SYNC:
629 ipu_dp_init(channel, params->mem_dp_fg_sync.in_pixel_fmt,
630 params->mem_dp_fg_sync.out_pixel_fmt);
631
632 ipu_dc_use_count++;
633 ipu_dp_use_count++;
634 ipu_dmfc_use_count++;
635 break;
636 default:
637 printf("Missing channel initialization\n");
638 break;
639 }
640
641
642 g_channel_init_mask |= 1L << IPU_CHAN_ID(channel);
643 if (ipu_dc_use_count == 1)
644 ipu_conf |= IPU_CONF_DC_EN;
645 if (ipu_dp_use_count == 1)
646 ipu_conf |= IPU_CONF_DP_EN;
647 if (ipu_dmfc_use_count == 1)
648 ipu_conf |= IPU_CONF_DMFC_EN;
649 if (ipu_di_use_count[0] == 1) {
650 ipu_conf |= IPU_CONF_DI0_EN;
651 }
652 if (ipu_di_use_count[1] == 1) {
653 ipu_conf |= IPU_CONF_DI1_EN;
654 }
655
656 __raw_writel(ipu_conf, IPU_CONF);
657
658err:
659 return ret;
660}
661
662
663
664
665
666
667void ipu_uninit_channel(ipu_channel_t channel)
668{
669 uint32_t reg;
670 uint32_t in_dma, out_dma = 0;
671 uint32_t ipu_conf;
672
673 if ((g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) == 0) {
674 debug("Channel already uninitialized %d\n",
675 IPU_CHAN_ID(channel));
676 return;
677 }
678
679
680
681
682
683 in_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
684 out_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
685
686 if (idma_is_set(IDMAC_CHA_EN, in_dma) ||
687 idma_is_set(IDMAC_CHA_EN, out_dma)) {
688 printf(
689 "Channel %d is not disabled, disable first\n",
690 IPU_CHAN_ID(channel));
691 return;
692 }
693
694 ipu_conf = __raw_readl(IPU_CONF);
695
696
697 reg = __raw_readl(IPU_CHA_DB_MODE_SEL(in_dma));
698 __raw_writel(reg & ~idma_mask(in_dma), IPU_CHA_DB_MODE_SEL(in_dma));
699 reg = __raw_readl(IPU_CHA_DB_MODE_SEL(out_dma));
700 __raw_writel(reg & ~idma_mask(out_dma), IPU_CHA_DB_MODE_SEL(out_dma));
701
702 switch (channel) {
703 case MEM_DC_SYNC:
704 ipu_dc_uninit(1);
705 ipu_di_use_count[g_dc_di_assignment[1]]--;
706 ipu_dc_use_count--;
707 ipu_dmfc_use_count--;
708 break;
709 case MEM_BG_SYNC:
710 ipu_dp_uninit(channel);
711 ipu_dc_uninit(5);
712 ipu_di_use_count[g_dc_di_assignment[5]]--;
713 ipu_dc_use_count--;
714 ipu_dp_use_count--;
715 ipu_dmfc_use_count--;
716 break;
717 case MEM_FG_SYNC:
718 ipu_dp_uninit(channel);
719 ipu_dc_use_count--;
720 ipu_dp_use_count--;
721 ipu_dmfc_use_count--;
722 break;
723 default:
724 break;
725 }
726
727 g_channel_init_mask &= ~(1L << IPU_CHAN_ID(channel));
728
729 if (ipu_dc_use_count == 0)
730 ipu_conf &= ~IPU_CONF_DC_EN;
731 if (ipu_dp_use_count == 0)
732 ipu_conf &= ~IPU_CONF_DP_EN;
733 if (ipu_dmfc_use_count == 0)
734 ipu_conf &= ~IPU_CONF_DMFC_EN;
735 if (ipu_di_use_count[0] == 0) {
736 ipu_conf &= ~IPU_CONF_DI0_EN;
737 }
738 if (ipu_di_use_count[1] == 0) {
739 ipu_conf &= ~IPU_CONF_DI1_EN;
740 }
741
742 __raw_writel(ipu_conf, IPU_CONF);
743
744 if (ipu_conf == 0) {
745 clk_disable(g_ipu_clk);
746 g_ipu_clk_enabled = 0;
747 }
748
749}
750
751static inline void ipu_ch_param_dump(int ch)
752{
753#ifdef DEBUG
754 struct ipu_ch_param *p = ipu_ch_param_addr(ch);
755 debug("ch %d word 0 - %08X %08X %08X %08X %08X\n", ch,
756 p->word[0].data[0], p->word[0].data[1], p->word[0].data[2],
757 p->word[0].data[3], p->word[0].data[4]);
758 debug("ch %d word 1 - %08X %08X %08X %08X %08X\n", ch,
759 p->word[1].data[0], p->word[1].data[1], p->word[1].data[2],
760 p->word[1].data[3], p->word[1].data[4]);
761 debug("PFS 0x%x, ",
762 ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 85, 4));
763 debug("BPP 0x%x, ",
764 ipu_ch_param_read_field(ipu_ch_param_addr(ch), 0, 107, 3));
765 debug("NPB 0x%x\n",
766 ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 78, 7));
767
768 debug("FW %d, ",
769 ipu_ch_param_read_field(ipu_ch_param_addr(ch), 0, 125, 13));
770 debug("FH %d, ",
771 ipu_ch_param_read_field(ipu_ch_param_addr(ch), 0, 138, 12));
772 debug("Stride %d\n",
773 ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 102, 14));
774
775 debug("Width0 %d+1, ",
776 ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 116, 3));
777 debug("Width1 %d+1, ",
778 ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 119, 3));
779 debug("Width2 %d+1, ",
780 ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 122, 3));
781 debug("Width3 %d+1, ",
782 ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 125, 3));
783 debug("Offset0 %d, ",
784 ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 128, 5));
785 debug("Offset1 %d, ",
786 ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 133, 5));
787 debug("Offset2 %d, ",
788 ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 138, 5));
789 debug("Offset3 %d\n",
790 ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 143, 5));
791#endif
792}
793
794static inline void ipu_ch_params_set_packing(struct ipu_ch_param *p,
795 int red_width, int red_offset,
796 int green_width, int green_offset,
797 int blue_width, int blue_offset,
798 int alpha_width, int alpha_offset)
799{
800
801 ipu_ch_param_set_field(p, 1, 116, 3, red_width - 1);
802 ipu_ch_param_set_field(p, 1, 128, 5, red_offset);
803
804 ipu_ch_param_set_field(p, 1, 119, 3, green_width - 1);
805 ipu_ch_param_set_field(p, 1, 133, 5, green_offset);
806
807 ipu_ch_param_set_field(p, 1, 122, 3, blue_width - 1);
808 ipu_ch_param_set_field(p, 1, 138, 5, blue_offset);
809
810 ipu_ch_param_set_field(p, 1, 125, 3, alpha_width - 1);
811 ipu_ch_param_set_field(p, 1, 143, 5, alpha_offset);
812}
813
814static void ipu_ch_param_init(int ch,
815 uint32_t pixel_fmt, uint32_t width,
816 uint32_t height, uint32_t stride,
817 uint32_t u, uint32_t v,
818 uint32_t uv_stride, dma_addr_t addr0,
819 dma_addr_t addr1)
820{
821 uint32_t u_offset = 0;
822 uint32_t v_offset = 0;
823 struct ipu_ch_param params;
824
825 memset(¶ms, 0, sizeof(params));
826
827 ipu_ch_param_set_field(¶ms, 0, 125, 13, width - 1);
828
829 if ((ch == 8) || (ch == 9) || (ch == 10)) {
830 ipu_ch_param_set_field(¶ms, 0, 138, 12, (height / 2) - 1);
831 ipu_ch_param_set_field(¶ms, 1, 102, 14, (stride * 2) - 1);
832 } else {
833 ipu_ch_param_set_field(¶ms, 0, 138, 12, height - 1);
834 ipu_ch_param_set_field(¶ms, 1, 102, 14, stride - 1);
835 }
836
837 ipu_ch_param_set_field(¶ms, 1, 0, 29, addr0 >> 3);
838 ipu_ch_param_set_field(¶ms, 1, 29, 29, addr1 >> 3);
839
840 switch (pixel_fmt) {
841 case IPU_PIX_FMT_GENERIC:
842
843 ipu_ch_param_set_field(¶ms, 0, 107, 3, 5);
844 ipu_ch_param_set_field(¶ms, 1, 85, 4, 6);
845 ipu_ch_param_set_field(¶ms, 1, 78, 7, 63);
846
847 break;
848 case IPU_PIX_FMT_GENERIC_32:
849
850 break;
851 case IPU_PIX_FMT_RGB565:
852 ipu_ch_param_set_field(¶ms, 0, 107, 3, 3);
853 ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);
854 ipu_ch_param_set_field(¶ms, 1, 78, 7, 15);
855
856 ipu_ch_params_set_packing(¶ms, 5, 0, 6, 5, 5, 11, 8, 16);
857 break;
858 case IPU_PIX_FMT_BGR24:
859 ipu_ch_param_set_field(¶ms, 0, 107, 3, 1);
860 ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);
861 ipu_ch_param_set_field(¶ms, 1, 78, 7, 19);
862
863 ipu_ch_params_set_packing(¶ms, 8, 0, 8, 8, 8, 16, 8, 24);
864 break;
865 case IPU_PIX_FMT_RGB24:
866 case IPU_PIX_FMT_YUV444:
867 ipu_ch_param_set_field(¶ms, 0, 107, 3, 1);
868 ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);
869 ipu_ch_param_set_field(¶ms, 1, 78, 7, 19);
870
871 ipu_ch_params_set_packing(¶ms, 8, 16, 8, 8, 8, 0, 8, 24);
872 break;
873 case IPU_PIX_FMT_BGRA32:
874 case IPU_PIX_FMT_BGR32:
875 ipu_ch_param_set_field(¶ms, 0, 107, 3, 0);
876 ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);
877 ipu_ch_param_set_field(¶ms, 1, 78, 7, 15);
878
879 ipu_ch_params_set_packing(¶ms, 8, 8, 8, 16, 8, 24, 8, 0);
880 break;
881 case IPU_PIX_FMT_RGBA32:
882 case IPU_PIX_FMT_RGB32:
883 ipu_ch_param_set_field(¶ms, 0, 107, 3, 0);
884 ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);
885 ipu_ch_param_set_field(¶ms, 1, 78, 7, 15);
886
887 ipu_ch_params_set_packing(¶ms, 8, 24, 8, 16, 8, 8, 8, 0);
888 break;
889 case IPU_PIX_FMT_ABGR32:
890 ipu_ch_param_set_field(¶ms, 0, 107, 3, 0);
891 ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);
892
893 ipu_ch_params_set_packing(¶ms, 8, 0, 8, 8, 8, 16, 8, 24);
894 break;
895 case IPU_PIX_FMT_UYVY:
896 ipu_ch_param_set_field(¶ms, 0, 107, 3, 3);
897 ipu_ch_param_set_field(¶ms, 1, 85, 4, 0xA);
898 ipu_ch_param_set_field(¶ms, 1, 78, 7, 15);
899 break;
900 case IPU_PIX_FMT_YUYV:
901 ipu_ch_param_set_field(¶ms, 0, 107, 3, 3);
902 ipu_ch_param_set_field(¶ms, 1, 85, 4, 0x8);
903 ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);
904 break;
905 case IPU_PIX_FMT_YUV420P2:
906 case IPU_PIX_FMT_YUV420P:
907 ipu_ch_param_set_field(¶ms, 1, 85, 4, 2);
908
909 if (uv_stride < stride / 2)
910 uv_stride = stride / 2;
911
912 u_offset = stride * height;
913 v_offset = u_offset + (uv_stride * height / 2);
914
915 if ((ch == 8) || (ch == 9) || (ch == 10)) {
916 ipu_ch_param_set_field(¶ms, 1, 78, 7, 15);
917 uv_stride = uv_stride*2;
918 } else {
919 ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);
920 }
921 break;
922 case IPU_PIX_FMT_YVU422P:
923
924 ipu_ch_param_set_field(¶ms, 1, 85, 4, 1);
925 ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);
926
927 if (uv_stride < stride / 2)
928 uv_stride = stride / 2;
929
930 v_offset = (v == 0) ? stride * height : v;
931 u_offset = (u == 0) ? v_offset + v_offset / 2 : u;
932 break;
933 case IPU_PIX_FMT_YUV422P:
934
935 ipu_ch_param_set_field(¶ms, 1, 85, 4, 1);
936 ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);
937
938 if (uv_stride < stride / 2)
939 uv_stride = stride / 2;
940
941 u_offset = (u == 0) ? stride * height : u;
942 v_offset = (v == 0) ? u_offset + u_offset / 2 : v;
943 break;
944 case IPU_PIX_FMT_NV12:
945
946 ipu_ch_param_set_field(¶ms, 1, 85, 4, 4);
947 ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);
948 uv_stride = stride;
949 u_offset = (u == 0) ? stride * height : u;
950 break;
951 default:
952 puts("mxc ipu: unimplemented pixel format\n");
953 break;
954 }
955
956
957 if (uv_stride)
958 ipu_ch_param_set_field(¶ms, 1, 128, 14, uv_stride - 1);
959
960
961 if (u || v) {
962 u_offset = u;
963 v_offset = v;
964 }
965
966
967 if (u_offset/8 > 0x3fffff)
968 puts("The value of U offset exceeds IPU limitation\n");
969 if (v_offset/8 > 0x3fffff)
970 puts("The value of V offset exceeds IPU limitation\n");
971
972 ipu_ch_param_set_field(¶ms, 0, 46, 22, u_offset / 8);
973 ipu_ch_param_set_field(¶ms, 0, 68, 22, v_offset / 8);
974
975 debug("initializing idma ch %d @ %p\n", ch, ipu_ch_param_addr(ch));
976 memcpy(ipu_ch_param_addr(ch), ¶ms, sizeof(params));
977};
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
1011 uint32_t pixel_fmt,
1012 uint16_t width, uint16_t height,
1013 uint32_t stride,
1014 dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
1015 uint32_t u, uint32_t v)
1016{
1017 uint32_t reg;
1018 uint32_t dma_chan;
1019
1020 dma_chan = channel_2_dma(channel, type);
1021 if (!idma_is_valid(dma_chan))
1022 return -EINVAL;
1023
1024 if (stride < width * bytes_per_pixel(pixel_fmt))
1025 stride = width * bytes_per_pixel(pixel_fmt);
1026
1027 if (stride % 4) {
1028 printf(
1029 "Stride not 32-bit aligned, stride = %d\n", stride);
1030 return -EINVAL;
1031 }
1032
1033 ipu_ch_param_init(dma_chan, pixel_fmt, width, height, stride, u, v, 0,
1034 phyaddr_0, phyaddr_1);
1035
1036 if (ipu_is_dmfc_chan(dma_chan)) {
1037 ipu_dmfc_set_wait4eot(dma_chan, width);
1038 }
1039
1040 if (idma_is_set(IDMAC_CHA_PRI, dma_chan))
1041 ipu_ch_param_set_high_priority(dma_chan);
1042
1043 ipu_ch_param_dump(dma_chan);
1044
1045 reg = __raw_readl(IPU_CHA_DB_MODE_SEL(dma_chan));
1046 if (phyaddr_1)
1047 reg |= idma_mask(dma_chan);
1048 else
1049 reg &= ~idma_mask(dma_chan);
1050 __raw_writel(reg, IPU_CHA_DB_MODE_SEL(dma_chan));
1051
1052
1053 __raw_writel(idma_mask(dma_chan), IPU_CHA_CUR_BUF(dma_chan));
1054
1055 return 0;
1056}
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066int32_t ipu_enable_channel(ipu_channel_t channel)
1067{
1068 uint32_t reg;
1069 uint32_t in_dma;
1070 uint32_t out_dma;
1071
1072 if (g_channel_enable_mask & (1L << IPU_CHAN_ID(channel))) {
1073 printf("Warning: channel already enabled %d\n",
1074 IPU_CHAN_ID(channel));
1075 }
1076
1077
1078 out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
1079 in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
1080
1081 if (idma_is_valid(in_dma)) {
1082 reg = __raw_readl(IDMAC_CHA_EN(in_dma));
1083 __raw_writel(reg | idma_mask(in_dma), IDMAC_CHA_EN(in_dma));
1084 }
1085 if (idma_is_valid(out_dma)) {
1086 reg = __raw_readl(IDMAC_CHA_EN(out_dma));
1087 __raw_writel(reg | idma_mask(out_dma), IDMAC_CHA_EN(out_dma));
1088 }
1089
1090 if ((channel == MEM_DC_SYNC) || (channel == MEM_BG_SYNC) ||
1091 (channel == MEM_FG_SYNC))
1092 ipu_dp_dc_enable(channel);
1093
1094 g_channel_enable_mask |= 1L << IPU_CHAN_ID(channel);
1095
1096 return 0;
1097}
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110void ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type,
1111 uint32_t bufNum)
1112{
1113 uint32_t dma_ch = channel_2_dma(channel, type);
1114
1115 if (!idma_is_valid(dma_ch))
1116 return;
1117
1118 __raw_writel(0xF0000000, IPU_GPR);
1119 if (bufNum == 0) {
1120 if (idma_is_set(IPU_CHA_BUF0_RDY, dma_ch)) {
1121 __raw_writel(idma_mask(dma_ch),
1122 IPU_CHA_BUF0_RDY(dma_ch));
1123 }
1124 } else {
1125 if (idma_is_set(IPU_CHA_BUF1_RDY, dma_ch)) {
1126 __raw_writel(idma_mask(dma_ch),
1127 IPU_CHA_BUF1_RDY(dma_ch));
1128 }
1129 }
1130 __raw_writel(0x0, IPU_GPR);
1131}
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144int32_t ipu_disable_channel(ipu_channel_t channel)
1145{
1146 uint32_t reg;
1147 uint32_t in_dma;
1148 uint32_t out_dma;
1149
1150 if ((g_channel_enable_mask & (1L << IPU_CHAN_ID(channel))) == 0) {
1151 debug("Channel already disabled %d\n",
1152 IPU_CHAN_ID(channel));
1153 return 0;
1154 }
1155
1156
1157 out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
1158 in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
1159
1160 if ((idma_is_valid(in_dma) &&
1161 !idma_is_set(IDMAC_CHA_EN, in_dma))
1162 && (idma_is_valid(out_dma) &&
1163 !idma_is_set(IDMAC_CHA_EN, out_dma)))
1164 return -EINVAL;
1165
1166 if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) ||
1167 (channel == MEM_DC_SYNC)) {
1168 ipu_dp_dc_disable(channel, 0);
1169 }
1170
1171
1172 if (idma_is_valid(in_dma)) {
1173 reg = __raw_readl(IDMAC_CHA_EN(in_dma));
1174 __raw_writel(reg & ~idma_mask(in_dma), IDMAC_CHA_EN(in_dma));
1175 __raw_writel(idma_mask(in_dma), IPU_CHA_CUR_BUF(in_dma));
1176 }
1177 if (idma_is_valid(out_dma)) {
1178 reg = __raw_readl(IDMAC_CHA_EN(out_dma));
1179 __raw_writel(reg & ~idma_mask(out_dma), IDMAC_CHA_EN(out_dma));
1180 __raw_writel(idma_mask(out_dma), IPU_CHA_CUR_BUF(out_dma));
1181 }
1182
1183 g_channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel));
1184
1185
1186 if (idma_is_valid(in_dma)) {
1187 ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 0);
1188 ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 1);
1189 }
1190 if (idma_is_valid(out_dma)) {
1191 ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, 0);
1192 ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, 1);
1193 }
1194
1195 return 0;
1196}
1197
1198uint32_t bytes_per_pixel(uint32_t fmt)
1199{
1200 switch (fmt) {
1201 case IPU_PIX_FMT_GENERIC:
1202 case IPU_PIX_FMT_RGB332:
1203 case IPU_PIX_FMT_YUV420P:
1204 case IPU_PIX_FMT_YUV422P:
1205 return 1;
1206 break;
1207 case IPU_PIX_FMT_RGB565:
1208 case IPU_PIX_FMT_YUYV:
1209 case IPU_PIX_FMT_UYVY:
1210 return 2;
1211 break;
1212 case IPU_PIX_FMT_BGR24:
1213 case IPU_PIX_FMT_RGB24:
1214 return 3;
1215 break;
1216 case IPU_PIX_FMT_GENERIC_32:
1217 case IPU_PIX_FMT_BGR32:
1218 case IPU_PIX_FMT_BGRA32:
1219 case IPU_PIX_FMT_RGB32:
1220 case IPU_PIX_FMT_RGBA32:
1221 case IPU_PIX_FMT_ABGR32:
1222 return 4;
1223 break;
1224 default:
1225 return 1;
1226 break;
1227 }
1228 return 0;
1229}
1230
1231ipu_color_space_t format_to_colorspace(uint32_t fmt)
1232{
1233 switch (fmt) {
1234 case IPU_PIX_FMT_RGB666:
1235 case IPU_PIX_FMT_RGB565:
1236 case IPU_PIX_FMT_BGR24:
1237 case IPU_PIX_FMT_RGB24:
1238 case IPU_PIX_FMT_BGR32:
1239 case IPU_PIX_FMT_BGRA32:
1240 case IPU_PIX_FMT_RGB32:
1241 case IPU_PIX_FMT_RGBA32:
1242 case IPU_PIX_FMT_ABGR32:
1243 case IPU_PIX_FMT_LVDS666:
1244 case IPU_PIX_FMT_LVDS888:
1245 return RGB;
1246 break;
1247
1248 default:
1249 return YCbCr;
1250 break;
1251 }
1252 return RGB;
1253}
1254
1255
1256int ipu_set_ldb_clock(int rate)
1257{
1258 ldb_clk.rate = rate;
1259
1260 return 0;
1261}
1262
1263bool ipu_clk_enabled(void)
1264{
1265 return g_ipu_clk_enabled;
1266}
1267