From patchwork Fri Mar 7 03:27:00 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guangjie Song X-Patchwork-Id: 14005787 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 641DDC19F32 for ; Fri, 7 Mar 2025 03:37:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type: Content-Transfer-Encoding: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=xlhPBaPDQlxN4mEBmcB22vZGGR0wheXIAp+lo36yNd4=; b=0a1v0tGTBihyrnHUdjRKZY3CBg LlfbjUUmn0J7nLctjs89T5MFKY++Rnau6i1cp59sMDuL+TLQ5Mjv8I2dO9itBVYLB7NDoFE7rXPyA 3Sj6bgc151ofqoBnzy+ffa0bDigUw5+J4N2dFwuKS4uMc7fYP1cB5c2LkKEQRyt5Maalr5sTXs8t6 GJRzd5eICL5rCrRRW2LTTYZ8j72NnrxsBwP67jQxFVg/uyTNdIJ/WwY9LwEq9MpOx36JJ0kF/otge ONVecXQaFQKF5UW4kOEDBUmRILxk1KnJVVL8BUGpBJ/bdpOvP6Auo3mU9WVSKE1aMFxWCcl6HVu14 1QeFr3pg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tqOWi-0000000D0Xp-1gz4; Fri, 07 Mar 2025 03:37:32 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tqOS2-0000000CzMb-434p; Fri, 07 Mar 2025 03:32:44 +0000 X-UUID: d1860c50fb0411efa1e849db4cc18d44-20250306 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=xlhPBaPDQlxN4mEBmcB22vZGGR0wheXIAp+lo36yNd4=; b=sFR18x0lb953eoDeq/26gIZOSW7z1/rTpiGrjHv2QPqnuN65XG4MJxmZMQlPEYT5K9am8omZBeVxqeNNCSMzPGxEu/8HNjc9tih4zW6zTsVXbgiac13Cxby/qs/HpB0KBDo23DiT9OwOhs/M6vFX0iSBxPMlUnni23peM6EQVJY=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.2.1,REQID:3abd37eb-c9a9-4695-bf79-1dbb7c8dbf80,IP:0,UR L:0,TC:0,Content:0,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION:r elease,TS:0 X-CID-META: VersionHash:0ef645f,CLOUDID:99e207c6-16da-468a-87f7-8ca8d6b3b9f7,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:81|82|102,TC:nil,Content:0|50,EDM:-3 ,IP:nil,URL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV :0,LES:1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: d1860c50fb0411efa1e849db4cc18d44-20250306 Received: from mtkmbs09n2.mediatek.inc [(172.21.101.94)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1158287544; Thu, 06 Mar 2025 20:32:38 -0700 Received: from mtkmbs11n2.mediatek.inc (172.21.101.187) by MTKMBS14N1.mediatek.inc (172.21.101.75) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.28; Fri, 7 Mar 2025 11:32:37 +0800 Received: from mhfsdcap04.gcn.mediatek.inc (10.17.3.154) by mtkmbs11n2.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1258.28 via Frontend Transport; Fri, 7 Mar 2025 11:32:36 +0800 From: Guangjie Song To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Richard Cochran CC: , , , , , , Guangjie Song , Subject: [PATCH 04/26] clk: mediatek: Support voting for gate Date: Fri, 7 Mar 2025 11:27:00 +0800 Message-ID: <20250307032942.10447-5-guangjie.song@mediatek.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20250307032942.10447-1-guangjie.song@mediatek.com> References: <20250307032942.10447-1-guangjie.song@mediatek.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20250306_193243_009758_4185A935 X-CRM114-Status: GOOD ( 20.19 ) 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 Add data fields and ops to support voting for gate. Signed-off-by: Guangjie Song --- drivers/clk/mediatek/clk-gate.c | 230 +++++++++++++++++++++++++++++++- drivers/clk/mediatek/clk-gate.h | 5 + 2 files changed, 228 insertions(+), 7 deletions(-) diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c index 67d9e741c5e7..be6cf4a6d246 100644 --- a/drivers/clk/mediatek/clk-gate.c +++ b/drivers/clk/mediatek/clk-gate.c @@ -12,14 +12,19 @@ #include #include +#include "clk-mtk.h" #include "clk-gate.h" struct mtk_clk_gate { struct clk_hw hw; struct regmap *regmap; + struct regmap *vote_regmap; int set_ofs; int clr_ofs; int sta_ofs; + int vote_set_ofs; + int vote_clr_ofs; + int vote_sta_ofs; u8 bit; }; @@ -100,6 +105,143 @@ static void mtk_cg_disable_inv(struct clk_hw *hw) mtk_cg_clr_bit(hw); } +static int mtk_cg_vote_is_set(struct clk_hw *hw) +{ + struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); + u32 val = 0; + + regmap_read(cg->vote_regmap, cg->vote_set_ofs, &val); + + val &= BIT(cg->bit); + + return val != 0; +} + +static int mtk_cg_vote_is_done(struct clk_hw *hw) +{ + struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); + u32 val = 0; + + regmap_read(cg->vote_regmap, cg->vote_sta_ofs, &val); + + val &= BIT(cg->bit); + + return val != 0; +} + +static int __cg_vote_enable(struct clk_hw *hw, bool inv) +{ + struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); + u32 val = 0, val2 = 0; + bool is_done = false; + int i = 0; + + regmap_write(cg->vote_regmap, cg->vote_set_ofs, BIT(cg->bit)); + + while (!mtk_cg_vote_is_set(hw)) { + if (i < MTK_WAIT_VOTE_PREPARE_CNT) { + udelay(MTK_WAIT_VOTE_PREPARE_US); + } else { + pr_err("%s cg prepare timeout\n", clk_hw_get_name(hw)); + return -EBUSY; + } + + i++; + } + + i = 0; + + while (1) { + if (!is_done) + regmap_read(cg->vote_regmap, cg->vote_sta_ofs, &val); + + if ((val & BIT(cg->bit)) != 0) + is_done = true; + + if (is_done) { + regmap_read(cg->regmap, cg->sta_ofs, &val2); + if ((inv && (val2 & BIT(cg->bit)) != 0) || + (!inv && (val2 & BIT(cg->bit)) == 0)) + break; + } + + if (i < MTK_WAIT_VOTE_DONE_CNT) { + udelay(MTK_WAIT_VOTE_DONE_US); + } else { + pr_err("%s cg enable timeout(%x %x)\n", clk_hw_get_name(hw), val, val2); + + if (inv) + regmap_write(cg->regmap, cg->set_ofs, BIT(cg->bit)); + else + regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit)); + + return -EBUSY; + } + + i++; + } + + return 0; +} + +static int mtk_cg_vote_enable(struct clk_hw *hw) +{ + return __cg_vote_enable(hw, false); +} + +static int mtk_cg_vote_enable_inv(struct clk_hw *hw) +{ + return __cg_vote_enable(hw, true); +} + +static void mtk_cg_vote_disable(struct clk_hw *hw) +{ + struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); + u32 val; + int i = 0; + + /* dummy read to clr idle signal of hw voter bus */ + regmap_read(cg->vote_regmap, cg->vote_clr_ofs, &val); + + regmap_write(cg->vote_regmap, cg->vote_clr_ofs, BIT(cg->bit)); + + while (mtk_cg_vote_is_set(hw)) { + if (i < MTK_WAIT_VOTE_PREPARE_CNT) { + udelay(MTK_WAIT_VOTE_PREPARE_US); + } else { + pr_err("%s cg unprepare timeout\n", clk_hw_get_name(hw)); + return; + } + + i++; + } + + i = 0; + + while (!mtk_cg_vote_is_done(hw)) { + if (i < MTK_WAIT_VOTE_DONE_CNT) { + udelay(MTK_WAIT_VOTE_DONE_US); + } else { + pr_err("%s cg disable timeout\n", clk_hw_get_name(hw)); + return; + } + + i++; + } +} + +static void mtk_cg_vote_disable_unused(struct clk_hw *hw) +{ + mtk_cg_vote_enable(hw); + mtk_cg_vote_disable(hw); +} + +static void mtk_cg_vote_disable_unused_inv(struct clk_hw *hw) +{ + mtk_cg_vote_enable_inv(hw); + mtk_cg_vote_disable(hw); +} + static int mtk_cg_enable_no_setclr(struct clk_hw *hw) { mtk_cg_clr_bit_no_setclr(hw); @@ -138,6 +280,22 @@ const struct clk_ops mtk_clk_gate_ops_setclr_inv = { }; EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_setclr_inv); +const struct clk_ops mtk_clk_gate_ops_vote = { + .is_enabled = mtk_cg_bit_is_cleared, + .enable = mtk_cg_vote_enable, + .disable = mtk_cg_vote_disable, + .disable_unused = mtk_cg_vote_disable_unused, +}; +EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_vote); + +const struct clk_ops mtk_clk_gate_ops_vote_inv = { + .is_enabled = mtk_cg_bit_is_set, + .enable = mtk_cg_vote_enable_inv, + .disable = mtk_cg_vote_disable, + .disable_unused = mtk_cg_vote_disable_unused_inv, +}; +EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_vote_inv); + const struct clk_ops mtk_clk_gate_ops_no_setclr = { .is_enabled = mtk_cg_bit_is_cleared, .enable = mtk_cg_enable_no_setclr, @@ -190,6 +348,53 @@ static struct clk_hw *mtk_clk_register_gate(struct device *dev, const char *name return &cg->hw; } +static struct clk_hw *mtk_clk_register_gate_vote(struct device *dev, + const struct mtk_gate *gate, + struct regmap *regmap, + struct regmap *vote_regmap) +{ + struct mtk_clk_gate *cg; + int ret; + struct clk_init_data init = {}; + + cg = kzalloc(sizeof(*cg), GFP_KERNEL); + if (!cg) + return ERR_PTR(-ENOMEM); + + init.name = gate->name; + init.flags = gate->flags | CLK_SET_RATE_PARENT; + init.parent_names = gate->parent_name ? &gate->parent_name : NULL; + init.num_parents = gate->parent_name ? 1 : 0; + if (vote_regmap) + init.ops = gate->ops; + else + init.ops = gate->dma_ops; + + cg->regmap = regmap; + cg->vote_regmap = vote_regmap; + if (gate->regs) { + cg->set_ofs = gate->regs->set_ofs; + cg->clr_ofs = gate->regs->clr_ofs; + cg->sta_ofs = gate->regs->sta_ofs; + } + if (gate->vote_regs) { + cg->vote_set_ofs = gate->vote_regs->set_ofs; + cg->vote_clr_ofs = gate->vote_regs->clr_ofs; + cg->vote_sta_ofs = gate->vote_regs->sta_ofs; + } + cg->bit = gate->shift; + + cg->hw.init = &init; + + ret = clk_hw_register(dev, &cg->hw); + if (ret) { + kfree(cg); + return ERR_PTR(ret); + } + + return &cg->hw; +} + static void mtk_clk_unregister_gate(struct clk_hw *hw) { struct mtk_clk_gate *cg; @@ -209,6 +414,7 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node, int i; struct clk_hw *hw; struct regmap *regmap; + struct regmap *vote_regmap = NULL; if (!clk_data) return -ENOMEM; @@ -228,13 +434,23 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node, continue; } - hw = mtk_clk_register_gate(dev, gate->name, gate->parent_name, - regmap, - gate->regs->set_ofs, - gate->regs->clr_ofs, - gate->regs->sta_ofs, - gate->shift, gate->ops, - gate->flags); + if (gate->flags & CLK_USE_VOTE) { + if (gate->vote_comp) { + vote_regmap = syscon_regmap_lookup_by_phandle(node, gate->vote_comp); + if (IS_ERR(vote_regmap)) + vote_regmap = NULL; + } + + hw = mtk_clk_register_gate_vote(dev, gate, regmap, vote_regmap); + } else { + hw = mtk_clk_register_gate(dev, gate->name, gate->parent_name, + regmap, + gate->regs->set_ofs, + gate->regs->clr_ofs, + gate->regs->sta_ofs, + gate->shift, gate->ops, + gate->flags); + } if (IS_ERR(hw)) { pr_err("Failed to register clk %s: %pe\n", gate->name, diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h index 1a46b4c56fc5..7d93fc84ad51 100644 --- a/drivers/clk/mediatek/clk-gate.h +++ b/drivers/clk/mediatek/clk-gate.h @@ -19,6 +19,8 @@ extern const struct clk_ops mtk_clk_gate_ops_setclr; extern const struct clk_ops mtk_clk_gate_ops_setclr_inv; extern const struct clk_ops mtk_clk_gate_ops_no_setclr; extern const struct clk_ops mtk_clk_gate_ops_no_setclr_inv; +extern const struct clk_ops mtk_clk_gate_ops_vote; +extern const struct clk_ops mtk_clk_gate_ops_vote_inv; struct mtk_gate_regs { u32 sta_ofs; @@ -30,9 +32,12 @@ struct mtk_gate { int id; const char *name; const char *parent_name; + const char *vote_comp; const struct mtk_gate_regs *regs; + const struct mtk_gate_regs *vote_regs; int shift; const struct clk_ops *ops; + const struct clk_ops *dma_ops; unsigned long flags; };