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