From patchwork Tue Feb 28 13:29:58 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Brunet X-Patchwork-Id: 9595593 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id CADB9601D7 for ; Tue, 28 Feb 2017 13:31:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B84A828524 for ; Tue, 28 Feb 2017 13:31:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ACF2E28528; Tue, 28 Feb 2017 13:31:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.3 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1E44728526 for ; Tue, 28 Feb 2017 13:31:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752673AbdB1Nbh (ORCPT ); Tue, 28 Feb 2017 08:31:37 -0500 Received: from mail-wm0-f53.google.com ([74.125.82.53]:35520 "EHLO mail-wm0-f53.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752574AbdB1Na6 (ORCPT ); Tue, 28 Feb 2017 08:30:58 -0500 Received: by mail-wm0-f53.google.com with SMTP id v186so85503268wmd.0 for ; Tue, 28 Feb 2017 05:30:35 -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=qDsz9jwThzDetPi4Rs/UmVT7DI13lE3sZqIpvWGhGtQ=; b=tNIymn6FZbVCT8iykZ/doO4MgL5u3IG0vCj77s1bo9NmVKACrDANwXxPCkp3z2kYk/ Rx+1U40dISqBJT/Jgqr6F2S/outDFdSI8FfUKUds9HtSAhUawFk3+28VwRsARcOABle2 BzhQZro1J0sH1H7Ap1EzFj/fQjYErBzynGbTlOpRGGjPfVTNNuEoCCLd2DOU0GFuro7X qhCT4eo5vzZx6tjeb3b/waw7hHAvJgOKKbFuAZ7l1kTo/KqaNmzyUHmmBxzbfi0fIJw8 0atTZEsPBnpqizC7ZA5NdDuvS/UlxCTQXOCUnRCPlANWNpKodkSzEanp6eACL9yuFewE Jjtw== 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=qDsz9jwThzDetPi4Rs/UmVT7DI13lE3sZqIpvWGhGtQ=; b=p1sJrLN0aOMUWlrMLtab06mqdMFlSgdWcEqDr7QVTtyga/HUHoghLKCA/7yJdBgY0H WCitIYfENiMonfh9AmQbrYe5wBSHmbuuc8obMjZHiSOywtacvNCmmoBmVydpY/h+OaI7 QssNlbUsLi0I7Fz0It9KFfc3whSQpJIdgr7xT2jiiNZ9dFz7MVAEUzmmjPIDUeRB2hJw D7cvWDyulIN5ZDL3LnBNzPAHa+dTOjBzncPjXICHmweTMd1dH8s7GqXrP+B2t/gBgO4Z aak3M/3I93p/6O4RCkAECm01eLrfCPPN67nyKyjL1xQ80X8ADZXMUlRjvLQZQeapp9aR FYkg== X-Gm-Message-State: AMke39lZtZ+d9BU/FjmFy6n0DBaz5VeyNaah88OCuuR8nLWMV2cedKBuwRe5UWfT282GHNXL X-Received: by 10.28.140.135 with SMTP id o129mr2456031wmd.101.1488288619669; Tue, 28 Feb 2017 05:30:19 -0800 (PST) Received: from localhost.localdomain ([90.63.244.31]) by smtp.googlemail.com with ESMTPSA id k70sm18550982wmc.3.2017.02.28.05.30.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 28 Feb 2017 05:30:19 -0800 (PST) From: Jerome Brunet To: Michael Turquette , Stephen Boyd , Kevin Hilman , Carlo Caione Cc: Jerome Brunet , linux-clk@vger.kernel.org, linux-amlogic@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH 3/7] clk: meson: mpll: add rw operation Date: Tue, 28 Feb 2017 14:29:58 +0100 Message-Id: <20170228133002.17894-4-jbrunet@baylibre.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170228133002.17894-1-jbrunet@baylibre.com> References: <20170228133002.17894-1-jbrunet@baylibre.com> Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds new callbacks to the meson-mpll driver to control and set the pll rate. For this, we also need to add the enable bit and sdm enable bit. The corresponding parameters are added to mpll data structure. Signed-off-by: Jerome Brunet --- drivers/clk/meson/clk-mpll.c | 152 +++++++++++++++++++++++++++++++++++++++++-- drivers/clk/meson/clkc.h | 4 +- drivers/clk/meson/gxbb.c | 30 +++++++++ 3 files changed, 180 insertions(+), 6 deletions(-) diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c index 03af79005ddb..342b85d4e22a 100644 --- a/drivers/clk/meson/clk-mpll.c +++ b/drivers/clk/meson/clk-mpll.c @@ -64,16 +64,50 @@ #include #include "clkc.h" -#define SDM_MAX 16384 +#define SDM_DEN 16384 +#define SDM_MIN 1 +#define SDM_MAX 16383 +#define N2_MIN 4 +#define N2_MAX 127 #define to_meson_clk_mpll(_hw) container_of(_hw, struct meson_clk_mpll, hw) +static unsigned long rate_from_params(unsigned long parent_rate, + unsigned long sdm, + unsigned long n2) +{ + return (parent_rate * SDM_DEN) / ((SDM_DEN * n2) + sdm); +} + +static void params_from_rate(unsigned long requested_rate, + unsigned long parent_rate, + unsigned long *sdm, + unsigned long *n2) +{ + uint64_t div = parent_rate; + unsigned long rem = do_div(div, requested_rate); + + if (div < N2_MIN) { + *n2 = N2_MIN; + *sdm = SDM_MIN; + } else if (div > N2_MAX) { + *n2 = N2_MAX; + *sdm = SDM_MAX; + } else { + *n2 = div; + *sdm = DIV_ROUND_UP(rem * SDM_DEN, requested_rate); + if (*sdm < SDM_MIN) + *sdm = SDM_MIN; + else if (*sdm > SDM_MAX) + *sdm = SDM_MAX; + } +} + static unsigned long mpll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); struct parm *p; - unsigned long rate = 0; unsigned long reg, sdm, n2; p = &mpll->sdm; @@ -84,11 +118,119 @@ static unsigned long mpll_recalc_rate(struct clk_hw *hw, reg = readl(mpll->base + p->reg_off); n2 = PARM_GET(p->width, p->shift, reg); - rate = (parent_rate * SDM_MAX) / ((SDM_MAX * n2) + sdm); + return rate_from_params(parent_rate, sdm, n2); +} + +static long mpll_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long sdm, n2; + + params_from_rate(rate, *parent_rate, &sdm, &n2); + return rate_from_params(*parent_rate, sdm, n2); +} + +static int mpll_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); + struct parm *p; + unsigned long reg, sdm, n2; + unsigned long flags = 0; + + params_from_rate(rate, parent_rate, &sdm, &n2); + + if (mpll->lock) + spin_lock_irqsave(mpll->lock, flags); + else + __acquire(mpll->lock); + + p = &mpll->sdm; + reg = readl(mpll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, sdm); + writel(reg, mpll->base + p->reg_off); + + p = &mpll->sdm_en; + reg = readl(mpll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, 1); + writel(reg, mpll->base + p->reg_off); + + p = &mpll->n2; + reg = readl(mpll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, n2); + writel(reg, mpll->base + p->reg_off); + + if (mpll->lock) + spin_unlock_irqrestore(mpll->lock, flags); + else + __release(mpll->lock); - return rate; + return 0; +} + +static void mpll_enable_core(struct clk_hw *hw, int enable) +{ + struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); + struct parm *p; + unsigned long reg; + unsigned long flags = 0; + + if (mpll->lock) + spin_lock_irqsave(mpll->lock, flags); + else + __acquire(mpll->lock); + + p = &mpll->en; + reg = readl(mpll->base + p->reg_off); + reg = PARM_SET(p->width, p->shift, reg, enable ? 1 : 0); + writel(reg, mpll->base + p->reg_off); + + if (mpll->lock) + spin_unlock_irqrestore(mpll->lock, flags); + else + __release(mpll->lock); +} + + +static int mpll_enable(struct clk_hw *hw) +{ + mpll_enable_core(hw, 1); + + return 0; +} + +static void mpll_disable(struct clk_hw *hw) +{ + mpll_enable_core(hw, 0); +} + +static int mpll_is_enabled(struct clk_hw *hw) +{ + struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); + struct parm *p; + unsigned long reg; + int en; + + p = &mpll->en; + reg = readl(mpll->base + p->reg_off); + en = PARM_GET(p->width, p->shift, reg); + + return en; } const struct clk_ops meson_clk_mpll_ro_ops = { - .recalc_rate = mpll_recalc_rate, + .recalc_rate = mpll_recalc_rate, + .round_rate = mpll_round_rate, + .is_enabled = mpll_is_enabled, +}; + +const struct clk_ops meson_clk_mpll_ops = { + .recalc_rate = mpll_recalc_rate, + .round_rate = mpll_round_rate, + .set_rate = mpll_set_rate, + .enable = mpll_enable, + .disable = mpll_disable, + .is_enabled = mpll_is_enabled, }; diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 9bb70e7a7d6a..54d58a465039 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -92,8 +92,9 @@ struct meson_clk_mpll { struct clk_hw hw; void __iomem *base; struct parm sdm; + struct parm sdm_en; struct parm n2; - /* FIXME ssen gate control? */ + struct parm en; spinlock_t *lock; }; @@ -116,5 +117,6 @@ extern const struct clk_ops meson_clk_pll_ro_ops; extern const struct clk_ops meson_clk_pll_ops; extern const struct clk_ops meson_clk_cpu_ops; extern const struct clk_ops meson_clk_mpll_ro_ops; +extern const struct clk_ops meson_clk_mpll_ops; #endif /* __CLKC_H */ diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 388b0c8838af..6b97f4da1708 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -441,11 +441,21 @@ static struct meson_clk_mpll gxbb_mpll0 = { .shift = 0, .width = 14, }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 15, + .width = 1, + }, .n2 = { .reg_off = HHI_MPLL_CNTL7, .shift = 16, .width = 9, }, + .en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 14, + .width = 1, + }, .lock = &clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll0", @@ -461,11 +471,21 @@ static struct meson_clk_mpll gxbb_mpll1 = { .shift = 0, .width = 14, }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 15, + .width = 1, + }, .n2 = { .reg_off = HHI_MPLL_CNTL8, .shift = 16, .width = 9, }, + .en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 14, + .width = 1, + }, .lock = &clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll1", @@ -481,11 +501,21 @@ static struct meson_clk_mpll gxbb_mpll2 = { .shift = 0, .width = 14, }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 15, + .width = 1, + }, .n2 = { .reg_off = HHI_MPLL_CNTL9, .shift = 16, .width = 9, }, + .en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 14, + .width = 1, + }, .lock = &clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll2",