X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fvideo%2Fipu_common.c;h=cbe1984e4f7579a3c20fb054b78a449a2dd2a85f;hb=ff5d5cc2331033c8a6987bb644827b52484160d9;hp=0f2d113a6f18d0e2ecc32eb00b2f13ad6d7454a1;hpb=cae4a8a2a81ca6cd16d5de1b55d47e315cbff05a;p=u-boot diff --git a/drivers/video/ipu_common.c b/drivers/video/ipu_common.c index 0f2d113a6f..cbe1984e4f 100644 --- a/drivers/video/ipu_common.c +++ b/drivers/video/ipu_common.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Porting to u-boot: * @@ -7,24 +8,6 @@ * Linux IPU driver for MX51: * * (C) Copyright 2005-2010 Freescale Semiconductor, Inc. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA */ /* #define DEBUG */ @@ -32,9 +15,11 @@ #include #include #include -#include +#include #include #include +#include +#include #include "ipu.h" #include "ipu_regs.h" @@ -94,6 +79,12 @@ struct ipu_ch_param { temp1; \ }) +#define IPU_SW_RST_TOUT_USEC (10000) + +#define IPUV3_CLK_MX51 133000000 +#define IPUV3_CLK_MX53 200000000 +#define IPUV3_CLK_MX6Q 264000000 +#define IPUV3_CLK_MX6DL 198000000 void clk_enable(struct clk *clk) { @@ -140,8 +131,12 @@ struct clk *clk_get_parent(struct clk *clk) int clk_set_rate(struct clk *clk, unsigned long rate) { - if (clk && clk->set_rate) + if (!clk) + return 0; + + if (clk->set_rate) clk->set_rate(clk, rate); + return clk->rate; } @@ -210,7 +205,6 @@ static void clk_ipu_disable(struct clk *clk) static struct clk ipu_clk = { .name = "ipu_clk", - .rate = CONFIG_IPUV3_CLK, #if defined(CONFIG_MX51) || defined(CONFIG_MX53) .enable_reg = (u32 *)(CCM_BASE_ADDR + offsetof(struct mxc_ccm_reg, CCGR5)), @@ -225,9 +219,13 @@ static struct clk ipu_clk = { .usecount = 0, }; +#if !defined CONFIG_SYS_LDB_CLOCK +#define CONFIG_SYS_LDB_CLOCK 65000000 +#endif + static struct clk ldb_clk = { .name = "ldb_clk", - .rate = 65000000, + .rate = CONFIG_SYS_LDB_CLOCK, .usecount = 0, }; @@ -286,50 +284,86 @@ static inline void ipu_ch_param_set_buffer(uint32_t ch, int bufNum, static void ipu_pixel_clk_recalc(struct clk *clk) { - u32 div = __raw_readl(DI_BS_CLKGEN0(clk->id)); - if (div == 0) - clk->rate = 0; - else - clk->rate = (clk->parent->rate * 16) / div; + u32 div; + u64 final_rate = (unsigned long long)clk->parent->rate * 16; + + div = __raw_readl(DI_BS_CLKGEN0(clk->id)); + debug("read BS_CLKGEN0 div:%d, final_rate:%lld, prate:%ld\n", + div, final_rate, clk->parent->rate); + + clk->rate = 0; + if (div != 0) { + do_div(final_rate, div); + clk->rate = final_rate; + } } static unsigned long ipu_pixel_clk_round_rate(struct clk *clk, unsigned long rate) { - u32 div, div1; - u32 tmp; + u64 div, final_rate; + u32 remainder; + u64 parent_rate = (unsigned long long)clk->parent->rate * 16; + /* * Calculate divider * Fractional part is 4 bits, * so simply multiply by 2^4 to get fractional part. */ - tmp = (clk->parent->rate * 16); - div = tmp / rate; - + div = parent_rate; + remainder = do_div(div, rate); + /* Round the divider value */ + if (remainder > (rate / 2)) + div++; if (div < 0x10) /* Min DI disp clock divider is 1 */ div = 0x10; if (div & ~0xFEF) div &= 0xFF8; else { - div1 = div & 0xFE0; - if ((tmp/div1 - tmp/div) < rate / 4) - div = div1; - else - div &= 0xFF8; + /* Round up divider if it gets us closer to desired pix clk */ + if ((div & 0xC) == 0xC) { + div += 0x10; + div &= ~0xF; + } } - return (clk->parent->rate * 16) / div; + final_rate = parent_rate; + do_div(final_rate, div); + + return final_rate; } static int ipu_pixel_clk_set_rate(struct clk *clk, unsigned long rate) { - u32 div = (clk->parent->rate * 16) / rate; + u64 div, parent_rate; + u32 remainder; + + parent_rate = (unsigned long long)clk->parent->rate * 16; + div = parent_rate; + remainder = do_div(div, rate); + /* Round the divider value */ + if (remainder > (rate / 2)) + div++; + + /* Round up divider if it gets us closer to desired pix clk */ + if ((div & 0xC) == 0xC) { + div += 0x10; + div &= ~0xF; + } + if (div > 0x1000) + debug("Overflow, DI_BS_CLKGEN0 div:0x%x\n", (u32)div); __raw_writel(div, DI_BS_CLKGEN0(clk->id)); - /* Setup pixel clock timing */ + /* + * Setup pixel clock timing + * Down time is half of period + */ __raw_writel((div / 16) << 16, DI_BS_CLKGEN1(clk->id)); - clk->rate = (clk->parent->rate * 16) / div; + do_div(parent_rate, div); + + clk->rate = parent_rate; + return 0; } @@ -394,15 +428,24 @@ static struct clk pixel_clk[] = { /* * This function resets IPU */ -void ipu_reset(void) +static void ipu_reset(void) { u32 *reg; u32 value; + int timeout = IPU_SW_RST_TOUT_USEC; reg = (u32 *)SRC_BASE_ADDR; value = __raw_readl(reg); value = value | SW_IPU_RST; __raw_writel(value, reg); + + while (__raw_readl(reg) & SW_IPU_RST) { + udelay(1); + if (!(timeout--)) { + printf("ipu software reset timeout\n"); + break; + } + }; } /* @@ -441,6 +484,13 @@ int ipu_probe(void) g_pixel_clk[1] = &pixel_clk[1]; g_ipu_clk = &ipu_clk; +#if defined(CONFIG_MX51) + g_ipu_clk->rate = IPUV3_CLK_MX51; +#elif defined(CONFIG_MX53) + g_ipu_clk->rate = IPUV3_CLK_MX53; +#else + g_ipu_clk->rate = is_mx6sdl() ? IPUV3_CLK_MX6DL : IPUV3_CLK_MX6Q; +#endif debug("ipu_clk = %u\n", clk_get_rate(g_ipu_clk)); g_ldb_clk = &ldb_clk; debug("ldb_clk = %u\n", clk_get_rate(g_ldb_clk)); @@ -1200,3 +1250,16 @@ ipu_color_space_t format_to_colorspace(uint32_t fmt) } return RGB; } + +/* should be removed when clk framework is availiable */ +int ipu_set_ldb_clock(int rate) +{ + ldb_clk.rate = rate; + + return 0; +} + +bool ipu_clk_enabled(void) +{ + return g_ipu_clk_enabled; +}