From patchwork Wed Sep 28 12:41:46 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 77081 Delivered-To: patch@linaro.org Received: by 10.140.106.72 with SMTP id d66csp409469qgf; Wed, 28 Sep 2016 05:42:00 -0700 (PDT) X-Received: by 10.98.83.130 with SMTP id h124mr55836884pfb.154.1475066520076; Wed, 28 Sep 2016 05:42:00 -0700 (PDT) Return-Path: Received: from gabe.freedesktop.org (gabe.freedesktop.org. [2610:10:20:722:a800:ff:fe36:1795]) by mx.google.com with ESMTPS id n11si8372577pfk.264.2016.09.28.05.41.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 28 Sep 2016 05:42:00 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 2610:10:20:722:a800:ff:fe36:1795 as permitted sender) client-ip=2610:10:20:722:a800:ff:fe36:1795; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@baylibre-com.20150623.gappssmtp.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 2610:10:20:722:a800:ff:fe36:1795 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 74F566E3F1; Wed, 28 Sep 2016 12:41:57 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-wm0-x22c.google.com (mail-wm0-x22c.google.com [IPv6:2a00:1450:400c:c09::22c]) by gabe.freedesktop.org (Postfix) with ESMTPS id 43AC86E3F1 for ; Wed, 28 Sep 2016 12:41:56 +0000 (UTC) Received: by mail-wm0-x22c.google.com with SMTP id w84so233791603wmg.1 for ; Wed, 28 Sep 2016 05:41:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id; bh=n66R13E+hIuGDSe6qF1Y72bNp+wcRBPtFP4gfuZOL3c=; b=d2D6qQt0MQQQ2WgeTTFICUiciKSAQ9WGJbDcQyFfbA1LTCKB2/Dm2/d7IqnDj6H6d5 l+7omb7hqSVc7bet0H1zRh0lEO59tju1chmvM6FIrBnSMtyBsjmTK2NH6QuxGihuYgkT OrLAh1q2v5Gj925mApUzzN+mO5N6IDS0Hiz/AON2Q/H2IZo8bkSMeBCCQy86oSqUDW2L ZuWjdrKMxpsh3Ki/2YKNfDfdxPIKe1+FpU2wgP+vm+9V/TdDKHZwZDm2cP/pvjCcbI17 YrsF2D/SlTz7xY0ju4ujeeqNy0u9bn1JyRX2rFrdFZUBWF3Jp/nND6KA4kPYchR6yV/6 RMYg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=n66R13E+hIuGDSe6qF1Y72bNp+wcRBPtFP4gfuZOL3c=; b=S80L8khknU4UDjlPAJwRqWvUX6ISCBu6cUToq03OZUjKITy/kzOMS/PQh3us0rAPQ7 EO5VJU16HXhg74cYT+1Iz64qAESmtfJJ4TttZ+o3Yy+JcOCIYBMzmn2R4/nakliItfKp WDG59Wl7O3XfotwcMhw0qCcl2lR1B6KazNi/G3eKXG+CZ8tC4m8B1Zk1UpAKdxYnshfB iSlNUcW9oSdnct3Zns55JaU9GkPGV64bc9OOpDu5DyiwKbVK9hcscGFPxh4G9RHRaAzT GLkopujx8RAhOVQJqWmdEKBwwBq995CreHoI3nuFG0PWJ553UaXreLS7Zhl6ANNp26dz znIA== X-Gm-Message-State: AA6/9Rk48ixfhht6PH6jjjZ7/0Y1xkgJo6iff5+8Q7/l1lpmNo88hpLBjmHoZJ7bp3Bc9iVA X-Received: by 10.194.124.168 with SMTP id mj8mr7796917wjb.50.1475066514802; Wed, 28 Sep 2016 05:41:54 -0700 (PDT) Received: from localhost.localdomain ([90.63.244.31]) by smtp.gmail.com with ESMTPSA id f15sm8655295wmf.8.2016.09.28.05.41.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 28 Sep 2016 05:41:54 -0700 (PDT) From: Bartosz Golaszewski To: Jyri Sarha , Tomi Valkeinen , David Airlie , Kevin Hilman , Michael Turquette , Sekhar Nori Subject: [PATCH v2] drm: tilcdc: add a workaround for failed clk_set_rate() Date: Wed, 28 Sep 2016 14:41:46 +0200 Message-Id: <1475066506-31750-1-git-send-email-bgolaszewski@baylibre.com> X-Mailer: git-send-email 2.1.4 Cc: Bartosz Golaszewski , LKML , linux-drm X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Some architectures don't use the common clock framework and don't implement all the clk interfaces for every clock. This is the case for da850-lcdk where clk_set_rate() only works for PLL0 and PLL1. Trying to set the clock rate for the LCDC clock results in -EINVAL being returned. As a workaround for that: if the call to clk_set_rate() fails, fall back to adjusting the clock divider instead. Proper divider value is calculated by dividing the current clock rate by the required pixel clock rate in HZ. This code is based on a hack initially developed internally for baylibre by Karl Beldan . Tested with a da850-lcdk with an LCD display connected over VGA. Signed-off-by: Bartosz Golaszewski --- v1 -> v2: - rebased on top of current drm-next - removed unnecessary error messages - removed an extra newline - added a warning if the effective pixel clock rate differs much from the requested rate Retested with modetest -M tilcdc -s 26:800x600@RG16 using some additional work-in-progress changes on top of this patch. drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 50 ++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 52ebe8f..7346f300b 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -320,23 +320,63 @@ static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc, return true; } +/* + * Calculate the percentage difference between the requested pixel clock rate + * and the effective rate resulting from calculating the clock divider value. + */ +static unsigned int tilcdc_pclk_diff(unsigned long rate, + unsigned long real_rate) +{ + int r = rate / 100, rr = real_rate / 100; + + return (unsigned int)(abs(((rr - r) * 100) / r)); +} + static void tilcdc_crtc_set_clk(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct tilcdc_drm_private *priv = dev->dev_private; struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); - const unsigned clkdiv = 2; /* using a fixed divider of 2 */ + unsigned long rate, real_rate; + unsigned int clkdiv; int ret; + clkdiv = 2; /* first try using a standard divider of 2 */ + /* mode.clock is in KHz, set_rate wants parameter in Hz */ ret = clk_set_rate(priv->clk, crtc->mode.clock * 1000 * clkdiv); + rate = clk_get_rate(priv->clk); if (ret < 0) { - dev_err(dev->dev, "failed to set display clock rate to: %d\n", - crtc->mode.clock); - return; + /* + * If we fail to set the clock rate (some architectures don't + * use the common clock framework yet and may not implement + * all the clk API calls for every clock), try the next best + * thing: adjusting the clock divider, unless clk_get_rate() + * failed as well. + */ + if (!rate) { + /* Nothing more we can do. Just bail out. */ + dev_err(dev->dev, + "failed to set the pixel clock - unable to read current lcdc clock rate\n"); + return; + } + + clkdiv = DIV_ROUND_CLOSEST(rate, (crtc->mode.clock * 1000)); + + /* + * Emit a warning if the real clock rate resulting from the + * calculated divider differs much from the requested rate. + * + * 5% is an arbitrary value - LCDs are usually quite tolerant + * about pixel clock rates. + */ + real_rate = clkdiv * crtc->mode.clock * 1000; + + WARN_ONCE(tilcdc_pclk_diff(rate, real_rate) > 5, + "real pixel clock rate diverged from the requested rate more than 5%%\n"); } - tilcdc_crtc->lcd_fck_rate = clk_get_rate(priv->clk); + tilcdc_crtc->lcd_fck_rate = rate; DBG("lcd_clk=%u, mode clock=%d, div=%u", tilcdc_crtc->lcd_fck_rate, crtc->mode.clock, clkdiv);