aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/da8xx-fb.c85
1 files changed, 65 insertions, 20 deletions
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index d8b295ab85f5..dfe757254e26 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -132,6 +132,9 @@
132#define WSI_TIMEOUT 50 132#define WSI_TIMEOUT 50
133#define PALETTE_SIZE 256 133#define PALETTE_SIZE 256
134 134
135#define CLK_MIN_DIV 2
136#define CLK_MAX_DIV 255
137
135static void __iomem *da8xx_fb_reg_base; 138static void __iomem *da8xx_fb_reg_base;
136static unsigned int lcd_revision; 139static unsigned int lcd_revision;
137static irq_handler_t lcdc_irq_handler; 140static irq_handler_t lcdc_irq_handler;
@@ -684,38 +687,76 @@ static void da8xx_fb_lcd_reset(void)
684 } 687 }
685} 688}
686 689
687static inline unsigned da8xx_fb_calc_clk_divider(struct da8xx_fb_par *par, 690static int da8xx_fb_config_clk_divider(struct da8xx_fb_par *par,
688 unsigned pixclock) 691 unsigned lcdc_clk_div,
689{ 692 unsigned lcdc_clk_rate)
690 return par->lcd_fck_rate / (PICOS2KHZ(pixclock) * 1000);
691}
692
693static inline unsigned da8xx_fb_round_clk(struct da8xx_fb_par *par,
694 unsigned pixclock)
695{ 693{
696 unsigned div; 694 int ret;
697 695
698 div = da8xx_fb_calc_clk_divider(par, pixclock); 696 if (par->lcd_fck_rate != lcdc_clk_rate) {
699 return KHZ2PICOS(par->lcd_fck_rate / (1000 * div)); 697 ret = clk_set_rate(par->lcdc_clk, lcdc_clk_rate);
700} 698 if (IS_ERR_VALUE(ret)) {
699 dev_err(par->dev,
700 "unable to set clock rate at %u\n",
701 lcdc_clk_rate);
702 return ret;
703 }
704 par->lcd_fck_rate = clk_get_rate(par->lcdc_clk);
705 }
701 706
702static inline void da8xx_fb_config_clk_divider(unsigned div)
703{
704 /* Configure the LCD clock divisor. */ 707 /* Configure the LCD clock divisor. */
705 lcdc_write(LCD_CLK_DIVISOR(div) | 708 lcdc_write(LCD_CLK_DIVISOR(lcdc_clk_div) |
706 (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); 709 (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG);
707 710
708 if (lcd_revision == LCD_VERSION_2) 711 if (lcd_revision == LCD_VERSION_2)
709 lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN | 712 lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN |
710 LCD_V2_CORE_CLK_EN, LCD_CLK_ENABLE_REG); 713 LCD_V2_CORE_CLK_EN, LCD_CLK_ENABLE_REG);
714
715 return 0;
716}
717
718static unsigned int da8xx_fb_calc_clk_divider(struct da8xx_fb_par *par,
719 unsigned pixclock,
720 unsigned *lcdc_clk_rate)
721{
722 unsigned lcdc_clk_div;
723
724 pixclock = PICOS2KHZ(pixclock) * 1000;
725
726 *lcdc_clk_rate = par->lcd_fck_rate;
727
728 if (pixclock < (*lcdc_clk_rate / CLK_MAX_DIV)) {
729 *lcdc_clk_rate = clk_round_rate(par->lcdc_clk,
730 pixclock * CLK_MAX_DIV);
731 lcdc_clk_div = CLK_MAX_DIV;
732 } else if (pixclock > (*lcdc_clk_rate / CLK_MIN_DIV)) {
733 *lcdc_clk_rate = clk_round_rate(par->lcdc_clk,
734 pixclock * CLK_MIN_DIV);
735 lcdc_clk_div = CLK_MIN_DIV;
736 } else {
737 lcdc_clk_div = *lcdc_clk_rate / pixclock;
738 }
739
740 return lcdc_clk_div;
711} 741}
712 742
713static inline void da8xx_fb_calc_config_clk_divider(struct da8xx_fb_par *par, 743static int da8xx_fb_calc_config_clk_divider(struct da8xx_fb_par *par,
714 struct fb_videomode *mode) 744 struct fb_videomode *mode)
715{ 745{
716 unsigned div = da8xx_fb_calc_clk_divider(par, mode->pixclock); 746 unsigned lcdc_clk_rate;
747 unsigned lcdc_clk_div = da8xx_fb_calc_clk_divider(par, mode->pixclock,
748 &lcdc_clk_rate);
717 749
718 da8xx_fb_config_clk_divider(div); 750 return da8xx_fb_config_clk_divider(par, lcdc_clk_div, lcdc_clk_rate);
751}
752
753static inline unsigned da8xx_fb_round_clk(struct da8xx_fb_par *par,
754 unsigned pixclock)
755{
756 unsigned lcdc_clk_div, lcdc_clk_rate;
757
758 lcdc_clk_div = da8xx_fb_calc_clk_divider(par, pixclock, &lcdc_clk_rate);
759 return KHZ2PICOS(lcdc_clk_rate / (1000 * lcdc_clk_div));
719} 760}
720 761
721static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, 762static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
@@ -724,7 +765,11 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
724 u32 bpp; 765 u32 bpp;
725 int ret = 0; 766 int ret = 0;
726 767
727 da8xx_fb_calc_config_clk_divider(par, panel); 768 ret = da8xx_fb_calc_config_clk_divider(par, panel);
769 if (IS_ERR_VALUE(ret)) {
770 dev_err(par->dev, "unable to configure clock\n");
771 return ret;
772 }
728 773
729 if (panel->sync & FB_SYNC_CLK_INVERT) 774 if (panel->sync & FB_SYNC_CLK_INVERT)
730 lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) | 775 lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) |