From patchwork Mon May 30 14:32:35 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abhishek Sahu X-Patchwork-Id: 9141573 X-Patchwork-Delegate: sboyd@codeaurora.org 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 C617960777 for ; Mon, 30 May 2016 14:34:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B939128185 for ; Mon, 30 May 2016 14:34:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ADE6A2819E; Mon, 30 May 2016 14:34:41 +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.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI 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 4371528185 for ; Mon, 30 May 2016 14:34:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755059AbcE3Odb (ORCPT ); Mon, 30 May 2016 10:33:31 -0400 Received: from smtp.codeaurora.org ([198.145.29.96]:48577 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754905AbcE3Od2 (ORCPT ); Mon, 30 May 2016 10:33:28 -0400 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 1D5DB612CD; Mon, 30 May 2016 14:33:27 +0000 (UTC) Received: from chewinlnx07.qualcomm.com (unknown [202.46.23.62]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: absahu@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 6E4FE612E9; Mon, 30 May 2016 14:33:19 +0000 (UTC) From: Abhishek Sahu To: andy.gross@linaro.org, david.brown@linaro.org, sboyd@codeaurora.org, robh+dt@kernel.org, pawel.moll@arm.com, mark.rutland@arm.com, ijc+devicetree@hellion.org.uk Cc: mturquette@baylibre.com, galak@codeaurora.org, pradeepb@codeaurora.org, mmcclint@codeaurora.org, varada@codeaurora.org, sricharan@codeaurora.org, architt@codeaurora.org, ntelkar@codeaurora.org, linux-arm-msm@vger.kernel.org, linux-soc@vger.kernel.org, linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Abhishek Sahu Subject: [PATCH 2/5] clk: qcom: ipq4019: Added the apss cpu pll divider clock node Date: Mon, 30 May 2016 20:02:35 +0530 Message-Id: <1464618758-20965-3-git-send-email-absahu@codeaurora.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1464618758-20965-1-git-send-email-absahu@codeaurora.org> References: <1464618758-20965-1-git-send-email-absahu@codeaurora.org> 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 The existing code does not have support for all the frequency supported by APPS CPU. APPS CPU frequency is provided with APSS CPU PLL divider which divides down the VCO frequency. This divider is nonlinear and specific to IPQ4019 so the standard divider code cannot be used for this. This patch adds new node and its clock operations for APPS CPU clock divider. Since, this divider is nonlinear, so frequency table is also added for this, which contains the frequency and its corresponding hardware divider values. Signed-off-by: Abhishek Sahu --- drivers/clk/qcom/gcc-ipq4019.c | 140 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/drivers/clk/qcom/gcc-ipq4019.c b/drivers/clk/qcom/gcc-ipq4019.c index db24cb8..45f4749 100644 --- a/drivers/clk/qcom/gcc-ipq4019.c +++ b/drivers/clk/qcom/gcc-ipq4019.c @@ -20,6 +20,11 @@ #include #include #include +#include +#include +#include +#include +#include #include @@ -28,6 +33,7 @@ #include "clk-rcg.h" #include "clk-branch.h" #include "reset.h" +#include "clk-regmap-divider.h" enum { P_XO, @@ -40,6 +46,18 @@ enum { P_DDRPLLAPSS, }; +#define to_clk_regmap_div(_hw) container_of(to_clk_regmap(_hw),\ + struct clk_regmap_div, clkr) + +#define to_clk_cdiv_rcg(_hw) container_of((to_clk_regmap_div(_hw)),\ + struct clk_apps_cpu_div, cdiv) + +struct clk_apps_cpu_div { + struct clk_regmap_div cdiv; + const u8 *parent_map; + const struct freq_tbl *freq_tbl; +}; + static struct parent_map gcc_xo_200_500_map[] = { { P_XO, 0 }, { P_FEPLL200, 1 }, @@ -524,6 +542,128 @@ static struct clk_rcg2 sdcc1_apps_clk_src = { }, }; +/* +* Round rate function for APPS CPU PLL Clock divider. +* It Returns the input rate without changing it. The hardware supported rate +* will be calculated in set function by getting the same from frequency table. +*/ +static long clk_cpu_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *p_rate) +{ + return rate; +}; + +/* +* Clock set rate function for APPS CPU PLL Clock divider. +* It looks up the frequency table and updates the PLL divider to corresponding +* divider value. +*/ +static int clk_cpu_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_apps_cpu_div *rcg = to_clk_cdiv_rcg(hw); + const struct freq_tbl *f; + u32 mask; + int ret; + + f = qcom_find_freq(rcg->freq_tbl, rate); + if (!f) + return -EINVAL; + + mask = (BIT(rcg->cdiv.width) - 1) << rcg->cdiv.shift; + ret = regmap_update_bits(rcg->cdiv.clkr.regmap, + rcg->cdiv.reg, mask, + (f->pre_div << rcg->cdiv.shift) & mask); + udelay(1); + + return 0; +}; + +/* +* Clock frequency calculation function for APPS CPU PLL Clock divider. +* It first calculates the VCO frequency with the parent rate. This clock divider +* is nonlinear so this function calculates the actual divider and returns the +* output frequency by dividing VCO Frequency with this actual divider value. +*/ +static unsigned long clk_cpu_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_apps_cpu_div *rcg = to_clk_cdiv_rcg(hw); + u32 fdbkdiv, cdiv, rate, pre_div; + u32 fdbkdiv_shift = 16, fdbkdiv_mask = 0xff; + u64 vco; + + regmap_read(rcg->cdiv.clkr.regmap, rcg->cdiv.reg, &cdiv); + fdbkdiv = cdiv & (fdbkdiv_mask << fdbkdiv_shift); + fdbkdiv = fdbkdiv >> fdbkdiv_shift; + + cdiv &= (BIT(rcg->cdiv.width) - 1) << rcg->cdiv.shift; + cdiv = cdiv >> rcg->cdiv.shift; + + /* + * Some dividers have value in 0.5 fraction so multiply both VCO + * frequency and pre_div with 2 to make integer calculation. + */ + vco = parent_rate; + vco *= fdbkdiv; + vco *= 2; + + if (cdiv > 10) + pre_div = (cdiv + 1) * 2; + else + pre_div = cdiv + 12; + + do_div(vco, pre_div); + do_div(vco, 1000000); + rate = (u32)vco * 1000000; + + return rate; +}; + +const struct clk_ops clk_regmap_cpu_div_ops = { + .round_rate = clk_cpu_div_round_rate, + .set_rate = clk_cpu_div_set_rate, + .recalc_rate = clk_cpu_div_recalc_rate, +}; + +static const struct freq_tbl ftbl_apps_ddr_pll[] = { + {380000000, P_XO, 0xD, 0}, + {409000000, P_XO, 0xC, 0, 0}, + {444000000, P_XO, 0xB, 0, 0}, + {484000000, P_XO, 0xA, 0, 0}, + {507000000, P_XO, 0x9, 0, 0}, + {532000000, P_XO, 0x8, 0, 0}, + {560000000, P_XO, 0x7, 0, 0}, + {592000000, P_XO, 0x6, 0, 0}, + {626000000, P_XO, 0x5, 0, 0}, + {666000000, P_XO, 0x4, 0, 0}, + {710000000, P_XO, 0x3, 0, 0}, + {761000000, P_XO, 0x2, 0, 0}, + {819000000, P_XO, 0x1, 0, 0}, + {888000000, P_XO, 0x0, 0, 0}, + {} +}; + +static struct clk_apps_cpu_div gcc_apps_cpu_div_clk = { + .cdiv.reg = 0x2E020, + .cdiv.shift = 4, + .cdiv.width = 4, + .cdiv.clkr = { + .enable_reg = 0x2E000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_apps_cpu_div_clk", + .parent_names = (const char *[]){ + "xo", + }, + .num_parents = 1, + .ops = &clk_regmap_cpu_div_ops, + .flags = CLK_IGNORE_UNUSED, + }, + }, + .freq_tbl = ftbl_apps_ddr_pll, +}; + static const struct freq_tbl ftbl_gcc_apps_clk[] = { F(48000000, P_XO, 1, 0, 0), F(200000000, P_FEPLL200, 1, 0, 0),