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