Received: by 2002:ac0:a5a7:0:0:0:0:0 with SMTP id m36-v6csp4204013imm; Mon, 30 Jul 2018 10:21:36 -0700 (PDT) X-Google-Smtp-Source: AAOMgpd509TA9vifY2Lm4x3bfKG37Oqjd9Q2qRKEaem9Bf2wwEKIN/7M/J+591JADfX8ChObTv0h X-Received: by 2002:a62:b20c:: with SMTP id x12-v6mr19022298pfe.64.1532971296797; Mon, 30 Jul 2018 10:21:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1532971296; cv=none; d=google.com; s=arc-20160816; b=V8FjHNqchgt9dsLSf77nRF2ons5ltz/XYB4DyqJLGA19aoooLcTT1KXWYwtUpqV+AK 5cLtmOXzwxqfqMCeXu93QkYBMxLbS9Pt32Hrq9b6t8Aavb2yCuBYa1eeCVi1dGZ9tjmv w7sHlnTakhKmySH9O/z2gQ5SlKZFNdWsp9o/1b88UcHtElK2/ummtxIipdjsPIF4N49h 7ld/9E85KaxfykdJH6wVIp8Gz7GdFD44JZvf9p1Po5rhmW1bsqH3qUYW32ZYsh6swAIE Q7xUgLN8FAp/iCZJ+a/cjlictfn8XidKy83wLTGKoez+FBDdEg7Z727AYdqx1USWVWFx 9RuA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=tQCqayEMK41C4y3BmWz+jmmctohZs3nE0vsXro4g00o=; b=S3NgIhRmY/XPPGRra/Vjdbf0dedI8W/sd0KVm/xg8ejSHGlQ9I/Pxi/k4LVoDe/YjJ fskizr98IwPWGWPF2KdJ1Yz30slvfuDJBwRsDybuqC+F+U40bYseHa9Wa3v92VeI3kH/ 0TOlzZvBp3DQCrPzqUvQ6St4ryNpQ0BMblewHbd1DCS00GAQN30stUzMKHZMZXyUaSed aaAczhQfBj1tn2jZe/6z/4rX0D66dkmn1V/+Y+tVLq0GECX5Agirv/jGH2DmRcX9gc6f smCD3GcWSp134jZYbTKG/PJPSdjnvlywhT++OHXp1ulatT6rYnMt/PUteRTdluAxszos t0HA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v63-v6si10790251pgd.658.2018.07.30.10.21.22; Mon, 30 Jul 2018 10:21:36 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731355AbeG3S4d (ORCPT + 99 others); Mon, 30 Jul 2018 14:56:33 -0400 Received: from relay4-d.mail.gandi.net ([217.70.183.196]:42509 "EHLO relay4-d.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726752AbeG3S4c (ORCPT ); Mon, 30 Jul 2018 14:56:32 -0400 X-Originating-IP: 2.224.242.101 Received: from w540.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay4-d.mail.gandi.net (Postfix) with ESMTPSA id 0E285E0006; Mon, 30 Jul 2018 17:20:30 +0000 (UTC) From: Jacopo Mondi To: Laurent Pinchart , David Airlie Cc: Jacopo Mondi , dri-devel@lists.freedesktop.org (open list:DRM DRIVERS FOR RENESAS), linux-renesas-soc@vger.kernel.org (open list:DRM DRIVERS FOR RENESAS), linux-kernel@vger.kernel.org (open list) Subject: [PATCH 3/3] drm: rcar-du: Improve non-DPLL clock selection Date: Mon, 30 Jul 2018 19:20:14 +0200 Message-Id: <1532971214-17962-4-git-send-email-jacopo@jmondi.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1532971214-17962-1-git-send-email-jacopo@jmondi.org> References: <1532971214-17962-1-git-send-email-jacopo@jmondi.org> X-Spam-Level: Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org DU channels not equipped with a DPLL use an internal (aka SoC provided) or external clock source combined with an internal divider to generate the desired output dot clock frequency. The current clock selection procedure does not fully exploit the ability of external clock sources to generate the exact dot clock frequency by themselves, but relies instead on tuning the internal DU clock divider only, resulting in a less precise clock generation process. When possible, and desirable, ask the external clock source for the exact output dot clock frequency, and test all available clock sources (internally generated clock, externally generated clock rounded to the closest possible frequency, and not rounded externally generated clock) to better approximate the desired output dot clock. This patch specifically targets platforms (like Salvator-X[S] and ULCBs) where the DU's input dotclock.in is generated by the versaclock VC5 clock source, which is capable of generating the exact rate the DU needs as pixel clock output. This patch fixes higher resolution modes wich requires an high pixel clock output currently not working on non-HDMI DU channel (as VGA 1920x1080@60Hz). Fixes: 1b30dbde8 "drm: rcar-du: Add support for external pixel clock" Signed-off-by: Jacopo Mondi --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 96 ++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 4d7907c..0dfb28ff 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -207,12 +207,12 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) { const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode; struct rcar_du_device *rcdu = rcrtc->group->dev; - unsigned long mode_clock = mode->clock * 1000; + unsigned long mode_pixelclock = mode->clock * 1000; u32 dsmr; u32 escr; if (rcdu->info->dpll_ch & (1 << rcrtc->index)) { - unsigned long target = mode_clock; + unsigned long target = mode_pixelclock; struct dpll_info dpll = { 0 }; unsigned long extclk; u32 dpllcr; @@ -258,42 +258,92 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) escr = ESCR_DCLKSEL_DCLKIN | div; } else { - unsigned long clk; + struct du_clkin_desc { + unsigned long dist; + unsigned long rate; + struct clk *clk; + u32 escr; + } du_clkins[3]; + struct du_clkin_desc *du_clkin = du_clkins; + struct du_clkin_desc *clkin_best; + unsigned long best = -1UL; + unsigned long pixelclock; + unsigned long cpgrate; u32 div; /* * Compute the clock divisor and select the internal or external * dot clock based on the requested frequency. */ - clk = clk_get_rate(rcrtc->clock); - div = DIV_ROUND_CLOSEST(clk, mode_clock); - div = clamp(div, 1U, 64U) - 1; + cpgrate = clk_get_rate(rcrtc->clock); + div = clamp(DIV_ROUND_CLOSEST(cpgrate, mode_pixelclock), + 1UL, 64UL) - 1; + pixelclock = cpgrate / (div + 1); - escr = ESCR_DCLKSEL_CLKS | div; + du_clkin->dist = abs(pixelclock - mode_pixelclock); + du_clkin->escr = ESCR_DCLKSEL_CLKS | div; + du_clkin->clk = rcrtc->clock; + du_clkin->rate = cpgrate; + clkin_best = du_clkin; if (rcrtc->extclock) { - unsigned long extclk; + unsigned long roundrate; unsigned long extrate; - unsigned long rate; - u32 extdiv; - - extclk = clk_get_rate(rcrtc->extclock); - extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock); - extdiv = clamp(extdiv, 1U, 64U) - 1; - extrate = extclk / (extdiv + 1); - rate = clk / (div + 1); - - if (abs((long)extrate - (long)mode_clock) < - abs((long)rate - (long)mode_clock)) - escr = ESCR_DCLKSEL_DCLKIN | extdiv; + /* + * If an external clock source is present ask it + * for the exact dot clock rate, and test all possible + * combinations (internal, external rounded, external + * not rounded) to achieve the best possible clock + * accuracy. + */ + extrate = clk_get_rate(rcrtc->extclock); + roundrate = clk_round_rate(rcrtc->extclock, + mode_pixelclock); + + if (roundrate == mode_pixelclock) { + /* We can't do better than this... */ + clk_set_rate(rcrtc->extclock, roundrate); + escr = ESCR_DCLKSEL_DCLKIN; + goto set_escr; + } - dev_dbg(rcrtc->group->dev->dev, - "mode clock %lu extrate %lu rate %lu ESCR 0x%08x\n", - mode_clock, extrate, rate, escr); + /* Test the external clock 'plain' rate. */ + du_clkin++; + div = clamp(DIV_ROUND_CLOSEST(extrate, mode_pixelclock), + 1UL, 64UL) - 1; + pixelclock = extrate / (div + 1); + du_clkin->dist = abs(pixelclock - mode_pixelclock); + du_clkin->escr = ESCR_DCLKSEL_DCLKIN | div; + du_clkin->clk = rcrtc->extclock; + du_clkin->rate = extrate; + + /* Test the external clock 'rounded' rate. */ + du_clkin++; + div = clamp(DIV_ROUND_CLOSEST(roundrate, mode_pixelclock), + 1UL, 64UL) - 1; + pixelclock = roundrate / (div + 1); + du_clkin->dist = abs(pixelclock - mode_pixelclock); + du_clkin->escr = ESCR_DCLKSEL_DCLKIN | div; + du_clkin->clk = rcrtc->extclock; + du_clkin->rate = roundrate; + + /* Find out the best approximation we got. */ + for (; du_clkin >= du_clkins; --du_clkin) { + if (du_clkin->dist < best) { + best = du_clkin->dist; + clkin_best = du_clkin; + } + } + clk_set_rate(clkin_best->clk, clkin_best->rate); } + + escr = clkin_best->escr; } +set_escr: + dev_err(rcrtc->group->dev->dev, "%s: ESCR 0x%08x\n", __func__, escr); + rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR, escr); rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0); -- 2.7.4