Received: by 2002:a05:6a10:af89:0:0:0:0 with SMTP id iu9csp1365610pxb; Fri, 21 Jan 2022 16:38:07 -0800 (PST) X-Google-Smtp-Source: ABdhPJymkQ8l8VhG7B7RQJfIewtK3HI0g4eXIbhqVWXuJLaLob4d1BfkDPsjFqCmRGdalI8NZaUe X-Received: by 2002:a17:90b:1c11:: with SMTP id oc17mr3104436pjb.128.1642811887399; Fri, 21 Jan 2022 16:38:07 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1642811887; cv=none; d=google.com; s=arc-20160816; b=H0Kr3MPlb6qXko/ip/l/YUiVsUSq+K9/CQIVLO/LQ5L436SK8KbLSI38M97AavGXdp zGIymYIxEcwk4GOGoDOpK/JcfW1wlw+qhZOdi5r8UdZDxyMmSKP1EXOjwsE75n3+GBEW GunQe7118tpiawHfWu6IXJGWgfmTkj4JUWOT+dV8x672NVrDwyc/5AiGkiGctnwiOx9w WNOfQQkQb5i+ww3VqfwzLAo/ls43GmDNa92SV3AM0PoZeb++ulOdnNTQh7y/ZrjL5Xke XjmPzTl7p0OJthsSTYJ2Ar8kE+qDq+dOX7NaVsRs+e44IF7El/vGt3OTtJLTmU5q04fl Jgxg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=5gjqbs3NwFyGs1S+vRKe8ZTXQAOBYNM6Y0KaK4Vr3Xo=; b=ezmQHWsoD6TgWxqtFEOpcY7UubcV0f1pRcWEN/dfEV4AGeO36CfqV/Tsnc4OnW5mdR 8ZdwiUzFEhYsIw6uYX61ZexDJCqvRUEAvg50Q93Ox8pubzeo1cg7c6wyQ7VoNMwARqmI YrwdGEnCZFrFvkWv+h3W60IODFHyemoYNSuPHV1jqZJvLY7noiAoN7cQWn6pIaPMrBjs 38lriu3RqYr2SMnQDIPmIKkS0R5T8QuGe/C6VK27T8oLheLOqCTt0ly9S4aCGRMtIHz6 Qvhc0agyAQlWtQ1fZgiNciUzNb9iwawGtsL4WEhccNvR9oU0tG4iDbz8wmlVWd/LBxdH zFwQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id bj12si7181885plb.182.2022.01.21.16.37.55; Fri, 21 Jan 2022 16:38:07 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1379120AbiAUHpV (ORCPT + 99 others); Fri, 21 Jan 2022 02:45:21 -0500 Received: from mail-sz.amlogic.com ([211.162.65.117]:14996 "EHLO mail-sz.amlogic.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348992AbiAUHpP (ORCPT ); Fri, 21 Jan 2022 02:45:15 -0500 Received: from droid11-sz.amlogic.com (10.28.8.21) by mail-sz.amlogic.com (10.28.11.5) with Microsoft SMTP Server id 15.1.2176.2; Fri, 21 Jan 2022 15:45:14 +0800 From: Liang Yang To: Neil Armstrong , Jerome Brunet , Kevin Hilman , Michael Turquette , Stephen Boyd , Rob Herring , CC: Liang Yang , Martin Blumenstingl , Jianxin Pan , Victor Wan , XianWei Zhao , Kelvin Zhang , BiChao Zheng , YongHui Yu , , , , Subject: [PATCH v10 1/4] clk: meson: add one based divider support for sclk Date: Fri, 21 Jan 2022 15:45:05 +0800 Message-ID: <20220121074508.42168-2-liang.yang@amlogic.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220121074508.42168-1-liang.yang@amlogic.com> References: <20220121074508.42168-1-liang.yang@amlogic.com> MIME-Version: 1.0 Content-Transfer-Encoding: 7BIT Content-Type: text/plain; charset=US-ASCII X-Originating-IP: [10.28.8.21] Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When MESON_SCLK_ONE_BASED flag is set, the sclk divider will be: one based divider (div = val), and zero value gates the clock Signed-off-by: Liang Yang --- drivers/clk/meson/sclk-div.c | 59 ++++++++++++++++++++++-------------- drivers/clk/meson/sclk-div.h | 3 ++ 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/drivers/clk/meson/sclk-div.c b/drivers/clk/meson/sclk-div.c index 76d31c0a3342..4ddc1763a12d 100644 --- a/drivers/clk/meson/sclk-div.c +++ b/drivers/clk/meson/sclk-div.c @@ -4,16 +4,17 @@ * Author: Jerome Brunet * * Sample clock generator divider: - * This HW divider gates with value 0 but is otherwise a zero based divider: + * This HW divider gates with value 0: * * val >= 1 - * divider = val + 1 + * divider = val + 1 if ONE_BASED is not set, otherwise divider = val. * * The duty cycle may also be set for the LR clock variant. The duty cycle * ratio is: * * hi = [0 - val] - * duty_cycle = (1 + hi) / (1 + val) + * duty_cycle = (1 + hi) / (1 + val) if ONE_BASED is not set, otherwise: + * duty_cycle = hi / (1 + val) */ #include @@ -28,22 +29,37 @@ meson_sclk_div_data(struct clk_regmap *clk) return (struct meson_sclk_div_data *)clk->data; } -static int sclk_div_maxval(struct meson_sclk_div_data *sclk) +static inline int sclk_get_reg(int val, unsigned char flag) { - return (1 << sclk->div.width) - 1; + if ((flag & MESON_SCLK_ONE_BASED) || !val) + return val; + return val - 1; +} + +static inline int sclk_get_divider(int reg, unsigned char flag) +{ + if (flag & MESON_SCLK_ONE_BASED) + return reg; + return reg + 1; } static int sclk_div_maxdiv(struct meson_sclk_div_data *sclk) { - return sclk_div_maxval(sclk) + 1; + unsigned int reg = (1 << sclk->div.width) - 1; + + return sclk_get_divider(reg, sclk->flags); } static int sclk_div_getdiv(struct clk_hw *hw, unsigned long rate, - unsigned long prate, int maxdiv) + unsigned long prate) { int div = DIV_ROUND_CLOSEST_ULL((u64)prate, rate); + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); + int mindiv = sclk_get_divider(1, sclk->flags); + int maxdiv = sclk_div_maxdiv(sclk); - return clamp(div, 2, maxdiv); + return clamp(div, mindiv, maxdiv); } static int sclk_div_bestdiv(struct clk_hw *hw, unsigned long rate, @@ -51,25 +67,25 @@ static int sclk_div_bestdiv(struct clk_hw *hw, unsigned long rate, struct meson_sclk_div_data *sclk) { struct clk_hw *parent = clk_hw_get_parent(hw); - int bestdiv = 0, i; + int bestdiv = 0, i, mindiv; unsigned long maxdiv, now, parent_now; unsigned long best = 0, best_parent = 0; if (!rate) rate = 1; - maxdiv = sclk_div_maxdiv(sclk); - if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) - return sclk_div_getdiv(hw, rate, *prate, maxdiv); + return sclk_div_getdiv(hw, rate, *prate); /* * The maximum divider we can use without overflowing * unsigned long in rate * i below */ + maxdiv = sclk_div_maxdiv(sclk); maxdiv = min(ULONG_MAX / rate, maxdiv); + mindiv = sclk_get_divider(1, sclk->flags); - for (i = 2; i <= maxdiv; i++) { + for (i = mindiv; i <= maxdiv; i++) { /* * It's the most ideal case if the requested rate can be * divided from parent clock without needing to change @@ -115,10 +131,7 @@ static void sclk_apply_ratio(struct clk_regmap *clk, sclk->cached_duty.num, sclk->cached_duty.den); - if (hi) - hi -= 1; - - meson_parm_write(clk->map, &sclk->hi, hi); + meson_parm_write(clk->map, &sclk->hi, sclk_get_reg(hi, sclk->flags)); } static int sclk_div_set_duty_cycle(struct clk_hw *hw, @@ -149,7 +162,7 @@ static int sclk_div_get_duty_cycle(struct clk_hw *hw, } hi = meson_parm_read(clk->map, &sclk->hi); - duty->num = hi + 1; + duty->num = sclk_get_divider(hi, sclk->flags); duty->den = sclk->cached_div; return 0; } @@ -157,10 +170,13 @@ static int sclk_div_get_duty_cycle(struct clk_hw *hw, static void sclk_apply_divider(struct clk_regmap *clk, struct meson_sclk_div_data *sclk) { + unsigned int div; + if (MESON_PARM_APPLICABLE(&sclk->hi)) sclk_apply_ratio(clk, sclk); - meson_parm_write(clk->map, &sclk->div, sclk->cached_div - 1); + div = sclk_get_reg(sclk->cached_div, sclk->flags); + meson_parm_write(clk->map, &sclk->div, div); } static int sclk_div_set_rate(struct clk_hw *hw, unsigned long rate, @@ -168,9 +184,8 @@ static int sclk_div_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); - unsigned long maxdiv = sclk_div_maxdiv(sclk); - sclk->cached_div = sclk_div_getdiv(hw, rate, prate, maxdiv); + sclk->cached_div = sclk_div_getdiv(hw, rate, prate); if (clk_hw_is_enabled(hw)) sclk_apply_divider(clk, sclk); @@ -228,7 +243,7 @@ static int sclk_div_init(struct clk_hw *hw) if (!val) sclk->cached_div = sclk_div_maxdiv(sclk); else - sclk->cached_div = val + 1; + sclk->cached_div = sclk_get_divider(val, sclk->flags); sclk_div_get_duty_cycle(hw, &sclk->cached_duty); diff --git a/drivers/clk/meson/sclk-div.h b/drivers/clk/meson/sclk-div.h index b64b2a32005f..944dab5ec0cf 100644 --- a/drivers/clk/meson/sclk-div.h +++ b/drivers/clk/meson/sclk-div.h @@ -10,11 +10,14 @@ #include #include "parm.h" +#define MESON_SCLK_ONE_BASED BIT(0) + struct meson_sclk_div_data { struct parm div; struct parm hi; unsigned int cached_div; struct clk_duty cached_duty; + u8 flags; }; extern const struct clk_ops meson_sclk_div_ops; -- 2.34.1