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