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