From patchwork Tue Jan 29 06:35:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "andrew-sh.cheng" X-Patchwork-Id: 10785529 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3F0CA1390 for ; Tue, 29 Jan 2019 06:36:05 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2EA182AE96 for ; Tue, 29 Jan 2019 06:36:05 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 227F12B4A0; Tue, 29 Jan 2019 06:36:05 +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=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 5D37C2AE96 for ; Tue, 29 Jan 2019 06:36:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=iz0e3f5Ie7WGieGSnH/lLTdf+Pjs93lFVHZd1pNmx30=; b=rXyYto4O+Q7LLm PwVMMtCtxdRgG9NYa7dGOy/KZRKdvwooDzYLXUEhmKTeRJ0YpqkPXECC1ReAqjto7cit8OuM8Ywnp NSyBbfU0j1Oyt5MbGyn56+eVuXRVrBTA3np+AGesWwu1LGmXS9+uy0qkefmHm6rrvLYdOUxQUrN+A RLFucnEqwdw0UAnKo0rlNigvoolADf6w61hrUzDTyGfLJDPdWQcZx6O9LSdru/gZewtwS0JwXrgwK YuLP7FxOQtmfPmsDlYjcTBHiIQ3zdxTG8a1F55J61sxjGAh0Jus5epevypjwhOiV3mrI70dAErOcR WuBlFRNIXjK8oKbn3rNw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1goN04-0006KW-Qw; Tue, 29 Jan 2019 06:36:00 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1goMzW-0005od-Q5; Tue, 29 Jan 2019 06:35:28 +0000 X-UUID: b2e2946d9a6a4445935e4bc985ac9ba6-20190128 X-UUID: b2e2946d9a6a4445935e4bc985ac9ba6-20190128 Received: from mtkcas67.mediatek.inc [(172.29.193.45)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 643623121; Mon, 28 Jan 2019 22:35:17 -0800 Received: from MTKMBS01N2.mediatek.inc (172.21.101.79) by MTKMBS62N2.mediatek.inc (172.29.193.42) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Mon, 28 Jan 2019 22:35:16 -0800 Received: from mtkcas08.mediatek.inc (172.21.101.126) by mtkmbs01n2.mediatek.inc (172.21.101.79) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Tue, 29 Jan 2019 14:35:10 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas08.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Tue, 29 Jan 2019 14:35:10 +0800 From: Andrew-sh Cheng To: MyungJoo Ham , Kyungmin Park , Chanwoo Choi , "Rob Herring" , Mark Rutland , "Matthias Brugger" , "Rafael J. Wysocki" , Viresh Kumar Subject: [PATCH 3/3] devfreq: add mediatek cci devfreq Date: Tue, 29 Jan 2019 14:35:04 +0800 Message-ID: <1548743704-16821-4-git-send-email-andrew-sh.cheng@mediatek.com> X-Mailer: git-send-email 1.8.1.1.dirty In-Reply-To: <1548743704-16821-1-git-send-email-andrew-sh.cheng@mediatek.com> References: <1548743704-16821-1-git-send-email-andrew-sh.cheng@mediatek.com> MIME-Version: 1.0 X-TM-SNTS-SMTP: AB3E92C340FECE0B34C63EFF9A9587E5758820EC4A6AD836B24201A1DC3711C32000:8 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190128_223526_909759_AEF66D7B X-CRM114-Status: GOOD ( 20.11 ) X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, "Andrew-sh.Cheng" , srv_heupstream@mediatek.com, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, fan.chen@mediatek.com, linux-mediatek@lists.infradead.org, linux-arm-kernel@lists.infradead.org Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP From: "Andrew-sh.Cheng" For big/little cpu cluster architecture, not only CPU frequency, but CCI frequency will also affect performance. Little cores and cci share the same buck in Mediatek mt8183 IC, so we add a CCI devfreq which will get notification when buck voltage is changed, then CCI devfreq can set cci frequency as high as possible. Signed-off-by: Andrew-sh.Cheng --- drivers/devfreq/Kconfig | 9 ++ drivers/devfreq/Makefile | 1 + drivers/devfreq/mt8183-cci-devfreq.c | 224 +++++++++++++++++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 drivers/devfreq/mt8183-cci-devfreq.c diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 6a172d3..0b14aab 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -113,6 +113,15 @@ config ARM_RK3399_DMC_DEVFREQ It sets the frequency for the memory controller and reads the usage counts from hardware. +config ARM_MT8183_CCI_DEVFREQ + tristate "MT8183 CCI DEVFREQ Driver" + depends on ARM_MEDIATEK_CPUFREQ + help + This adds devfreq for cci clock + which is shared the same regulator with cpu cluster. + It can track buck voltage and update a proper cci frequency. + Use notification to get regulator status. + source "drivers/devfreq/event/Kconfig" endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 32b8d4d..25afe8c 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o +obj-$(CONFIG_ARM_MT8183_CCI_DEVFREQ) += mt8183-cci-devfreq.o # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ diff --git a/drivers/devfreq/mt8183-cci-devfreq.c b/drivers/devfreq/mt8183-cci-devfreq.c new file mode 100644 index 0000000..4837892 --- /dev/null +++ b/drivers/devfreq/mt8183-cci-devfreq.c @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. +#include +#include +#include +#include +#include +#include +#include + +#include "governor.h" + +struct cci_devfreq_data { + struct devfreq *devfreq; + struct regulator *proc_reg; + struct clk *cci_clk; + unsigned long buck_volt; + int volt_increasing; + struct notifier_block nb; +}; + +static int mtk_cci_governor_get_target(struct devfreq *devfreq, + unsigned long *freq) +{ + struct cci_devfreq_data *cci_devdata; + int i, opp_count; + struct dev_pm_opp *opp; + unsigned long opp_rate, opp_voltage; + + cci_devdata = dev_get_drvdata(devfreq->dev.parent); + + /* find available frequency */ + opp_count = dev_pm_opp_get_opp_count(devfreq->dev.parent); + for (i = 0, opp_rate = ULONG_MAX; i < opp_count; i++, opp_rate--) { + opp = dev_pm_opp_find_freq_floor(devfreq->dev.parent, + &opp_rate); + opp_voltage = dev_pm_opp_get_voltage(opp); + dev_pm_opp_put(opp); + + if (opp_voltage <= cci_devdata->buck_volt) + break; + } + *freq = opp_rate; + + return 0; +} + +static int mtk_cci_governor_event_handler(struct devfreq *devfreq, + unsigned int event, void *data) +{ + return 0; +} + +static struct devfreq_governor mtk_cci_devfreq_governor = { + .name = "voltage_monitor", + .get_target_freq = mtk_cci_governor_get_target, + .event_handler = mtk_cci_governor_event_handler, +}; + +static int mtk_cci_devfreq_target(struct device *dev, unsigned long *freq, + u32 flags) +{ + struct cci_devfreq_data *cci_devdata; + + cci_devdata = dev_get_drvdata(dev); + + clk_set_rate(cci_devdata->cci_clk, *freq); + + return 0; +} + +static struct devfreq_dev_profile cci_devfreq_profile = { + .polling_ms = 0, + .target = mtk_cci_devfreq_target, +}; + +static int cci_devfreq_regulator_notifier(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct cci_devfreq_data *cci_devdata = + container_of(nb, struct cci_devfreq_data, nb); + + /* deal with reduce frequency */ + if (val & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) { + struct pre_voltage_change_data *pvc_data = data; + + if (pvc_data->old_uV > pvc_data->min_uV) { + cci_devdata->volt_increasing = 0; + cci_devdata->buck_volt = + (unsigned long)(pvc_data->min_uV); + mutex_lock(&cci_devdata->devfreq->lock); + update_devfreq(cci_devdata->devfreq); + mutex_unlock(&cci_devdata->devfreq->lock); + } else { + cci_devdata->volt_increasing = 1; + } + } + /* deal with abort reduce frequency */ + if ((val & REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE) || + /* deal with increase frequency */ + ((val & REGULATOR_EVENT_VOLTAGE_CHANGE) && + cci_devdata->volt_increasing == 1)) { + cci_devdata->buck_volt = (unsigned long)data; + mutex_lock(&cci_devdata->devfreq->lock); + update_devfreq(cci_devdata->devfreq); + mutex_unlock(&cci_devdata->devfreq->lock); + } + + return 0; +} + +static int mtk_cci_devfreq_probe(struct platform_device *pdev) +{ + struct device *cci_dev = &pdev->dev; + struct cci_devfreq_data *cci_devdata; + struct notifier_block *nb; + int ret; + + dev_pm_opp_of_add_table(&pdev->dev); + + cci_devdata = devm_kzalloc(cci_dev, sizeof(*cci_devdata), GFP_KERNEL); + if (!cci_devdata) + return -ENOMEM; + nb = &cci_devdata->nb; + cci_devdata->cci_clk = ERR_PTR(-ENODEV); + cci_devdata->proc_reg = ERR_PTR(-ENODEV); + + cci_devdata->cci_clk = clk_get(cci_dev, "cci_clock"); + ret = PTR_ERR_OR_ZERO(cci_devdata->cci_clk); + if (ret) { + if (ret == -EPROBE_DEFER) + pr_err("cci clock not ready, retry\n"); + else + pr_err("no clock for cci: %d\n", ret); + + goto out_free_resources; + } + + cci_devdata->proc_reg = regulator_get_optional(cci_dev, "proc"); + ret = PTR_ERR_OR_ZERO(cci_devdata->proc_reg); + if (ret) { + if (ret == -EPROBE_DEFER) + pr_err("cci regulator not ready, retry\n"); + else + pr_err("no regulator for cci: %d\n", ret); + + goto out_free_resources; + } + + platform_set_drvdata(pdev, cci_devdata); + + /* create cci_devfreq and add to cci device. + * governor is voltage_monitor. + * governor will get platform_device data to make decision. + */ + cci_devdata->devfreq = devm_devfreq_add_device(cci_dev, + &cci_devfreq_profile, + "voltage_monitor", + NULL); + + nb->notifier_call = cci_devfreq_regulator_notifier; + regulator_register_notifier(cci_devdata->proc_reg, + nb); + + return 0; + +out_free_resources: + if (!IS_ERR(cci_devdata->cci_clk)) + clk_put(cci_devdata->cci_clk); + if (!IS_ERR(cci_devdata->proc_reg)) + regulator_put(cci_devdata->proc_reg); + + return ret; +} + +static const struct of_device_id mediatek_cci_devfreq_of_match[] = { + { .compatible = "mediatek,mt8183-cci" }, + { }, +}; +MODULE_DEVICE_TABLE(of, mediatek_cci_devfreq_of_match); + +static struct platform_driver cci_devfreq_driver = { + .probe = mtk_cci_devfreq_probe, + .driver = { + .name = "mediatek-cci-devfreq", + .of_match_table = mediatek_cci_devfreq_of_match, + }, +}; + +static int __init mtk_cci_devfreq_init(void) +{ + int ret = 0; + + ret = devfreq_add_governor(&mtk_cci_devfreq_governor); + if (ret) { + pr_err("%s: failed to add governor: %d\n", __func__, ret); + return ret; + } + + ret = platform_driver_register(&cci_devfreq_driver); + if (ret) + devfreq_remove_governor(&mtk_cci_devfreq_governor); + + return ret; +} +module_init(mtk_cci_devfreq_init) + +static void __exit mtk_cci_devfreq_exit(void) +{ + int ret = 0; + + platform_driver_unregister(&cci_devfreq_driver); + + ret = devfreq_remove_governor(&mtk_cci_devfreq_governor); + if (ret) + pr_err("%s: failed to remove governor: %d\n", __func__, ret); +} +module_exit(mtk_cci_devfreq_exit) + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Mediatek CCI devfreq driver"); +MODULE_AUTHOR("andrew-sh.cheng"); +