From patchwork Wed Jul 31 07:01:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peng Fan X-Patchwork-Id: 1139541 X-Patchwork-Delegate: lukma@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="qWVUAN/j"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 45z4JP5y8tz9sDQ for ; Wed, 31 Jul 2019 17:08:05 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 84422C21DFB; Wed, 31 Jul 2019 07:04:38 +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 3EB86C21E26; Wed, 31 Jul 2019 07:02:38 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 24FA1C21E0F; Wed, 31 Jul 2019 07:01:40 +0000 (UTC) Received: from EUR02-AM5-obe.outbound.protection.outlook.com (mail-eopbgr00052.outbound.protection.outlook.com [40.107.0.52]) by lists.denx.de (Postfix) with ESMTPS id 81850C21DF8 for ; Wed, 31 Jul 2019 07:01:37 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Jef8JyKgRlYdsihinjrg4CH+ph7Dsr0hEW8jwjPIzpFwqdCv2GzOLL9Gu+Tj+orPqIEAhSgLu34026PqHjG9DszituxYP+YstyUjeBwfszVG/DHrTGEyRePBQEfkPmpVZ0Hu/Es85gthDaUDWV071CBRMK6FvVzvfvdmuD8G8KTiB2xDbJ/vpKjEk5ymR8QleVSlO1VVE1KLgbSW7K23h+Q/MeZqljfXjMUCiAjiDmt9CahdLw63HbI7/iUl3B9WVrz2IJoL00gFwGEPkZ4UHaoP3L1UzCJ6IYcXS4K/sA+GHByLNOhd0zhH3ZxZJ5GjfreFFhjPYZiMAIOiGzA2nQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=0EHPDqAKv66X7YsyGtML9n9qhXTrJWJ+WI9HzNXAXDs=; b=YayReWAOV4YcXHgQFkWxEbCouNOpPdlj0ADc1lSsOPwzu1VOXN8MJ7Bhk25ufZwkL4RqxsEVxD3w+GSVphbuVWl4SCVMh1bqUS93RSv7NSegFki3QJqjip6u1CTnIrkfwJ8zEWCukVMHKBbGv/Cn0bzKXCcaXhsqMXKg7qUVUyxsddVfpWbowAJMav85bVfCUhjzzlZJp03NkR465dxieUu7/7UNtOoP+ST3S4nuvgep5KvWmy+xUVcLm/qNFVTDGTZjtjOKEsWQZtsQIGbHZ0q0GaQ4HDUFlJxEpdlgePKJcEK/ka815ML9wo97ysIdS8hDpwpZvYHEmvvu5cdgnQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1;spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com;arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=0EHPDqAKv66X7YsyGtML9n9qhXTrJWJ+WI9HzNXAXDs=; b=qWVUAN/jwZjYLg36GR8GljK0N0ZFgliteJY5dxulNwsDf+SjK8+vWMS0hpoZe2wg5q73GFg8WIy6MDZ/n9Q6eo0VuuZV5AHVcpFiseAE7kRxbP3Mr+tcxt8gYM+cJqi33TyiCRvJ79+TKyHM6ICHzvGCRcvwFTsuttDE46LtnUA= Received: from AM0PR04MB4481.eurprd04.prod.outlook.com (52.135.147.15) by AM0PR04MB5826.eurprd04.prod.outlook.com (20.178.203.86) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2115.13; Wed, 31 Jul 2019 07:01:34 +0000 Received: from AM0PR04MB4481.eurprd04.prod.outlook.com ([fe80::5d98:e1f4:aa72:16b4]) by AM0PR04MB4481.eurprd04.prod.outlook.com ([fe80::5d98:e1f4:aa72:16b4%4]) with mapi id 15.20.2115.005; Wed, 31 Jul 2019 07:01:34 +0000 From: Peng Fan To: "lukma@denx.de" Thread-Topic: [PATCH V3 05/16] clk: add clk-gate support Thread-Index: AQHVR23JPzKCi/GDcUOP3h/4v7aGvw== Date: Wed, 31 Jul 2019 07:01:34 +0000 Message-ID: <20190731071654.9970-5-peng.fan@nxp.com> References: <20190731071654.9970-1-peng.fan@nxp.com> In-Reply-To: <20190731071654.9970-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: HK0PR03CA0026.apcprd03.prod.outlook.com (2603:1096:203:2f::14) 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: 13e4004f-45fd-4367-b2cc-08d71584ec54 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(2390118)(7020095)(4652040)(8989299)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(5600148)(711020)(4605104)(1401327)(4618075)(2017052603328)(7193020); SRVR:AM0PR04MB5826; x-ms-traffictypediagnostic: AM0PR04MB5826: x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:800; x-forefront-prvs: 011579F31F x-forefront-antispam-report: SFV:NSPM; SFS:(10009020)(4636009)(396003)(366004)(136003)(346002)(376002)(39860400002)(189003)(199004)(44832011)(102836004)(486006)(2501003)(6506007)(52116002)(386003)(11346002)(446003)(2616005)(76176011)(476003)(478600001)(54906003)(53936002)(6512007)(3846002)(6116002)(316002)(66066001)(25786009)(2351001)(186003)(99286004)(26005)(2906002)(14454004)(4326008)(256004)(14444005)(6486002)(6436002)(50226002)(6916009)(305945005)(8936002)(71200400001)(71190400001)(86362001)(5640700003)(1076003)(36756003)(8676002)(81166006)(81156014)(1730700003)(66946007)(5660300002)(66446008)(64756008)(66556008)(66476007)(68736007)(7736002); DIR:OUT; SFP:1101; SCL:1; SRVR:AM0PR04MB5826; 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: LZI6YT+TkE/GC3l9z8bnzSpB6miGK8CV6dZ/7xtouoph4V3+ocHGgg6VES5I3MB/rpSrChY3aPZLy/0lG7sFd6MdiwHzYsUiFN3YcxTe7bzCyqnCZm1DgXfuKMs1GqprNbcv+VDfhCtm5YODE0tv9ELaraI7VUBiBvWNukNZfFFb2BlM/Z4Hu+i10mMeTB7ytCkewVDaycdWmgWIXZZLD0+Uyn3ecEUx3mszzzYYYeranehOGf0HxgSs8wT/puyJqxUk2fdoz0WwBGeW482pHHsTLgAztoXIDmk7Z9lXywMCzxYgJvyf0pO6X5vs/t7b66teTHAjs05LxbCMbVX2XhaZWRPiyyZG5OyfRxhjA7D0baWwQumgJyHurqZxVEMZ0a6hobIGlJ9TumNCpQ15hLWVhck6psLpjl6ocv8WlHU= MIME-Version: 1.0 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 13e4004f-45fd-4367-b2cc-08d71584ec54 X-MS-Exchange-CrossTenant-originalarrivaltime: 31 Jul 2019 07:01:34.2763 (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-CrossTenant-userprincipalname: peng.fan@nxp.com X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM0PR04MB5826 Cc: "u-boot@lists.denx.de" , dl-uboot-imx Subject: [U-Boot] [PATCH V3 05/16] 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 --- V2: None V3: Rebase drivers/clk/Makefile | 2 +- drivers/clk/clk-gate.c | 148 +++++++++++++++++++++++++++++++++++++++++++ include/linux/clk-provider.h | 18 ++++++ 3 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/clk-gate.c diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index b7fec605c6..39154eca59 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 += analogbits/ diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c new file mode 100644 index 0000000000..a3a1fdd3b2 --- /dev/null +++ b/drivers/clk/clk-gate.c @@ -0,0 +1,148 @@ +// 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) ? + dev_get_clk_ptr(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) ? + dev_get_clk_ptr(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, 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 6d62f862d2..8b04ecd7a5 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -69,6 +69,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;