diff mbox

[RESEND,1/1] clk: add DT support for clock gating control

Message ID 4FFE7979.4060000@googlemail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Sebastian Hesselbarth July 12, 2012, 7:15 a.m. UTC
As Rob's clock binding support patch is now up on clk-next, I'd like to
draw attention on this patch again.
--
This patch adds support for using clock gates (clk-gate) from DT based
on Rob Herrings DT clk binding support for 3.6.

It adds a helper function to clk-gate to allocate all resources required by
a set of individual clock gates, i.e. register base address and lock. Each
clock gate is described as a child of the clock-gating-control in DT and
also created by the helper function.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@googlemail.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Rob Landley <rob@landley.net>
Cc: Mike Turquette <mturquette@ti.com>
Cc: devicetree-discuss@lists.ozlabs.org
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
---
  .../bindings/clock/clock-gating-control.txt        |   80 +++++++++++++++++++
  drivers/clk/clk-gate.c                             |   84 ++++++++++++++++++++
  include/linux/clk-provider.h                       |    2 +
  3 files changed, 166 insertions(+)
  create mode 100644 Documentation/devicetree/bindings/clock/clock-gating-control.txt
This patch adds support for using clock gates (clk-gate) from DT based
on Rob Herrings DT clk binding support for 3.6.

It adds a helper function to clk-gate to allocate all resources required by
a set of individual clock gates, i.e. register base address and lock. Each
clock gate is described as a child of the clock-gating-control in DT and
also created by the helper function.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@googlemail.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Rob Landley <rob@landley.net>
Cc: Mike Turquette <mturquette@ti.com>
Cc: devicetree-discuss@lists.ozlabs.org
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
---
 .../bindings/clock/clock-gating-control.txt        |   80 +++++++++++++++++++
 drivers/clk/clk-gate.c                             |   84 ++++++++++++++++++++
 include/linux/clk-provider.h                       |    2 +
 3 files changed, 166 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/clock-gating-control.txt

diff --git a/Documentation/devicetree/bindings/clock/clock-gating-control.txt b/Documentation/devicetree/bindings/clock/clock-gating-control.txt
new file mode 100644
index 0000000..05f5728
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/clock-gating-control.txt
@@ -0,0 +1,80 @@
+Binding for simple clock gating control based on clock gate register with one
+bit per clock gate. This is a clock consumer and also a clock provider for a
+set of gated clocks that are described as children of this node. Each clock gate
+is described by a bit number and polarity to control the gate.
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+==Clock gating control==
+
+Required properties:
+- compatible : shall be "clock-gating-control".
+- reg : should contain the register physical address and length for
+        the clock gating control.
+- clocks : shared parent clock for all gated clocks.
+- #clock-cells : from common clock binding; shall be set to 0.
+- #address-cells : number of cells required to describe a clock gate;
+                   should be <2>.
+- #size-cells : should be zero.
+
+Each individual clock gate bit is described as a child of the
+corresponding gating control register with the following properties.
+
+Required child properties:
+- reg : should contain the individual bit and polarity to control
+        the clock gate. A polarity of 0 means that by setting the
+        bit to 1 the clock passes through the clock gate while
+	setting the bit to 0 disables the clock. Any other value
+     	for polarity inverts the meaning of the control bit.
+
+Optional child properties:
+- clocks : overrides the shared parent clock for this clock gate
+           by the clock passed in this property.
+- clock-output-names : from common clock binding; allows to set
+                       a specific name for the gated clock output.
+
+==Example==
+
+	/* fixed root clock */
+	osc: oscillator {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <166666667>;
+	};
+
+	/* sata peripheral clock */
+	sata_clk: ext-oscillator {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <25000000>;
+	};
+
+	/* register-based clock gating control */
+	gating-control@f10d0038 {
+		compatible = "clock-gating-control";
+		reg = <0xf10d0038 0x4>;
+		clocks = <&osc>;
+		#clock-cells = <0>;
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		/* USB0 clock gate on register bit 0 with inverted polarity */
+		cg_usb0: clockgate@0 {
+			reg = <0 1>; /* register bit 0, inverted polarity */
+		};
+
+		/* PCIe0 clock gate on register bit 1 with normal polarity
+		 * and named output clock */
+		cg_pcie0: clockgate@1 {
+			reg = <1 0>; /* register bit 1, normal polarity */
+			clock-output-names = "pcie0_clk";
+		};
+
+		/* SATA clock gate with different parent clock */
+		cg_sata: clockgate@3 {
+			reg = <3 0>; /* register bit 3, normal polarity */
+			clocks = <&sata_clk>;
+		};
+	};
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 578465e..1e88907 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -15,6 +15,9 @@
 #include <linux/io.h>
 #include <linux/err.h>
 #include <linux/string.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
 
 /**
  * DOC: basic gatable clock which can gate and ungate it's ouput
@@ -148,3 +151,84 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 
 	return clk;
 }
+
+#ifdef CONFIG_OF
+/**
+ * of_clock_gating_control_setup() - Setup function for clock gate control
+ *   This is a helper for using clk-gate from OF device tree. It allocates
+ *   a common lock for a base register and creates the individual clk-gates.
+ */
+void __init of_clock_gating_control_setup(struct device_node *np)
+{
+	struct device_node *child;
+	const char *pclk_name;
+	void __iomem *base;
+	spinlock_t *lockp;
+	unsigned int rnum;
+	u64 addr;
+
+	pclk_name = of_clk_get_parent_name(np, 0);
+	if (!pclk_name) {
+		pr_debug("%s: unable to get parent clock for %s\n",
+			__func__, np->full_name);
+		return;
+	}
+
+	lockp = kzalloc(sizeof(spinlock_t), GFP_KERNEL);
+	if (!lockp) {
+		pr_debug("%s: unable to allocate spinlock for %s\n",
+			 __func__, np->full_name);
+		return;
+	}
+
+	spin_lock_init(lockp);
+	base = of_iomap(np, 0);
+	rnum = sizeof(resource_size_t) * 8;
+	addr = of_translate_address(np, of_get_property(np, "reg", NULL));
+
+	pr_debug("create clock gate control %s\n", np->full_name);
+
+	for_each_child_of_node(np, child) {
+		struct clk *cg;
+		const char *cg_name;
+		const char *cg_pclk_name;
+		u32 propval[2];
+		unsigned int rbit;
+
+		if (of_property_read_u32_array(child, "reg", propval, 2)) {
+			pr_debug("%s: wrong #reg on %s\n",
+				 __func__, child->full_name);
+			continue;
+		}
+
+		rbit = propval[0];
+		if (rbit >= rnum) {
+			pr_debug("%s: bit position of %s exceeds resources\n",
+				 __func__, child->full_name);
+			continue;
+		}
+
+		cg_pclk_name = of_clk_get_parent_name(child, 0);
+		if (!pclk_name)
+			cg_pclk_name = pclk_name;
+
+		if (of_property_read_string(child, "clock-output-names",
+					    &cg_name)) {
+			unsigned int nlen = 4 + 16 + strlen(child->name);
+			char *name = kzalloc(nlen+1, GFP_KERNEL);
+			if (!name)
+				continue;
+			snprintf(name, nlen, "%u@%llx.%s", rbit,
+				 (unsigned long long)addr, child->name);
+			cg_name = name;
+		}
+
+		pr_debug("  create clock gate: %s\n", cg_name);
+
+		cg = clk_register_gate(NULL, cg_name, cg_pclk_name, 0,
+				       base, rbit, propval[1], lockp);
+		if (cg)
+			of_clk_add_provider(child, of_clk_src_simple_get, cg);
+	}
+}
+#endif
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index b97f61e..499eac2 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -205,6 +205,8 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 		void __iomem *reg, u8 bit_idx,
 		u8 clk_gate_flags, spinlock_t *lock);
 
+void of_clock_gating_control_setup(struct device_node *np);
+
 /**
  * struct clk_divider - adjustable divider clock
  *

Comments

Rob Herring July 12, 2012, 12:14 p.m. UTC | #1
On 07/12/2012 02:15 AM, Sebastian Hesselbarth wrote:
> As Rob's clock binding support patch is now up on clk-next, I'd like to
> draw attention on this patch again.
> -- 
> This patch adds support for using clock gates (clk-gate) from DT based
> on Rob Herrings DT clk binding support for 3.6.
> 
> It adds a helper function to clk-gate to allocate all resources required by
> a set of individual clock gates, i.e. register base address and lock. Each
> clock gate is described as a child of the clock-gating-control in DT and
> also created by the helper function.
> 
> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@googlemail.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: Rob Herring <rob.herring@calxeda.com>
> Cc: Rob Landley <rob@landley.net>
> Cc: Mike Turquette <mturquette@ti.com>
> Cc: devicetree-discuss@lists.ozlabs.org
> Cc: linux-doc@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Cc: linux-arm-kernel@lists.infradead.org
> ---
>  .../bindings/clock/clock-gating-control.txt        |   80
> +++++++++++++++++++
>  drivers/clk/clk-gate.c                             |   84
> ++++++++++++++++++++
>  include/linux/clk-provider.h                       |    2 +
>  3 files changed, 166 insertions(+)
>  create mode 100644
> Documentation/devicetree/bindings/clock/clock-gating-control.txt
> 
> diff --git
> a/Documentation/devicetree/bindings/clock/clock-gating-control.txt
> b/Documentation/devicetree/bindings/clock/clock-gating-control.txt
> new file mode 100644
> index 0000000..05f5728
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/clock-gating-control.txt
> @@ -0,0 +1,80 @@
> +Binding for simple clock gating control based on clock gate register
> with one
> +bit per clock gate. This is a clock consumer and also a clock provider
> for a
> +set of gated clocks that are described as children of this node. Each
> clock gate
> +is described by a bit number and polarity to control the gate.
> +
> +This binding uses the common clock binding[1].
> +
> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
> +
> +==Clock gating control==
> +
> +Required properties:
> +- compatible : shall be "clock-gating-control".
> +- reg : should contain the register physical address and length for
> +        the clock gating control.
> +- clocks : shared parent clock for all gated clocks.
> +- #clock-cells : from common clock binding; shall be set to 0.
> +- #address-cells : number of cells required to describe a clock gate;
> +                   should be <2>.
> +- #size-cells : should be zero.
> +
> +Each individual clock gate bit is described as a child of the
> +corresponding gating control register with the following properties.
> +
> +Required child properties:
> +- reg : should contain the individual bit and polarity to control
> +        the clock gate. A polarity of 0 means that by setting the
> +        bit to 1 the clock passes through the clock gate while
> +    setting the bit to 0 disables the clock. Any other value
> +         for polarity inverts the meaning of the control bit.

This is a bit of overloading reg to specify the polarity.

> +
> +Optional child properties:
> +- clocks : overrides the shared parent clock for this clock gate
> +           by the clock passed in this property.
> +- clock-output-names : from common clock binding; allows to set
> +                       a specific name for the gated clock output.
> +
> +==Example==
> +
> +    /* fixed root clock */
> +    osc: oscillator {
> +        compatible = "fixed-clock";
> +        #clock-cells = <0>;
> +        clock-frequency = <166666667>;
> +    };
> +
> +    /* sata peripheral clock */
> +    sata_clk: ext-oscillator {
> +        compatible = "fixed-clock";
> +        #clock-cells = <0>;
> +        clock-frequency = <25000000>;
> +    };
> +
> +    /* register-based clock gating control */
> +    gating-control@f10d0038 {
> +        compatible = "clock-gating-control";
> +        reg = <0xf10d0038 0x4>;
> +        clocks = <&osc>;
> +        #clock-cells = <0>;
> +        #address-cells = <2>;
> +        #size-cells = <0>;
> +
> +        /* USB0 clock gate on register bit 0 with inverted polarity */
> +        cg_usb0: clockgate@0 {
> +            reg = <0 1>; /* register bit 0, inverted polarity */
> +        };
> +
> +        /* PCIe0 clock gate on register bit 1 with normal polarity
> +         * and named output clock */
> +        cg_pcie0: clockgate@1 {
> +            reg = <1 0>; /* register bit 1, normal polarity */
> +            clock-output-names = "pcie0_clk";
> +        };
> +
> +        /* SATA clock gate with different parent clock */
> +        cg_sata: clockgate@3 {
> +            reg = <3 0>; /* register bit 3, normal polarity */
> +            clocks = <&sata_clk>;
> +        };

I'm not sure I like the node per bit. What about a bit mask for valid
bits and polarities. Then add a clock cell to specify the bit or index.

i.MX has 2-bit enable fields for its leaf clocks, so how and if you
would support that is something to think about.

Rob

> +    };
> diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
> index 578465e..1e88907 100644
> --- a/drivers/clk/clk-gate.c
> +++ b/drivers/clk/clk-gate.c
> @@ -15,6 +15,9 @@
>  #include <linux/io.h>
>  #include <linux/err.h>
>  #include <linux/string.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
>   /**
>   * DOC: basic gatable clock which can gate and ungate it's ouput
> @@ -148,3 +151,84 @@ struct clk *clk_register_gate(struct device *dev,
> const char *name,
>       return clk;
>  }
> +
> +#ifdef CONFIG_OF
> +/**
> + * of_clock_gating_control_setup() - Setup function for clock gate control
> + *   This is a helper for using clk-gate from OF device tree. It allocates
> + *   a common lock for a base register and creates the individual
> clk-gates.
> + */
> +void __init of_clock_gating_control_setup(struct device_node *np)
> +{
> +    struct device_node *child;
> +    const char *pclk_name;
> +    void __iomem *base;
> +    spinlock_t *lockp;
> +    unsigned int rnum;
> +    u64 addr;
> +
> +    pclk_name = of_clk_get_parent_name(np, 0);
> +    if (!pclk_name) {
> +        pr_debug("%s: unable to get parent clock for %s\n",
> +            __func__, np->full_name);
> +        return;
> +    }
> +
> +    lockp = kzalloc(sizeof(spinlock_t), GFP_KERNEL);
> +    if (!lockp) {
> +        pr_debug("%s: unable to allocate spinlock for %s\n",
> +             __func__, np->full_name);
> +        return;
> +    }
> +
> +    spin_lock_init(lockp);
> +    base = of_iomap(np, 0);
> +    rnum = sizeof(resource_size_t) * 8;
> +    addr = of_translate_address(np, of_get_property(np, "reg", NULL));
> +
> +    pr_debug("create clock gate control %s\n", np->full_name);
> +
> +    for_each_child_of_node(np, child) {
> +        struct clk *cg;
> +        const char *cg_name;
> +        const char *cg_pclk_name;
> +        u32 propval[2];
> +        unsigned int rbit;
> +
> +        if (of_property_read_u32_array(child, "reg", propval, 2)) {
> +            pr_debug("%s: wrong #reg on %s\n",
> +                 __func__, child->full_name);
> +            continue;
> +        }
> +
> +        rbit = propval[0];
> +        if (rbit >= rnum) {
> +            pr_debug("%s: bit position of %s exceeds resources\n",
> +                 __func__, child->full_name);
> +            continue;
> +        }
> +
> +        cg_pclk_name = of_clk_get_parent_name(child, 0);
> +        if (!pclk_name)
> +            cg_pclk_name = pclk_name;
> +
> +        if (of_property_read_string(child, "clock-output-names",
> +                        &cg_name)) {
> +            unsigned int nlen = 4 + 16 + strlen(child->name);
> +            char *name = kzalloc(nlen+1, GFP_KERNEL);
> +            if (!name)
> +                continue;
> +            snprintf(name, nlen, "%u@%llx.%s", rbit,
> +                 (unsigned long long)addr, child->name);
> +            cg_name = name;
> +        }
> +
> +        pr_debug("  create clock gate: %s\n", cg_name);
> +
> +        cg = clk_register_gate(NULL, cg_name, cg_pclk_name, 0,
> +                       base, rbit, propval[1], lockp);
> +        if (cg)
> +            of_clk_add_provider(child, of_clk_src_simple_get, cg);
> +    }
> +}
> +#endif
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index b97f61e..499eac2 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -205,6 +205,8 @@ struct clk *clk_register_gate(struct device *dev,
> const char *name,
>          void __iomem *reg, u8 bit_idx,
>          u8 clk_gate_flags, spinlock_t *lock);
>  +void of_clock_gating_control_setup(struct device_node *np);
> +
>  /**
>   * struct clk_divider - adjustable divider clock
>   *
Sebastian Hesselbarth July 12, 2012, 1:08 p.m. UTC | #2
On 07/12/2012 02:14 PM, Rob Herring wrote:
>> +Required child properties:
>> +- reg : should contain the individual bit and polarity to control
>> +        the clock gate. A polarity of 0 means that by setting the
>> +        bit to 1 the clock passes through the clock gate while
>> +    setting the bit to 0 disables the clock. Any other value
>> +         for polarity inverts the meaning of the control bit.
>
> This is a bit of overloading reg to specify the polarity.

Well, yes it is overloading but still matches reg somehow, as the
extra information is required to access the resource. But I agree,
expecially wrt more-than-one-bit clk-gate (see below).

>> +        /* SATA clock gate with different parent clock */
>> +        cg_sata: clockgate@3 {
>> +            reg =<3 0>; /* register bit 3, normal polarity */
>> +            clocks =<&sata_clk>;
>> +        };
>
> I'm not sure I like the node per bit. What about a bit mask for valid
> bits and polarities. Then add a clock cell to specify the bit or index.
>
> i.MX has 2-bit enable fields for its leaf clocks, so how and if you
> would support that is something to think about.

Yeah, I thought of "what if the clk_gate needs to be enabled with more
than 1 bit" already. But this is a short-comming of the current clk-gate
implementation.

Just to get it right, i.MX requires to set more than one bit to change
the state of the gate for one leaf clock?

If this is true, that would require a change of the generic clk-gate
anyway.

I had a look at pinctrl-bindings.txt maybe this is the way to go for
clock gating control, too. That would require clk-gate to handle an
'active' and 'gated' state and leave it to a clock gate control to
actually set the required bits in any registers. This would allow
other special implementations of clock gating controllers to reuse
clk-gate DT description. Additionally, there could be a
simple-clock-gating-control that can set states by reg address and
for each controlled gate a mask, enable value, and disable value.

Sebastian
Rob Herring July 13, 2012, 3:19 a.m. UTC | #3
On 07/12/2012 08:08 AM, Sebastian Hesselbarh wrote:
> On 07/12/2012 02:14 PM, Rob Herring wrote:
>>> +Required child properties:
>>> +- reg : should contain the individual bit and polarity to control
>>> +        the clock gate. A polarity of 0 means that by setting the
>>> +        bit to 1 the clock passes through the clock gate while
>>> +    setting the bit to 0 disables the clock. Any other value
>>> +         for polarity inverts the meaning of the control bit.
>>
>> This is a bit of overloading reg to specify the polarity.
> 
> Well, yes it is overloading but still matches reg somehow, as the
> extra information is required to access the resource. But I agree,
> expecially wrt more-than-one-bit clk-gate (see below).
> 

You can define your own property names.

>>> +        /* SATA clock gate with different parent clock */
>>> +        cg_sata: clockgate@3 {
>>> +            reg =<3 0>; /* register bit 3, normal polarity */
>>> +            clocks =<&sata_clk>;
>>> +        };
>>
>> I'm not sure I like the node per bit. What about a bit mask for valid
>> bits and polarities. Then add a clock cell to specify the bit or index.
>>
>> i.MX has 2-bit enable fields for its leaf clocks, so how and if you
>> would support that is something to think about.
> 
> Yeah, I thought of "what if the clk_gate needs to be enabled with more
> than 1 bit" already. But this is a short-comming of the current clk-gate
> implementation.

What's implemented in Linux should not define the binding. The binding
should describe the hardware.

> Just to get it right, i.MX requires to set more than one bit to change
> the state of the gate for one leaf clock?

It's basically ON, OFF, and "ON in run/OFF in wfi".

Perhaps the iMX case is unique enough we don't try to make it use a
common binding.

> If this is true, that would require a change of the generic clk-gate
> anyway.

True, but not your problem to implement. A binding doesn't necessarily
mean there is a full Linux implementation. We just don't want to create
something only to find others need something completely different.

Rob

> I had a look at pinctrl-bindings.txt maybe this is the way to go for
> clock gating control, too. That would require clk-gate to handle an
> 'active' and 'gated' state and leave it to a clock gate control to
> actually set the required bits in any registers. This would allow
> other special implementations of clock gating controllers to reuse
> clk-gate DT description. Additionally, there could be a
> simple-clock-gating-control that can set states by reg address and
> for each controlled gate a mask, enable value, and disable value.
> 
> Sebastian
Sebastian Hesselbarth July 13, 2012, 9:42 a.m. UTC | #4
On 07/13/2012 05:19 AM, Rob Herring wrote:
> What's implemented in Linux should not define the binding. The binding
> should describe the hardware.
> [...]
> True, but not your problem to implement. A binding doesn't necessarily
> mean there is a full Linux implementation. We just don't want to create
> something only to find others need something completely different.

Ok, what about a DT describing the following for a simple register-based
clock gating controller and the corresponding gated-clock independent of
the controller. I am sure there are a bunch of SoCs out there that
control their clock gates by writing some bits to a register. If that
DT description matches your expectations, I ll prepare patches with
documentation and implementation for common clock framework.

Sebastian

--
  /* Simple clock gating controller based on bitmasks and register */
cgc: clock-gating-control@f1000000 {
   compatible = "clock-gating-control-register";
   reg = <0xf1000000 0x4>;

   /* Clock gating control with one bit at bit position 0
      enable with (1<<0), disable with (0<<0) */
   cgctrl_usb0: cgc_usb0 {
     clock-gating-control,shift = <0>;
     clock-gating-control,mask = <1>;
     clock-gating-control,enable = <1>;
     clock-gating-control,disable = <0>;
   };

   /* Clock gating control with two bits at bit position 1-2
      enable with (2<<1), disable with (0<<1) */
   cgctrl_sata: cgc_sata {
     clock-gating-control,shift = <1>;
     clock-gating-control,mask = <3>;
     clock-gating-control,enable = <2>;
     clock-gating-control,disable = <0>;
   };
};

/* Generic clock gate description that can be used with
    any clock gating controller */
cg_usb0: clockgate@0 {
   compatible = "gated-clock";
   #clock-cells = <0>;
   clocks = <&osc>;
   clock-gate-control = <&cgctrl_usb0>;
};
Rob Herring July 14, 2012, 5 a.m. UTC | #5
On 07/13/2012 04:42 AM, Sebastian Hesselbarh wrote:
> On 07/13/2012 05:19 AM, Rob Herring wrote:
>> What's implemented in Linux should not define the binding. The binding
>> should describe the hardware.
>> [...]
>> True, but not your problem to implement. A binding doesn't necessarily
>> mean there is a full Linux implementation. We just don't want to create
>> something only to find others need something completely different.
> 
> Ok, what about a DT describing the following for a simple register-based
> clock gating controller and the corresponding gated-clock independent of
> the controller. I am sure there are a bunch of SoCs out there that
> control their clock gates by writing some bits to a register. If that
> DT description matches your expectations, I ll prepare patches with
> documentation and implementation for common clock framework.
> 

Clock gates are just 1 part. There's muxes, dividers, plls, etc. I'm not
convinced that it makes sense to define clocks at this level. For
complex chips, I think just defining the chips clock controller module
as a single node with lots of clock outputs. The primary need is to
describe board specific changes not SOC level clock tree. Much of it is
static and generally only a few clocks may change config board to board.

> Sebastian
> 
> -- 
>  /* Simple clock gating controller based on bitmasks and register */
> cgc: clock-gating-control@f1000000 {
>   compatible = "clock-gating-control-register";
>   reg = <0xf1000000 0x4>;
> 
>   /* Clock gating control with one bit at bit position 0
>      enable with (1<<0), disable with (0<<0) */
>   cgctrl_usb0: cgc_usb0 {
>     clock-gating-control,shift = <0>;
>     clock-gating-control,mask = <1>;
>     clock-gating-control,enable = <1>;
>     clock-gating-control,disable = <0>;
>   };
> 
>   /* Clock gating control with two bits at bit position 1-2
>      enable with (2<<1), disable with (0<<1) */
>   cgctrl_sata: cgc_sata {
>     clock-gating-control,shift = <1>;
>     clock-gating-control,mask = <3>;
>     clock-gating-control,enable = <2>;
>     clock-gating-control,disable = <0>;
>   };
> };
> 
> /* Generic clock gate description that can be used with
>    any clock gating controller */
> cg_usb0: clockgate@0 {
>   compatible = "gated-clock";
>   #clock-cells = <0>;
>   clocks = <&osc>;
>   clock-gate-control = <&cgctrl_usb0>;
> };

I don't see this scaling to ~50 clocks.

Rob
Rob Landley July 15, 2012, 8:45 p.m. UTC | #6
I believe clock anything is Thomas Gleixner, just making sure he's seen
it...

Rob

On 07/13/2012 04:42 AM, Sebastian Hesselbarh wrote:
> On 07/13/2012 05:19 AM, Rob Herring wrote:
>> What's implemented in Linux should not define the binding. The binding
>> should describe the hardware.
>> [...]
>> True, but not your problem to implement. A binding doesn't necessarily
>> mean there is a full Linux implementation. We just don't want to create
>> something only to find others need something completely different.
> 
> Ok, what about a DT describing the following for a simple register-based
> clock gating controller and the corresponding gated-clock independent of
> the controller. I am sure there are a bunch of SoCs out there that
> control their clock gates by writing some bits to a register. If that
> DT description matches your expectations, I ll prepare patches with
> documentation and implementation for common clock framework.
> 
> Sebastian
> 
> -- 
>  /* Simple clock gating controller based on bitmasks and register */
> cgc: clock-gating-control@f1000000 {
>   compatible = "clock-gating-control-register";
>   reg = <0xf1000000 0x4>;
> 
>   /* Clock gating control with one bit at bit position 0
>      enable with (1<<0), disable with (0<<0) */
>   cgctrl_usb0: cgc_usb0 {
>     clock-gating-control,shift = <0>;
>     clock-gating-control,mask = <1>;
>     clock-gating-control,enable = <1>;
>     clock-gating-control,disable = <0>;
>   };
> 
>   /* Clock gating control with two bits at bit position 1-2
>      enable with (2<<1), disable with (0<<1) */
>   cgctrl_sata: cgc_sata {
>     clock-gating-control,shift = <1>;
>     clock-gating-control,mask = <3>;
>     clock-gating-control,enable = <2>;
>     clock-gating-control,disable = <0>;
>   };
> };
> 
> /* Generic clock gate description that can be used with
>    any clock gating controller */
> cg_usb0: clockgate@0 {
>   compatible = "gated-clock";
>   #clock-cells = <0>;
>   clocks = <&osc>;
>   clock-gate-control = <&cgctrl_usb0>;
> };
>
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/clock/clock-gating-control.txt 
b/Documentation/devicetree/bindings/clock/clock-gating-control.txt
new file mode 100644
index 0000000..05f5728
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/clock-gating-control.txt
@@ -0,0 +1,80 @@ 
+Binding for simple clock gating control based on clock gate register with one
+bit per clock gate. This is a clock consumer and also a clock provider for a
+set of gated clocks that are described as children of this node. Each clock gate
+is described by a bit number and polarity to control the gate.
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+==Clock gating control==
+
+Required properties:
+- compatible : shall be "clock-gating-control".
+- reg : should contain the register physical address and length for
+        the clock gating control.
+- clocks : shared parent clock for all gated clocks.
+- #clock-cells : from common clock binding; shall be set to 0.
+- #address-cells : number of cells required to describe a clock gate;
+                   should be <2>.
+- #size-cells : should be zero.
+
+Each individual clock gate bit is described as a child of the
+corresponding gating control register with the following properties.
+
+Required child properties:
+- reg : should contain the individual bit and polarity to control
+        the clock gate. A polarity of 0 means that by setting the
+        bit to 1 the clock passes through the clock gate while
+	setting the bit to 0 disables the clock. Any other value
+     	for polarity inverts the meaning of the control bit.
+
+Optional child properties:
+- clocks : overrides the shared parent clock for this clock gate
+           by the clock passed in this property.
+- clock-output-names : from common clock binding; allows to set
+                       a specific name for the gated clock output.
+
+==Example==
+
+	/* fixed root clock */
+	osc: oscillator {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <166666667>;
+	};
+
+	/* sata peripheral clock */
+	sata_clk: ext-oscillator {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <25000000>;
+	};
+
+	/* register-based clock gating control */
+	gating-control@f10d0038 {
+		compatible = "clock-gating-control";
+		reg = <0xf10d0038 0x4>;
+		clocks = <&osc>;
+		#clock-cells = <0>;
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		/* USB0 clock gate on register bit 0 with inverted polarity */
+		cg_usb0: clockgate@0 {
+			reg = <0 1>; /* register bit 0, inverted polarity */
+		};
+
+		/* PCIe0 clock gate on register bit 1 with normal polarity
+		 * and named output clock */
+		cg_pcie0: clockgate@1 {
+			reg = <1 0>; /* register bit 1, normal polarity */
+			clock-output-names = "pcie0_clk";
+		};
+
+		/* SATA clock gate with different parent clock */
+		cg_sata: clockgate@3 {
+			reg = <3 0>; /* register bit 3, normal polarity */
+			clocks = <&sata_clk>;
+		};
+	};
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 578465e..1e88907 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -15,6 +15,9 @@ 
  #include <linux/io.h>
  #include <linux/err.h>
  #include <linux/string.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
   /**
   * DOC: basic gatable clock which can gate and ungate it's ouput
@@ -148,3 +151,84 @@  struct clk *clk_register_gate(struct device *dev, const char *name,
   	return clk;
  }
+
+#ifdef CONFIG_OF
+/**
+ * of_clock_gating_control_setup() - Setup function for clock gate control
+ *   This is a helper for using clk-gate from OF device tree. It allocates
+ *   a common lock for a base register and creates the individual clk-gates.
+ */
+void __init of_clock_gating_control_setup(struct device_node *np)
+{
+	struct device_node *child;
+	const char *pclk_name;
+	void __iomem *base;
+	spinlock_t *lockp;
+	unsigned int rnum;
+	u64 addr;
+
+	pclk_name = of_clk_get_parent_name(np, 0);
+	if (!pclk_name) {
+		pr_debug("%s: unable to get parent clock for %s\n",
+			__func__, np->full_name);
+		return;
+	}
+
+	lockp = kzalloc(sizeof(spinlock_t), GFP_KERNEL);
+	if (!lockp) {
+		pr_debug("%s: unable to allocate spinlock for %s\n",
+			 __func__, np->full_name);
+		return;
+	}
+
+	spin_lock_init(lockp);
+	base = of_iomap(np, 0);
+	rnum = sizeof(resource_size_t) * 8;
+	addr = of_translate_address(np, of_get_property(np, "reg", NULL));
+
+	pr_debug("create clock gate control %s\n", np->full_name);
+
+	for_each_child_of_node(np, child) {
+		struct clk *cg;
+		const char *cg_name;
+		const char *cg_pclk_name;
+		u32 propval[2];
+		unsigned int rbit;
+
+		if (of_property_read_u32_array(child, "reg", propval, 2)) {
+			pr_debug("%s: wrong #reg on %s\n",
+				 __func__, child->full_name);
+			continue;
+		}
+
+		rbit = propval[0];
+		if (rbit >= rnum) {
+			pr_debug("%s: bit position of %s exceeds resources\n",
+				 __func__, child->full_name);
+			continue;
+		}
+
+		cg_pclk_name = of_clk_get_parent_name(child, 0);
+		if (!pclk_name)
+			cg_pclk_name = pclk_name;
+
+		if (of_property_read_string(child, "clock-output-names",
+					    &cg_name)) {
+			unsigned int nlen = 4 + 16 + strlen(child->name);
+			char *name = kzalloc(nlen+1, GFP_KERNEL);
+			if (!name)
+				continue;
+			snprintf(name, nlen, "%u@%llx.%s", rbit,
+				 (unsigned long long)addr, child->name);
+			cg_name = name;
+		}
+
+		pr_debug("  create clock gate: %s\n", cg_name);
+
+		cg = clk_register_gate(NULL, cg_name, cg_pclk_name, 0,
+				       base, rbit, propval[1], lockp);
+		if (cg)
+			of_clk_add_provider(child, of_clk_src_simple_get, cg);
+	}
+}
+#endif
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index b97f61e..499eac2 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -205,6 +205,8 @@  struct clk *clk_register_gate(struct device *dev, const char *name,
  		void __iomem *reg, u8 bit_idx,
  		u8 clk_gate_flags, spinlock_t *lock);
  +void of_clock_gating_control_setup(struct device_node *np);
+
  /**
   * struct clk_divider - adjustable divider clock
   *
-- 
1.7.10