Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp2173832pxb; Mon, 22 Feb 2021 23:40:09 -0800 (PST) X-Google-Smtp-Source: ABdhPJy2fTbYFFR8BsFeq6lFpYS2erq+R0BuMOr+bBCCI/FEZDZ39IS4mvrCNyGVlKzPMaV7cjoQ X-Received: by 2002:aa7:da92:: with SMTP id q18mr15996137eds.1.1614066009614; Mon, 22 Feb 2021 23:40:09 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1614066009; cv=none; d=google.com; s=arc-20160816; b=1KjAdXGUF1ATYEYNjAa+m+UFa0YtY85222QCPKC8oxBmfnHlSyfmn30FnxbaL9XfI6 scPQZvuJugwWKjfb8Q47XLE1e9v8MgVFNN3jHRjzXtZG6wjHUQFnGxzD3hO4QLrOqqpy eCE6WDhiiJYm7bg+AOC50SDS4915B0v6MaA72BlZGnzg2tl3gnWYypQDQ+/w0/sOgl1W rIKXhtNj2SDcgXG39F2wikA+9dE5OH6D6qsrAsxXIy1Qllee+77FwjWyrFHQsJ4y0s/B dF0ohX475oVGNAW9R9CiKCcziFxQ5C16Q3Qw9PL3geuGmXUJUR4A2bFivlf+/ekXpV+3 9YPw== 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 :dkim-signature; bh=FiwkdxgUuiFEBGvozFkS9wYiAG4xc9dkgNE57ypiTFA=; b=xfWZKxKt0aTb+hVXXeO53q0tQpVvpgwDOLZMzmJ1QD0N0sygR5YxkxVg2jBSlzg16Y PmD8XNcFStpjgjqb5UKA6jeP0U+sDy5tSOMeAaNNvkfI/rITa9b33yLD/w+gnF1rcHuB g2yqpNenRGUpxuoFBKkwNSLjZ6+iwifKvaeEHrw1newOUjdXDHdG2C68yjIRUs0b6HH5 3In56VriUZV9cE9cKengXHbhBGmmLaWK8yVeudsgM5CJGZKaT41OAh8A10zCrpaDpHyf vQkbrDjAkhJDh2tj36ZOmIMD/P0Iq+mEBIiF/WBe/e0EazPpXETsAl9Ni3cRPLNTNbKC G95w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@0x0f.com header.s=google header.b=qHhlEJDo; 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 b8si12264053ejq.235.2021.02.22.23.39.44; Mon, 22 Feb 2021 23:40:09 -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; dkim=pass header.i=@0x0f.com header.s=google header.b=qHhlEJDo; 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 S231691AbhBWGVA (ORCPT + 99 others); Tue, 23 Feb 2021 01:21:00 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37254 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231594AbhBWGUf (ORCPT ); Tue, 23 Feb 2021 01:20:35 -0500 Received: from mail-pj1-x1029.google.com (mail-pj1-x1029.google.com [IPv6:2607:f8b0:4864:20::1029]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 88922C061793 for ; Mon, 22 Feb 2021 22:19:18 -0800 (PST) Received: by mail-pj1-x1029.google.com with SMTP id o6so1175971pjf.5 for ; Mon, 22 Feb 2021 22:19:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=0x0f.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=FiwkdxgUuiFEBGvozFkS9wYiAG4xc9dkgNE57ypiTFA=; b=qHhlEJDoKS0bGLBJkXQumxuZYQtt+LnK51fZrdtF5aYJAKDUqTG6QYliiMi4Uu+9n0 UStAJ3IqJKwIqp5DcsGCV2icmewN+B62eqx96tGE2DFE4T/t1aQqjPZCAUm377Q7TjHr 3bdVfJLCqfeBHOr6wwsmbzr3cEAwb66NJoWzM= 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:mime-version:content-transfer-encoding; bh=FiwkdxgUuiFEBGvozFkS9wYiAG4xc9dkgNE57ypiTFA=; b=ilIOOLdNwdg8mssfU0kcD5VmTfVvXBb2G8yzM6W436mbX3kZUxGHGUYNZ56Y44b7cz D2XKlbQKzOeDPurLYVlAs5PJV3iGV+mstkTqywgBEgN8YlTTRYXFDUBRKUxAIBjGE5CU trthSlTn0q+n5K7L0j1vNdjFX0H9rTF448JQW8E2wlYFT8egsZh/4jv3RNlfYamoo/1Z SWPrYl6fj6bJpXn1xz96j0T3KzblsHpJZbc3DtlWJJDf3f/pgYe9rXcsQ5MtiTb2lGdZ pRxA4goMes2I0T3e6MLxEC8/8Eyx5gVjZoIITVrK9KWWgSH32AYpigOWrDAZuq6qftTS cm0Q== X-Gm-Message-State: AOAM533321gjcIf+34R5pKgH3RzONrrBvH/70PiA2lTyLkGljG97pO9v cRdLGzzqJjwP6RmjtLQOehYJkQ== X-Received: by 2002:a17:90a:cf0e:: with SMTP id h14mr26388902pju.96.1614061158104; Mon, 22 Feb 2021 22:19:18 -0800 (PST) Received: from shiro.work (p345188-ipngn200408sizuokaden.shizuoka.ocn.ne.jp. [124.98.97.188]) by smtp.googlemail.com with ESMTPSA id n10sm20135169pgk.91.2021.02.22.22.19.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Feb 2021 22:19:17 -0800 (PST) From: Daniel Palmer To: devicetree@vger.kernel.org, linux-clk@vger.kernel.org, soc@kernel.org, sboyd@kernel.org Cc: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, w@1wt.eu, Daniel Palmer Subject: [PATCH 2/8] clk: mstar: msc313 cpupll clk driver Date: Tue, 23 Feb 2021 15:18:24 +0900 Message-Id: <20210223061830.1913700-3-daniel@0x0f.com> X-Mailer: git-send-email 2.30.0.rc2 In-Reply-To: <20210223061830.1913700-1-daniel@0x0f.com> References: <20210223061830.1913700-1-daniel@0x0f.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add a driver for the CPU pll/ARM pll/MIPS pll that is present in MStar SoCs. Currently there is no documentation for this block so it's possible this driver isn't entirely correct. Only tested on the version of this IP in the MStar/SigmaStar ARMv7 SoCs. Co-authored-by: Willy Tarreau Signed-off-by: Daniel Palmer --- drivers/clk/mstar/Kconfig | 7 + drivers/clk/mstar/Makefile | 1 + drivers/clk/mstar/clk-msc313-cpupll.c | 228 ++++++++++++++++++++++++++ 3 files changed, 236 insertions(+) create mode 100644 drivers/clk/mstar/clk-msc313-cpupll.c diff --git a/drivers/clk/mstar/Kconfig b/drivers/clk/mstar/Kconfig index de37e1bce2d2..a44ca2b180ff 100644 --- a/drivers/clk/mstar/Kconfig +++ b/drivers/clk/mstar/Kconfig @@ -7,3 +7,10 @@ config MSTAR_MSC313_MPLL help Support for the MPLL PLL and dividers block present on MStar/Sigmastar SoCs. + +config MSTAR_MSC313_CPUPLL + bool "MStar CPUPLL driver" + depends on ARCH_MSTARV7 || COMPILE_TEST + default ARCH_MSTARV7 + help + Support for the CPU PLL present on MStar/Sigmastar SoCs. diff --git a/drivers/clk/mstar/Makefile b/drivers/clk/mstar/Makefile index f8dcd25ede1d..9f05b73a0619 100644 --- a/drivers/clk/mstar/Makefile +++ b/drivers/clk/mstar/Makefile @@ -4,3 +4,4 @@ # obj-$(CONFIG_MSTAR_MSC313_MPLL) += clk-msc313-mpll.o +obj-$(CONFIG_MSTAR_MSC313_CPUPLL) += clk-msc313-cpupll.o diff --git a/drivers/clk/mstar/clk-msc313-cpupll.c b/drivers/clk/mstar/clk-msc313-cpupll.c new file mode 100644 index 000000000000..3f250404ecda --- /dev/null +++ b/drivers/clk/mstar/clk-msc313-cpupll.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Daniel Palmer + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * This IP is not documented outside of the messy vendor driver. + * Below is what we think the registers look like based on looking at + * the vendor code and poking at the hardware: + * + * 0x140 -- LPF low. Seems to store one half of the clock transition + * 0x144 / + * 0x148 -- LPF high. Seems to store one half of the clock transition + * 0x14c / + * 0x150 -- vendor code says "toggle lpf enable" + * 0x154 -- mu? + * 0x15c -- lpf_update_count? + * 0x160 -- vendor code says "switch to LPF". Clock source config? Register bank? + * 0x164 -- vendor code says "from low to high" which seems to mean transition from LPF low to LPF high. + * 0x174 -- Seems to be the PLL lock status bit + * 0x180 -- Seems to be the current frequency, this might need to be populated by software? + * 0x184 / The vendor driver uses these to set the initial value of LPF low + * + * Frequency seems to be calculated like this: + * (parent clock (432mhz) / register_magic_value) * 16 * 524288 + * Only the lower 24 bits of the resulting value will be used. In addition, the + * PLL doesn't seem to be able to lock on frequencies lower than 220 MHz, as + * divisor 0xfb586f (220 MHz) works but 0xfb7fff locks up. + * + * Vendor values: + * frequency - register value + * + * 400000000 - 0x0067AE14 + * 600000000 - 0x00451EB8, + * 800000000 - 0x0033D70A, + * 1000000000 - 0x002978d4, + */ + +#define REG_LPF_LOW_L 0x140 +#define REG_LPF_LOW_H 0x144 +#define REG_LPF_HIGH_BOTTOM 0x148 +#define REG_LPF_HIGH_TOP 0x14c +#define REG_LPF_TOGGLE 0x150 +#define REG_LPF_MYSTERYTWO 0x154 +#define REG_LPF_UPDATE_COUNT 0x15c +#define REG_LPF_MYSTERYONE 0x160 +#define REG_LPF_TRANSITIONCTRL 0x164 +#define REG_LPF_LOCK 0x174 +#define REG_CURRENT 0x180 + +#define MULTIPLIER_1 16 +#define MULTIPLIER_2 524288 +#define MULTIPLIER (MULTIPLIER_1 * MULTIPLIER_2) + +struct msc313_cpupll { + void __iomem *base; + struct clk_hw clk_hw; +}; + +#define to_cpupll(_hw) container_of(_hw, struct msc313_cpupll, clk_hw) + +static u32 msc313_cpupll_reg_read32(struct msc313_cpupll *cpupll, unsigned int reg) +{ + u32 value; + + value = ioread16(cpupll->base + reg + 4) << 16; + value |= ioread16(cpupll->base + reg); + + return value; +} + +static void msc313_cpupll_reg_write32(struct msc313_cpupll *cpupll, unsigned int reg, u32 value) +{ + u16 l = value & 0xffff, h = (value >> 16) & 0xffff; + + iowrite16(l, cpupll->base + reg); + iowrite16(h, cpupll->base + reg + 4); +} + +static void msc313_cpupll_setfreq(struct msc313_cpupll *cpupll, u32 regvalue) +{ + msc313_cpupll_reg_write32(cpupll, REG_LPF_HIGH_BOTTOM, regvalue); + + iowrite16(0x1, cpupll->base + REG_LPF_MYSTERYONE); + iowrite16(0x6, cpupll->base + REG_LPF_MYSTERYTWO); + iowrite16(0x8, cpupll->base + REG_LPF_UPDATE_COUNT); + iowrite16(BIT(12), cpupll->base + REG_LPF_TRANSITIONCTRL); + + iowrite16(0, cpupll->base + REG_LPF_TOGGLE); + iowrite16(1, cpupll->base + REG_LPF_TOGGLE); + + while (!(ioread16(cpupll->base + REG_LPF_LOCK))) + cpu_relax(); + + iowrite16(0, cpupll->base + REG_LPF_TOGGLE); + + msc313_cpupll_reg_write32(cpupll, REG_LPF_LOW_L, regvalue); +} + +static unsigned long msc313_cpupll_frequencyforreg(u32 reg, unsigned long parent_rate) +{ + unsigned long long prescaled = ((unsigned long long)parent_rate) * MULTIPLIER; + unsigned long long scaled; + + if (prescaled == 0 || reg == 0) + return 0; + scaled = DIV_ROUND_DOWN_ULL(prescaled, reg); + + return scaled; +} + +static u32 msc313_cpupll_regforfrequecy(unsigned long rate, unsigned long parent_rate) +{ + unsigned long long prescaled = ((unsigned long long)parent_rate) * MULTIPLIER; + unsigned long long scaled; + u32 reg; + + if (prescaled == 0 || rate == 0) + return 0; + + scaled = DIV_ROUND_UP_ULL(prescaled, rate); + reg = scaled; + + return reg; +} + +static unsigned long msc313_cpupll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct msc313_cpupll *cpupll = to_cpupll(hw); + + return msc313_cpupll_frequencyforreg(msc313_cpupll_reg_read32(cpupll, REG_LPF_LOW_L), parent_rate); +} + +static long msc313_cpupll_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *parent_rate) +{ + u32 reg = msc313_cpupll_regforfrequecy(rate, *parent_rate); + long rounded = msc313_cpupll_frequencyforreg(reg, *parent_rate); + + /* + * This is my poor attempt at making sure the resulting + * rate doesn't overshoot the requested rate. + */ + for (; rounded >= rate && reg > 0; reg--) + rounded = msc313_cpupll_frequencyforreg(reg, *parent_rate); + + return rounded; +} + +static int msc313_cpupll_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct msc313_cpupll *cpupll = to_cpupll(hw); + u32 reg = msc313_cpupll_regforfrequecy(rate, parent_rate); + + msc313_cpupll_setfreq(cpupll, reg); + + return 0; +} + +static const struct clk_ops msc313_cpupll_ops = { + .recalc_rate = msc313_cpupll_recalc_rate, + .round_rate = msc313_cpupll_round_rate, + .set_rate = msc313_cpupll_set_rate, +}; + +static const struct of_device_id msc313_cpupll_of_match[] = { + { + .compatible = "mstar,msc313-cpupll", + }, + {} +}; + +static const struct clk_parent_data cpupll_parent = { + .index = 0, +}; + +static int msc313_cpupll_probe(struct platform_device *pdev) +{ + struct clk_init_data clk_init = {}; + struct device *dev = &pdev->dev; + struct msc313_cpupll *cpupll; + int ret; + + cpupll = devm_kzalloc(&pdev->dev, sizeof(*cpupll), GFP_KERNEL); + if (!cpupll) + return -ENOMEM; + + cpupll->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(cpupll->base)) + return PTR_ERR(cpupll->base); + + /* LPF might not contain the current frequency so fix that up */ + msc313_cpupll_reg_write32(cpupll, REG_LPF_LOW_L, + msc313_cpupll_reg_read32(cpupll, REG_CURRENT)); + + clk_init.name = dev_name(dev); + clk_init.ops = &msc313_cpupll_ops; + clk_init.flags = CLK_IS_CRITICAL; + clk_init.parent_data = &cpupll_parent; + clk_init.num_parents = 1; + cpupll->clk_hw.init = &clk_init; + + ret = devm_clk_hw_register(dev, &cpupll->clk_hw); + if (ret) + return ret; + + return of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_simple_get, &cpupll->clk_hw); +} + +static struct platform_driver msc313_cpupll_driver = { + .driver = { + .name = "mstar-msc313-cpupll", + .of_match_table = msc313_cpupll_of_match, + }, + .probe = msc313_cpupll_probe, +}; +builtin_platform_driver(msc313_cpupll_driver); -- 2.30.0.rc2