From patchwork Mon Oct 11 16:57:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hector Martin X-Patchwork-Id: 12550623 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E2FF1C433EF for ; Mon, 11 Oct 2021 17:01:23 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id AFEBD60F3A for ; Mon, 11 Oct 2021 17:01:23 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org AFEBD60F3A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=marcan.st Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=p5Y9BbILK5IcHt71H8EotSClLaV1uyULmNb9ccSnj0w=; b=OomrgFoYoFh88E mTDFVnWNr/IT+RCmxKd21VwWr60qlaChcJGbzxhLbmEPc1iljqHkImoxjq0r9hOWHFFDpA7vxCCwy tC9HfQFgPLDflgnZigO4IpjFV7IWo+vOY6W+bPtqboJRebVg0RcZRRuE9E0m05eM/BgSN6gkc0Hr3 Q/NgUmUTXkZrl5hhpHXrqT/rpK4C/OQcKHj/paNgzTIJPcpi6jXX3u6x1YdR/g2B/BiDDJw2mOgOn cX8raNVaZ98ahKGvcmngl53XnsoUz15gv+zwbPuyqdkRiMIXA1i9/ypHx7SWm84Cl2Jhr9wTsXKOY A/OVXruKbb8PEM9rh+yg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mZydr-00A8oN-MJ; Mon, 11 Oct 2021 16:59:11 +0000 Received: from marcansoft.com ([2a01:298:fe:f::2] helo=mail.marcansoft.com) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mZycs-00A8NE-EZ for linux-arm-kernel@lists.infradead.org; Mon, 11 Oct 2021 16:58:12 +0000 Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: hector@marcansoft.com) by mail.marcansoft.com (Postfix) with ESMTPSA id AD71E425BD; Mon, 11 Oct 2021 16:58:03 +0000 (UTC) From: Hector Martin To: linux-arm-kernel@lists.infradead.org Cc: Hector Martin , Alyssa Rosenzweig , Sven Peter , Marc Zyngier , Mark Kettenis , Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Viresh Kumar , Nishanth Menon , Catalin Marinas , "Rafael J. Wysocki" , Kevin Hilman , Ulf Hansson , linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH 7/9] clk: apple: Add clk-apple-cluster driver to manage CPU p-states Date: Tue, 12 Oct 2021 01:57:05 +0900 Message-Id: <20211011165707.138157-8-marcan@marcan.st> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20211011165707.138157-1-marcan@marcan.st> References: <20211011165707.138157-1-marcan@marcan.st> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211011_095810_675054_3ABF9C67 X-CRM114-Status: GOOD ( 22.89 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org This driver exposes the CPU performance state switching hardware in Apple SoCs as a clock controller that can be used together with the generic cpufreq-dt mechanism to implement cpufreq support. It also supports binding to an apple-mcc instance, to increase memory controller performance when the CPUs are in the highest performance states. Signed-off-by: Hector Martin --- drivers/clk/Kconfig | 9 ++ drivers/clk/Makefile | 1 + drivers/clk/clk-apple-cluster.c | 184 ++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 drivers/clk/clk-apple-cluster.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c5b3dc97396a..f3c8ad041f91 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -390,6 +390,15 @@ config COMMON_CLK_K210 help Support for the Canaan Kendryte K210 RISC-V SoC clocks. +config COMMON_CLK_APPLE_CLUSTER + bool "Clock driver for Apple SoC CPU clusters" + depends on ARCH_APPLE || COMPILE_TEST + select CPUFREQ_DT + default ARCH_APPLE + help + This driver supports CPU cluster frequency switching on Apple SoC + platforms. + source "drivers/clk/actions/Kconfig" source "drivers/clk/analogbits/Kconfig" source "drivers/clk/baikal-t1/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index e42312121e51..6dba8c2052c7 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI) += clk-fsl-flexspi.o obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o +obj-$(CONFIG_COMMON_CLK_APPLE_CLUSTER) += clk-apple-cluster.o obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o obj-$(CONFIG_MACH_ASPEED_G6) += clk-ast2600.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o diff --git a/drivers/clk/clk-apple-cluster.c b/drivers/clk/clk-apple-cluster.c new file mode 100644 index 000000000000..9e9be38f13b2 --- /dev/null +++ b/drivers/clk/clk-apple-cluster.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple SoC CPU cluster performance state driver + * + * Copyright The Asahi Linux Contributors + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define APPLE_CLUSTER_PSTATE 0x20 +#define APPLE_CLUSTER_PSTATE_BUSY BIT(31) +#define APPLE_CLUSTER_PSTATE_SET BIT(25) +#define APPLE_CLUSTER_PSTATE_DESIRED2 GENMASK(15, 12) +#define APPLE_CLUSTER_PSTATE_DESIRED1 GENMASK(3, 0) + +struct apple_cluster_clk { + struct clk_hw hw; + struct device *dev; + void __iomem *reg_base; + bool has_pd; +}; + +#define to_apple_cluster_clk(_hw) container_of(_hw, struct apple_cluster_clk, hw) + +#define APPLE_CLUSTER_SWITCH_TIMEOUT 100 + +static int apple_cluster_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct apple_cluster_clk *cluster = to_apple_cluster_clk(hw); + struct dev_pm_opp *opp; + unsigned int level; + u64 reg; + + opp = dev_pm_opp_find_freq_floor(cluster->dev, &rate); + + if (IS_ERR(opp)) + return PTR_ERR(opp); + + level = dev_pm_opp_get_level(opp); + + dev_dbg(cluster->dev, "set_rate: %ld -> %d\n", rate, level); + + if (readq_poll_timeout(cluster->reg_base + APPLE_CLUSTER_PSTATE, reg, + !(reg & APPLE_CLUSTER_PSTATE_BUSY), 2, + APPLE_CLUSTER_SWITCH_TIMEOUT)) { + dev_err(cluster->dev, "timed out waiting for busy flag\n"); + return -EIO; + } + + reg &= ~(APPLE_CLUSTER_PSTATE_DESIRED1 | APPLE_CLUSTER_PSTATE_DESIRED2); + reg |= FIELD_PREP(APPLE_CLUSTER_PSTATE_DESIRED1, level); + reg |= FIELD_PREP(APPLE_CLUSTER_PSTATE_DESIRED2, level); + reg |= APPLE_CLUSTER_PSTATE_SET; + + writeq_relaxed(reg, cluster->reg_base + APPLE_CLUSTER_PSTATE); + + if (cluster->has_pd) + dev_pm_genpd_set_performance_state(cluster->dev, + dev_pm_opp_get_required_pstate(opp, 0)); + + return 0; +} + +static unsigned long apple_cluster_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct apple_cluster_clk *cluster = to_apple_cluster_clk(hw); + struct dev_pm_opp *opp; + u64 reg; + + reg = readq_relaxed(cluster->reg_base + APPLE_CLUSTER_PSTATE); + + opp = dev_pm_opp_find_level_exact(cluster->dev, + FIELD_GET(APPLE_CLUSTER_PSTATE_DESIRED1, reg)); + + if (IS_ERR(opp)) { + dev_err(cluster->dev, "failed to find level: 0x%llx (%ld)\n", reg, PTR_ERR(opp)); + return 0; + } + + return dev_pm_opp_get_freq(opp); +} + +static long apple_cluster_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct apple_cluster_clk *cluster = to_apple_cluster_clk(hw); + struct dev_pm_opp *opp; + + opp = dev_pm_opp_find_freq_floor(cluster->dev, &rate); + + if (IS_ERR(opp)) { + dev_err(cluster->dev, "failed to find rate: %ld (%ld)\n", rate, PTR_ERR(opp)); + return PTR_ERR(opp); + } + + return rate; +} + +static const struct clk_ops apple_cluster_clk_ops = { + .set_rate = apple_cluster_clk_set_rate, + .recalc_rate = apple_cluster_clk_recalc_rate, + .round_rate = apple_cluster_clk_round_rate, +}; + +static int apple_cluster_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct apple_cluster_clk *cluster; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + memset(&init, 0, sizeof(init)); + cluster = devm_kzalloc(dev, sizeof(*cluster), GFP_KERNEL); + if (!cluster) + return -ENOMEM; + + cluster->dev = dev; + cluster->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(cluster->reg_base)) + return PTR_ERR(cluster->reg_base); + + hw = &cluster->hw; + hw->init = &init; + + init.name = pdev->name; + init.num_parents = 0; + init.ops = &apple_cluster_clk_ops; + init.flags = 0; + + ret = dev_pm_opp_of_add_table_noclk(dev, 0); + if (ret < 0) { + dev_err(dev, "failed to get opp table\n"); + return ret; + } + + cluster->has_pd = of_property_read_bool(node, "power-domains"); + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); + if (ret < 0) + return ret; + + ret = devm_clk_hw_register(dev, hw); + if (ret) { + dev_err(dev, "failed to register clock\n"); + return ret; + } + + return 0; +} + +static const struct of_device_id apple_cluster_clk_of_match[] = { + { .compatible = "apple,cluster-clk" }, + {} +}; + +MODULE_DEVICE_TABLE(of, apple_cluster_clk_of_match); + +static struct platform_driver apple_cluster_clk_driver = { + .probe = apple_cluster_clk_probe, + .driver = { + .name = "apple-cluster-clk", + .of_match_table = apple_cluster_clk_of_match, + }, +}; + +MODULE_AUTHOR("Hector Martin "); +MODULE_DESCRIPTION("CPU cluster performance state driver for Apple SoCs"); +MODULE_LICENSE("GPL v2"); + +module_platform_driver(apple_cluster_clk_driver);