1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Porting to u-boot: 4 * 5 * (C) Copyright 2010 6 * Stefano Babic, DENX Software Engineering, sbabic@denx.de 7 * 8 * Linux IPU driver for MX51: 9 * 10 * (C) Copyright 2005-2010 Freescale Semiconductor, Inc. 11 */ 12 13/* #define DEBUG */ 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 /* Handshake with IPU when certain clock rates are changed. */ 171 reg = __raw_readl(&mxc_ccm->ccdr); 172 reg &= ~MXC_CCM_CCDR_IPU_HS_MASK; 173 __raw_writel(reg, &mxc_ccm->ccdr); 174 175 /* Handshake with IPU when LPM is entered as its enabled. */ 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 * No handshake with IPU whe dividers are changed 194 * as its not enabled. 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 /* No handshake with IPU when LPM is entered as its not enabled. */ 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 CFG_SYS_LDB_CLOCK 225#define CFG_SYS_LDB_CLOCK 65000000 226#endif 227 228static struct clk ldb_clk = { 229 .name = "ldb_clk", 230 .rate = CFG_SYS_LDB_CLOCK, 231 .usecount = 0, 232}; 233 234/* Globals */ 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/* Static functions */ 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/* Either DP BG or DP FG can be graphic window */ 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 * Calculate divider 312 * Fractional part is 4 bits, 313 * so simply multiply by 2^4 to get fractional part. 314 */ 315 div = parent_rate; 316 remainder = do_div(div, rate); 317 /* Round the divider value */ 318 if (remainder > (rate / 2)) 319 div++; 320 if (div < 0x10) /* Min DI disp clock divider is 1 */ 321 div = 0x10; 322 if (div & ~0xFEF) 323 div &= 0xFF8; 324 else { 325 /* Round up divider if it gets us closer to desired pix clk */ 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 /* Round the divider value */ 346 if (remainder > (rate / 2)) 347 div++; 348 349 /* Round up divider if it gets us closer to desired pix clk */ 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 * Setup pixel clock timing 361 * Down time is half of period 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 * This function resets IPU 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 * This function is called by the driver framework to initialize the IPU 455 * hardware. 456 * 457 * @param dev The device structure for the IPU passed in by the 458 * driver framework. 459 * 460 * Return: Returns 0 on success or negative error code on error 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 /* CSI mode reserved*/ 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 /* DMFC Init */ 520 ipu_dmfc_init(DMFC_NORMAL, 1); 521 522 /* Set sync refresh channels as high priority */ 523 __raw_writel(0x18800000L, IDMAC_CHA_PRI(0)); 524 525 /* Set MCU_T to divide MCU access window into 2 */ 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 * This function is called to initialize a logical IPU channel. 571 * 572 * @param channel Input parameter for the logical channel ID to init. 573 * 574 * @param params Input parameter containing union of channel 575 * initialization parameters. 576 * 577 * Return: Returns 0 on success or negative error code on fail 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 /* Enable IPU sub module */ 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 * This function is called to uninitialize a logical IPU channel. 665 * 666 * @param channel Input parameter for the logical channel ID to uninit. 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 * Make sure channel is disabled 682 * Get input and output dma channels 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 /* Reset the double buffer */ 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 /* Setup red width and offset */ 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 /* Setup green width and offset */ 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 /* Setup blue width and offset */ 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 /* Setup alpha width and offset */ 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 /*Represents 8-bit Generic data */ 844 ipu_ch_param_set_field(¶ms, 0, 107, 3, 5); /* bits/pixel */ 845 ipu_ch_param_set_field(¶ms, 1, 85, 4, 6); /* pix format */ 846 ipu_ch_param_set_field(¶ms, 1, 78, 7, 63); /* burst size */ 847 848 break; 849 case IPU_PIX_FMT_GENERIC_32: 850 /*Represents 32-bit Generic data */ 851 break; 852 case IPU_PIX_FMT_RGB565: 853 ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ 854 ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ 855 ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ 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); /* bits/pixel */ 861 ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ 862 ipu_ch_param_set_field(¶ms, 1, 78, 7, 19); /* burst size */ 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); /* bits/pixel */ 869 ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ 870 ipu_ch_param_set_field(¶ms, 1, 78, 7, 19); /* burst size */ 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); /* bits/pixel */ 877 ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ 878 ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ 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); /* bits/pixel */ 885 ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ 886 ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ 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); /* bits/pixel */ 892 ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ 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); /* bits/pixel */ 898 ipu_ch_param_set_field(¶ms, 1, 85, 4, 0xA); /* pix format */ 899 ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ 900 break; 901 case IPU_PIX_FMT_YUYV: 902 ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ 903 ipu_ch_param_set_field(¶ms, 1, 85, 4, 0x8); /* pix format */ 904 ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ 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); /* pix format */ 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 /* burst size */ 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 /* BPP & pixel format */ 925 ipu_ch_param_set_field(¶ms, 1, 85, 4, 1); /* pix format */ 926 ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ 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 /* BPP & pixel format */ 936 ipu_ch_param_set_field(¶ms, 1, 85, 4, 1); /* pix format */ 937 ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ 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 /* BPP & pixel format */ 947 ipu_ch_param_set_field(¶ms, 1, 85, 4, 4); /* pix format */ 948 ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ 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 /* Get the uv offset from user when need cropping */ 962 if (u || v) { 963 u_offset = u; 964 v_offset = v; 965 } 966 967 /* UBO and VBO are 22-bit */ 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 * This function is called to initialize a buffer for logical IPU channel. 982 * 983 * @param channel Input parameter for the logical channel ID. 984 * 985 * @param type Input parameter which buffer to initialize. 986 * 987 * @param pixel_fmt Input parameter for pixel format of buffer. 988 * Pixel format is a FOURCC ASCII code. 989 * 990 * @param width Input parameter for width of buffer in pixels. 991 * 992 * @param height Input parameter for height of buffer in pixels. 993 * 994 * @param stride Input parameter for stride length of buffer 995 * in pixels. 996 * 997 * @param phyaddr_0 Input parameter buffer 0 physical address. 998 * 999 * @param phyaddr_1 Input parameter buffer 1 physical address. 1000 * Setting this to a value other than NULL enables 1001 * double buffering mode. 1002 * 1003 * @param u private u offset for additional cropping, 1004 * zero if not used. 1005 * 1006 * @param v private v offset for additional cropping, 1007 * zero if not used. 1008 * 1009 * Return: Returns 0 on success or negative error code on fail 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 /* Build parameter memory data for DMA channel */ 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 /* Reset to buffer 0 */ 1054 __raw_writel(idma_mask(dma_chan), IPU_CHA_CUR_BUF(dma_chan)); 1055 1056 return 0; 1057} 1058 1059/* 1060 * This function enables a logical channel. 1061 * 1062 * @param channel Input parameter for the logical channel ID. 1063 * 1064 * Return: This function returns 0 on success or negative error code on 1065 * fail. 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 /* Get input and output dma channels */ 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 * This function clear buffer ready for a logical channel. 1102 * 1103 * @param channel Input parameter for the logical channel ID. 1104 * 1105 * @param type Input parameter which buffer to clear. 1106 * 1107 * @param bufNum Input parameter for which buffer number clear 1108 * ready state. 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); /* write one to clear */ 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); /* write one to set */ 1132} 1133 1134/* 1135 * This function disables a logical channel. 1136 * 1137 * @param channel Input parameter for the logical channel ID. 1138 * 1139 * @param wait_for_stop Flag to set whether to wait for channel end 1140 * of frame or return immediately. 1141 * 1142 * Return: This function returns 0 on success or negative error code on 1143 * fail. 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 /* Get input and output dma channels */ 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 /* Disable DMA channel(s) */ 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 /* Set channel buffers NOT to be ready */ 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: /*generic data */ 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: /*generic data */ 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/* should be removed when clk framework is availiable */ 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