summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2014-12-21 15:27:45 (GMT)
committerHans de Goede <hdegoede@redhat.com>2015-01-14 13:56:39 (GMT)
commit5489ebc7af2e0f46eb5e818e2dc646d03bd96541 (patch)
treea7bed75b3f8ad3b7e9e2db4834f55d7bff9f80fd
parent0e045215578bc67fab00009ba4985bbdcd90de23 (diff)
downloadu-boot-5489ebc7af2e0f46eb5e818e2dc646d03bd96541.tar.xz
sunxi: video: Modify sunxi_lcdc_pll_set to work with both tcon0 and tcon1
Modify sunxi_lcdc_pll_set to work with both tcon0 and tcon1, this is a preparation patch for adding lcd support. While at it also swap the divider search order, searching from low to high, as the comment above the code says we should do. In cases where there are multiple solutions this will result in picking a lower pll clock and divider, which is more stable and saves power. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Ian Campbell <ijc@hellion.org.uk>
-rw-r--r--arch/arm/include/asm/arch-sunxi/clock_sun6i.h2
-rw-r--r--drivers/video/sunxi_display.c31
2 files changed, 26 insertions, 7 deletions
diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
index 1beeff3..653f63c 100644
--- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
+++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h
@@ -255,6 +255,8 @@ struct sunxi_ccm_reg {
#define CCM_LCD_CH0_CTRL_PLL3_2X (2 << 24)
#define CCM_LCD_CH0_CTRL_PLL7_2X (3 << 24)
#define CCM_LCD_CH0_CTRL_MIPI_PLL (4 << 24)
+/* No reset bit in ch0_clk_cfg (reset is controlled through ahb_reset1) */
+#define CCM_LCD_CH0_CTRL_RST 0
#define CCM_LCD_CH0_CTRL_GATE (0x1 << 31)
#define CCM_LCD_CH1_CTRL_M(n) ((((n) - 1) & 0xf) << 0)
diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c
index f990ab9..e4f95d4 100644
--- a/drivers/video/sunxi_display.c
+++ b/drivers/video/sunxi_display.c
@@ -323,20 +323,29 @@ static void sunxi_composer_enable(void)
/*
* LCDC, what allwinner calls a CRTC, so timing controller and serializer.
*/
-static void sunxi_lcdc_pll_set(int dotclock, int *clk_div, int *clk_double)
+static void sunxi_lcdc_pll_set(int tcon, int dotclock,
+ int *clk_div, int *clk_double)
{
struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
- int value, n, m, diff;
+ int value, n, m, min_m, max_m, diff;
int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
int best_double = 0;
+ if (tcon == 0) {
+ min_m = 6;
+ max_m = 127;
+ } else {
+ min_m = 1;
+ max_m = 15;
+ }
+
/*
* Find the lowest divider resulting in a matching clock, if there
* is no match, pick the closest lower clock, as monitors tend to
* not sync to higher frequencies.
*/
- for (m = 15; m > 0; m--) {
+ for (m = min_m; m <= max_m; m++) {
n = (m * dotclock) / 3000;
if ((n >= 9) && (n <= 127)) {
@@ -373,9 +382,17 @@ static void sunxi_lcdc_pll_set(int dotclock, int *clk_div, int *clk_double)
clock_set_pll3(best_n * 3000000);
- writel(CCM_LCD_CH1_CTRL_GATE |
- (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X : CCM_LCD_CH1_CTRL_PLL3) |
- CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
+ if (tcon == 0) {
+ writel(CCM_LCD_CH0_CTRL_GATE | CCM_LCD_CH0_CTRL_RST |
+ (best_double ? CCM_LCD_CH0_CTRL_PLL3_2X :
+ CCM_LCD_CH0_CTRL_PLL3),
+ &ccm->lcd0_ch0_clk_cfg);
+ } else {
+ writel(CCM_LCD_CH1_CTRL_GATE |
+ (best_double ? CCM_LCD_CH1_CTRL_PLL3_2X :
+ CCM_LCD_CH1_CTRL_PLL3) |
+ CCM_LCD_CH1_CTRL_M(best_m), &ccm->lcd0_ch1_clk_cfg);
+ }
*clk_div = best_m;
*clk_double = best_double;
@@ -453,7 +470,7 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
writel(SUNXI_LCDC_X(mode->hsync_len) | SUNXI_LCDC_Y(mode->vsync_len),
&lcdc->tcon1_timing_sync);
- sunxi_lcdc_pll_set(mode->pixclock_khz, clk_div, clk_double);
+ sunxi_lcdc_pll_set(1, mode->pixclock_khz, clk_div, clk_double);
}
#ifdef CONFIG_MACH_SUN6I