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