• Home
  • Raw
  • Download

Lines Matching +full:clk +full:- +full:divider +full:- +full:mode

1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
14 #include <video/imx-ipu-v3.h>
15 #include "ipu-prv.h"
21 struct clk *clk_di; /* display input clock */
22 struct clk *clk_ipu; /* IPU bus clock */
23 struct clk *clk_di_pixel; /* resulting pixel clock */
76 #define DI_SW_GEN0(gen) (0x000c + 4 * ((gen) - 1))
77 #define DI_SW_GEN1(gen) (0x0030 + 4 * ((gen) - 1))
78 #define DI_STP_REP(gen) (0x0148 + 4 * (((gen) - 1)/2))
125 return readl(di->base + offset); in ipu_di_read()
130 writel(value, di->base + offset); in ipu_di_write()
166 if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) || in ipu_di_sync_config()
167 (c->repeat_count >= 0x1000) || in ipu_di_sync_config()
168 (c->cnt_up >= 0x400) || in ipu_di_sync_config()
169 (c->cnt_down >= 0x400)) { in ipu_di_sync_config()
170 dev_err(di->ipu->dev, "DI%d counters out of range.\n", in ipu_di_sync_config()
171 di->id); in ipu_di_sync_config()
175 reg = DI_SW_GEN0_RUN_COUNT(c->run_count) | in ipu_di_sync_config()
176 DI_SW_GEN0_RUN_SRC(c->run_src) | in ipu_di_sync_config()
177 DI_SW_GEN0_OFFSET_COUNT(c->offset_count) | in ipu_di_sync_config()
178 DI_SW_GEN0_OFFSET_SRC(c->offset_src); in ipu_di_sync_config()
181 reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) | in ipu_di_sync_config()
182 DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) | in ipu_di_sync_config()
184 c->cnt_polarity_trigger_src) | in ipu_di_sync_config()
185 DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) | in ipu_di_sync_config()
186 DI_SW_GEN1_CNT_DOWN(c->cnt_down) | in ipu_di_sync_config()
187 DI_SW_GEN1_CNT_UP(c->cnt_up); in ipu_di_sync_config()
190 if (c->repeat_count == 0) in ipu_di_sync_config()
196 reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1))); in ipu_di_sync_config()
197 reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1)); in ipu_di_sync_config()
205 u32 h_total = sig->mode.hactive + sig->mode.hsync_len + in ipu_di_sync_config_interlaced()
206 sig->mode.hback_porch + sig->mode.hfront_porch; in ipu_di_sync_config_interlaced()
207 u32 v_total = sig->mode.vactive + sig->mode.vsync_len + in ipu_di_sync_config_interlaced()
208 sig->mode.vback_porch + sig->mode.vfront_porch; in ipu_di_sync_config_interlaced()
212 .run_count = v_total * 2 - 1, in ipu_di_sync_config_interlaced()
216 .run_count = h_total - 1, in ipu_di_sync_config_interlaced()
220 .cnt_down = sig->mode.hsync_len * 2, in ipu_di_sync_config_interlaced()
223 .run_count = v_total - 1, in ipu_di_sync_config_interlaced()
227 .cnt_down = sig->mode.vsync_len * 2, in ipu_di_sync_config_interlaced()
240 .offset_count = (sig->mode.vsync_len + in ipu_di_sync_config_interlaced()
241 sig->mode.vback_porch) / 2, in ipu_di_sync_config_interlaced()
243 .repeat_count = sig->mode.vactive / 2, in ipu_di_sync_config_interlaced()
248 .offset_count = sig->mode.hsync_len + in ipu_di_sync_config_interlaced()
249 sig->mode.hback_porch, in ipu_di_sync_config_interlaced()
251 .repeat_count = sig->mode.hactive, in ipu_di_sync_config_interlaced()
255 .run_count = h_total / 2 - 1, in ipu_di_sync_config_interlaced()
262 ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF); in ipu_di_sync_config_interlaced()
268 u32 h_total = sig->mode.hactive + sig->mode.hsync_len + in ipu_di_sync_config_noninterlaced()
269 sig->mode.hback_porch + sig->mode.hfront_porch; in ipu_di_sync_config_noninterlaced()
270 u32 v_total = sig->mode.vactive + sig->mode.vsync_len + in ipu_di_sync_config_noninterlaced()
271 sig->mode.vback_porch + sig->mode.vfront_porch; in ipu_di_sync_config_noninterlaced()
275 .run_count = h_total - 1, in ipu_di_sync_config_noninterlaced()
279 .run_count = h_total - 1, in ipu_di_sync_config_noninterlaced()
281 .offset_count = div * sig->v_to_h_sync, in ipu_di_sync_config_noninterlaced()
285 .cnt_down = sig->mode.hsync_len * 2, in ipu_di_sync_config_noninterlaced()
288 .run_count = v_total - 1, in ipu_di_sync_config_noninterlaced()
292 .cnt_down = sig->mode.vsync_len * 2, in ipu_di_sync_config_noninterlaced()
296 .offset_count = sig->mode.vsync_len + in ipu_di_sync_config_noninterlaced()
297 sig->mode.vback_porch, in ipu_di_sync_config_noninterlaced()
299 .repeat_count = sig->mode.vactive, in ipu_di_sync_config_noninterlaced()
304 .offset_count = sig->mode.hsync_len + in ipu_di_sync_config_noninterlaced()
305 sig->mode.hback_porch, in ipu_di_sync_config_noninterlaced()
307 .repeat_count = sig->mode.hactive, in ipu_di_sync_config_noninterlaced()
323 .run_count = h_total - 1, in ipu_di_sync_config_noninterlaced()
327 .run_count = v_total - 1, in ipu_di_sync_config_noninterlaced()
332 .offset_count = sig->mode.vsync_len + in ipu_di_sync_config_noninterlaced()
333 sig->mode.vback_porch, in ipu_di_sync_config_noninterlaced()
335 .repeat_count = sig->mode.vactive, in ipu_di_sync_config_noninterlaced()
339 .run_count = h_total - 1, in ipu_di_sync_config_noninterlaced()
341 .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */ in ipu_di_sync_config_noninterlaced()
345 .cnt_down = sig->mode.hsync_len * 2, in ipu_di_sync_config_noninterlaced()
349 .offset_count = sig->mode.hsync_len + in ipu_di_sync_config_noninterlaced()
350 sig->mode.hback_porch, in ipu_di_sync_config_noninterlaced()
352 .repeat_count = sig->mode.hactive, in ipu_di_sync_config_noninterlaced()
356 .run_count = v_total - 1, in ipu_di_sync_config_noninterlaced()
362 .cnt_down = sig->mode.vsync_len * 2, in ipu_di_sync_config_noninterlaced()
364 /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */ in ipu_di_sync_config_noninterlaced()
365 .run_count = h_total - 1, in ipu_di_sync_config_noninterlaced()
367 .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */ in ipu_di_sync_config_noninterlaced()
371 .cnt_down = sig->mode.hsync_len * 2, in ipu_di_sync_config_noninterlaced()
373 /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */ in ipu_di_sync_config_noninterlaced()
374 .run_count = v_total - 1, in ipu_di_sync_config_noninterlaced()
380 .cnt_down = sig->mode.vsync_len * 2, in ipu_di_sync_config_noninterlaced()
386 ipu_di_write(di, v_total - 1, DI_SCR_CONF); in ipu_di_sync_config_noninterlaced()
387 if (sig->hsync_pin == 2 && sig->vsync_pin == 3) in ipu_di_sync_config_noninterlaced()
396 struct clk *clk; in ipu_di_config_clock() local
400 if (sig->clkflags & IPU_DI_CLKMODE_EXT) { in ipu_di_config_clock()
406 clk = di->clk_di; in ipu_di_config_clock()
408 if (sig->clkflags & IPU_DI_CLKMODE_SYNC) { in ipu_di_config_clock()
419 * We can use the divider. We should really have in ipu_di_config_clock()
421 * cope with a fractional divider or not. For the in ipu_di_config_clock()
428 clk_set_rate(clk, sig->mode.pixelclock); in ipu_di_config_clock()
430 in_rate = clk_get_rate(clk); in ipu_di_config_clock()
431 div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock); in ipu_di_config_clock()
447 clkrate = clk_get_rate(di->clk_ipu); in ipu_di_config_clock()
448 div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock); in ipu_di_config_clock()
452 error = rate / (sig->mode.pixelclock / 1000); in ipu_di_config_clock()
454 dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %c%d.%d%%\n", in ipu_di_config_clock()
455 rate, div, error < 1000 ? '-' : '+', in ipu_di_config_clock()
456 abs(error - 1000) / 10, abs(error - 1000) % 10); in ipu_di_config_clock()
460 clk = di->clk_ipu; in ipu_di_config_clock()
467 clk = di->clk_di; in ipu_di_config_clock()
469 clk_set_rate(clk, sig->mode.pixelclock); in ipu_di_config_clock()
471 in_rate = clk_get_rate(clk); in ipu_di_config_clock()
472 div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock); in ipu_di_config_clock()
479 di->clk_di_pixel = clk; in ipu_di_config_clock()
481 /* Set the divider */ in ipu_di_config_clock()
487 * based on the divider above. We want a 50% duty cycle, so set in ipu_di_config_clock()
488 * the falling edge to be half the divider. in ipu_di_config_clock()
494 if (clk == di->clk_di) in ipu_di_config_clock()
498 dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n", in ipu_di_config_clock()
499 sig->mode.pixelclock, in ipu_di_config_clock()
500 clk_get_rate(di->clk_ipu), in ipu_di_config_clock()
501 clk_get_rate(di->clk_di), in ipu_di_config_clock()
502 clk == di->clk_di ? "DI" : "IPU", in ipu_di_config_clock()
503 clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4)); in ipu_di_config_clock()
507 * This function is called to adjust a video mode to IPU restrictions.
510 int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode) in ipu_di_adjust_videomode() argument
514 if (mode->vfront_porch >= 2) in ipu_di_adjust_videomode()
517 diff = 2 - mode->vfront_porch; in ipu_di_adjust_videomode()
519 if (mode->vback_porch >= diff) { in ipu_di_adjust_videomode()
520 mode->vfront_porch = 2; in ipu_di_adjust_videomode()
521 mode->vback_porch -= diff; in ipu_di_adjust_videomode()
522 } else if (mode->vsync_len > diff) { in ipu_di_adjust_videomode()
523 mode->vfront_porch = 2; in ipu_di_adjust_videomode()
524 mode->vsync_len = mode->vsync_len - diff; in ipu_di_adjust_videomode()
526 dev_warn(di->ipu->dev, "failed to adjust videomode\n"); in ipu_di_adjust_videomode()
527 return -EINVAL; in ipu_di_adjust_videomode()
530 dev_dbg(di->ipu->dev, "videomode adapted for IPU restrictions\n"); in ipu_di_adjust_videomode()
564 dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n", in ipu_di_init_sync_panel()
565 di->id, sig->mode.hactive, sig->mode.vactive); in ipu_di_init_sync_panel()
567 dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n", in ipu_di_init_sync_panel()
568 clk_get_rate(di->clk_ipu), in ipu_di_init_sync_panel()
569 clk_get_rate(di->clk_di), in ipu_di_init_sync_panel()
570 sig->mode.pixelclock); in ipu_di_init_sync_panel()
577 div = div / 16; /* Now divider is integer portion */ in ipu_di_init_sync_panel()
583 ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1); in ipu_di_init_sync_panel()
589 if (sig->mode.flags & DISPLAY_FLAGS_INTERLACED) { in ipu_di_init_sync_panel()
600 if (di->id == 1) in ipu_di_init_sync_panel()
605 if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3)) in ipu_di_init_sync_panel()
609 if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH) in ipu_di_init_sync_panel()
610 di_gen |= ipu_di_gen_polarity(sig->hsync_pin); in ipu_di_init_sync_panel()
611 if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH) in ipu_di_init_sync_panel()
612 di_gen |= ipu_di_gen_polarity(sig->vsync_pin); in ipu_di_init_sync_panel()
614 if (sig->clk_pol) in ipu_di_init_sync_panel()
619 ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002, in ipu_di_init_sync_panel()
625 if (sig->enable_pol) in ipu_di_init_sync_panel()
627 if (sig->data_pol) in ipu_di_init_sync_panel()
642 WARN_ON(IS_ERR(di->clk_di_pixel)); in ipu_di_enable()
644 ret = clk_prepare_enable(di->clk_di_pixel); in ipu_di_enable()
648 ipu_module_enable(di->ipu, di->module); in ipu_di_enable()
656 WARN_ON(IS_ERR(di->clk_di_pixel)); in ipu_di_disable()
658 ipu_module_disable(di->ipu, di->module); in ipu_di_disable()
660 clk_disable_unprepare(di->clk_di_pixel); in ipu_di_disable()
668 return di->id; in ipu_di_get_num()
679 return ERR_PTR(-EINVAL); in ipu_di_get()
681 di = ipu->di_priv[disp]; in ipu_di_get()
685 if (di->inuse) { in ipu_di_get()
686 di = ERR_PTR(-EBUSY); in ipu_di_get()
690 di->inuse = true; in ipu_di_get()
702 di->inuse = false; in ipu_di_put()
710 u32 module, struct clk *clk_ipu) in ipu_di_init()
715 return -ENODEV; in ipu_di_init()
719 return -ENOMEM; in ipu_di_init()
721 ipu->di_priv[id] = di; in ipu_di_init()
723 di->clk_di = devm_clk_get(dev, id ? "di1" : "di0"); in ipu_di_init()
724 if (IS_ERR(di->clk_di)) in ipu_di_init()
725 return PTR_ERR(di->clk_di); in ipu_di_init()
727 di->module = module; in ipu_di_init()
728 di->id = id; in ipu_di_init()
729 di->clk_ipu = clk_ipu; in ipu_di_init()
730 di->base = devm_ioremap(dev, base, PAGE_SIZE); in ipu_di_init()
731 if (!di->base) in ipu_di_init()
732 return -ENOMEM; in ipu_di_init()
737 id, base, di->base); in ipu_di_init()
738 di->inuse = false; in ipu_di_init()
739 di->ipu = ipu; in ipu_di_init()