From patchwork Tue Apr 30 10:18:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peng Fan X-Patchwork-Id: 1093147 X-Patchwork-Delegate: sbabic@denx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=nxp.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=nxp.com header.i=@nxp.com header.b="KwArm5gN"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 44tcyD2nnfz9s47 for ; Tue, 30 Apr 2019 20:21:40 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id DF2EEC21F04; Tue, 30 Apr 2019 10:19:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=SPF_HELO_PASS, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 67A36C21DE8; Tue, 30 Apr 2019 10:18:16 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 86528C21E35; Tue, 30 Apr 2019 10:18:08 +0000 (UTC) Received: from EUR04-VI1-obe.outbound.protection.outlook.com (mail-eopbgr80053.outbound.protection.outlook.com [40.107.8.53]) by lists.denx.de (Postfix) with ESMTPS id 02E88C21D83 for ; Tue, 30 Apr 2019 10:18:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=wS+iOpvDD+L3kTMvxC6nll70Cbd7vX6cy73+VlX/wn4=; b=KwArm5gNaIb7KeKNB2Y29Qkywg1mz5/16us8fOHRBtkxaT4w2mt8fdUlzJRK8h9V00O7tky0spbA0urYr9/jMR9fQyaVIwUfuYpAWIXKNORyPDYgRS4AQWKTgLB7mr9VbOk5oVjpJGre4qkXnOD/AIzY82arNiGjTIXsq8xZjD0= Received: from AM0PR04MB4481.eurprd04.prod.outlook.com (52.135.147.15) by AM0PR04MB5204.eurprd04.prod.outlook.com (20.176.214.85) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1835.15; Tue, 30 Apr 2019 10:18:01 +0000 Received: from AM0PR04MB4481.eurprd04.prod.outlook.com ([fe80::3173:24:d401:2378]) by AM0PR04MB4481.eurprd04.prod.outlook.com ([fe80::3173:24:d401:2378%6]) with mapi id 15.20.1835.018; Tue, 30 Apr 2019 10:18:01 +0000 From: Peng Fan To: "sbabic@denx.de" , "festevam@gmail.com" , "lukma@denx.de" Thread-Topic: [i.MX8MM+CCF 09/41] clk: add clk-gate support Thread-Index: AQHU/z39OLfh3tJ8k0al92t7hAzpaQ== Date: Tue, 30 Apr 2019 10:18:01 +0000 Message-ID: <20190430103056.32537-10-peng.fan@nxp.com> References: <20190430103056.32537-1-peng.fan@nxp.com> In-Reply-To: <20190430103056.32537-1-peng.fan@nxp.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-mailer: git-send-email 2.16.4 x-clientproxiedby: HK0PR03CA0057.apcprd03.prod.outlook.com (2603:1096:203:52::21) To AM0PR04MB4481.eurprd04.prod.outlook.com (2603:10a6:208:70::15) authentication-results: spf=none (sender IP is ) smtp.mailfrom=peng.fan@nxp.com; x-ms-exchange-messagesentrepresentingtype: 1 x-originating-ip: [119.31.174.71] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 56198aae-ba95-4955-a565-08d6cd552013 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(2390118)(7020095)(4652040)(8989299)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(5600141)(711020)(4605104)(4618075)(2017052603328)(7193020); SRVR:AM0PR04MB5204; x-ms-traffictypediagnostic: AM0PR04MB5204: x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:800; x-forefront-prvs: 00235A1EEF x-forefront-antispam-report: SFV:NSPM; SFS:(10009020)(979002)(39860400002)(396003)(376002)(136003)(346002)(366004)(189003)(199004)(7736002)(8676002)(110136005)(305945005)(6512007)(53936002)(50226002)(81156014)(66066001)(4326008)(68736007)(25786009)(97736004)(2501003)(316002)(44832011)(54906003)(8936002)(26005)(186003)(102836004)(446003)(476003)(486006)(76176011)(66446008)(71190400001)(71200400001)(11346002)(66946007)(99286004)(81166006)(66556008)(64756008)(52116002)(66476007)(6506007)(14454004)(6486002)(2616005)(1076003)(73956011)(6436002)(2201001)(478600001)(3846002)(86362001)(5660300002)(386003)(14444005)(36756003)(2906002)(6116002)(256004)(969003)(989001)(999001)(1009001)(1019001); DIR:OUT; SFP:1101; SCL:1; SRVR:AM0PR04MB5204; H:AM0PR04MB4481.eurprd04.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; MX:1; A:1; received-spf: None (protection.outlook.com: nxp.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 x-microsoft-antispam-message-info: mYOitRvhQfInUvZ1nvBFU/t9/t/BjyWwE/hDfyYMLQ38Uzj9aA/8pkOgfOnXpF2zRBRwlbq/6/iRufdwTDslzCMzrPhLyO30EUiUOfOUl6TpSYWMH6oO2xX4iy3+ed/croelXeazHlvgddP7pC0xHh60bczDNDKXYz95Hck3TULxafnd8sH42ySAdbIFrU+5BaiPNP5KfxOuOK+xT+oh8IDjYAOo99JPVz5vq3dWrLVnDwLtST1xRankB4UP9kccoGtiFEGNzXVKwLkJ3GgrhcAhJbZxIX0GA9ukUZPVcDa8g0unKRJ33IEXaAIkhn4oUoZN4dFdbJT916W3+lzaTGhDCZwGyfmBT7UjV95qD98syw+mP5tDSes6bTUbWSi7+HmQkMLQVbop4eZ2VxMX5NTBbZSEmqgHK7lqdq+UfuQ= MIME-Version: 1.0 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 56198aae-ba95-4955-a565-08d6cd552013 X-MS-Exchange-CrossTenant-originalarrivaltime: 30 Apr 2019 10:18:01.5895 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM0PR04MB5204 Cc: "trini@konsulko.com" , "u-boot@lists.denx.de" , dl-uboot-imx , "sr@denx.de" Subject: [U-Boot] [i.MX8MM+CCF 09/41] clk: add clk-gate support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Import clk-gate support from Linux Kernel 5.1-rc5 Signed-off-by: Peng Fan --- drivers/clk/Makefile | 2 +- drivers/clk/clk-gate.c | 151 +++++++++++++++++++++++++++++++++++++++++++ include/linux/clk-provider.h | 18 ++++++ 3 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/clk-gate.c diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 9fcc75e0ea..0bc8f7e5ce 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_$(SPL_TPL_)CLK) += clk-uclass.o obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_rate.o obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_factor.o -obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk.o clk-divider.o clk-mux.o +obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk.o clk-divider.o clk-mux.o clk-gate.o obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk-fixed-factor.o obj-y += imx/ diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c new file mode 100644 index 0000000000..bb59d0e04e --- /dev/null +++ b/drivers/clk/clk-gate.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2010-2011 Canonical Ltd + * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd + * Copyright 2019 NXP + * + * Gated clock implementation + */ + +#include +#include +#include +#include +#include +#include +#include +#include "clk.h" + +#define UBOOT_DM_CLK_GATE "clk_gate" + +/** + * DOC: basic gatable clock which can gate and ungate it's output + * + * Traits of this clock: + * prepare - clk_(un)prepare only ensures parent is (un)prepared + * enable - clk_enable and clk_disable are functional & control gating + * rate - inherits rate from parent. No clk_set_rate support + * parent - fixed parent. No clk_set_parent support + */ + +/* + * It works on following logic: + * + * For enabling clock, enable = 1 + * set2dis = 1 -> clear bit -> set = 0 + * set2dis = 0 -> set bit -> set = 1 + * + * For disabling clock, enable = 0 + * set2dis = 1 -> set bit -> set = 1 + * set2dis = 0 -> clear bit -> set = 0 + * + * So, result is always: enable xor set2dis. + */ +static void clk_gate_endisable(struct clk *clk, int enable) +{ + struct clk_gate *gate = to_clk_gate(clk_dev_binded(clk) ? + (struct clk *)dev_get_driver_data(clk->dev) : + clk); + int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; + u32 reg; + + set ^= enable; + + if (gate->flags & CLK_GATE_HIWORD_MASK) { + reg = BIT(gate->bit_idx + 16); + if (set) + reg |= BIT(gate->bit_idx); + } else { + reg = readl(gate->reg); + + if (set) + reg |= BIT(gate->bit_idx); + else + reg &= ~BIT(gate->bit_idx); + } + + writel(reg, gate->reg); +} + +static int clk_gate_enable(struct clk *clk) +{ + clk_gate_endisable(clk, 1); + + return 0; +} + +static int clk_gate_disable(struct clk *clk) +{ + clk_gate_endisable(clk, 0); + + return 0; +} + +int clk_gate_is_enabled(struct clk *clk) +{ + struct clk_gate *gate = to_clk_gate(clk_dev_binded(clk) ? + (struct clk *)dev_get_driver_data(clk->dev) : + clk); + u32 reg; + + reg = readl(gate->reg); + + /* if a set bit disables this clk, flip it before masking */ + if (gate->flags & CLK_GATE_SET_TO_DISABLE) + reg ^= BIT(gate->bit_idx); + + reg &= BIT(gate->bit_idx); + + return reg ? 1 : 0; +} + +const struct clk_ops clk_gate_ops = { + .enable = clk_gate_enable, + .disable = clk_gate_disable, + .get_rate = clk_generic_get_rate, +}; + +struct clk *clk_register_gate(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock) +{ + struct clk_gate *gate; + struct clk *clk; + int ret; + + if (clk_gate_flags & CLK_GATE_HIWORD_MASK) { + if (bit_idx > 15) { + pr_err("gate bit exceeds LOWORD field\n"); + return ERR_PTR(-EINVAL); + } + } + + /* allocate the gate */ + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + /* struct clk_gate assignments */ + gate->reg = reg; + gate->bit_idx = bit_idx; + gate->flags = clk_gate_flags; + + clk = &gate->clk; + + ret = clk_register(clk, UBOOT_DM_CLK_GATE, (ulong)clk, + name, parent_name); + if (ret) { + kfree(gate); + return ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(clk_gate) = { + .name = UBOOT_DM_CLK_GATE, + .id = UCLASS_CLK, + .ops = &clk_gate_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index a60cf6e833..3ed0db86d2 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -59,6 +59,24 @@ struct clk_mux { extern const struct clk_ops clk_mux_ops; u8 clk_mux_get_parent(struct clk *clk); +struct clk_gate { + struct clk clk; + void __iomem *reg; + u8 bit_idx; + u8 flags; +}; + +#define to_clk_gate(_clk) container_of(_clk, struct clk_gate, clk) + +#define CLK_GATE_SET_TO_DISABLE BIT(0) +#define CLK_GATE_HIWORD_MASK BIT(1) + +extern const struct clk_ops clk_gate_ops; +struct clk *clk_register_gate(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock); + struct clk_div_table { unsigned int val; unsigned int div;