Received: by 10.223.176.5 with SMTP id f5csp786065wra; Fri, 2 Feb 2018 06:10:06 -0800 (PST) X-Google-Smtp-Source: AH8x224NEFlnnLl7p3wH4XWq4moFAkeadfqDbivIYnyTVlBQOq8teVcQ6iCrCc9YUWJs7/zQxUi7 X-Received: by 10.99.67.66 with SMTP id q63mr1999656pga.175.1517580605997; Fri, 02 Feb 2018 06:10:05 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1517580605; cv=none; d=google.com; s=arc-20160816; b=Yc4wyu5xQWkUUTvtxSsrupKhGNgZ/GhT9Ze1c2bXeu5KG6KI3MEFFhVHIRv+PTGJud a3wcj+FeMLKRYz9rWq6S/R5CQsaUVnzFDN5K/PtWt5ZrjNUCUQirtfE9t0sHP/C4jSct YrGBcaWq1qpfLozUdGRG2w7uI+MI57uJNKtng61YBVd+JoTzi1+Ohzb07NRmCPCz6j5R ytKYDvFojemSoEMput7lz68SjBCSB/BeN3Kbr1THz9N87rLO2CJm0B8BYtWb7zGK0WpP 7hjyAkVOKTp3FVkxUqng9sO6wjtDimkmJkXQQTShcjxZ7wYOsZSrSGa0ifICPaokGNB3 mjJA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=Rkdqyi+zWB+htX51etRAF3J+vT59w+yPXFMwwz8GXXE=; b=rBbVENk0YNzS66t1MBAkOyFUl2+ELPRLljFEykxHo5PLrtQq3BrACh/wMiKF40kBZh ZNQW2fw64Zflkz/omJ+q68Zv9uIJP19eqOs4DP6F+fyMtiaVuLp+kUQRnTUYQ9S7JgaQ 4SBKlwak5Y+4mp8zpZxik4wDupaFs8ZAAjwxIm5XCNLKtBkPsAjtDAqXscKb1hR0FPAN K9jRulOt4OGUnukPH/yerp7vX1hNIS0QgVntkrRxKVUTsGVei2z0lMlPZnpHnLnFY/Ou /HWmYy+JULY9cZcSh4OyT9vXetB6pVUbvLG5hIIQz/F7AdOZalExXbBul4QcPE1NwwC8 L5UQ== 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 n19-v6si1825185plp.808.2018.02.02.06.09.51; Fri, 02 Feb 2018 06:10:05 -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; 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 S1752336AbeBBOHh (ORCPT + 99 others); Fri, 2 Feb 2018 09:07:37 -0500 Received: from mx07-00178001.pphosted.com ([62.209.51.94]:43714 "EHLO mx07-00178001.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752150AbeBBOEm (ORCPT ); Fri, 2 Feb 2018 09:04:42 -0500 Received: from pps.filterd (m0046037.ppops.net [127.0.0.1]) by mx07-.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id w12E4Fas015246; Fri, 2 Feb 2018 15:04:15 +0100 Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com with ESMTP id 2fvb1x4r96-1 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT); Fri, 02 Feb 2018 15:04:15 +0100 Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 11C9E38; Fri, 2 Feb 2018 14:04:14 +0000 (GMT) Received: from Webmail-eu.st.com (sfhdag4node2.st.com [10.75.127.11]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id E07C15228; Fri, 2 Feb 2018 14:04:13 +0000 (GMT) Received: from localhost (10.75.127.51) by SFHDAG4NODE2.st.com (10.75.127.11) with Microsoft SMTP Server (TLS) id 15.0.1347.2; Fri, 2 Feb 2018 15:04:13 +0100 From: To: Rob Herring , Mark Rutland , Lee Jones , Maxime Coquelin , Alexandre Torgue , Michael Turquette , Stephen Boyd , Gabriel Fernandez CC: , , , , , Subject: [PATCH 06/14] clk: stm32mp1: add PLL clocks Date: Fri, 2 Feb 2018 15:03:34 +0100 Message-ID: <1517580222-23301-7-git-send-email-gabriel.fernandez@st.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1517580222-23301-1-git-send-email-gabriel.fernandez@st.com> References: <1517580222-23301-1-git-send-email-gabriel.fernandez@st.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.75.127.51] X-ClientProxiedBy: SFHDAG6NODE1.st.com (10.75.127.16) To SFHDAG4NODE2.st.com (10.75.127.11) X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2018-02-02_04:,, signatures=0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Gabriel Fernandez STMP32MP1 has 4 PLLs. PLL supports integer and fractional mode. Each PLL has 3 output dividers (p, q, r) Signed-off-by: Gabriel Fernandez --- drivers/clk/clk-stm32mp1.c | 209 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 1c9a84a..33f0d09 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -506,6 +507,181 @@ static struct clk_hw *clk_register_mp1_gate(struct device *dev, return hw; } +/* STM32 PLL */ + +struct stm32_pll_obj { + /* lock pll enable/disable registers */ + spinlock_t *lock; + void __iomem *reg; + struct clk_hw hw; +}; + +#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw) + +#define PLL_ON BIT(0) +#define PLL_RDY BIT(1) +#define DIVN_MASK 0x1FF +#define DIVM_MASK 0x3F +#define DIVM_SHIFT 16 +#define DIVN_SHIFT 0 +#define FRAC_OFFSET 0xC +#define FRAC_MASK 0x1FFF +#define FRAC_SHIFT 3 +#define FRACLE BIT(16) + +static int __pll_is_enabled(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + + return readl_relaxed(clk_elem->reg) & PLL_ON; +} + +#define TIMEOUT 5 + +static int pll_enable(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg; + unsigned long flags = 0; + unsigned int timeout = TIMEOUT; + int bit_status = 0; + + spin_lock_irqsave(clk_elem->lock, flags); + + if (__pll_is_enabled(hw)) + goto unlock; + + reg = readl_relaxed(clk_elem->reg); + reg |= PLL_ON; + writel_relaxed(reg, clk_elem->reg); + + /* We can't use readl_poll_timeout() because we can be blocked if + * someone enables this clock before clocksource changes. + * Only jiffies counter is available. Jiffies are incremented by + * interruptions and enable op does not allow to be interrupted. + */ + do { + bit_status = !(readl_relaxed(clk_elem->reg) & PLL_RDY); + + if (bit_status) + udelay(120); + + } while (bit_status && --timeout); + +unlock: + spin_unlock_irqrestore(clk_elem->lock, flags); + + return bit_status; +} + +static void pll_disable(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg; + unsigned long flags = 0; + + spin_lock_irqsave(clk_elem->lock, flags); + + reg = readl_relaxed(clk_elem->reg); + reg &= ~PLL_ON; + writel_relaxed(reg, clk_elem->reg); + + spin_unlock_irqrestore(clk_elem->lock, flags); +} + +static u32 pll_frac_val(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg, frac = 0; + + reg = readl_relaxed(clk_elem->reg + FRAC_OFFSET); + if (reg & FRACLE) + frac = (reg >> FRAC_SHIFT) & FRAC_MASK; + + return frac; +} + +static unsigned long pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg; + u32 frac, divm, divn; + u64 rate, rate_frac = 0; + + reg = readl_relaxed(clk_elem->reg + 4); + + divm = ((reg >> DIVM_SHIFT) & DIVM_MASK) + 1; + divn = ((reg >> DIVN_SHIFT) & DIVN_MASK) + 1; + rate = (u64)parent_rate * divn; + + do_div(rate, divm); + + frac = pll_frac_val(hw); + if (frac) { + rate_frac = (u64)parent_rate * (u64)frac; + do_div(rate_frac, (divm * 8192)); + } + + return rate + rate_frac; +} + +static int pll_is_enabled(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + unsigned long flags = 0; + int ret; + + spin_lock_irqsave(clk_elem->lock, flags); + ret = __pll_is_enabled(hw); + spin_unlock_irqrestore(clk_elem->lock, flags); + + return ret; +} + +static const struct clk_ops pll_ops = { + .enable = pll_enable, + .disable = pll_disable, + .recalc_rate = pll_recalc_rate, + .is_enabled = pll_is_enabled, +}; + +static struct clk_hw *clk_register_pll(struct device *dev, const char *name, + const char *parent_name, + void __iomem *reg, + unsigned long flags, + spinlock_t *lock) +{ + struct stm32_pll_obj *element; + struct clk_init_data init; + struct clk_hw *hw; + int err; + + element = kzalloc(sizeof(*element), GFP_KERNEL); + if (!element) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &pll_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + element->hw.init = &init; + element->reg = reg; + element->lock = lock; + + hw = &element->hw; + err = clk_hw_register(dev, hw); + + if (err) { + kfree(element); + return ERR_PTR(err); + } + + return hw; +} + static struct clk_hw * _clk_register_mp1_gate(struct device *dev, struct clk_hw_onecell_data *clk_data, @@ -524,6 +700,21 @@ static struct clk_hw *clk_register_mp1_gate(struct device *dev, lock); } +struct stm32_pll_cfg { + u32 offset; +}; + +struct clk_hw *_clk_register_pll(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg; + + return clk_register_pll(dev, cfg->name, cfg->parent_name, + base + stm_pll_cfg->offset, cfg->flags, lock); +} + #define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ {\ .id = _id,\ @@ -602,6 +793,18 @@ static struct clk_hw *clk_register_mp1_gate(struct device *dev, .func = _clk_register_mp1_gate,\ } +#define PLL(_id, _name, _parent, _flags, _offset)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = &(struct stm32_pll_cfg) {\ + .offset = _offset,\ + },\ + .func = _clk_register_pll,\ +} + static const struct clock_config stm32mp1_clock_cfg[] = { /* Oscillator divider */ DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2, @@ -625,6 +828,12 @@ static struct clk_hw *clk_register_mp1_gate(struct device *dev, MUX(NO_ID, "ref4", ref4_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK4SELR, 0, 2, CLK_MUX_READ_ONLY), + + /* PLLs */ + PLL(PLL1, "pll1", "ref1", CLK_IGNORE_UNUSED, RCC_PLL1CR), + PLL(PLL2, "pll2", "ref1", CLK_IGNORE_UNUSED, RCC_PLL2CR), + PLL(PLL3, "pll3", "ref3", CLK_IGNORE_UNUSED, RCC_PLL3CR), + PLL(PLL4, "pll4", "ref4", CLK_IGNORE_UNUSED, RCC_PLL4CR), }; struct stm32_clock_match_data { -- 1.9.1