From patchwork Tue Jan 15 13:44:36 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Afzal Mohammed X-Patchwork-Id: 1978621 Return-Path: X-Original-To: patchwork-linux-fbdev@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 7D33F3FE33 for ; Tue, 15 Jan 2013 13:44:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757473Ab3AONny (ORCPT ); Tue, 15 Jan 2013 08:43:54 -0500 Received: from comal.ext.ti.com ([198.47.26.152]:46899 "EHLO comal.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756752Ab3AONnv (ORCPT ); Tue, 15 Jan 2013 08:43:51 -0500 Received: from dbdp20.itg.ti.com ([172.24.170.38]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id r0FDhg8Z022431; Tue, 15 Jan 2013 07:43:43 -0600 Received: from DBDE70.ent.ti.com (localhost [127.0.0.1]) by dbdp20.itg.ti.com (8.13.8/8.13.8) with ESMTP id r0FDhfCV007253; Tue, 15 Jan 2013 19:13:41 +0530 (IST) Received: from dbdp32.itg.ti.com (172.24.170.251) by dbde70.ent.ti.com (172.24.170.148) with Microsoft SMTP Server id 14.1.323.3; Tue, 15 Jan 2013 19:13:41 +0530 Received: from ucmsshproxy.india.ext.ti.com (dbdp20.itg.ti.com [172.24.170.38]) by dbdp32.itg.ti.com (8.13.8/8.13.8) with SMTP id r0FDhcWm003961; Tue, 15 Jan 2013 19:13:38 +0530 Received: from symphony.india.ext.ti.com (unknown [192.168.247.13]) by ucmsshproxy.india.ext.ti.com (Postfix) with ESMTP id 3CE9F158002; Tue, 15 Jan 2013 19:13:33 +0530 (IST) Received: from ubuntu-psp-linux.india.ext.ti.com (ubuntu-psp-linux [192.168.247.46]) by symphony.india.ext.ti.com (8.11.7p1+Sun/8.11.7) with ESMTP id r0FDhWR02890; Tue, 15 Jan 2013 19:13:32 +0530 (IST) From: Afzal Mohammed To: Florian Tobias Schandinat , Tomi Valkeinen , Grant Likely , Rob Herring , Rob Landley , Mike Turquette , Sekhar Nori , , , , , Subject: [PATCH v2 12/12] video: da8xx-fb: set upstream clock rate (if reqd) Date: Tue, 15 Jan 2013 19:14:36 +0530 Message-ID: <26e787b021cda89a080f80657c2094b9ff2decaf.1358251448.git.afzal@ti.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: References: MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org LCDC IP has a clock divider to adjust pixel clock, this limits pixel clock range to fck/255 - fck/2(fck - rate of input clock to LCDC IP). In the case of AM335x, where this IP is present, default fck is not sufficient to provide normal pixel clock rates, hence rendering this driver unusable on AM335x. If input clock too is configurable, allowable range of pixel clock would increase. Here initially it is checked whether with present fck, divider in IP could be configured to obtain required rate, if not, fck is adjusted. This makes it usable on AM335x. Note: A better (if allowable) solution may be to represent clock divider in LCDC IP as a basic divider clock - the one defined in common clock framework. But for this to happen, all the platform's using this driver should be using common clock framework (DaVinci is yet to be converted to use common clock framework). And it has to be determined whether common clock framework allows this kind of a clock modelling inside a driver and for this to be part of clock tree. Advantage of doing so would be better resolution for pixel clock, even though without this existing use cases are working properly. Or another extreme alternative would be to replicate clk-divider of common clock framework inside the driver, but that probably is not preferred and not worth as it would be duplication and without much advantage to existing users. Signed-off-by: Afzal Mohammed --- v2: new patch drivers/video/da8xx-fb.c | 76 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 5455682..09dfa12 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -133,6 +133,9 @@ #define WSI_TIMEOUT 50 #define PALETTE_SIZE 256 +#define CLK_MIN_DIV 2 +#define CLK_MAX_DIV 255 + static void __iomem *da8xx_fb_reg_base; static struct resource *lcdc_regs; static unsigned int lcd_revision; @@ -683,23 +686,21 @@ static void da8xx_fb_lcd_reset(void) } } -static inline unsigned da8xx_fb_calc_clk_divider(struct da8xx_fb_par *par, - unsigned pixclock) -{ - return par->lcd_fck_rate / (PICOS2KHZ(pixclock) * 1000); -} - -static inline unsigned da8xx_fb_round_clk(struct da8xx_fb_par *par, - unsigned pixclock) +static int da8xx_fb_config_clk_divider(struct da8xx_fb_par *par, + unsigned div, unsigned rate) { - unsigned div; + int ret; - div = da8xx_fb_calc_clk_divider(par, pixclock); - return KHZ2PICOS(par->lcd_fck_rate / (1000 * div)); -} + if (par->lcd_fck_rate != rate) { + ret = clk_set_rate(par->lcdc_clk, rate); + if (IS_ERR_VALUE(ret)) { + dev_err(par->dev, + "unable to set clock rate at %u\n", rate); + return ret; + } + par->lcd_fck_rate = clk_get_rate(par->lcdc_clk); + } -static inline void da8xx_fb_config_clk_divider(unsigned div) -{ /* Configure the LCD clock divisor. */ lcdc_write(LCD_CLK_DIVISOR(div) | (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); @@ -707,14 +708,49 @@ static inline void da8xx_fb_config_clk_divider(unsigned div) if (lcd_revision == LCD_VERSION_2) lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN | LCD_V2_CORE_CLK_EN, LCD_CLK_ENABLE_REG); + + return 0; +} + +static unsigned int da8xx_fb_calc_clk_divider(struct da8xx_fb_par *par, + unsigned pixclock, + unsigned *rate) +{ + unsigned div; + + pixclock = PICOS2KHZ(pixclock) * 1000; + + *rate = par->lcd_fck_rate; + + if (pixclock < (*rate / CLK_MAX_DIV)) { + *rate = clk_round_rate(par->lcdc_clk, pixclock * CLK_MAX_DIV); + div = CLK_MAX_DIV; + } else if (pixclock > (*rate / CLK_MIN_DIV)) { + *rate = clk_round_rate(par->lcdc_clk, pixclock * CLK_MIN_DIV); + div = CLK_MIN_DIV; + } else { + div = *rate / pixclock; + } + + return div; } -static inline void da8xx_fb_calc_config_clk_divider(struct da8xx_fb_par *par, +static inline int da8xx_fb_calc_config_clk_divider(struct da8xx_fb_par *par, struct fb_videomode *mode) { - unsigned div = da8xx_fb_calc_clk_divider(par, mode->pixclock); + unsigned rate; + unsigned div = da8xx_fb_calc_clk_divider(par, mode->pixclock, &rate); - da8xx_fb_config_clk_divider(div); + return da8xx_fb_config_clk_divider(par, div, rate); +} + +static inline unsigned da8xx_fb_round_clk(struct da8xx_fb_par *par, + unsigned pixclock) +{ + unsigned div, rate; + + div = da8xx_fb_calc_clk_divider(par, pixclock, &rate); + return KHZ2PICOS(rate / (1000 * div)); } static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, @@ -723,7 +759,11 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, u32 bpp; int ret = 0; - da8xx_fb_calc_config_clk_divider(par, panel); + ret = da8xx_fb_calc_config_clk_divider(par, panel); + if (IS_ERR_VALUE(ret)) { + dev_err(par->dev, "unable to configure clock\n"); + return ret; + } if (panel->sync & FB_SYNC_CLK_INVERT) lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) |