From patchwork Mon Feb 19 11:21:39 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Brunet X-Patchwork-Id: 128803 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp3387751ljc; Mon, 19 Feb 2018 03:23:50 -0800 (PST) X-Google-Smtp-Source: AH8x226fM8LONuhTz9z1XxMdelxAP3QPCjLvYbLjubD4ZaV5YffZ9J6ORl/SMJQ0DU8yVzkYaqjo X-Received: by 10.99.54.196 with SMTP id d187mr10077146pga.154.1519039430759; Mon, 19 Feb 2018 03:23:50 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519039430; cv=none; d=google.com; s=arc-20160816; b=jHz6dWNNjofYp8HeOGqtAuyulI9Ev4ELfKKZ5cwiSaxUf8BCXlF8K9RCGNP9y3B2fq 4qiaPAbrTuNmV3s7jkkU9FtK0tbFZ4VyKP/WQeMaWtc4uEJeJmyp5g3obgIgHMAaktzj vNZDjldj7JHuq0o0tqzWTD8nyflYRyMadTX4GsBKvtytwWqEw/Wu7iZmQJUZWtlSDUqu rcT6vC4+XEQe44Y+a84IIYQNQ0PhiLgdwhExwTYmI4SQPkp9lffHypM4O1/+sQtcDTXo K7ZdKQ5if4ONM7W78WpGT5Dc8GEafGJZxT+5MH4+RtJh0LPCRPw7GY3Lbw+YKi0KY4x1 Zs3g== 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:dkim-signature:arc-authentication-results; bh=XcpwNWqP+bXpPxwXabyWP03yFleGPXzTTFfplqJPL+I=; b=Cz2tGAFudq66s/EOi6qLHGkXII8e45fQ4wybLb6eLFZyZLTfbrA7vq7dMn5LoViW1A R1J5YszNV3FSyfurIdIspGXR7kERctIVF3Vk0oybolAAk64rbWAy3kjM9AaUvZpncRz+ TJikxC0Hjsp2kh2ABHIQcpjLcBZhG8J3kU7hh2I5T2sf6JXF1NSG0N+Enka8rCg6lHLU +dikvRyZUXNEXYQxvoLzIFCcBU56zJRRORlHfbXo5JRj7T67N5mhoUZlZqzgluJ+qa22 S3EFmTIyC7cJIoZ0AVEN4hk6nXGIoju/SUFxDYVU3z4pA3hCf2b366/E2PlMMj5v/i7o wzmA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@baylibre-com.20150623.gappssmtp.com header.s=20150623 header.b=EiCDKbwz; 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 a12-v6si985541pln.421.2018.02.19.03.23.50; Mon, 19 Feb 2018 03:23:50 -0800 (PST) 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; dkim=pass header.i=@baylibre-com.20150623.gappssmtp.com header.s=20150623 header.b=EiCDKbwz; 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 S1752536AbeBSLXr (ORCPT + 28 others); Mon, 19 Feb 2018 06:23:47 -0500 Received: from mail-wm0-f67.google.com ([74.125.82.67]:33738 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752606AbeBSLV4 (ORCPT ); Mon, 19 Feb 2018 06:21:56 -0500 Received: by mail-wm0-f67.google.com with SMTP id x4so14835977wmc.0 for ; Mon, 19 Feb 2018 03:21:56 -0800 (PST) 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:in-reply-to:references; bh=XcpwNWqP+bXpPxwXabyWP03yFleGPXzTTFfplqJPL+I=; b=EiCDKbwz5qbwJ5YZAENdLIlaCNuvDOEL82/30QNue5sfMkFVTN0gY8L10iqJFxHpRH 9esJzMQJdaxsj/um77YgwjhkoSb3VtcyY8GBQHzmTdnZnBfpXlXmHz46IgsvVJTifAS5 zG3E73+CfjlWo+eyPz44ZEj/A+xP0ae+mtgFBKpWIxYjjrLXf0hi6FkWyNW9pIcQVfLU Mnfdx45XUrwv3A/rX4KRRWDDcxVpsXlQnN2lYG1L48BDRy30vqxRkHkR5UfZsSMW0amB 3mpT0wbWYRk9YDsgH1LCB0QdBUcjTygY94Ns8bTAnxwzHbk3/gYgbwT5BC+nnVWa1k2c pNlg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=XcpwNWqP+bXpPxwXabyWP03yFleGPXzTTFfplqJPL+I=; b=Jvzy36d+94lnDp48Mg+9ARHzFTA+AoWLa1mwiwNbqJuzRpNP6CBXEg6BvHYCOW2iYv 0jekdceJj03Ltyh4sOH+K+8cgXR7Odj2UeRzxn3OvIYFlmR/fsTm3CXW6+fBGSeMJa21 XLQ4Lo7IMnpw3cALewGBrEhxmjwL3V0D2W9FgXZ4mmmGuhqR8JK1QBt7p4C5wZYFccoU jGeO99y8hE7GyuN6U644Sqy+LOXTRluNkJ6WOpvHTGIqT+lC/jNf2Jp0c1uJ3YEQ+xPn pl9RSQe7s6/MOmtpJh76hQPhaGjWf2zcE2WQEbfcDf9ol+ldjLRDYE3ZcJ/onkY4UVXe ym6g== X-Gm-Message-State: APf1xPAsc1hhDFxDhQzx4BjITlRgWAQC1U4HJxEKUAep6p9RQ2YH8aij xp1neCo/Xw4W14ibcVYHuTGHKQ== X-Received: by 10.28.216.149 with SMTP id p143mr10766777wmg.80.1519039315287; Mon, 19 Feb 2018 03:21:55 -0800 (PST) Received: from boomer.baylibre.local ([90.63.244.31]) by smtp.googlemail.com with ESMTPSA id n20sm8933978wrg.84.2018.02.19.03.21.54 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 19 Feb 2018 03:21:54 -0800 (PST) From: Jerome Brunet To: Neil Armstrong , Kevin Hilman Cc: Jerome Brunet , Stephen Boyd , Michael Turquette , Carlo Caione , linux-amlogic@lists.infradead.org, linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 04/11] clk: meson: improve pll driver results with frac Date: Mon, 19 Feb 2018 12:21:39 +0100 Message-Id: <20180219112146.21746-5-jbrunet@baylibre.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180219112146.21746-1-jbrunet@baylibre.com> References: <20180219112146.21746-1-jbrunet@baylibre.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Finding the appropriate settings of meson plls is too tricky to be done entirely at runtime, using calculation only. Many combination of m, n and od won't lock which is why we are using a table for this. However, for plls having a fractional parameters, it is possible to improve on the result provided by the table by calculating the frac parameter. This change adds the calculation of frac when the parameter is available and the rate provided by the table is not an exact match for the requested rate. Signed-off-by: Jerome Brunet --- drivers/clk/meson/clk-pll.c | 137 +++++++++++++++++++++++++++++--------------- drivers/clk/meson/clkc.h | 13 +---- 2 files changed, 91 insertions(+), 59 deletions(-) -- 2.14.3 diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 0b9b4422c968..d58961f35b71 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -2,6 +2,9 @@ * Copyright (c) 2015 Endless Mobile, Inc. * Author: Carlo Caione * + * Copyright (c) 2018 Baylibre, SAS. + * Author: Jerome Brunet + * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. @@ -27,7 +30,7 @@ * | | * FREF VCO * - * out = (in * M / N) >> OD + * out = in * (m + frac / frac_max) / (n << sum(ods)) */ #include @@ -48,73 +51,110 @@ meson_clk_pll_data(struct clk_regmap *clk) return (struct meson_clk_pll_data *)clk->data; } +static unsigned long __pll_params_to_rate(unsigned long parent_rate, + const struct pll_rate_table *pllt, + u16 frac, + struct meson_clk_pll_data *pll) +{ + u64 rate = (u64)parent_rate * pllt->m; + unsigned int od = pllt->od + pllt->od2 + pllt->od3; + + if (frac && MESON_PARM_APPLICABLE(&pll->frac)) { + u64 frac_rate = (u64)parent_rate * frac; + + rate += DIV_ROUND_UP_ULL(frac_rate, + (1 << pll->frac.width)); + } + + return DIV_ROUND_UP_ULL(rate, pllt->n << od); +} + static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - u64 rate; - u16 n, m, frac = 0, od, od2 = 0, od3 = 0; - - n = meson_parm_read(clk->map, &pll->n); - m = meson_parm_read(clk->map, &pll->m); - od = meson_parm_read(clk->map, &pll->od); - - if (MESON_PARM_APPLICABLE(&pll->od2)) - od2 = meson_parm_read(clk->map, &pll->od2); + struct pll_rate_table pllt; + u16 frac; - if (MESON_PARM_APPLICABLE(&pll->od3)) - od3 = meson_parm_read(clk->map, &pll->od3); + pllt.n = meson_parm_read(clk->map, &pll->n); + pllt.m = meson_parm_read(clk->map, &pll->m); + pllt.od = meson_parm_read(clk->map, &pll->od); - rate = (u64)m * parent_rate; + pllt.od2 = MESON_PARM_APPLICABLE(&pll->od2) ? + meson_parm_read(clk->map, &pll->od2) : + 0; - if (MESON_PARM_APPLICABLE(&pll->frac)) { - frac = meson_parm_read(clk->map, &pll->frac); + pllt.od3 = MESON_PARM_APPLICABLE(&pll->od3) ? + meson_parm_read(clk->map, &pll->od3) : + 0; - rate += mul_u64_u32_shr(parent_rate, frac, pll->frac.width); - } + frac = MESON_PARM_APPLICABLE(&pll->frac) ? + meson_parm_read(clk->map, &pll->frac) : + 0; - return div_u64(rate, n) >> od >> od2 >> od3; + return __pll_params_to_rate(parent_rate, &pllt, frac, pll); } -static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static u16 __pll_params_with_frac(unsigned long rate, + unsigned long parent_rate, + const struct pll_rate_table *pllt, + struct meson_clk_pll_data *pll) { - struct clk_regmap *clk = to_clk_regmap(hw); - struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - const struct pll_rate_table *pllt; - - /* - * if the table is missing, just return the current rate - * since we don't have the other available frequencies - */ - if (!pll->table) - return meson_clk_pll_recalc_rate(hw, *parent_rate); + u16 frac_max = (1 << pll->frac.width); + u64 val = (u64)rate * pllt->n; - for (pllt = pll->table; pllt->rate; pllt++) { - if (rate <= pllt->rate) - return pllt->rate; - } + val <<= pllt->od + pllt->od2 + pllt->od3; + val = div_u64(val * frac_max, parent_rate); + val -= pllt->m * frac_max; - /* else return the smallest value */ - return pll->table[0].rate; + return min((u16)val, (u16)(frac_max - 1)); } static const struct pll_rate_table * -meson_clk_get_pll_settings(const struct pll_rate_table *table, - unsigned long rate) +meson_clk_get_pll_settings(unsigned long rate, + struct meson_clk_pll_data *pll) { - const struct pll_rate_table *pllt; + const struct pll_rate_table *table = pll->table; + unsigned int i = 0; if (!table) return NULL; - for (pllt = table; pllt->rate; pllt++) { - if (rate == pllt->rate) - return pllt; - } + /* Find the first table element exceeding rate */ + while (table[i].rate && table[i].rate <= rate) + i++; + + /* Select the setting of the rounded down rate */ + if (i != 0) + i--; + + return (struct pll_rate_table *)&table[i]; +} + +static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + const struct pll_rate_table *pllt = + meson_clk_get_pll_settings(rate, pll); + u16 frac; + + if (!pllt) + return meson_clk_pll_recalc_rate(hw, *parent_rate); + + if (!MESON_PARM_APPLICABLE(&pll->frac) + || rate == pllt->rate) + return pllt->rate; - return NULL; + /* + * The rate provided by the setting is not an exact match, let's + * try to improve the result using the fractional parameter + */ + frac = __pll_params_with_frac(rate, *parent_rate, pllt, pll); + + return __pll_params_to_rate(*parent_rate, pllt, frac, pll); } static int meson_clk_pll_wait_lock(struct clk_hw *hw) @@ -154,13 +194,14 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); const struct pll_rate_table *pllt; unsigned long old_rate; + u16 frac = 0; if (parent_rate == 0 || rate == 0) return -EINVAL; old_rate = rate; - pllt = meson_clk_get_pll_settings(pll->table, rate); + pllt = meson_clk_get_pll_settings(rate, pll); if (!pllt) return -EINVAL; @@ -177,8 +218,10 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, if (MESON_PARM_APPLICABLE(&pll->od3)) meson_parm_write(clk->map, &pll->od3, pllt->od3); - if (MESON_PARM_APPLICABLE(&pll->frac)) - meson_parm_write(clk->map, &pll->frac, pllt->frac); + if (MESON_PARM_APPLICABLE(&pll->frac)) { + frac = __pll_params_with_frac(rate, parent_rate, pllt, pll); + meson_parm_write(clk->map, &pll->frac, frac); + } /* make sure the reset is cleared at this point */ meson_parm_write(clk->map, &pll->rst, 0); diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index ebd88afe1eb5..9cdcd9b6c16c 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -61,7 +61,6 @@ struct pll_rate_table { u16 od; u16 od2; u16 od3; - u16 frac; }; #define PLL_RATE(_r, _m, _n, _od) \ @@ -70,17 +69,7 @@ struct pll_rate_table { .m = (_m), \ .n = (_n), \ .od = (_od), \ - } \ - -#define PLL_FRAC_RATE(_r, _m, _n, _od, _od2, _frac) \ - { \ - .rate = (_r), \ - .m = (_m), \ - .n = (_n), \ - .od = (_od), \ - .od2 = (_od2), \ - .frac = (_frac), \ - } \ + } struct meson_clk_pll_data { struct parm m;