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