From patchwork Fri May 10 15:02:06 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Hogan X-Patchwork-Id: 2551511 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by patchwork1.kernel.org (Postfix) with ESMTP id B17B33FC5A for ; Fri, 10 May 2013 15:05:41 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Uaorq-0002aK-LT; Fri, 10 May 2013 15:04:19 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UaorP-00009B-Vb; Fri, 10 May 2013 15:03:51 +0000 Received: from multi.imgtec.com ([194.200.65.239]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Uaoqr-0008VN-7L for linux-arm-kernel@lists.infradead.org; Fri, 10 May 2013 15:03:19 +0000 From: James Hogan To: Mike Turquette , Subject: [PATCH RFC 1/2] clk: metag/clk-gate: add metag specific clock gate Date: Fri, 10 May 2013 16:02:06 +0100 Message-ID: <1368198127-1295-5-git-send-email-james.hogan@imgtec.com> X-Mailer: git-send-email 1.8.1.2 In-Reply-To: <1368198127-1295-1-git-send-email-james.hogan@imgtec.com> References: <1368198127-1295-1-git-send-email-james.hogan@imgtec.com> MIME-Version: 1.0 X-SEF-Processed: 7_3_0_01181__2013_05_10_16_02_51 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130510_110317_432574_9FA915E6 X-CRM114-Status: GOOD ( 21.28 ) X-Spam-Score: -3.2 (---) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-3.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -1.3 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: James Hogan , linux-kernel@vger.kernel.org, Arnd Bergmann X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Add a metag architecture specific clk-gate which extends the generic one to use global lock2 to protect the register fields. It is common with metag to have an RTOS running on a different thread or core with access to different bits in the same register (in this case clock gate bits for other clocks). Access to such registers must be serialised with a global lock such as the one provided by the metag architecture port in Signed-off-by: James Hogan Cc: Mike Turquette --- .../bindings/clock/img,meta-gate-clock.txt | 28 ++++ drivers/clk/Makefile | 1 + drivers/clk/metag/Makefile | 2 + drivers/clk/metag/clk-gate.c | 179 +++++++++++++++++++++ 4 files changed, 210 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/img,meta-gate-clock.txt create mode 100644 drivers/clk/metag/Makefile create mode 100644 drivers/clk/metag/clk-gate.c diff --git a/Documentation/devicetree/bindings/clock/img,meta-gate-clock.txt b/Documentation/devicetree/bindings/clock/img,meta-gate-clock.txt new file mode 100644 index 0000000..483097c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/img,meta-gate-clock.txt @@ -0,0 +1,28 @@ +Binding for clock gate requiring global Meta locking. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : Shall be "img,meta-mux-clock". +- #clock-cells : From common clock binding; shall be set to 0. +- reg : Address of configuration register. +- bit : Bit number of gate switch in configuration register. +- clocks : From common clock binding. + +Required source clocks: +- 0 : Input clock that can be gated (doesn't have to be named). + +Optional properties: +- clock-output-names : From common clock binding. + +Example: + clock { + compatible = "img,meta-gate-clock"; + #clock-cells = <0>; + clocks = <&sys_clk>; + reg = <0x02004010 0x4>; + bit = <0>; + clock-output-names = "scb0"; + }; diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index e7f7fe9..a800077 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o obj-$(CONFIG_ARCH_TEGRA) += tegra/ +obj-$(CONFIG_METAG) += metag/ obj-$(CONFIG_X86) += x86/ # Chip specific diff --git a/drivers/clk/metag/Makefile b/drivers/clk/metag/Makefile new file mode 100644 index 0000000..8e9a6ac --- /dev/null +++ b/drivers/clk/metag/Makefile @@ -0,0 +1,2 @@ +# metag clock types +obj-$(CONFIG_COMMON_CLK) += clk-gate.o diff --git a/drivers/clk/metag/clk-gate.c b/drivers/clk/metag/clk-gate.c new file mode 100644 index 0000000..63da8d9 --- /dev/null +++ b/drivers/clk/metag/clk-gate.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2013 Imagination Technologies Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Metag gated clock implementation + * Based on gated clock implementation, but does appropriate locking to protect + * registers shared between hardware threads. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct clk_metag_gate - metag gating clock + * + * @mux: the parent class + * @ops: pointer to clk_ops of parent class + * + * Clock which can gate its output. Extends basic mux by using a global + * exclusive lock when read-modify-writing the mux field so that multiple + * threads/cores can use different fields in the same register. + */ +struct clk_metag_gate { + struct clk_gate gate; + const struct clk_ops *ops; +}; + +static inline struct clk_metag_gate *to_clk_metag_gate(struct clk_hw *hw) +{ + struct clk_gate *gate = container_of(hw, struct clk_gate, hw); + + return container_of(gate, struct clk_metag_gate, gate); +} + +/* Acquire exclusive lock since other cores may access the same register */ +static int clk_metag_gate_enable(struct clk_hw *hw) +{ + struct clk_metag_gate *gate = to_clk_metag_gate(hw); + int ret; + unsigned long flags; + + __global_lock2(flags); + ret = gate->ops->enable(&gate->gate.hw); + __global_unlock2(flags); + + return ret; +} + +/* Acquire exclusive lock since other cores may access the same register */ +static void clk_metag_gate_disable(struct clk_hw *hw) +{ + struct clk_metag_gate *gate = to_clk_metag_gate(hw); + unsigned long flags; + + __global_lock2(flags); + gate->ops->disable(&gate->gate.hw); + __global_unlock2(flags); +} + +static int clk_metag_gate_is_enabled(struct clk_hw *hw) +{ + struct clk_metag_gate *gate = to_clk_metag_gate(hw); + + return gate->ops->is_enabled(&gate->gate.hw); +} + +static const struct clk_ops clk_metag_gate_ops = { + .enable = clk_metag_gate_enable, + .disable = clk_metag_gate_disable, + .is_enabled = clk_metag_gate_is_enabled, +}; + +/** + * clk_register_metag_gate - register a Meta gate clock with the clock framework + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_name: name of this clock's parent + * @flags: framework-specific flags for this clock + * @reg: register address to control gating of this clock + * @bit_idx: which bit in the register controls gating of this clock + * @clk_gate_flags: gate-specific flags for this clock + */ +static struct clk *__init clk_register_metag_gate(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, u8 clk_gate_flags) +{ + struct clk_metag_gate *gate; + struct clk *clk; + struct clk_init_data init; + + /* allocate the gate */ + gate = kzalloc(sizeof(struct clk_metag_gate), GFP_KERNEL); + if (!gate) { + pr_err("%s: could not allocate gated clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &clk_metag_gate_ops; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + /* struct clk_gate assignments */ + gate->gate.reg = reg; + gate->gate.bit_idx = bit_idx; + gate->gate.flags = clk_gate_flags; + gate->gate.hw.init = &init; + + /* struct clk_metag_gate assignments */ + gate->ops = &clk_gate_ops; + + clk = clk_register(dev, &gate->gate.hw); + + if (IS_ERR(clk)) + kfree(gate); + + return clk; +} + +#ifdef CONFIG_OF +/** + * of_metag_gate_clk_setup() - Setup function for simple fixed rate clock + */ +static void __init of_metag_gate_clk_setup(struct device_node *node) +{ + struct clk *clk; + const char *clk_name = node->name; + u32 bit_idx; + void __iomem *reg; + const char *parent_name; + u8 flags = 0; + + of_property_read_string(node, "clock-output-names", &clk_name); + + if (of_property_read_u32(node, "bit", &bit_idx)) { + pr_err("%s(%s): could not read bit property\n", + __func__, clk_name); + return; + } + + parent_name = of_clk_get_parent_name(node, 0); + if (!parent_name) { + pr_err("%s(%s): could not read parent clock\n", + __func__, clk_name); + return; + } + + reg = of_iomap(node, 0); + if (!reg) { + pr_err("%s(%s): of_iomap failed\n", + __func__, clk_name); + return; + } + + clk = clk_register_metag_gate(NULL, clk_name, parent_name, + CLK_SET_RATE_PARENT, reg, bit_idx, flags); + if (IS_ERR(clk)) + goto err_iounmap; + + of_clk_add_provider(node, of_clk_src_simple_get, clk); + + return; + +err_iounmap: + iounmap(reg); +} +CLK_OF_DECLARE(metag_gate_clk, "img,meta-gate-clock", of_metag_gate_clk_setup); +#endif /* CONFIG_OF */