linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] Marvell Berlin full clock support
@ 2014-05-11 20:24 Sebastian Hesselbarth
  2014-05-11 20:24 ` [PATCH 1/8] clk: add helper for unique DT clock names Sebastian Hesselbarth
                   ` (8 more replies)
  0 siblings, 9 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-11 20:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Mike Turquette, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Alexandre Belloni,
	Antoine Tenart, devicetree, linux-arm-kernel, linux-kernel

This is a patch set combining initial effort from Alexandre Belloni [1][2]
and a bad one from me [3] to bring proper DT based clocks to Marvell Berlin
SoCs. As I was unsure, how Alexandre's initial patch sets fit in the whole
picture, I had to look at it myself. It took me a while to sort out the messy
clk related registers of Berlin, but finally IMHO I found a good compromise
between DT and driver registered clocks.

As I don't have any access to BG2Q code/documentation, it needs some
additional patches from Alexandre. This is basically berlin2q.dtsi changes
and a core clock driver for BG2Q. Anyway, this is nothing that should stall
a proper driver-/DT-related review.

Apoloigies for the noise the three approaches may have caused, but anybody
who takes a closer look at either this patches or the corresponding GPL'd
Chromecast SDK [4][5] will quickly see that Marvell HW engineers really hate
those who have to write the drivers for their register sets. It is full of
"similar" registers for the same IP that received some TLC, like one register
is shifted by 4 bits with respect to the other registers dealing with the
same functionalities. *sigh*

The patches are based on v3.15-rc1 and I have compared the resulting clock
frequencies with u-boot's reported frequencies where possible on Chromecast
(BG2CD) and NSZ-GS7 (BG2).

I'd love to see them in for v3.16 as it will allow us to proceed with working
on drivers that actually need those clocks. Current support for Marvell Berlin
SoCs is almost limited to serial console, so there is absolutely nothing to
break. To make sure it will not break others, I prepared a topic branch and
added it to berlin's linux-next branch.

The topic branch can be found at
https://github.com/shesselba/linux-berlin.git topic/clk

Patch 1 first adds a helper function to derive a unique clock name out of
the DT nodes name and either the reg property or a magic number. This is
taken from DT's platform code, that derives similar unique names for proper
platform devices.

Patch 2 adds the whole binding documentation for all clock related IP.

Patches 3, 4, and 5 then add clock drivers for the Audio/Video PLL, simple
PLLs, and complex clock divider cells found on Berlin SoCs. Where required,
currently known differences between BG2/BG2CD and BG2Q are taken care of.

Patch 6 adds a clock driver for the remaining core clocks of BG2/BG2CD. The
register set dealing with it, is shared among input and bypass muxes, clock
dividers and clock gates.

Patches 7 and 8 finally convert the DT SoC include for BG2 and BG2CD to make
use of the new clock related DT nodes.

[1] https://lkml.org/lkml/2014/4/23/831
[2] https://lkml.org/lkml/2014/4/24/624
[3] https://lkml.org/lkml/2014/5/8/592
[4] https://code.google.com/p/chromecast-mirrored-source/source/browse/bootloader/berlin_tools/bootloader/clock/galois_speed.c?repo=sdk
[5] https://code.google.com/p/chromecast-mirrored-source/source/browse/bootloader/berlin_tools/bootloader/include/Firmware_Berlin_BG2CD_A0/global.h?repo=sdk

Alexandre Belloni (2):
  clk: berlin: add driver for BG2x simple PLLs
  clk: berlin: add driver for BG2x complex divider cells

Sebastian Hesselbarth (6):
  clk: add helper for unique DT clock names
  clk: berlin: add clock binding docs for Marvell Berlin2 SoCs
  clk: berlin: add driver for BG2x audio/video PLL
  clk: berlin: add core clock driver for BG2/BG2CD
  ARM: dts: berlin: convert BG2CD to DT clock nodes
  ARM: dts: berlin: convert BG2 to DT clock nodes

 .../devicetree/bindings/clock/berlin2-clock.txt    | 169 +++++++
 arch/arm/boot/dts/berlin2.dtsi                     | 200 ++++++--
 arch/arm/boot/dts/berlin2cd.dtsi                   | 198 ++++++--
 drivers/clk/Makefile                               |   1 +
 drivers/clk/berlin/Makefile                        |   3 +
 drivers/clk/berlin/berlin2-avpll.c                 | 373 +++++++++++++++
 drivers/clk/berlin/berlin2-div.c                   | 326 +++++++++++++
 drivers/clk/berlin/berlin2-div.h                   |  80 ++++
 drivers/clk/berlin/berlin2-pll.c                   | 171 +++++++
 drivers/clk/berlin/bg2.c                           | 509 +++++++++++++++++++++
 drivers/clk/clk.c                                  |  29 ++
 include/dt-bindings/clock/berlin2.h                |  35 ++
 include/linux/clk-provider.h                       |   5 +
 13 files changed, 2042 insertions(+), 57 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/berlin2-clock.txt
 create mode 100644 drivers/clk/berlin/Makefile
 create mode 100644 drivers/clk/berlin/berlin2-avpll.c
 create mode 100644 drivers/clk/berlin/berlin2-div.c
 create mode 100644 drivers/clk/berlin/berlin2-div.h
 create mode 100644 drivers/clk/berlin/berlin2-pll.c
 create mode 100644 drivers/clk/berlin/bg2.c
 create mode 100644 include/dt-bindings/clock/berlin2.h

---
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
-- 
1.9.1


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 1/8] clk: add helper for unique DT clock names
  2014-05-11 20:24 [PATCH 0/8] Marvell Berlin full clock support Sebastian Hesselbarth
@ 2014-05-11 20:24 ` Sebastian Hesselbarth
  2014-05-13 19:49   ` Mike Turquette
  2014-05-11 20:24 ` [PATCH 2/8] clk: berlin: add clock binding docs for Marvell Berlin2 SoCs Sebastian Hesselbarth
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-11 20:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Mike Turquette, Grant Likely, Rob Herring, Alexandre Belloni,
	Antoine Tenart, devicetree, linux-arm-kernel, linux-kernel

Currently, most DT clock drivers pick a unique node name to allow unique
clock names. As ePAPR recommends node names to be generic, we therefore
provide a helper to generate a unique clock name from the DT node name
plus reg property or a magic number instead. This is basically the same
we already do for proper devices and may vanish as soon as there is some
(early) device support for clocks available.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Grant Likely <grant.likely@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 drivers/clk/clk.c            | 29 +++++++++++++++++++++++++++++
 include/linux/clk-provider.h |  5 +++++
 2 files changed, 34 insertions(+)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index dff0373f53c1..b449a635dbfa 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -17,6 +17,7 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -2543,6 +2544,34 @@ const char *of_clk_get_parent_name(struct device_node *np, int index)
 }
 EXPORT_SYMBOL_GPL(of_clk_get_parent_name);
 
+/**
+ * of_clk_create_name() - Allocate and create a unique clock name
+ * @np: Device node pointer of the clock node
+ *
+ * This will allocate and create a unique clock name based on the
+ * reg property value. As a last resort, it will use the node name
+ * followed by a unique number. The caller has to deallocate the
+ * buffer.
+ */
+char *of_clk_create_name(struct device_node *np)
+{
+	static atomic_t clk_no_reg_magic;
+	const __be32 *reg;
+	u64 addr;
+	int magic;
+
+	reg = of_get_property(np, "reg", NULL);
+	if (reg) {
+		addr = of_translate_address(np, reg);
+		return kasprintf(GFP_KERNEL, "%llx.%s",
+				 (unsigned long long)addr, np->name);
+	}
+
+	magic = atomic_add_return(1, &clk_no_reg_magic);
+	return kasprintf(GFP_KERNEL, "%s.%d", np->name, magic);
+}
+EXPORT_SYMBOL_GPL(of_clk_create_name);
+
 struct clock_provider {
 	of_clk_init_cb_t clk_init_cb;
 	struct device_node *np;
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 511917416fb0..c6f3ca1cd81c 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -514,6 +514,7 @@ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
 struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
 int of_clk_get_parent_count(struct device_node *np);
 const char *of_clk_get_parent_name(struct device_node *np, int index);
+char *of_clk_create_name(struct device_node *np);
 
 void of_clk_init(const struct of_device_id *matches);
 
@@ -543,6 +544,10 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
 {
 	return NULL;
 }
+static inline char *of_clk_create_name(struct device_node *np)
+{
+	return NULL;
+}
 #define of_clk_init(matches) \
 	{ while (0); }
 #endif /* CONFIG_OF */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 2/8] clk: berlin: add clock binding docs for Marvell Berlin2 SoCs
  2014-05-11 20:24 [PATCH 0/8] Marvell Berlin full clock support Sebastian Hesselbarth
  2014-05-11 20:24 ` [PATCH 1/8] clk: add helper for unique DT clock names Sebastian Hesselbarth
@ 2014-05-11 20:24 ` Sebastian Hesselbarth
  2014-05-13  8:38   ` Sebastian Hesselbarth
                     ` (2 more replies)
  2014-05-11 20:24 ` [PATCH 3/8] clk: berlin: add driver for BG2x audio/video PLL Sebastian Hesselbarth
                   ` (6 subsequent siblings)
  8 siblings, 3 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-11 20:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Mike Turquette, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Randy Dunlap, Alexandre Belloni,
	Antoine Tenart, devicetree, linux-doc, linux-arm-kernel,
	linux-kernel

This adds mandatory device tree binding documentation for the clock related
IP found on Marvell Berlin2 (BG2, BG2CD, and BG2Q) SoCs.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
Cc: devicetree@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 .../devicetree/bindings/clock/berlin2-clock.txt    | 169 +++++++++++++++++++++
 1 file changed, 169 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/berlin2-clock.txt

diff --git a/Documentation/devicetree/bindings/clock/berlin2-clock.txt b/Documentation/devicetree/bindings/clock/berlin2-clock.txt
new file mode 100644
index 000000000000..3da87a488402
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/berlin2-clock.txt
@@ -0,0 +1,169 @@
+* Marvell Berlin2 clock bindings
+
+Marvell Berlin2 (BG2, BG2CD, BG2Q) share the same IP for PLLs and clocks,
+with some minor differences in features and register layout. The below
+describes the individual clock related IP:
+
+* Audio/Video PLL
+
+The Audio/Video PLL (AVPLL) is a dual-VCO PLL with 8 channels each. Each
+of the VCOs can sythesize a single VCO frequency based on a single input
+reference clock. Each of the 8 channels then, can derive an output clock
+from that VCO frequency by various dividers/multipliers.
+
+Required properties:
+- compatible: shall be "marvell,berlin2-avpll"
+- reg: address and length of the corresponding AVPLL registers
+- #clock-cells: shall be set to 2
+- clocks: single clock specifier referencing the AVPLL input clock
+
+To ease match-up with the desired AVPLL output clock, clock specifiers
+referencing AVPLL clocks shall contain two cells. The first refers to
+the VCO (0=AVPLL_A, 1=AVPLL_B) while the second refers to the corresponding
+channel starting with 1. For example, to reference AVPLL_B3 the clock
+specifier shall be: <&avpll 1 3>.
+
+Example:
+
+avpll: pll@ea0040 {
+	compatible = "marvell,berlin2-avpll";
+	#clock-cells = <2>;
+	reg = <0xea0050 0x100>;
+	clocks = <&refclk>;
+};
+
+* Simple PLLs
+
+Simple PLLs are memory mapped PLLs that can sythesize a single output clock
+based on a single input reference clock.
+
+Required properties:
+- compatible: shall be one of the following:
+	"marvell,berlin2-pll" for Berlin BG2/BG2CD PLLs
+	"marvell,berlin2q-pll" for Berlin BG2Q PLLs
+- reg: address and length of the corresponding PLL registers
+- #clock-cells: shall be set to 0
+- clocks: single clock specifier referencing the PLL input clock
+
+Example:
+
+cpupll: pll@ea003c {
+	compatible = "marvell,berlin2-pll";
+	#clock-cells = <0>;
+	reg = <0xea003c 0x14>;
+	clocks = <&refclk>;
+};
+
+* Single-register clock dividers
+
+Single-register clock dividers are complex divider cells, allowing
+to divide a reference clock with a set of fixed dividers. Also they
+comprise and input clock mux with bypass and an ouput clock gate.
+
+Required properties:
+- compatible: shall be "marvell,berlin2-clk-div"
+- reg: address and length of the corresponding DIV registers
+- #clock-cells: shall be set to 0
+- clocks: clock specifiers referencing the DIV input clocks
+- clock-names: array of strings describing the clock specifiers above.
+    Allowed clock-names are "mux_bypass" for the clock mux bypass selection
+    and "muxN" (N=0..7) for each of the 8 possible clock mux inputs.
+
+Example:
+
+gfx3dcore_clk: clock@ea022c {
+	compatible = "marvell,berlin2-clk-div";
+	#clock-cells = <0>;
+	reg = <0xea0022c 0x4>;
+	clocks = <&syspll>,
+		<&avpll AVPLL_B 4>, <&avpll AVPLL_B 5>,
+		<&avpll AVPLL_B 6>, <&avpll AVPLL_B 7>;
+	clock-names = "mux_bypass",
+		"mux0", "mux1", "mux2", "mux3";
+};
+
+* SoC-specific core clocks
+
+In addition to the above, there is a register set dealing with SoC
+specific clock dividers, muxes, and gates. There is also the complex
+divider cell used above, but instead of independent registers, they
+share a common set of registers. The core clocks are represented by
+a single DT node providing access to the remaining clocks.
+
+Required properties:
+- compatible: shall be one of
+	"marvell,berlin2-core-clocks" for BG2/BG2CD SoCs
+	"marvell,berlin2q-core-clocks" for BG2Q SoCs
+- reg: address and length of the corresponding clock registers
+- #clock-cells: shall be set to 1
+- clocks: clock specifiers referencing the core clock input clocks
+- clock-names: array of strings describing the clock specifiers above.
+    Allowed clock-names for the reference clocks are
+      "refclk", "syspll", "mempll", "cpupll"
+    also Audio/Video PLL clocks shall be named with
+      "avpll_VN" (V=0...1 for AVPLL_A and AVPLL_B, N=1..8 for the
+      corresponding reference input from AVPLL).
+
+Optional properties for BG2/BG2CD SoCs:
+- clocks/clock-names: in addition to the allowed clock names above,
+    there is an external video clock input that shall be named "video_ext0".
+
+Clocks provided by core clocks shall be referenced by a clock specifier
+indexing one of the provided clocks. A SoC-specific list of available clocks
+is below the example.
+
+Example:
+coreclk: clock@ea0150 {
+	compatible = "marvell,berlin2-core-clocks";
+	#clock-cells = <1>;
+	reg = <0xea0150 0x1c>;
+	clocks = <&refclk>, <&syspll>, <&mempll>, <&cpupll>,
+		<&avpll 0 1>, <&avpll 0 2>,
+		<&avpll 0 3>, <&avpll 0 4>,
+		<&avpll 0 5>, <&avpll 0 6>,
+		<&avpll 0 7>, <&avpll 0 8>,
+		<&avpll 1 1>, <&avpll 1 2>,
+		<&avpll 1 3>, <&avpll 1 4>,
+		<&avpll 1 5>, <&avpll 1 6>,
+		<&avpll 1 7>, <&avpll 1 8>,
+		<&externalvideoclk>;
+	clock-names = "refclk", "syspll", "mempll", "cpupll",
+		"avpll_a1", "avpll_a2", "avpll_a3", "avpll_a4",
+		"avpll_a5", "avpll_a6", "avpll_a7", "avpll_a8",
+		"avpll_b1", "avpll_b2", "avpll_b3", "avpll_b4",
+		"avpll_b5", "avpll_b6", "avpll_b7", "avpll_b8",
+		"video_ext0";
+};
+
+* BG2/BG2CD core clock indicies:
+0  - SYS
+1  - CPU
+2  - DRMFIGO
+3  - CFG
+4  - GFX
+5  - ZSP
+6  - PERIF
+7  - PCUBE
+8  - VSCOPE
+9  - NFC_ECC
+10 - VPP
+11 - APP
+12 - AUDIO0
+23 - AUDIO2
+14 - AUDIO3
+15 - AUDIO1
+16 - GETH0
+17 - GETH1
+18 - SATA
+19 - AHBAPB
+20 - USB0
+21 - USB1
+22 - PBRIDGE
+23 - SDIO0
+24 - SDIO1
+25 - NFC
+26 - SMEMC
+27 - AUDIOHD
+28 - VIDEO0
+29 - VIDEO1
+30 - VIDEO2
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 3/8] clk: berlin: add driver for BG2x audio/video PLL
  2014-05-11 20:24 [PATCH 0/8] Marvell Berlin full clock support Sebastian Hesselbarth
  2014-05-11 20:24 ` [PATCH 1/8] clk: add helper for unique DT clock names Sebastian Hesselbarth
  2014-05-11 20:24 ` [PATCH 2/8] clk: berlin: add clock binding docs for Marvell Berlin2 SoCs Sebastian Hesselbarth
@ 2014-05-11 20:24 ` Sebastian Hesselbarth
  2014-05-11 20:24 ` [PATCH 4/8] clk: berlin: add driver for BG2x simple PLLs Sebastian Hesselbarth
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-11 20:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Alexandre Belloni, Mike Turquette, Antoine Tenart,
	linux-arm-kernel, linux-kernel

This is a driver for the dual-VCO PLL with 8 channels each found on
Marvell Berlin2 SoCs. While both VCOs share the same register set,
sometimes registers shifts for one of the VCOs is a bit off. Nothing
serious that should require a separate driver, so deal with both VCOs
in a single driver instead.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 drivers/clk/Makefile               |   1 +
 drivers/clk/berlin/Makefile        |   1 +
 drivers/clk/berlin/berlin2-avpll.c | 373 +++++++++++++++++++++++++++++++++++++
 3 files changed, 375 insertions(+)
 create mode 100644 drivers/clk/berlin/Makefile
 create mode 100644 drivers/clk/berlin/berlin2-avpll.c

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 5f8a28735c96..f651b2ace915 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_COMMON_CLK_WM831X)		+= clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_XGENE)		+= clk-xgene.o
 obj-$(CONFIG_COMMON_CLK_AT91)		+= at91/
 obj-$(CONFIG_ARCH_BCM_MOBILE)		+= bcm/
+obj-$(CONFIG_ARCH_BERLIN)		+= berlin/
 obj-$(CONFIG_ARCH_HI3xxx)		+= hisilicon/
 obj-$(CONFIG_ARCH_HIP04)		+= hisilicon/
 obj-$(CONFIG_COMMON_CLK_KEYSTONE)	+= keystone/
diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile
new file mode 100644
index 000000000000..5905733fc7c7
--- /dev/null
+++ b/drivers/clk/berlin/Makefile
@@ -0,0 +1 @@
+obj-y += berlin2-avpll.o
diff --git a/drivers/clk/berlin/berlin2-avpll.c b/drivers/clk/berlin/berlin2-avpll.c
new file mode 100644
index 000000000000..1216e3c3d2ed
--- /dev/null
+++ b/drivers/clk/berlin/berlin2-avpll.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+/*
+ * Berlin2 AVPLL comprises two PLLs (VCOs) with 8 channels each,
+ * channel 8 is the odd-one-out and does not provide mul/div.
+ *
+ * Unfortunately, its registers are just numbered from 0-63. To
+ * get in at least some kind of structure, we split both VCOs and
+ * each of the channels into separate clock drivers.
+ *
+ * Also, here and there the VCO registers are a bit different with
+ * respect to bit shifts. Make sure to add a comment for those.
+ */
+#define NUM_VCOS	2
+#define NUM_CHANNELS	8
+
+#define AVPLL_CTRL(x)		((x) * 0x4)
+/* Second VCO starts at AVPLL_CTRL31 */
+#define VCO_OFFSET		AVPLL_CTRL(31)
+
+#define VCO_CTRL0		AVPLL_CTRL(0)
+/* VCO_B has an additional shift of 4 for its VCO_CTRL0 reg */
+#define  VCO_RESET		BIT(0)
+#define  VCO_POWERUP		BIT(1)
+#define  VCO_INTERPOL_SHIFT	2
+#define  VCO_INTERPOL_MASK	(0xf << VCO_INTERPOL_SHIFT)
+#define  VCO_REG1V45_SEL_SHIFT	6
+#define  VCO_REG1V45_SEL(x)	((x) << VCO_REG1V45_SEL_SHIFT)
+#define  VCO_REG1V45_SEL_1V40	VCO_REG1V45_SEL(0)
+#define  VCO_REG1V45_SEL_1V45	VCO_REG1V45_SEL(1)
+#define  VCO_REG1V45_SEL_1V50	VCO_REG1V45_SEL(2)
+#define  VCO_REG1V45_SEL_1V55	VCO_REG1V45_SEL(3)
+#define  VCO_REG1V45_SEL_MASK	VCO_REG1V45_SEL(3)
+#define  VCO_REG0V9_SEL_SHIFT	8
+#define  VCO_REG0V9_SEL_MASK	(0xf << VCO_REG0V9_SEL_SHIFT)
+#define  VCO_VTHCAL_SHIFT	12
+#define  VCO_VTHCAL(x)		((x) << VCO_VTHCAL_SHIFT)
+#define  VCO_VTHCAL_0V90	VCO_VTHCAL(0)
+#define  VCO_VTHCAL_0V95	VCO_VTHCAL(1)
+#define  VCO_VTHCAL_1V00	VCO_VTHCAL(2)
+#define  VCO_VTHCAL_1V05	VCO_VTHCAL(3)
+#define  VCO_VTHCAL_MASK	VCO_VTHCAL(3)
+#define  VCO_KVCOEXT_SHIFT	14
+#define  VCO_KVCOEXT_MASK	(0x3 << VCO_KVCOEXT_SHIFT)
+#define  VCO_KVCOEXT_ENABLE	BIT(17)
+#define  VCO_V2IEXT_SHIFT	18
+#define  VCO_V2IEXT_MASK	(0xf << VCO_V2IEXT_SHIFT)
+#define  VCO_V2IEXT_ENABLE	BIT(22)
+#define  VCO_SPEED_SHIFT	23
+#define  VCO_SPEED(x)		((x) << VCO_SPEED_SHIFT)
+#define  VCO_SPEED_1G08_1G21	VCO_SPEED(0)
+#define  VCO_SPEED_1G21_1G40	VCO_SPEED(1)
+#define  VCO_SPEED_1G40_1G61	VCO_SPEED(2)
+#define  VCO_SPEED_1G61_1G86	VCO_SPEED(3)
+#define  VCO_SPEED_1G86_2G00	VCO_SPEED(4)
+#define  VCO_SPEED_2G00_2G22	VCO_SPEED(5)
+#define  VCO_SPEED_2G22		VCO_SPEED(6)
+#define  VCO_SPEED_MASK		VCO_SPEED(0x7)
+#define  VCO_CLKDET_ENABLE	BIT(26)
+#define VCO_CTRL1		AVPLL_CTRL(1)
+#define  VCO_REFDIV_SHIFT	0
+#define  VCO_REFDIV(x)		((x) << VCO_REFDIV_SHIFT)
+#define  VCO_REFDIV_1		VCO_REFDIV(0)
+#define  VCO_REFDIV_2		VCO_REFDIV(1)
+#define  VCO_REFDIV_4		VCO_REFDIV(2)
+#define  VCO_REFDIV_3		VCO_REFDIV(3)
+#define  VCO_REFDIV_MASK	VCO_REFDIV(0x3f)
+#define  VCO_FBDIV_SHIFT	6
+#define  VCO_FBDIV(x)		((x) << VCO_FBDIV_SHIFT)
+#define  VCO_FBDIV_MASK		VCO_FBDIV(0xff)
+#define  VCO_ICP_SHIFT		14
+/* PLL Charge Pump Current = 10uA * (x + 1) */
+#define  VCO_ICP(x)		((x) << VCO_ICP_SHIFT)
+#define  VCO_ICP_MASK		VCO_ICP(0xf)
+#define  VCO_LOAD_CAP		BIT(18)
+#define  VCO_CALIBRATION_START	BIT(19)
+#define VCO_FREQOFFSETn(x)	AVPLL_CTRL(3 + (x))
+#define  VCO_FREQOFFSET_MASK	0x7ffff
+#define VCO_CTRL11		AVPLL_CTRL(11)
+#define VCO_CTRL12		AVPLL_CTRL(12)
+#define VCO_CTRL13		AVPLL_CTRL(13)
+#define VCO_CTRL14		AVPLL_CTRL(14)
+#define VCO_CTRL15		AVPLL_CTRL(15)
+#define VCO_SYNC1n(x)		AVPLL_CTRL(15 + (x))
+#define  VCO_SYNC1_MASK		0x1ffff
+#define VCO_SYNC2n(x)		AVPLL_CTRL(23 + (x))
+#define  VCO_SYNC2_MASK		0x1ffff
+#define VCO_CTRL30		AVPLL_CTRL(30)
+#define  VCO_DPLL_CH1_ENABLE	BIT(17)
+
+struct avpll_vco;
+struct avpll;
+
+struct avpll_channel {
+	struct clk_hw hw;
+	struct avpll_vco *vco;
+	u8 index;
+};
+
+struct avpll_vco {
+	struct clk_hw hw;
+	struct avpll_channel channel[NUM_CHANNELS];
+	struct clk *clks[NUM_CHANNELS];
+	void __iomem *base;
+	struct avpll *pll;
+	u8 index;
+};
+
+struct avpll {
+	struct avpll_vco vco[NUM_VCOS];
+	void __iomem *base;
+};
+
+#define to_avpll_vco(hw) container_of(hw, struct avpll_vco, hw)
+#define to_avpll_channel(hw) container_of(hw, struct avpll_channel, hw)
+
+static u8 vco_refdiv[] = { 1, 2, 4, 3 };
+
+static unsigned long
+avpll_vco_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct avpll_vco *vco = to_avpll_vco(hw);
+	u32 reg, refdiv;
+	u64 freq;
+
+	/* AVPLL VCO frequency: Fvco = (Fref / refdiv) * FBdiv */
+	reg = readl_relaxed(vco->base + VCO_CTRL1);
+	refdiv = (reg & VCO_REFDIV_MASK) >> VCO_REFDIV_SHIFT;
+	refdiv = vco_refdiv[refdiv];
+	freq = (reg & VCO_FBDIV_MASK) >> VCO_FBDIV_SHIFT;
+	freq *= parent_rate;
+	do_div(freq, refdiv);
+
+	return (unsigned long)freq;
+}
+
+static const struct clk_ops avpll_vco_ops = {
+	.recalc_rate	= avpll_vco_recalc_rate,
+};
+
+static const u8 div_hdmi[] = { 1, 2, 4, 6 };
+static const u8 div_av1[] = { 1, 2, 5, 5 };
+
+static unsigned long
+avpll_channel_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct avpll_channel *ch = to_avpll_channel(hw);
+	struct avpll_vco *vco = ch->vco;
+	u32 reg, divider = 1;
+	u64 freq = parent_rate;
+
+	reg = readl_relaxed(vco->base + VCO_CTRL30);
+	if ((reg & (VCO_DPLL_CH1_ENABLE << ch->index)) == 0)
+		goto skip_div;
+
+	/*
+	 * Fch = (Fref * sync2) /
+	 *    (sync1 * div_hdmi * div_av1 * div_av2 * div_av3)
+	 */
+
+	reg = readl_relaxed(vco->base + VCO_SYNC1n(ch->index));
+	/* SYNC1 for Channel 1 is shifted by 4 bits */
+	if (ch->index == 0)
+		reg >>= 4;
+	divider = reg & VCO_SYNC1_MASK;
+
+	reg = readl_relaxed(vco->base + VCO_SYNC2n(ch->index));
+	freq *= reg & VCO_SYNC2_MASK;
+
+	/* Channel 8 has no dividers */
+	if (ch->index == 7)
+		goto skip_div;
+
+	/*
+	 * HDMI divider start at VCO_CTRL11, bit 7; each 3 bits wide but
+	 * only 0-3 are valid values.
+	 */
+	reg = readl_relaxed(vco->base + VCO_CTRL11) >> 7;
+	divider *= div_hdmi[(reg >> (ch->index * 3)) & 0x3];
+
+	/*
+	 * AV1 divider start at VCO_CTRL11, bit 28; each 3 bits wide but
+	 * only 0-3 are valid values.
+	 */
+	if (ch->index == 0) {
+		reg = readl_relaxed(vco->base + VCO_CTRL11);
+		reg >>= 28;
+	} else {
+		reg = readl_relaxed(vco->base + VCO_CTRL12);
+		reg >>= (ch->index-1) * 3;
+	}
+	divider *= div_av1[reg & 0x3];
+
+	/*
+	 * AV2 divider start at VCO_CTRL12, bit 18; each 7 bits wide,
+	 * zero is not a valid value.
+	 */
+	if (ch->index < 2) {
+		reg = readl_relaxed(vco->base + VCO_CTRL12);
+		reg >>= 18 + (ch->index * 7);
+	} else if (ch->index < 7) {
+		reg = readl_relaxed(vco->base + VCO_CTRL13);
+		reg >>= (ch->index - 2) * 7;
+	} else {
+		reg = readl_relaxed(vco->base + VCO_CTRL14);
+	}
+
+	reg &= 0x7f;
+	if (reg)
+		divider *= reg;
+
+	/*
+	 * AV3 divider start at VCO_CTRL14, bit 7; each 4 bits wide,
+	 * only 0, 1 are valid values. AV3=1 divides by 1/2, AV3=0 is bypass.
+	 */
+	if (ch->index < 6) {
+		reg = readl_relaxed(vco->base + VCO_CTRL14);
+		reg >>= 7 + (ch->index * 4);
+	} else {
+		reg = readl_relaxed(vco->base + VCO_CTRL15);
+	}
+
+	if (reg & 0x1)
+		freq *= 2;
+
+skip_div:
+	do_div(freq, divider);
+	return (unsigned long)freq;
+}
+
+static const struct clk_ops avpll_channel_ops = {
+	.recalc_rate	= avpll_channel_recalc_rate,
+};
+
+/*
+ * Another nice quirk: on production SoC revisions, AVPLL_B outputs
+ * are scrambled. Use a translation table to deal with it.
+ */
+static const u8 avpllb_channel_map[] = { 0, 6, 5, 4, 3, 2, 1, 7 };
+
+struct clk *avpll_src_get(struct of_phandle_args *clkspec, void *data)
+{
+	struct avpll *pll = data;
+	unsigned int vco = clkspec->args[0];
+	unsigned int ch = clkspec->args[1] - 1;
+
+	if (vco > NUM_VCOS || ch > NUM_CHANNELS) {
+		pr_err("%s: invalid clock index %d.%d\n",
+		       __func__, vco, ch);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (vco == 1)
+		ch = avpllb_channel_map[ch];
+
+	return pll->vco[vco].clks[ch];
+}
+
+static void __init avpll_of_setup(struct device_node *np)
+{
+	struct avpll *pll;
+	struct clk_init_data init;
+	struct clk *refclk;
+	const char *refclk_name;
+	char *pll_name = NULL;
+	int nvco, nch;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return;
+
+	pll->base = of_iomap(np, 0);
+	if (!pll->base) {
+		pr_err("%s: Unable to map pll register\n", np->full_name);
+		kfree(pll);
+		return;
+	}
+
+	refclk = of_clk_get(np, 0);
+	if (IS_ERR(refclk)) {
+		pr_err("%s: Missing reference clock\n", np->full_name);
+		goto avpll_fail;
+	}
+	refclk_name = __clk_get_name(refclk);
+	clk_put(refclk);
+
+	pll_name = of_clk_create_name(np);
+
+	for (nvco = 0; nvco < NUM_VCOS; nvco++) {
+		struct avpll_vco *vco = &pll->vco[nvco];
+		const char *vco_name =
+			kasprintf(GFP_KERNEL, "%s.vco%d", pll_name, nvco);
+		struct clk *clk;
+
+		init.name = vco_name;
+		init.ops = &avpll_vco_ops;
+		init.parent_names = &refclk_name;
+		init.num_parents = 1;
+		init.flags = 0;
+
+		vco->hw.init = &init;
+		vco->base = pll->base + (nvco * VCO_OFFSET);
+		vco->pll = pll;
+		vco->index = nvco;
+
+		clk = clk_register(NULL, &vco->hw);
+		kfree(vco_name);
+		if (IS_ERR(clk)) {
+			pr_err("%s: Unable to register vco %d\n",
+			       np->full_name, nvco);
+			goto avpll_fail;
+		}
+		vco_name = __clk_get_name(clk);
+
+		for (nch = 0; nch < NUM_CHANNELS; nch++) {
+			struct avpll_channel *ch = &vco->channel[nch];
+			char *ch_name = kasprintf(GFP_KERNEL,
+						  "%s.%d", vco_name, nch);
+
+			init.name = ch_name;
+			init.ops = &avpll_channel_ops;
+			init.parent_names = &vco_name;
+			init.num_parents = 1;
+			init.flags = CLK_SET_RATE_PARENT;
+
+			ch->hw.init = &init;
+			ch->vco = vco;
+			ch->index = nch;
+
+			clk = clk_register(NULL, &ch->hw);
+			kfree(ch_name);
+			if (IS_ERR(clk)) {
+				pr_err("%s: Unable to register channel %d.%d\n",
+				       np->full_name, nvco, nch);
+				goto avpll_fail;
+			}
+			vco->clks[nch] = clk;
+		}
+	}
+
+	of_clk_add_provider(np, avpll_src_get, pll);
+	kfree(pll_name);
+	return;
+
+avpll_fail:
+	kfree(pll_name);
+	iounmap(pll->base);
+	kfree(pll);
+}
+CLK_OF_DECLARE(berlin2_avpll, "marvell,berlin2-avpll", avpll_of_setup);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 4/8] clk: berlin: add driver for BG2x simple PLLs
  2014-05-11 20:24 [PATCH 0/8] Marvell Berlin full clock support Sebastian Hesselbarth
                   ` (2 preceding siblings ...)
  2014-05-11 20:24 ` [PATCH 3/8] clk: berlin: add driver for BG2x audio/video PLL Sebastian Hesselbarth
@ 2014-05-11 20:24 ` Sebastian Hesselbarth
  2014-05-11 20:24 ` [PATCH 5/8] clk: berlin: add driver for BG2x complex divider cells Sebastian Hesselbarth
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-11 20:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Alexandre Belloni, Mike Turquette, Antoine Tenart,
	linux-arm-kernel, linux-kernel

From: Alexandre Belloni <alexandre.belloni@free-electrons.com>

This is a clock driver for the simple PLLs found on Berlin SoCs.
With repect to PLL registers and features, BG2/BG2CD and BG2Q are
slightly different, e.g. different allowed VCO dividers and bit
shifts.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 drivers/clk/berlin/Makefile      |   2 +-
 drivers/clk/berlin/berlin2-pll.c | 171 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 172 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/berlin/berlin2-pll.c

diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile
index 5905733fc7c7..9d3490e9782f 100644
--- a/drivers/clk/berlin/Makefile
+++ b/drivers/clk/berlin/Makefile
@@ -1 +1 @@
-obj-y += berlin2-avpll.o
+obj-y += berlin2-avpll.o berlin2-pll.o
diff --git a/drivers/clk/berlin/berlin2-pll.c b/drivers/clk/berlin/berlin2-pll.c
new file mode 100644
index 000000000000..ca2805fffdf2
--- /dev/null
+++ b/drivers/clk/berlin/berlin2-pll.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+
+struct berlin2_pll_map {
+	const u8 vcodiv[16];
+	u8 mult;
+	u8 fbdiv_shift;
+	u8 rfdiv_shift;
+	u8 divsel_shift;
+};
+
+struct berlin2_pll {
+	struct clk_hw hw;
+	void __iomem *base;
+	struct berlin2_pll_map map;
+};
+
+#define to_berlin2_pll(hw) container_of(hw, struct berlin2_pll, hw)
+
+#define SPLL_CTRL0	0x00
+#define SPLL_CTRL1	0x04
+#define SPLL_CTRL2	0x08
+#define SPLL_CTRL3	0x0c
+#define SPLL_CTRL4	0x10
+
+#define FBDIV_MASK	0x1ff
+#define RFDIV_MASK	0x1f
+#define DIVSEL_MASK	0xf
+
+/*
+ * The output frequency formula for the pll is:
+ * clkout = fbdiv / refdiv * parent / vcodiv
+ */
+static unsigned long
+berlin2_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct berlin2_pll *pll = to_berlin2_pll(hw);
+	struct berlin2_pll_map *map = &pll->map;
+	u32 val, fbdiv, rfdiv, vcodivsel, vcodiv;
+	u64 rate = parent_rate;
+
+	val = readl_relaxed(pll->base + SPLL_CTRL0);
+	fbdiv = (val >> map->fbdiv_shift) & FBDIV_MASK;
+	rfdiv = (val >> map->rfdiv_shift) & RFDIV_MASK;
+	if (rfdiv == 0) {
+		pr_warn("%s has zero rfdiv\n", __clk_get_name(hw->clk));
+		rfdiv = 1;
+	}
+
+	val = readl_relaxed(pll->base + SPLL_CTRL1);
+	vcodivsel = (val >> map->divsel_shift) & DIVSEL_MASK;
+	vcodiv = map->vcodiv[vcodivsel];
+	if (vcodiv == 0) {
+		pr_warn("%s has zero vcodiv (index %d)\n",
+			__clk_get_name(hw->clk), vcodivsel);
+		vcodiv = 1;
+	}
+
+	rate *= fbdiv * map->mult;
+	do_div(rate, rfdiv * vcodiv);
+
+	return (unsigned long)rate;
+}
+
+static const struct clk_ops berlin2_pll_ops = {
+	.recalc_rate	= berlin2_pll_recalc_rate,
+};
+
+static struct clk * __init
+berlin2_pll_register(const struct berlin2_pll_map *map,
+		     void __iomem *base, const char *name,
+		     const char *parent_name, unsigned long flags)
+{
+	struct clk_init_data init;
+	struct berlin2_pll *pll;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	/* copy pll_map to allow __initconst */
+	memcpy(&pll->map, map, sizeof(*map));
+	pll->base = base;
+	pll->hw.init = &init;
+	init.name = name;
+	init.ops = &berlin2_pll_ops;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+	init.flags = flags;
+
+	return clk_register(NULL, &pll->hw);
+}
+
+static const struct berlin2_pll_map bg2_pll_map __initconst = {
+	.vcodiv		= {10, 15, 20, 25, 30, 40, 50, 60, 80},
+	.mult		= 10,
+	.fbdiv_shift	= 6,
+	.rfdiv_shift	= 1,
+	.divsel_shift	= 7,
+};
+
+static const struct berlin2_pll_map bg2q_pll_map __initconst = {
+	.vcodiv		= {1, 0, 2, 0, 3, 4, 0, 6, 8},
+	.mult		= 1,
+	.fbdiv_shift	= 7,
+	.rfdiv_shift	= 2,
+	.divsel_shift	= 9,
+};
+
+static const struct of_device_id pll_matches[] __initconst = {
+	{ .compatible = "marvell,berlin2-pll", .data = &bg2_pll_map },
+	{ .compatible = "marvell,berlin2q-pll", .data = &bg2q_pll_map },
+	{ }
+};
+
+static void __init berlin2_pll_of_setup(struct device_node *np)
+{
+	const struct of_device_id *match = of_match_node(pll_matches, np);
+	const struct berlin2_pll_map *map = match->data;
+	void __iomem *base;
+	struct clk *refclk;
+	struct clk *pll;
+	char *pll_name;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("%s: Unable to map pll register\n", np->full_name);
+		return;
+	}
+
+	refclk = of_clk_get(np, 0);
+	if (IS_ERR(refclk)) {
+		pr_err("%s: Missing reference clock\n", np->full_name);
+		iounmap(base);
+		return;
+	}
+
+	pll_name = of_clk_create_name(np);
+	pll = berlin2_pll_register(map, base, pll_name,
+				   __clk_get_name(refclk), 0);
+	if (!IS_ERR(pll))
+		of_clk_add_provider(np, of_clk_src_simple_get, pll);
+
+	clk_put(refclk);
+	kfree(pll_name);
+}
+CLK_OF_DECLARE(berlin2_pll, "marvell,berlin2-pll", berlin2_pll_of_setup);
+CLK_OF_DECLARE(berlin2q_pll, "marvell,berlin2q-pll", berlin2_pll_of_setup);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 5/8] clk: berlin: add driver for BG2x complex divider cells
  2014-05-11 20:24 [PATCH 0/8] Marvell Berlin full clock support Sebastian Hesselbarth
                   ` (3 preceding siblings ...)
  2014-05-11 20:24 ` [PATCH 4/8] clk: berlin: add driver for BG2x simple PLLs Sebastian Hesselbarth
@ 2014-05-11 20:24 ` Sebastian Hesselbarth
  2014-05-13  8:40   ` Sebastian Hesselbarth
  2014-05-11 20:24 ` [PATCH 6/8] clk: berlin: add core clock driver for BG2/BG2CD Sebastian Hesselbarth
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-11 20:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Alexandre Belloni, Mike Turquette, Antoine Tenart,
	linux-arm-kernel, linux-kernel

From: Alexandre Belloni <alexandre.belloni@free-electrons.com>

This is a driver for the complex divider cells found on Marvell Berlin2
SoCs. The cells come in two flavors: single register cells and shared
register cells. The single register cells are registered by using a DT
node, while the shared ones will be taken care of in a SoC-specific
core clock driver.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 drivers/clk/berlin/Makefile      |   2 +-
 drivers/clk/berlin/berlin2-div.c | 326 +++++++++++++++++++++++++++++++++++++++
 drivers/clk/berlin/berlin2-div.h |  80 ++++++++++
 3 files changed, 407 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/berlin/berlin2-div.c
 create mode 100644 drivers/clk/berlin/berlin2-div.h

diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile
index 9d3490e9782f..f0a7dc8b5e30 100644
--- a/drivers/clk/berlin/Makefile
+++ b/drivers/clk/berlin/Makefile
@@ -1 +1 @@
-obj-y += berlin2-avpll.o berlin2-pll.o
+obj-y += berlin2-avpll.o berlin2-pll.o berlin2-div.o
diff --git a/drivers/clk/berlin/berlin2-div.c b/drivers/clk/berlin/berlin2-div.c
new file mode 100644
index 000000000000..96513a6e8ca7
--- /dev/null
+++ b/drivers/clk/berlin/berlin2-div.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "berlin2-div.h"
+
+/*
+ * Clock dividers in Berlin2 SoCs comprise a complex cell to select
+ * input pll and divider. The virtual structure as it is used in Marvell
+ * BSP code can be seen as:
+ *
+ *                      +---+
+ * pll0 --------------->| 0 |                   +---+
+ *           +---+      |(B)|--+--------------->| 0 |      +---+
+ * pll1.0 -->| 0 |  +-->| 1 |  |   +--------+   |(E)|----->| 0 |   +---+
+ * pll1.1 -->| 1 |  |   +---+  +-->|(C) 1:M |-->| 1 |      |(F)|-->|(G)|->
+ * ...    -->|(A)|--+          |   +--------+   +---+  +-->| 1 |   +---+
+ * ...    -->|   |             +-->|(D) 1:3 |----------+   +---+
+ * pll1.N -->| N |                 +---------
+ *           +---+
+ *
+ * (A) input pll clock mux controlled by               <PllSelect[1:n]>
+ * (B) input pll bypass mux controlled by              <PllSwitch>
+ * (C) programmable clock divider controlled by        <Select[1:n]>
+ * (D) constant div-by-3 clock divider
+ * (E) programmable clock divider bypass controlled by <Switch>
+ * (F) constant div-by-3 clock mux controlled by       <D3Switch>
+ * (G) clock gate controlled by                        <Enable>
+ *
+ * For whatever reason, above control signals come in two flavors:
+ * - single register dividers with all bits in one register
+ * - shared register dividers with bits spread over multiple registers
+ *   (including signals for the same cell spread over consecutive registers)
+ *
+ * Also, clock gate and pll mux is not available on every div cell, so
+ * we have to deal with those, too. We reuse common clock composite driver
+ * for it.
+ */
+
+#define PLL_SELECT_MASK	0x7
+#define DIV_SELECT_MASK	0x7
+
+struct berlin2_div {
+	struct clk_hw hw;
+	void __iomem *base;
+	struct berlin2_div_map map;
+	spinlock_t *lock;
+};
+
+#define to_berlin2_div(hw) container_of(hw, struct berlin2_div, hw)
+
+static u8 clk_div[] = { 1, 2, 4, 6, 8, 12, 1, 1 };
+
+static int berlin2_div_is_enabled(struct clk_hw *hw)
+{
+	struct berlin2_div *div = to_berlin2_div(hw);
+	struct berlin2_div_map *map = &div->map;
+	u32 reg;
+
+	if (div->lock)
+		spin_lock(div->lock);
+
+	reg = readl_relaxed(div->base + map->gate_offs);
+	reg >>= map->gate_shift;
+
+	if (div->lock)
+		spin_unlock(div->lock);
+
+	return (reg & 0x1);
+}
+
+static int berlin2_div_enable(struct clk_hw *hw)
+{
+	struct berlin2_div *div = to_berlin2_div(hw);
+	struct berlin2_div_map *map = &div->map;
+	u32 reg;
+
+	if (div->lock)
+		spin_lock(div->lock);
+
+	reg = readl_relaxed(div->base + map->gate_offs);
+	reg |= BIT(map->gate_shift);
+	writel_relaxed(reg, div->base + map->gate_offs);
+
+	if (div->lock)
+		spin_unlock(div->lock);
+
+	return 0;
+}
+
+static void berlin2_div_disable(struct clk_hw *hw)
+{
+	struct berlin2_div *div = to_berlin2_div(hw);
+	struct berlin2_div_map *map = &div->map;
+	u32 reg;
+
+	if (div->lock)
+		spin_lock(div->lock);
+
+	reg = readl_relaxed(div->base + map->gate_offs);
+	reg &= ~BIT(map->gate_shift);
+	writel_relaxed(reg, div->base + map->gate_offs);
+
+	if (div->lock)
+		spin_unlock(div->lock);
+}
+
+static int berlin2_div_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct berlin2_div *div = to_berlin2_div(hw);
+	struct berlin2_div_map *map = &div->map;
+	u32 reg;
+
+	if (div->lock)
+		spin_lock(div->lock);
+
+	/* index == 0 is PLL_SWITCH */
+	reg = readl_relaxed(div->base + map->pll_switch_offs);
+	if (index == 0)
+		reg &= ~BIT(map->pll_switch_shift);
+	else
+		reg |= BIT(map->pll_switch_shift);
+	writel_relaxed(reg, div->base + map->pll_switch_offs);
+
+	/* index > 0 is PLL_SELECT */
+	if (index > 0) {
+		reg = readl_relaxed(div->base + map->pll_select_offs);
+		reg &= ~(PLL_SELECT_MASK << map->pll_select_shift);
+		reg |= (index - 1) << map->pll_select_shift;
+		writel_relaxed(reg, div->base + map->pll_select_offs);
+	}
+
+	if (div->lock)
+		spin_unlock(div->lock);
+
+	return 0;
+}
+
+static u8 berlin2_div_get_parent(struct clk_hw *hw)
+{
+	struct berlin2_div *div = to_berlin2_div(hw);
+	struct berlin2_div_map *map = &div->map;
+	u32 reg;
+	u8 index = 0;
+
+	if (div->lock)
+		spin_lock(div->lock);
+
+	/* PLL_SWITCH == 0 is index 0 */
+	reg = readl_relaxed(div->base + map->pll_switch_offs);
+	reg &= BIT(map->pll_switch_shift);
+	if (reg) {
+		reg = readl_relaxed(div->base + map->pll_select_offs);
+		reg >>= map->pll_select_shift;
+		reg &= PLL_SELECT_MASK;
+		index = 1 + reg;
+	}
+
+	if (div->lock)
+		spin_unlock(div->lock);
+
+	return index;
+}
+
+static unsigned long berlin2_div_recalc_rate(struct clk_hw *hw,
+					     unsigned long parent_rate)
+{
+	struct berlin2_div *div = to_berlin2_div(hw);
+	struct berlin2_div_map *map = &div->map;
+	u32 divsw, div3sw, divider = 1;
+
+	if (div->lock)
+		spin_lock(div->lock);
+
+	divsw = readl_relaxed(div->base + map->div_switch_offs) &
+		(1 << map->div_switch_shift);
+	div3sw = readl_relaxed(div->base + map->div3_switch_offs) &
+		(1 << map->div3_switch_shift);
+
+	/* constant divide-by-3 (dominant) */
+	if (div3sw == 1) {
+		divider = 3;
+	/* divider can be bypassed with DIV_SWITCH == 0 */
+	} else if (divsw == 0) {
+		divider = 1;
+	/* clock divider determined by DIV_SELECT */
+	} else {
+		u32 reg;
+		reg = readl_relaxed(div->base + map->div_select_offs);
+		reg >>= map->div_select_shift;
+		reg &= DIV_SELECT_MASK;
+		divider = clk_div[reg];
+	}
+
+	if (div->lock)
+		spin_unlock(div->lock);
+
+	return parent_rate / divider;
+}
+
+static const struct clk_ops berlin2_div_rate_ops = {
+	.recalc_rate	= berlin2_div_recalc_rate,
+};
+
+static const struct clk_ops berlin2_div_gate_ops = {
+	.is_enabled	= berlin2_div_is_enabled,
+	.enable		= berlin2_div_enable,
+	.disable	= berlin2_div_disable,
+};
+
+static const struct clk_ops berlin2_div_mux_ops = {
+	.set_parent	= berlin2_div_set_parent,
+	.get_parent	= berlin2_div_get_parent,
+};
+
+struct clk * __init
+berlin2_div_register(const struct berlin2_div_map *map,
+		     void __iomem *base, const char *name, u8 div_flags,
+		     const char **parent_names, int num_parents,
+		     unsigned long flags, spinlock_t *lock)
+{
+	const struct clk_ops *mux_ops = &berlin2_div_mux_ops;
+	const struct clk_ops *rate_ops = &berlin2_div_rate_ops;
+	const struct clk_ops *gate_ops = &berlin2_div_gate_ops;
+	struct berlin2_div *div;
+
+	div = kzalloc(sizeof(*div), GFP_KERNEL);
+	if (!div)
+		return ERR_PTR(-ENOMEM);
+
+	/* copy div_map to allow __initconst */
+	memcpy(&div->map, map, sizeof(*map));
+	div->base = base;
+	div->lock = lock;
+
+	if ((div_flags & BERLIN2_DIV_HAS_GATE) == 0)
+		gate_ops = NULL;
+	if ((div_flags & BERLIN2_DIV_HAS_MUX) == 0)
+		mux_ops = NULL;
+
+	return clk_register_composite(NULL, name, parent_names, num_parents,
+				      &div->hw, mux_ops, &div->hw, rate_ops,
+				      &div->hw, gate_ops, flags);
+}
+
+static const struct berlin2_div_map berlin2_single_div_map __initconst = {
+	.gate_offs = 0,
+	.gate_shift = 0,
+	.pll_select_offs = 0,
+	.pll_select_shift = 1,
+	.pll_switch_offs = 0,
+	.pll_switch_shift = 4,
+	.div_switch_offs = 0,
+	.div_switch_shift = 5,
+	.div3_switch_offs = 0,
+	.div3_switch_shift = 6,
+	.div_select_offs = 0,
+	.div_select_shift = 7,
+};
+
+static void __init berlin2_div_of_setup(struct device_node *np)
+{
+	const char *parent_names[9] = {};
+	char *mux_name = "mux0";
+	int num_parents = 0;
+	void __iomem *base;
+	struct clk *iclk;
+	struct clk *div;
+	char *div_name;
+	int n;
+
+	iclk = of_clk_get_by_name(np, "mux_bypass");
+	if (IS_ERR(iclk)) {
+		pr_err("%s: Missing mux bypass clock\n", np->full_name);
+		return;
+	}
+	parent_names[0] = __clk_get_name(iclk);
+	clk_put(iclk);
+
+	/* collect mux input clock names */
+	for (n = 0; n < 8; n++) {
+		sprintf(mux_name, "mux%d", n);
+		iclk = of_clk_get_by_name(np, mux_name);
+		if (IS_ERR(iclk))
+			continue;
+		parent_names[1 + n] = __clk_get_name(iclk);
+		clk_put(iclk);
+	}
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("%s: Unable to map div register\n", np->full_name);
+		return;
+	}
+
+	div_name = of_clk_create_name(np);
+	div = berlin2_div_register(&berlin2_single_div_map, base, div_name,
+				   BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+				   parent_names, num_parents, 0, NULL);
+	if (!IS_ERR(div))
+		of_clk_add_provider(np, of_clk_src_simple_get, div);
+
+	kfree(div_name);
+}
+CLK_OF_DECLARE(berlin2_div, "marvell,berlin2-div", berlin2_div_of_setup);
diff --git a/drivers/clk/berlin/berlin2-div.h b/drivers/clk/berlin/berlin2-div.h
new file mode 100644
index 000000000000..344865181712
--- /dev/null
+++ b/drivers/clk/berlin/berlin2-div.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __BERLIN2_DIV_H
+#define __BERLIN2_DIV_H
+
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+
+#define BERLIN2_DIV_HAS_GATE	BIT(0)
+#define BERLIN2_DIV_HAS_MUX	BIT(1)
+
+#define BERLIN2_PLL_SELECT(_off, _sh)	\
+	.pll_select_offs = _off,	\
+	.pll_select_shift = _sh
+
+#define BERLIN2_PLL_SWITCH(_off, _sh)	\
+	.pll_switch_offs = _off,	\
+	.pll_switch_shift = _sh
+
+#define BERLIN2_DIV_SELECT(_off, _sh)	\
+	.div_select_offs = _off,	\
+	.div_select_shift = _sh
+
+#define BERLIN2_DIV_SWITCH(_off, _sh)	\
+	.div_switch_offs = _off,	\
+	.div_switch_shift = _sh
+
+#define BERLIN2_DIV_D3SWITCH(_off, _sh)	\
+	.div3_switch_offs = _off,	\
+	.div3_switch_shift = _sh
+
+#define BERLIN2_DIV_GATE(_off, _sh)	\
+	.gate_offs = _off,		\
+	.gate_shift = _sh
+
+struct berlin2_div_map {
+	u16 pll_select_offs;
+	u16 pll_switch_offs;
+	u16 div_select_offs;
+	u16 div_switch_offs;
+	u16 div3_switch_offs;
+	u16 gate_offs;
+	u8 pll_select_shift;
+	u8 pll_switch_shift;
+	u8 div_select_shift;
+	u8 div_switch_shift;
+	u8 div3_switch_shift;
+	u8 gate_shift;
+};
+
+struct berlin2_div_data {
+	const char *name;
+	unsigned long flags;
+	struct berlin2_div_map map;
+	u8 div_flags;
+};
+
+struct clk * __init
+berlin2_div_register(const struct berlin2_div_map *map,
+	     void __iomem *base,  const char *name, u8 div_flags,
+	     const char **parent_names, int num_parents,
+	     unsigned long flags,  spinlock_t *lock);
+
+#endif /* BERLIN2_DIV_H */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 6/8] clk: berlin: add core clock driver for BG2/BG2CD
  2014-05-11 20:24 [PATCH 0/8] Marvell Berlin full clock support Sebastian Hesselbarth
                   ` (4 preceding siblings ...)
  2014-05-11 20:24 ` [PATCH 5/8] clk: berlin: add driver for BG2x complex divider cells Sebastian Hesselbarth
@ 2014-05-11 20:24 ` Sebastian Hesselbarth
  2014-05-14 11:43   ` Alexandre Belloni
  2014-05-11 20:24 ` [PATCH 7/8] ARM: dts: berlin: convert BG2CD to DT clock nodes Sebastian Hesselbarth
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-11 20:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Mike Turquette, Alexandre Belloni, Antoine Tenart,
	linux-arm-kernel, linux-kernel

This driver deals with the core clocks found on Marvell Berlin
BG2 and BG2CD. For the shared register dividers, make use of the
corresponding driver and add some single clock muxes and gates for
the rest.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 drivers/clk/berlin/bg2.c | 509 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 509 insertions(+)
 create mode 100644 drivers/clk/berlin/bg2.c

diff --git a/drivers/clk/berlin/bg2.c b/drivers/clk/berlin/bg2.c
new file mode 100644
index 000000000000..7fe04e11861b
--- /dev/null
+++ b/drivers/clk/berlin/bg2.c
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#include "berlin2-div.h"
+
+/*
+ * BG2/BG2CD SoCs have the following audio/video I/O units:
+ *
+ * audiohd: HDMI TX audio
+ * audio0:  7.1ch TX
+ * audio1:  2ch TX
+ * audio2:  2ch RX
+ * audio3:  SPDIF TX
+ * video0:  HDMI video
+ * video1:  Secondary video
+ * video2:  SD auxiliary video
+ *
+ * There are no external audio clocks (ACLKI0, ACLKI1) and
+ * only one external video clock (VCLKI0).
+ *
+ * Currently missing bits and pieces:
+ * - audio_fast_pll is unknown
+ * - audiohd_pll is unknown
+ * - video0_pll is unknown
+ * - audio[023], audiohd parent pll is assumed to be audio_fast_pll
+ *
+ */
+
+struct bg2_gate_data {
+	const char *name;
+	const char *parent_name;
+	u8 bit_idx;
+	unsigned long flags;
+};
+
+#define REG_CLKENABLE		0x00
+#define REG_CLKSELECT0		0x04
+#define REG_CLKSELECT1		0x08
+#define REG_CLKSELECT2		0x0c
+#define REG_CLKSELECT3		0x10
+#define REG_CLKSWITCH0		0x14
+#define REG_CLKSWITCH1		0x18
+
+enum {
+	/* clock divider cells */
+	SYS, CPU, DRMFIGO, CFG, GFX, ZSP, PERIF, PCUBE, VSCOPE, NFC_ECC,
+	VPP, APP, AUDIO0, AUDIO2, AUDIO3, AUDIO1,
+	/* clock gates */
+	GETH0, GETH1, SATA, AHBAPB, USB0, USB1, PBRIDGE, SDIO0, SDIO1,
+	NFC, SMEMC, AUDIOHD, VIDEO0, VIDEO1, VIDEO2,
+	MAX_CLKS
+};
+
+enum { REFCLK, SYSPLL, MEMPLL, CPUPLL };
+static const char *refclk_names[] = { "refclk", "syspll", "mempll", "cpupll" };
+
+enum { CH1, CH2, CH3, CH4, CH5, CH6, CH7, CH8 };
+static const char *avplla_names[] = {
+	"avpll_a1", "avpll_a2", "avpll_a3", "avpll_a4",
+	"avpll_a5", "avpll_a6", "avpll_a7", "avpll_a8"
+};
+static const char *avpllb_names[] = {
+	"avpll_b1", "avpll_b2", "avpll_b3", "avpll_b4",
+	"avpll_b5", "avpll_b6", "avpll_b7", "avpll_a8"
+};
+static const char *video_ext0_name = "video_ext0";
+
+static DEFINE_SPINLOCK(lock);
+static struct clk *clks[MAX_CLKS];
+static struct clk_onecell_data clk_data;
+
+static const struct berlin2_div_data bg2_divs[] __initconst = {
+	{
+		.name = "sys",
+		.flags = CLK_IGNORE_UNUSED,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 0),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "cpu",
+		.flags = 0,
+		.map = {
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8),
+		},
+		.div_flags = BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "drmfigo",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 16),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 17),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 20),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "cfg",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 1),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 23),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 26),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "gfx",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 4),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 29),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 0),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "zsp",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 5),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 3),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 6),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "perif",
+		.flags = CLK_IGNORE_UNUSED,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 6),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 9),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 12),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "pcube",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 2),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 15),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 18),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "vscope",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 3),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 21),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 24),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "nfc_ecc",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 18),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 27),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 0),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "vpp",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 21),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT2, 3),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 6),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 4),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 5),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 6),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "app",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 20),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT2, 9),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 12),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 7),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 8),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 9),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "audio0",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 22),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 17),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 10),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 11),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE,
+	},
+	{
+		.name = "audio2",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 24),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 20),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 14),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 15),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE,
+	},
+	{
+		.name = "audio3",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 25),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 23),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 16),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 17),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE,
+	},
+	{
+		.name = "audio1",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 23),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT3, 0),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 12),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 13),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE,
+	},
+};
+
+static const struct bg2_gate_data bg2_gates[] __initconst = {
+	{ "geth0",	"perif",	7 },
+	{ "geth1",	"perif",	8 },
+	{ "sata",	"perif",	9 },
+	{ "ahbapb",	"perif",	10, CLK_IGNORE_UNUSED },
+	{ "usb0",	"perif",	11 },
+	{ "usb1",	"perif",	12 },
+	{ "pbridge",	"perif",	13, CLK_IGNORE_UNUSED },
+	{ "sdio0",	"perif",	14 },
+	{ "sdio1",	"perif",	15 },
+	{ "nfc",	"perif",	17 },
+	{ "smemc",	"perif",	19 },
+	{ "audiohd",	"audiohd_pll",	26 },
+	{ "video0",	"video0_in",	27 },
+	{ "video1",	"video1_in",	28 },
+	{ "video2",	"video2_in",	29 },
+};
+
+static int __init collect_refclks(struct device_node *np)
+{
+	struct clk *iclk;
+	int n;
+
+	/* overwrite default clock names with DT provided ones */
+	/* reference clocks */
+	for (n = 0; n < ARRAY_SIZE(refclk_names); n++) {
+		iclk = of_clk_get_by_name(np, refclk_names[n]);
+		if (!IS_ERR(iclk)) {
+			refclk_names[n] = __clk_get_name(iclk);
+			clk_put(iclk);
+		}
+	}
+
+	/* AVPLL_A inputs */
+	for (n = 0; n < ARRAY_SIZE(avplla_names); n++) {
+		iclk = of_clk_get_by_name(np, avplla_names[n]);
+		if (!IS_ERR(iclk)) {
+			avplla_names[n] = __clk_get_name(iclk);
+			clk_put(iclk);
+		}
+	}
+
+	/* AVPLL_B inputs */
+	for (n = 0; n < ARRAY_SIZE(avpllb_names); n++) {
+		iclk = of_clk_get_by_name(np, avpllb_names[n]);
+		if (!IS_ERR(iclk)) {
+			avpllb_names[n] = __clk_get_name(iclk);
+			clk_put(iclk);
+		}
+	}
+
+	/* video_ext0 input */
+	iclk = of_clk_get_by_name(np, video_ext0_name);
+	if (!IS_ERR(iclk)) {
+		video_ext0_name = __clk_get_name(iclk);
+		clk_put(iclk);
+	}
+
+	return 0;
+}
+
+static void __init berlin2_core_clock_of_setup(struct device_node *np)
+{
+	const struct berlin2_div_data *data;
+	const char *parent_names[9];
+	void __iomem *base;
+	struct clk *clk;
+	int n;
+
+	if (collect_refclks(np))
+		return;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("%s: Unable to map register base\n", np->full_name);
+		return;
+	}
+
+	/* reference clock bypass switches */
+	parent_names[0] = refclk_names[SYSPLL];
+	parent_names[1] = refclk_names[REFCLK];
+	clk = clk_register_mux(NULL, "syspll_in", parent_names, 2, 0,
+			       base + REG_CLKSWITCH0, 0, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+	refclk_names[SYSPLL] = __clk_get_name(clk);
+
+	parent_names[0] = refclk_names[MEMPLL];
+	parent_names[1] = refclk_names[REFCLK];
+	clk = clk_register_mux(NULL, "mempll_in", parent_names, 2, 0,
+			       base + REG_CLKSWITCH0, 1, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+	refclk_names[MEMPLL] = __clk_get_name(clk);
+
+	parent_names[0] = refclk_names[CPUPLL];
+	parent_names[1] = refclk_names[REFCLK];
+	clk = clk_register_mux(NULL, "cpupll_in", parent_names, 2, 0,
+			       base + REG_CLKSWITCH0, 2, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+	refclk_names[CPUPLL] = __clk_get_name(clk);
+
+	/* clock muxes */
+	parent_names[0] = avpllb_names[CH3];
+	parent_names[1] = avplla_names[CH3];
+	clk = clk_register_mux(NULL, "audio1_pll", parent_names, 2, 0,
+			       base + REG_CLKSELECT2, 29, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+
+	parent_names[0] = "video0_pll";
+	parent_names[1] = video_ext0_name;
+	clk = clk_register_mux(NULL, "video0_in", parent_names, 2, 0,
+			       base + REG_CLKSELECT3, 4, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+
+	parent_names[0] = "video1_pll";
+	parent_names[1] = video_ext0_name;
+	clk = clk_register_mux(NULL, "video1_in", parent_names, 2, 0,
+			       base + REG_CLKSELECT3, 6, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+
+	parent_names[0] = avplla_names[CH2];
+	parent_names[1] = avpllb_names[CH2];
+	clk = clk_register_mux(NULL, "video1_pll", parent_names, 2, 0,
+			       base + REG_CLKSELECT3, 7, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+
+	parent_names[0] = "video2_pll";
+	parent_names[1] = video_ext0_name;
+	clk = clk_register_mux(NULL, "video2_in", parent_names, 2, 0,
+			       base + REG_CLKSELECT3, 9, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+
+	parent_names[0] = avpllb_names[CH1];
+	parent_names[1] = avplla_names[CH5];
+	clk = clk_register_mux(NULL, "video2_pll", parent_names, 2, 0,
+			       base + REG_CLKSELECT3, 10, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+
+	/* clock divider cells */
+	parent_names[1] = avpllb_names[CH4];
+	parent_names[2] = avpllb_names[CH5];
+	parent_names[3] = avpllb_names[CH6];
+	parent_names[4] = avpllb_names[CH7];
+
+	parent_names[0] = refclk_names[SYSPLL];
+	data = &bg2_divs[SYS];
+	clks[SYS] = berlin2_div_register(&data->map, base, data->name,
+			 data->div_flags, parent_names, 5, data->flags, &lock);
+
+	parent_names[0] = refclk_names[CPUPLL];
+	parent_names[5] = refclk_names[MEMPLL];
+	data = &bg2_divs[CPU];
+	clks[CPU] = berlin2_div_register(&data->map, base, data->name,
+			 data->div_flags, parent_names, 6, data->flags, &lock);
+
+	parent_names[0] = refclk_names[SYSPLL];
+	for (n = DRMFIGO; n <= APP; n++) {
+		data = &bg2_divs[n];
+		clks[n] = berlin2_div_register(&data->map, base, data->name,
+			 data->div_flags, parent_names, 5, data->flags, &lock);
+	}
+
+	parent_names[0] = "audio_fast_pll";
+	for (n = AUDIO0; n <= AUDIO3; n++) {
+		data = &bg2_divs[n];
+		clks[n] = berlin2_div_register(&data->map, base, data->name,
+			 data->div_flags, parent_names, 1, data->flags, &lock);
+	}
+
+	parent_names[0] = "audio1_pll";
+	data = &bg2_divs[AUDIO1];
+	clks[AUDIO1] = berlin2_div_register(&data->map, base, data->name,
+			 data->div_flags, parent_names, 1, data->flags, &lock);
+
+	/* clock gate cells */
+	for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) {
+		const struct bg2_gate_data *gd = &bg2_gates[n];
+
+		clks[GETH0 + n] = clk_register_gate(NULL, gd->name,
+			    gd->parent_name, gd->flags, base + REG_CLKENABLE,
+			    gd->bit_idx, 0, &lock);
+	}
+
+	/* check for errors on leaf clocks */
+	for (n = 0; n < MAX_CLKS; n++) {
+		if (!IS_ERR(clks[n]))
+			continue;
+
+		pr_err("%s: Unable to register leaf clock %d\n",
+		       np->full_name, n);
+		goto core_clock_fail;
+	}
+
+	/* register clk-provider */
+	clk_data.clks = clks;
+	clk_data.clk_num = MAX_CLKS;
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+	return;
+
+core_clock_fail:
+	iounmap(base);
+}
+CLK_OF_DECLARE(berlin2_coreclk, "marvell,berlin2-core-clocks",
+	       berlin2_core_clock_of_setup);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 7/8] ARM: dts: berlin: convert BG2CD to DT clock nodes
  2014-05-11 20:24 [PATCH 0/8] Marvell Berlin full clock support Sebastian Hesselbarth
                   ` (5 preceding siblings ...)
  2014-05-11 20:24 ` [PATCH 6/8] clk: berlin: add core clock driver for BG2/BG2CD Sebastian Hesselbarth
@ 2014-05-11 20:24 ` Sebastian Hesselbarth
  2014-05-12 19:55   ` Sebastian Hesselbarth
  2014-05-13  8:42   ` Sebastian Hesselbarth
  2014-05-11 20:24 ` [PATCH 8/8] ARM: dts: berlin: convert BG2 " Sebastian Hesselbarth
  2014-05-14 20:15 ` [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
  8 siblings, 2 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-11 20:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Mike Turquette, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Alexandre Belloni,
	Antoine Tenart, devicetree, linux-arm-kernel, linux-kernel

This converts Berlin BG2CD SoC dtsi to make use of the new DT clock
nodes for Berlin SoCs. Also add a binding include to ease core clock
references.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 arch/arm/boot/dts/berlin2cd.dtsi    | 198 +++++++++++++++++++++++++++++++-----
 drivers/clk/berlin/Makefile         |   2 +
 include/dt-bindings/clock/berlin2.h |  35 +++++++
 3 files changed, 207 insertions(+), 28 deletions(-)
 create mode 100644 include/dt-bindings/clock/berlin2.h

diff --git a/arch/arm/boot/dts/berlin2cd.dtsi b/arch/arm/boot/dts/berlin2cd.dtsi
index 094968c27533..c1b8dc8264d3 100644
--- a/arch/arm/boot/dts/berlin2cd.dtsi
+++ b/arch/arm/boot/dts/berlin2cd.dtsi
@@ -12,6 +12,7 @@
  */
 
 #include "skeleton.dtsi"
+#include <dt-bindings/clock/berlin2.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 / {
@@ -30,24 +31,18 @@
 		};
 	};
 
-	clocks {
-		smclk: sysmgr-clock {
-			compatible = "fixed-clock";
-			#clock-cells = <0>;
-			clock-frequency = <25000000>;
-		};
-
-		cfgclk: cfg-clock {
-			compatible = "fixed-clock";
-			#clock-cells = <0>;
-			clock-frequency = <75000000>;
-		};
+	refclk: oscillator {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <25000000>;
+	};
 
-		sysclk: system-clock {
-			compatible = "fixed-clock";
-			#clock-cells = <0>;
-			clock-frequency = <300000000>;
-		};
+	twdclk: twdclk {
+		compatible = "fixed-factor-clock";
+		#clock-cells = <0>;
+		clocks = <&coreclk CLKID_CPU>;
+		clock-mult = <1>;
+		clock-div = <3>;
 	};
 
 	soc {
@@ -76,7 +71,7 @@
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0xad0600 0x20>;
 			interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&sysclk>;
+			clocks = <&twdclk>;
 		};
 
 		apb@e80000 {
@@ -91,7 +86,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c00 0x14>;
 				interrupts = <8>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "okay";
 			};
@@ -100,7 +95,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c14 0x14>;
 				interrupts = <9>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "okay";
 			};
@@ -109,7 +104,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c28 0x14>;
 				interrupts = <10>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -118,7 +113,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c3c 0x14>;
 				interrupts = <11>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -127,7 +122,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c50 0x14>;
 				interrupts = <12>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -136,7 +131,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c64 0x14>;
 				interrupts = <13>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -145,7 +140,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c78 0x14>;
 				interrupts = <14>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -154,7 +149,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c8c 0x14>;
 				interrupts = <15>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -169,6 +164,153 @@
 			};
 		};
 
+		syspll: pll@ea0014 {
+			compatible = "marvell,berlin2-pll";
+			#clock-cells = <0>;
+			reg = <0xea0014 0x14>;
+			clocks = <&refclk>;
+		};
+
+		mempll: pll@ea0028 {
+			compatible = "marvell,berlin2-pll";
+			#clock-cells = <0>;
+			reg = <0xea0028 0x14>;
+			clocks = <&refclk>;
+		};
+
+		cpupll: pll@ea003c {
+			compatible = "marvell,berlin2-pll";
+			#clock-cells = <0>;
+			reg = <0xea003c 0x14>;
+			clocks = <&refclk>;
+		};
+
+		avpll: pll@ea0040 {
+			compatible = "marvell,berlin2-avpll";
+			#clock-cells = <2>;
+			reg = <0xea0050 0x100>;
+			clocks = <&refclk>;
+		};
+
+		coreclk: clock@ea0150 {
+			compatible = "marvell,berlin2-core-clocks";
+			#clock-cells = <1>;
+			reg = <0xea0150 0x1c>;
+			clocks = <&refclk>, <&syspll>, <&mempll>, <&cpupll>,
+				<&avpll 0 1>, <&avpll 0 2>,
+				<&avpll 0 3>, <&avpll 0 4>,
+				<&avpll 0 5>, <&avpll 0 6>,
+				<&avpll 0 7>, <&avpll 0 8>,
+				<&avpll 1 1>, <&avpll 1 2>,
+				<&avpll 1 3>, <&avpll 1 4>,
+				<&avpll 1 5>, <&avpll 1 6>,
+				<&avpll 1 7>, <&avpll 1 8>;
+			clock-names = "refclk", "syspll", "mempll", "cpupll",
+				"avpll_a1", "avpll_a2", "avpll_a3", "avpll_a4",
+				"avpll_a5", "avpll_a6", "avpll_a7", "avpll_a8",
+				"avpll_b1", "avpll_b2", "avpll_b3", "avpll_b4",
+				"avpll_b5", "avpll_b6", "avpll_b7", "avpll_b8";
+		};
+
+		gfx3dcore_clk: clock@ea022c {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0022c 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		gfx3dsys_clk: clock@ea0230 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea00230 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		arc_clk: clock@ea0234 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea00234 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		vip_clk: clock@ea0238 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea00238 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		sdio0xin_clk: clock@ea023c {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0023c 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		sdio1xin_clk: clock@ea0240 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea00240 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		gfx3dextra_clk: clock@ea0244 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea00244 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		gc360_clk: clock@ea024c {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0024c 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		sdio_dllmst_clk: clock@ea0250 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea00250 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
 		apb@fc0000 {
 			compatible = "simple-bus";
 			#address-cells = <1>;
@@ -183,7 +325,7 @@
 				reg-shift = <2>;
 				reg-io-width = <1>;
 				interrupts = <8>;
-				clocks = <&smclk>;
+				clocks = <&refclk>;
 				status = "disabled";
 			};
 
@@ -193,7 +335,7 @@
 				reg-shift = <2>;
 				reg-io-width = <1>;
 				interrupts = <9>;
-				clocks = <&smclk>;
+				clocks = <&refclk>;
 				status = "disabled";
 			};
 
diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile
index f0a7dc8b5e30..2b33e1e74503 100644
--- a/drivers/clk/berlin/Makefile
+++ b/drivers/clk/berlin/Makefile
@@ -1 +1,3 @@
 obj-y += berlin2-avpll.o berlin2-pll.o berlin2-div.o
+obj-$(CONFIG_MACH_BERLIN_BG2)	+= bg2.o
+obj-$(CONFIG_MACH_BERLIN_BG2CD)	+= bg2.o
diff --git a/include/dt-bindings/clock/berlin2.h b/include/dt-bindings/clock/berlin2.h
new file mode 100644
index 000000000000..dacf7edec4d3
--- /dev/null
+++ b/include/dt-bindings/clock/berlin2.h
@@ -0,0 +1,35 @@
+/*
+ * Berlin2 BG2/BG2CD clock tree IDs
+ */
+
+#define CLKID_SYS		0
+#define CLKID_CPU		1
+#define CLKID_DRMFIGO		2
+#define CLKID_CFG		3
+#define CLKID_GFX		4
+#define CLKID_ZSP		5
+#define CLKID_PERIF		6
+#define CLKID_PCUBE		7
+#define CLKID_VSCOPE		8
+#define CLKID_NFC_ECC		9
+#define CLKID_VPP		10
+#define CLKID_APP		11
+#define CLKID_AUDIO0		12
+#define CLKID_AUDIO2		23
+#define CLKID_AUDIO3		14
+#define CLKID_AUDIO1		15
+#define CLKID_GETH0		16
+#define CLKID_GETH1		17
+#define CLKID_SATA		18
+#define CLKID_AHBAPB		19
+#define CLKID_USB0		20
+#define CLKID_USB1		21
+#define CLKID_PBRIDGE		22
+#define CLKID_SDIO0		23
+#define CLKID_SDIO1		24
+#define CLKID_NFC		25
+#define CLKID_SMEMC		26
+#define CLKID_AUDIOHD		27
+#define CLKID_VIDEO0		28
+#define CLKID_VIDEO1		29
+#define CLKID_VIDEO2		30
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 8/8] ARM: dts: berlin: convert BG2 to DT clock nodes
  2014-05-11 20:24 [PATCH 0/8] Marvell Berlin full clock support Sebastian Hesselbarth
                   ` (6 preceding siblings ...)
  2014-05-11 20:24 ` [PATCH 7/8] ARM: dts: berlin: convert BG2CD to DT clock nodes Sebastian Hesselbarth
@ 2014-05-11 20:24 ` Sebastian Hesselbarth
  2014-05-14 20:15 ` [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
  8 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-11 20:24 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Mike Turquette, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Alexandre Belloni,
	Antoine Tenart, devicetree, linux-arm-kernel, linux-kernel

This converts Berlin BG2 SoC dtsi to make use of the new DT clock
nodes for Berlin SoCs. While at it, also fix up twdclk which is
running at cpuclk/3 instead of sysclk.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 arch/arm/boot/dts/berlin2.dtsi | 200 +++++++++++++++++++++++++++++++++++------
 1 file changed, 171 insertions(+), 29 deletions(-)

diff --git a/arch/arm/boot/dts/berlin2.dtsi b/arch/arm/boot/dts/berlin2.dtsi
index 56a1af2f1052..5d84171a1e4b 100644
--- a/arch/arm/boot/dts/berlin2.dtsi
+++ b/arch/arm/boot/dts/berlin2.dtsi
@@ -12,6 +12,7 @@
  */
 
 #include "skeleton.dtsi"
+#include <dt-bindings/clock/berlin2.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 / {
@@ -37,24 +38,18 @@
 		};
 	};
 
-	clocks {
-		smclk: sysmgr-clock {
-			compatible = "fixed-clock";
-			#clock-cells = <0>;
-			clock-frequency = <25000000>;
-		};
-
-		cfgclk: cfg-clock {
-			compatible = "fixed-clock";
-			#clock-cells = <0>;
-			clock-frequency = <100000000>;
-		};
+	refclk: oscillator {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <25000000>;
+	};
 
-		sysclk: system-clock {
-			compatible = "fixed-clock";
-			#clock-cells = <0>;
-			clock-frequency = <400000000>;
-		};
+	twdclk: twdclk {
+		compatible = "fixed-factor-clock";
+		#clock-cells = <0>;
+		clocks = <&coreclk CLKID_CPU>;
+		clock-mult = <1>;
+		clock-div = <3>;
 	};
 
 	soc {
@@ -83,7 +78,7 @@
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0xad0600 0x20>;
 			interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&sysclk>;
+			clocks = <&twdclk>;
 		};
 
 		apb@e80000 {
@@ -98,7 +93,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c00 0x14>;
 				interrupts = <8>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "okay";
 			};
@@ -107,7 +102,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c14 0x14>;
 				interrupts = <9>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "okay";
 			};
@@ -116,7 +111,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c28 0x14>;
 				interrupts = <10>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -125,7 +120,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c3c 0x14>;
 				interrupts = <11>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -134,7 +129,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c50 0x14>;
 				interrupts = <12>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -143,7 +138,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c64 0x14>;
 				interrupts = <13>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -152,7 +147,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c78 0x14>;
 				interrupts = <14>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -161,7 +156,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c8c 0x14>;
 				interrupts = <15>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -176,6 +171,153 @@
 			};
 		};
 
+		syspll: pll@ea0014 {
+			compatible = "marvell,berlin2-pll";
+			#clock-cells = <0>;
+			reg = <0xea0014 0x14>;
+			clocks = <&refclk>;
+		};
+
+		mempll: pll@ea0028 {
+			compatible = "marvell,berlin2-pll";
+			#clock-cells = <0>;
+			reg = <0xea0028 0x14>;
+			clocks = <&refclk>;
+		};
+
+		cpupll: pll@ea003c {
+			compatible = "marvell,berlin2-pll";
+			#clock-cells = <0>;
+			reg = <0xea003c 0x14>;
+			clocks = <&refclk>;
+		};
+
+		avpll: pll@ea0040 {
+			compatible = "marvell,berlin2-avpll";
+			#clock-cells = <2>;
+			reg = <0xea0050 0x100>;
+			clocks = <&refclk>;
+		};
+
+		coreclk: clock@ea0150 {
+			compatible = "marvell,berlin2-core-clocks";
+			#clock-cells = <1>;
+			reg = <0xea0150 0x1c>;
+			clocks = <&refclk>, <&syspll>, <&mempll>, <&cpupll>,
+				<&avpll 0 1>, <&avpll 0 2>,
+				<&avpll 0 3>, <&avpll 0 4>,
+				<&avpll 0 5>, <&avpll 0 6>,
+				<&avpll 0 7>, <&avpll 0 8>,
+				<&avpll 1 1>, <&avpll 1 2>,
+				<&avpll 1 3>, <&avpll 1 4>,
+				<&avpll 1 5>, <&avpll 1 6>,
+				<&avpll 1 7>, <&avpll 1 8>;
+			clock-names = "refclk", "syspll", "mempll", "cpupll",
+				"avpll_a1", "avpll_a2", "avpll_a3", "avpll_a4",
+				"avpll_a5", "avpll_a6", "avpll_a7", "avpll_a8",
+				"avpll_b1", "avpll_b2", "avpll_b3", "avpll_b4",
+				"avpll_b5", "avpll_b6", "avpll_b7", "avpll_b8";
+		};
+
+		gfx3dcore_clk: clock@ea022c {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0022c 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		gfx3dsys_clk: clock@ea0230 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea00230 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		arc_clk: clock@ea0234 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea00234 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		vip_clk: clock@ea0238 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea00238 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		sdio0xin_clk: clock@ea023c {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0023c 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		sdio1xin_clk: clock@ea0240 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea00240 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		gfx3dextra_clk: clock@ea0244 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea00244 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		gc360_clk: clock@ea024c {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0024c 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		sdio_dllmst_clk: clock@ea0250 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea00250 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
 		apb@fc0000 {
 			compatible = "simple-bus";
 			#address-cells = <1>;
@@ -190,7 +332,7 @@
 				reg-shift = <2>;
 				reg-io-width = <1>;
 				interrupts = <8>;
-				clocks = <&smclk>;
+				clocks = <&refclk>;
 				status = "disabled";
 			};
 
@@ -200,7 +342,7 @@
 				reg-shift = <2>;
 				reg-io-width = <1>;
 				interrupts = <9>;
-				clocks = <&smclk>;
+				clocks = <&refclk>;
 				status = "disabled";
 			};
 
@@ -210,7 +352,7 @@
 				reg-shift = <2>;
 				reg-io-width = <1>;
 				interrupts = <10>;
-				clocks = <&smclk>;
+				clocks = <&refclk>;
 				status = "disabled";
 			};
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH 7/8] ARM: dts: berlin: convert BG2CD to DT clock nodes
  2014-05-11 20:24 ` [PATCH 7/8] ARM: dts: berlin: convert BG2CD to DT clock nodes Sebastian Hesselbarth
@ 2014-05-12 19:55   ` Sebastian Hesselbarth
  2014-05-13  8:42   ` Sebastian Hesselbarth
  1 sibling, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-12 19:55 UTC (permalink / raw)
  Cc: Mike Turquette, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Alexandre Belloni,
	Antoine Tenart, devicetree, linux-arm-kernel, linux-kernel

On 05/11/2014 10:24 PM, Sebastian Hesselbarth wrote:
> This converts Berlin BG2CD SoC dtsi to make use of the new DT clock
> nodes for Berlin SoCs. Also add a binding include to ease core clock
> references.
> 
> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> ---
> Cc: Mike Turquette <mturquette@linaro.org>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Pawel Moll <pawel.moll@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
> Cc: Kumar Gala <galak@codeaurora.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
> Cc: devicetree@vger.kernel.org
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: linux-kernel@vger.kernel.org
> ---
>  arch/arm/boot/dts/berlin2cd.dtsi    | 198 +++++++++++++++++++++++++++++++-----
>  drivers/clk/berlin/Makefile         |   2 +

This above shouldn't be part of this patch of course, I'll fix it
up.

Sebastian

>  include/dt-bindings/clock/berlin2.h |  35 +++++++
>  3 files changed, 207 insertions(+), 28 deletions(-)
>  create mode 100644 include/dt-bindings/clock/berlin2.h
> 
> diff --git a/arch/arm/boot/dts/berlin2cd.dtsi b/arch/arm/boot/dts/berlin2cd.dtsi
> index 094968c27533..c1b8dc8264d3 100644
> --- a/arch/arm/boot/dts/berlin2cd.dtsi
> +++ b/arch/arm/boot/dts/berlin2cd.dtsi
> @@ -12,6 +12,7 @@
>   */
>  
>  #include "skeleton.dtsi"
> +#include <dt-bindings/clock/berlin2.h>
>  #include <dt-bindings/interrupt-controller/arm-gic.h>
>  
>  / {
> @@ -30,24 +31,18 @@
>  		};
>  	};
>  
> -	clocks {
> -		smclk: sysmgr-clock {
> -			compatible = "fixed-clock";
> -			#clock-cells = <0>;
> -			clock-frequency = <25000000>;
> -		};
> -
> -		cfgclk: cfg-clock {
> -			compatible = "fixed-clock";
> -			#clock-cells = <0>;
> -			clock-frequency = <75000000>;
> -		};
> +	refclk: oscillator {
> +		compatible = "fixed-clock";
> +		#clock-cells = <0>;
> +		clock-frequency = <25000000>;
> +	};
>  
> -		sysclk: system-clock {
> -			compatible = "fixed-clock";
> -			#clock-cells = <0>;
> -			clock-frequency = <300000000>;
> -		};
> +	twdclk: twdclk {
> +		compatible = "fixed-factor-clock";
> +		#clock-cells = <0>;
> +		clocks = <&coreclk CLKID_CPU>;
> +		clock-mult = <1>;
> +		clock-div = <3>;
>  	};
>  
>  	soc {
> @@ -76,7 +71,7 @@
>  			compatible = "arm,cortex-a9-twd-timer";
>  			reg = <0xad0600 0x20>;
>  			interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
> -			clocks = <&sysclk>;
> +			clocks = <&twdclk>;
>  		};
>  
>  		apb@e80000 {
> @@ -91,7 +86,7 @@
>  				compatible = "snps,dw-apb-timer";
>  				reg = <0x2c00 0x14>;
>  				interrupts = <8>;
> -				clocks = <&cfgclk>;
> +				clocks = <&coreclk CLKID_CFG>;
>  				clock-names = "timer";
>  				status = "okay";
>  			};
> @@ -100,7 +95,7 @@
>  				compatible = "snps,dw-apb-timer";
>  				reg = <0x2c14 0x14>;
>  				interrupts = <9>;
> -				clocks = <&cfgclk>;
> +				clocks = <&coreclk CLKID_CFG>;
>  				clock-names = "timer";
>  				status = "okay";
>  			};
> @@ -109,7 +104,7 @@
>  				compatible = "snps,dw-apb-timer";
>  				reg = <0x2c28 0x14>;
>  				interrupts = <10>;
> -				clocks = <&cfgclk>;
> +				clocks = <&coreclk CLKID_CFG>;
>  				clock-names = "timer";
>  				status = "disabled";
>  			};
> @@ -118,7 +113,7 @@
>  				compatible = "snps,dw-apb-timer";
>  				reg = <0x2c3c 0x14>;
>  				interrupts = <11>;
> -				clocks = <&cfgclk>;
> +				clocks = <&coreclk CLKID_CFG>;
>  				clock-names = "timer";
>  				status = "disabled";
>  			};
> @@ -127,7 +122,7 @@
>  				compatible = "snps,dw-apb-timer";
>  				reg = <0x2c50 0x14>;
>  				interrupts = <12>;
> -				clocks = <&cfgclk>;
> +				clocks = <&coreclk CLKID_CFG>;
>  				clock-names = "timer";
>  				status = "disabled";
>  			};
> @@ -136,7 +131,7 @@
>  				compatible = "snps,dw-apb-timer";
>  				reg = <0x2c64 0x14>;
>  				interrupts = <13>;
> -				clocks = <&cfgclk>;
> +				clocks = <&coreclk CLKID_CFG>;
>  				clock-names = "timer";
>  				status = "disabled";
>  			};
> @@ -145,7 +140,7 @@
>  				compatible = "snps,dw-apb-timer";
>  				reg = <0x2c78 0x14>;
>  				interrupts = <14>;
> -				clocks = <&cfgclk>;
> +				clocks = <&coreclk CLKID_CFG>;
>  				clock-names = "timer";
>  				status = "disabled";
>  			};
> @@ -154,7 +149,7 @@
>  				compatible = "snps,dw-apb-timer";
>  				reg = <0x2c8c 0x14>;
>  				interrupts = <15>;
> -				clocks = <&cfgclk>;
> +				clocks = <&coreclk CLKID_CFG>;
>  				clock-names = "timer";
>  				status = "disabled";
>  			};
> @@ -169,6 +164,153 @@
>  			};
>  		};
>  
> +		syspll: pll@ea0014 {
> +			compatible = "marvell,berlin2-pll";
> +			#clock-cells = <0>;
> +			reg = <0xea0014 0x14>;
> +			clocks = <&refclk>;
> +		};
> +
> +		mempll: pll@ea0028 {
> +			compatible = "marvell,berlin2-pll";
> +			#clock-cells = <0>;
> +			reg = <0xea0028 0x14>;
> +			clocks = <&refclk>;
> +		};
> +
> +		cpupll: pll@ea003c {
> +			compatible = "marvell,berlin2-pll";
> +			#clock-cells = <0>;
> +			reg = <0xea003c 0x14>;
> +			clocks = <&refclk>;
> +		};
> +
> +		avpll: pll@ea0040 {
> +			compatible = "marvell,berlin2-avpll";
> +			#clock-cells = <2>;
> +			reg = <0xea0050 0x100>;
> +			clocks = <&refclk>;
> +		};
> +
> +		coreclk: clock@ea0150 {
> +			compatible = "marvell,berlin2-core-clocks";
> +			#clock-cells = <1>;
> +			reg = <0xea0150 0x1c>;
> +			clocks = <&refclk>, <&syspll>, <&mempll>, <&cpupll>,
> +				<&avpll 0 1>, <&avpll 0 2>,
> +				<&avpll 0 3>, <&avpll 0 4>,
> +				<&avpll 0 5>, <&avpll 0 6>,
> +				<&avpll 0 7>, <&avpll 0 8>,
> +				<&avpll 1 1>, <&avpll 1 2>,
> +				<&avpll 1 3>, <&avpll 1 4>,
> +				<&avpll 1 5>, <&avpll 1 6>,
> +				<&avpll 1 7>, <&avpll 1 8>;
> +			clock-names = "refclk", "syspll", "mempll", "cpupll",
> +				"avpll_a1", "avpll_a2", "avpll_a3", "avpll_a4",
> +				"avpll_a5", "avpll_a6", "avpll_a7", "avpll_a8",
> +				"avpll_b1", "avpll_b2", "avpll_b3", "avpll_b4",
> +				"avpll_b5", "avpll_b6", "avpll_b7", "avpll_b8";
> +		};
> +
> +		gfx3dcore_clk: clock@ea022c {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea0022c 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		gfx3dsys_clk: clock@ea0230 {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea00230 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		arc_clk: clock@ea0234 {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea00234 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		vip_clk: clock@ea0238 {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea00238 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		sdio0xin_clk: clock@ea023c {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea0023c 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		sdio1xin_clk: clock@ea0240 {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea00240 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		gfx3dextra_clk: clock@ea0244 {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea00244 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		gc360_clk: clock@ea024c {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea0024c 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		sdio_dllmst_clk: clock@ea0250 {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea00250 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
>  		apb@fc0000 {
>  			compatible = "simple-bus";
>  			#address-cells = <1>;
> @@ -183,7 +325,7 @@
>  				reg-shift = <2>;
>  				reg-io-width = <1>;
>  				interrupts = <8>;
> -				clocks = <&smclk>;
> +				clocks = <&refclk>;
>  				status = "disabled";
>  			};
>  
> @@ -193,7 +335,7 @@
>  				reg-shift = <2>;
>  				reg-io-width = <1>;
>  				interrupts = <9>;
> -				clocks = <&smclk>;
> +				clocks = <&refclk>;
>  				status = "disabled";
>  			};
>  
> diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile
> index f0a7dc8b5e30..2b33e1e74503 100644
> --- a/drivers/clk/berlin/Makefile
> +++ b/drivers/clk/berlin/Makefile
> @@ -1 +1,3 @@
>  obj-y += berlin2-avpll.o berlin2-pll.o berlin2-div.o
> +obj-$(CONFIG_MACH_BERLIN_BG2)	+= bg2.o
> +obj-$(CONFIG_MACH_BERLIN_BG2CD)	+= bg2.o
> diff --git a/include/dt-bindings/clock/berlin2.h b/include/dt-bindings/clock/berlin2.h
> new file mode 100644
> index 000000000000..dacf7edec4d3
> --- /dev/null
> +++ b/include/dt-bindings/clock/berlin2.h
> @@ -0,0 +1,35 @@
> +/*
> + * Berlin2 BG2/BG2CD clock tree IDs
> + */
> +
> +#define CLKID_SYS		0
> +#define CLKID_CPU		1
> +#define CLKID_DRMFIGO		2
> +#define CLKID_CFG		3
> +#define CLKID_GFX		4
> +#define CLKID_ZSP		5
> +#define CLKID_PERIF		6
> +#define CLKID_PCUBE		7
> +#define CLKID_VSCOPE		8
> +#define CLKID_NFC_ECC		9
> +#define CLKID_VPP		10
> +#define CLKID_APP		11
> +#define CLKID_AUDIO0		12
> +#define CLKID_AUDIO2		23
> +#define CLKID_AUDIO3		14
> +#define CLKID_AUDIO1		15
> +#define CLKID_GETH0		16
> +#define CLKID_GETH1		17
> +#define CLKID_SATA		18
> +#define CLKID_AHBAPB		19
> +#define CLKID_USB0		20
> +#define CLKID_USB1		21
> +#define CLKID_PBRIDGE		22
> +#define CLKID_SDIO0		23
> +#define CLKID_SDIO1		24
> +#define CLKID_NFC		25
> +#define CLKID_SMEMC		26
> +#define CLKID_AUDIOHD		27
> +#define CLKID_VIDEO0		28
> +#define CLKID_VIDEO1		29
> +#define CLKID_VIDEO2		30
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/8] clk: berlin: add clock binding docs for Marvell Berlin2 SoCs
  2014-05-11 20:24 ` [PATCH 2/8] clk: berlin: add clock binding docs for Marvell Berlin2 SoCs Sebastian Hesselbarth
@ 2014-05-13  8:38   ` Sebastian Hesselbarth
  2014-05-13 14:47   ` Alexandre Belloni
  2014-05-14 22:32   ` Mike Turquette
  2 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-13  8:38 UTC (permalink / raw)
  Cc: Mike Turquette, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Randy Dunlap, Alexandre Belloni,
	Antoine Tenart, devicetree, linux-doc, linux-arm-kernel,
	linux-kernel

On 05/11/2014 10:24 PM, Sebastian Hesselbarth wrote:
> This adds mandatory device tree binding documentation for the clock related
> IP found on Marvell Berlin2 (BG2, BG2CD, and BG2Q) SoCs.
>
> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> ---
> Cc: Mike Turquette <mturquette@linaro.org>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Pawel Moll <pawel.moll@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
> Cc: Kumar Gala <galak@codeaurora.org>
> Cc: Randy Dunlap <rdunlap@infradead.org>
> Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
> Cc: devicetree@vger.kernel.org
> Cc: linux-doc@vger.kernel.org
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: linux-kernel@vger.kernel.org
> ---
>   .../devicetree/bindings/clock/berlin2-clock.txt    | 169 +++++++++++++++++++++
>   1 file changed, 169 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/clock/berlin2-clock.txt
>
> diff --git a/Documentation/devicetree/bindings/clock/berlin2-clock.txt b/Documentation/devicetree/bindings/clock/berlin2-clock.txt
> new file mode 100644
> index 000000000000..3da87a488402
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/berlin2-clock.txt
> @@ -0,0 +1,169 @@
> +* Marvell Berlin2 clock bindings
> +
> +Marvell Berlin2 (BG2, BG2CD, BG2Q) share the same IP for PLLs and clocks,
> +with some minor differences in features and register layout. The below
> +describes the individual clock related IP:
> +
> +* Audio/Video PLL
> +
> +The Audio/Video PLL (AVPLL) is a dual-VCO PLL with 8 channels each. Each
> +of the VCOs can sythesize a single VCO frequency based on a single input
> +reference clock. Each of the 8 channels then, can derive an output clock
> +from that VCO frequency by various dividers/multipliers.
> +
> +Required properties:
> +- compatible: shall be "marvell,berlin2-avpll"
> +- reg: address and length of the corresponding AVPLL registers
> +- #clock-cells: shall be set to 2
> +- clocks: single clock specifier referencing the AVPLL input clock
> +
> +To ease match-up with the desired AVPLL output clock, clock specifiers
> +referencing AVPLL clocks shall contain two cells. The first refers to
> +the VCO (0=AVPLL_A, 1=AVPLL_B) while the second refers to the corresponding
> +channel starting with 1. For example, to reference AVPLL_B3 the clock
> +specifier shall be: <&avpll 1 3>.
> +
> +Example:
> +
> +avpll: pll@ea0040 {
> +	compatible = "marvell,berlin2-avpll";
> +	#clock-cells = <2>;
> +	reg = <0xea0050 0x100>;
> +	clocks = <&refclk>;
> +};
> +
> +* Simple PLLs
> +
> +Simple PLLs are memory mapped PLLs that can sythesize a single output clock
> +based on a single input reference clock.
> +
> +Required properties:
> +- compatible: shall be one of the following:
> +	"marvell,berlin2-pll" for Berlin BG2/BG2CD PLLs
> +	"marvell,berlin2q-pll" for Berlin BG2Q PLLs
> +- reg: address and length of the corresponding PLL registers
> +- #clock-cells: shall be set to 0
> +- clocks: single clock specifier referencing the PLL input clock
> +
> +Example:
> +
> +cpupll: pll@ea003c {
> +	compatible = "marvell,berlin2-pll";
> +	#clock-cells = <0>;
> +	reg = <0xea003c 0x14>;
> +	clocks = <&refclk>;
> +};
> +
> +* Single-register clock dividers
> +
> +Single-register clock dividers are complex divider cells, allowing
> +to divide a reference clock with a set of fixed dividers. Also they
> +comprise and input clock mux with bypass and an ouput clock gate.
> +
> +Required properties:
> +- compatible: shall be "marvell,berlin2-clk-div"
> +- reg: address and length of the corresponding DIV registers
> +- #clock-cells: shall be set to 0
> +- clocks: clock specifiers referencing the DIV input clocks
> +- clock-names: array of strings describing the clock specifiers above.
> +    Allowed clock-names are "mux_bypass" for the clock mux bypass selection
> +    and "muxN" (N=0..7) for each of the 8 possible clock mux inputs.
> +
> +Example:
> +
> +gfx3dcore_clk: clock@ea022c {
> +	compatible = "marvell,berlin2-clk-div";

Actually using the clock driver for SDHCI IP revealed some issues
already. Above compatible should have been "marvell,berlin2-div".
I'll fix it up for v2.

Also, the commit msg should start with 'dt-binding: clk:' I guess.

Sebastian

> +	#clock-cells = <0>;
> +	reg = <0xea0022c 0x4>;
> +	clocks = <&syspll>,
> +		<&avpll AVPLL_B 4>, <&avpll AVPLL_B 5>,
> +		<&avpll AVPLL_B 6>, <&avpll AVPLL_B 7>;
> +	clock-names = "mux_bypass",
> +		"mux0", "mux1", "mux2", "mux3";
> +};
> +
> +* SoC-specific core clocks
> +
> +In addition to the above, there is a register set dealing with SoC
> +specific clock dividers, muxes, and gates. There is also the complex
> +divider cell used above, but instead of independent registers, they
> +share a common set of registers. The core clocks are represented by
> +a single DT node providing access to the remaining clocks.
> +
> +Required properties:
> +- compatible: shall be one of
> +	"marvell,berlin2-core-clocks" for BG2/BG2CD SoCs
> +	"marvell,berlin2q-core-clocks" for BG2Q SoCs
> +- reg: address and length of the corresponding clock registers
> +- #clock-cells: shall be set to 1
> +- clocks: clock specifiers referencing the core clock input clocks
> +- clock-names: array of strings describing the clock specifiers above.
> +    Allowed clock-names for the reference clocks are
> +      "refclk", "syspll", "mempll", "cpupll"
> +    also Audio/Video PLL clocks shall be named with
> +      "avpll_VN" (V=0...1 for AVPLL_A and AVPLL_B, N=1..8 for the
> +      corresponding reference input from AVPLL).
> +
> +Optional properties for BG2/BG2CD SoCs:
> +- clocks/clock-names: in addition to the allowed clock names above,
> +    there is an external video clock input that shall be named "video_ext0".
> +
> +Clocks provided by core clocks shall be referenced by a clock specifier
> +indexing one of the provided clocks. A SoC-specific list of available clocks
> +is below the example.
> +
> +Example:
> +coreclk: clock@ea0150 {
> +	compatible = "marvell,berlin2-core-clocks";
> +	#clock-cells = <1>;
> +	reg = <0xea0150 0x1c>;
> +	clocks = <&refclk>, <&syspll>, <&mempll>, <&cpupll>,
> +		<&avpll 0 1>, <&avpll 0 2>,
> +		<&avpll 0 3>, <&avpll 0 4>,
> +		<&avpll 0 5>, <&avpll 0 6>,
> +		<&avpll 0 7>, <&avpll 0 8>,
> +		<&avpll 1 1>, <&avpll 1 2>,
> +		<&avpll 1 3>, <&avpll 1 4>,
> +		<&avpll 1 5>, <&avpll 1 6>,
> +		<&avpll 1 7>, <&avpll 1 8>,
> +		<&externalvideoclk>;
> +	clock-names = "refclk", "syspll", "mempll", "cpupll",
> +		"avpll_a1", "avpll_a2", "avpll_a3", "avpll_a4",
> +		"avpll_a5", "avpll_a6", "avpll_a7", "avpll_a8",
> +		"avpll_b1", "avpll_b2", "avpll_b3", "avpll_b4",
> +		"avpll_b5", "avpll_b6", "avpll_b7", "avpll_b8",
> +		"video_ext0";
> +};
> +
> +* BG2/BG2CD core clock indicies:
> +0  - SYS
> +1  - CPU
> +2  - DRMFIGO
> +3  - CFG
> +4  - GFX
> +5  - ZSP
> +6  - PERIF
> +7  - PCUBE
> +8  - VSCOPE
> +9  - NFC_ECC
> +10 - VPP
> +11 - APP
> +12 - AUDIO0
> +23 - AUDIO2
> +14 - AUDIO3
> +15 - AUDIO1
> +16 - GETH0
> +17 - GETH1
> +18 - SATA
> +19 - AHBAPB
> +20 - USB0
> +21 - USB1
> +22 - PBRIDGE
> +23 - SDIO0
> +24 - SDIO1
> +25 - NFC
> +26 - SMEMC
> +27 - AUDIOHD
> +28 - VIDEO0
> +29 - VIDEO1
> +30 - VIDEO2
>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 5/8] clk: berlin: add driver for BG2x complex divider cells
  2014-05-11 20:24 ` [PATCH 5/8] clk: berlin: add driver for BG2x complex divider cells Sebastian Hesselbarth
@ 2014-05-13  8:40   ` Sebastian Hesselbarth
  0 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-13  8:40 UTC (permalink / raw)
  Cc: Alexandre Belloni, Mike Turquette, Antoine Tenart,
	linux-arm-kernel, linux-kernel

On 05/11/2014 10:24 PM, Sebastian Hesselbarth wrote:
> From: Alexandre Belloni <alexandre.belloni@free-electrons.com>
>
> This is a driver for the complex divider cells found on Marvell Berlin2
> SoCs. The cells come in two flavors: single register cells and shared
> register cells. The single register cells are registered by using a DT
> node, while the shared ones will be taken care of in a SoC-specific
> core clock driver.
>
> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> ---
[...]
> diff --git a/drivers/clk/berlin/berlin2-div.c b/drivers/clk/berlin/berlin2-div.c
> new file mode 100644
> index 000000000000..96513a6e8ca7
> --- /dev/null
> +++ b/drivers/clk/berlin/berlin2-div.c
> @@ -0,0 +1,326 @@
[...]
> +static void __init berlin2_div_of_setup(struct device_node *np)
> +{
> +	const char *parent_names[9] = {};
> +	char *mux_name = "mux0";
> +	int num_parents = 0;

num_parents is always zero...

> +	void __iomem *base;
> +	struct clk *iclk;
> +	struct clk *div;
> +	char *div_name;
> +	int n;
> +
> +	iclk = of_clk_get_by_name(np, "mux_bypass");
> +	if (IS_ERR(iclk)) {
> +		pr_err("%s: Missing mux bypass clock\n", np->full_name);
> +		return;
> +	}
> +	parent_names[0] = __clk_get_name(iclk);

.. and needs to be incremented here..

> +	clk_put(iclk);
> +
> +	/* collect mux input clock names */
> +	for (n = 0; n < 8; n++) {
> +		sprintf(mux_name, "mux%d", n);
> +		iclk = of_clk_get_by_name(np, mux_name);
> +		if (IS_ERR(iclk))
> +			continue;
> +		parent_names[1 + n] = __clk_get_name(iclk);

.. and here.

I'll fix it up for v2.

Sebastian

> +		clk_put(iclk);
> +	}
> +
> +	base = of_iomap(np, 0);
> +	if (!base) {
> +		pr_err("%s: Unable to map div register\n", np->full_name);
> +		return;
> +	}
> +
> +	div_name = of_clk_create_name(np);
> +	div = berlin2_div_register(&berlin2_single_div_map, base, div_name,
> +				   BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +				   parent_names, num_parents, 0, NULL);
> +	if (!IS_ERR(div))
> +		of_clk_add_provider(np, of_clk_src_simple_get, div);
> +
> +	kfree(div_name);
> +}
> +CLK_OF_DECLARE(berlin2_div, "marvell,berlin2-div", berlin2_div_of_setup);


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 7/8] ARM: dts: berlin: convert BG2CD to DT clock nodes
  2014-05-11 20:24 ` [PATCH 7/8] ARM: dts: berlin: convert BG2CD to DT clock nodes Sebastian Hesselbarth
  2014-05-12 19:55   ` Sebastian Hesselbarth
@ 2014-05-13  8:42   ` Sebastian Hesselbarth
  1 sibling, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-13  8:42 UTC (permalink / raw)
  Cc: Mike Turquette, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Alexandre Belloni,
	Antoine Tenart, devicetree, linux-arm-kernel, linux-kernel

On 05/11/2014 10:24 PM, Sebastian Hesselbarth wrote:
> This converts Berlin BG2CD SoC dtsi to make use of the new DT clock
> nodes for Berlin SoCs. Also add a binding include to ease core clock
> references.
>
> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> ---
[...]
> diff --git a/arch/arm/boot/dts/berlin2cd.dtsi b/arch/arm/boot/dts/berlin2cd.dtsi
> index 094968c27533..c1b8dc8264d3 100644
> --- a/arch/arm/boot/dts/berlin2cd.dtsi
> +++ b/arch/arm/boot/dts/berlin2cd.dtsi
[...]
> @@ -169,6 +164,153 @@
>   			};
>   		};
>
> +		syspll: pll@ea0014 {
> +			compatible = "marvell,berlin2-pll";
> +			#clock-cells = <0>;
> +			reg = <0xea0014 0x14>;
> +			clocks = <&refclk>;
> +		};
> +
> +		mempll: pll@ea0028 {
> +			compatible = "marvell,berlin2-pll";
> +			#clock-cells = <0>;
> +			reg = <0xea0028 0x14>;
> +			clocks = <&refclk>;
> +		};
> +
> +		cpupll: pll@ea003c {
> +			compatible = "marvell,berlin2-pll";
> +			#clock-cells = <0>;
> +			reg = <0xea003c 0x14>;
> +			clocks = <&refclk>;
> +		};
> +
> +		avpll: pll@ea0040 {
> +			compatible = "marvell,berlin2-avpll";
> +			#clock-cells = <2>;
> +			reg = <0xea0050 0x100>;
> +			clocks = <&refclk>;
> +		};
> +
> +		coreclk: clock@ea0150 {
> +			compatible = "marvell,berlin2-core-clocks";
> +			#clock-cells = <1>;
> +			reg = <0xea0150 0x1c>;
> +			clocks = <&refclk>, <&syspll>, <&mempll>, <&cpupll>,
> +				<&avpll 0 1>, <&avpll 0 2>,
> +				<&avpll 0 3>, <&avpll 0 4>,
> +				<&avpll 0 5>, <&avpll 0 6>,
> +				<&avpll 0 7>, <&avpll 0 8>,
> +				<&avpll 1 1>, <&avpll 1 2>,
> +				<&avpll 1 3>, <&avpll 1 4>,
> +				<&avpll 1 5>, <&avpll 1 6>,
> +				<&avpll 1 7>, <&avpll 1 8>;
> +			clock-names = "refclk", "syspll", "mempll", "cpupll",
> +				"avpll_a1", "avpll_a2", "avpll_a3", "avpll_a4",
> +				"avpll_a5", "avpll_a6", "avpll_a7", "avpll_a8",
> +				"avpll_b1", "avpll_b2", "avpll_b3", "avpll_b4",
> +				"avpll_b5", "avpll_b6", "avpll_b7", "avpll_b8";
> +		};
> +
> +		gfx3dcore_clk: clock@ea022c {
> +			compatible = "marvell,berlin2-clk-div";

correct compatible should be "marvell,berlin2-div"...

> +			#clock-cells = <0>;
> +			reg = <0xea0022c 0x4>;

... and reg is off by an extra '0'.

I'll fix it up for v2.

Sebastian

> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		gfx3dsys_clk: clock@ea0230 {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea00230 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		arc_clk: clock@ea0234 {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea00234 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		vip_clk: clock@ea0238 {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea00238 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		sdio0xin_clk: clock@ea023c {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea0023c 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		sdio1xin_clk: clock@ea0240 {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea00240 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		gfx3dextra_clk: clock@ea0244 {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea00244 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		gc360_clk: clock@ea024c {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea0024c 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
> +		sdio_dllmst_clk: clock@ea0250 {
> +			compatible = "marvell,berlin2-clk-div";
> +			#clock-cells = <0>;
> +			reg = <0xea00250 0x4>;
> +			clocks = <&syspll>,
> +				<&avpll 1 4>, <&avpll 1 5>,
> +				<&avpll 1 6>, <&avpll 1 7>;
> +			clock-names = "mux_bypass",
> +				"mux0", "mux1", "mux2", "mux3";
> +		};
> +
>   		apb@fc0000 {
>   			compatible = "simple-bus";
>   			#address-cells = <1>;
> @@ -183,7 +325,7 @@
>   				reg-shift = <2>;
>   				reg-io-width = <1>;
>   				interrupts = <8>;
> -				clocks = <&smclk>;
> +				clocks = <&refclk>;
>   				status = "disabled";
>   			};
>
> @@ -193,7 +335,7 @@
>   				reg-shift = <2>;
>   				reg-io-width = <1>;
>   				interrupts = <9>;
> -				clocks = <&smclk>;
> +				clocks = <&refclk>;
>   				status = "disabled";
>   			};
>
> diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile
> index f0a7dc8b5e30..2b33e1e74503 100644
> --- a/drivers/clk/berlin/Makefile
> +++ b/drivers/clk/berlin/Makefile
> @@ -1 +1,3 @@
>   obj-y += berlin2-avpll.o berlin2-pll.o berlin2-div.o
> +obj-$(CONFIG_MACH_BERLIN_BG2)	+= bg2.o
> +obj-$(CONFIG_MACH_BERLIN_BG2CD)	+= bg2.o
> diff --git a/include/dt-bindings/clock/berlin2.h b/include/dt-bindings/clock/berlin2.h
> new file mode 100644
> index 000000000000..dacf7edec4d3
> --- /dev/null
> +++ b/include/dt-bindings/clock/berlin2.h
> @@ -0,0 +1,35 @@
> +/*
> + * Berlin2 BG2/BG2CD clock tree IDs
> + */
> +
> +#define CLKID_SYS		0
> +#define CLKID_CPU		1
> +#define CLKID_DRMFIGO		2
> +#define CLKID_CFG		3
> +#define CLKID_GFX		4
> +#define CLKID_ZSP		5
> +#define CLKID_PERIF		6
> +#define CLKID_PCUBE		7
> +#define CLKID_VSCOPE		8
> +#define CLKID_NFC_ECC		9
> +#define CLKID_VPP		10
> +#define CLKID_APP		11
> +#define CLKID_AUDIO0		12
> +#define CLKID_AUDIO2		23
> +#define CLKID_AUDIO3		14
> +#define CLKID_AUDIO1		15
> +#define CLKID_GETH0		16
> +#define CLKID_GETH1		17
> +#define CLKID_SATA		18
> +#define CLKID_AHBAPB		19
> +#define CLKID_USB0		20
> +#define CLKID_USB1		21
> +#define CLKID_PBRIDGE		22
> +#define CLKID_SDIO0		23
> +#define CLKID_SDIO1		24
> +#define CLKID_NFC		25
> +#define CLKID_SMEMC		26
> +#define CLKID_AUDIOHD		27
> +#define CLKID_VIDEO0		28
> +#define CLKID_VIDEO1		29
> +#define CLKID_VIDEO2		30
>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/8] clk: berlin: add clock binding docs for Marvell Berlin2 SoCs
  2014-05-11 20:24 ` [PATCH 2/8] clk: berlin: add clock binding docs for Marvell Berlin2 SoCs Sebastian Hesselbarth
  2014-05-13  8:38   ` Sebastian Hesselbarth
@ 2014-05-13 14:47   ` Alexandre Belloni
  2014-05-14 22:32   ` Mike Turquette
  2 siblings, 0 replies; 40+ messages in thread
From: Alexandre Belloni @ 2014-05-13 14:47 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Mike Turquette, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Randy Dunlap, Antoine Tenart,
	devicetree, linux-doc, linux-arm-kernel, linux-kernel


Hi,

Not much to say,

On 11/05/2014 at 22:24:35 +0200, Sebastian Hesselbarth wrote :
> +* Single-register clock dividers
> +
> +Single-register clock dividers are complex divider cells, allowing
> +to divide a reference clock with a set of fixed dividers. Also they
> +comprise and input clock mux with bypass and an ouput clock gate.
typo here-----^

> +
> +Required properties:
> +- compatible: shall be "marvell,berlin2-clk-div"
> +- reg: address and length of the corresponding DIV registers
> +- #clock-cells: shall be set to 0
> +- clocks: clock specifiers referencing the DIV input clocks
> +- clock-names: array of strings describing the clock specifiers above.
> +    Allowed clock-names are "mux_bypass" for the clock mux bypass selection
> +    and "muxN" (N=0..7) for each of the 8 possible clock mux inputs.
> +

-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/8] clk: add helper for unique DT clock names
  2014-05-11 20:24 ` [PATCH 1/8] clk: add helper for unique DT clock names Sebastian Hesselbarth
@ 2014-05-13 19:49   ` Mike Turquette
  2014-05-13 20:19     ` Sebastian Hesselbarth
  0 siblings, 1 reply; 40+ messages in thread
From: Mike Turquette @ 2014-05-13 19:49 UTC (permalink / raw)
  To: Sebastian Hesselbarth, Sebastian Hesselbarth
  Cc: Grant Likely, Rob Herring, Alexandre Belloni, Antoine Tenart,
	devicetree, linux-arm-kernel, linux-kernel

Quoting Sebastian Hesselbarth (2014-05-11 13:24:34)
> Currently, most DT clock drivers pick a unique node name to allow unique
> clock names. As ePAPR recommends node names to be generic, we therefore
> provide a helper to generate a unique clock name from the DT node name
> plus reg property or a magic number instead. This is basically the same
> we already do for proper devices and may vanish as soon as there is some
> (early) device support for clocks available.
> 
> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> ---
> Cc: Mike Turquette <mturquette@linaro.org>
> Cc: Grant Likely <grant.likely@linaro.org>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
> Cc: devicetree@vger.kernel.org
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: linux-kernel@vger.kernel.org
> ---
>  drivers/clk/clk.c            | 29 +++++++++++++++++++++++++++++
>  include/linux/clk-provider.h |  5 +++++
>  2 files changed, 34 insertions(+)
> 
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index dff0373f53c1..b449a635dbfa 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -17,6 +17,7 @@
>  #include <linux/list.h>
>  #include <linux/slab.h>
>  #include <linux/of.h>
> +#include <linux/of_address.h>
>  #include <linux/device.h>
>  #include <linux/init.h>
>  #include <linux/sched.h>
> @@ -2543,6 +2544,34 @@ const char *of_clk_get_parent_name(struct device_node *np, int index)
>  }
>  EXPORT_SYMBOL_GPL(of_clk_get_parent_name);
>  
> +/**
> + * of_clk_create_name() - Allocate and create a unique clock name
> + * @np: Device node pointer of the clock node
> + *
> + * This will allocate and create a unique clock name based on the
> + * reg property value. As a last resort, it will use the node name
> + * followed by a unique number. The caller has to deallocate the
> + * buffer.
> + */
> +char *of_clk_create_name(struct device_node *np)
> +{
> +       static atomic_t clk_no_reg_magic;
> +       const __be32 *reg;
> +       u64 addr;
> +       int magic;
> +
> +       reg = of_get_property(np, "reg", NULL);
> +       if (reg) {
> +               addr = of_translate_address(np, reg);
> +               return kasprintf(GFP_KERNEL, "%llx.%s",
> +                                (unsigned long long)addr, np->name);
> +       }
> +
> +       magic = atomic_add_return(1, &clk_no_reg_magic);
> +       return kasprintf(GFP_KERNEL, "%s.%d", np->name, magic);

For the case where we the reg property is present we use reg.name, but
for the case were the reg property is missing we use name.magic. Is it
intentional to switch the string and integer pairs?

Doing so avoids the case where magic might collide with a simple bus
clock (e.g. 'clk@1'), but I wanted to double check that it was
intentional.

Regards,
Mike

> +}
> +EXPORT_SYMBOL_GPL(of_clk_create_name);
> +
>  struct clock_provider {
>         of_clk_init_cb_t clk_init_cb;
>         struct device_node *np;
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index 511917416fb0..c6f3ca1cd81c 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -514,6 +514,7 @@ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
>  struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
>  int of_clk_get_parent_count(struct device_node *np);
>  const char *of_clk_get_parent_name(struct device_node *np, int index);
> +char *of_clk_create_name(struct device_node *np);
>  
>  void of_clk_init(const struct of_device_id *matches);
>  
> @@ -543,6 +544,10 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
>  {
>         return NULL;
>  }
> +static inline char *of_clk_create_name(struct device_node *np)
> +{
> +       return NULL;
> +}
>  #define of_clk_init(matches) \
>         { while (0); }
>  #endif /* CONFIG_OF */
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/8] clk: add helper for unique DT clock names
  2014-05-13 19:49   ` Mike Turquette
@ 2014-05-13 20:19     ` Sebastian Hesselbarth
       [not found]       ` <20140513205111.5943.12709@quantum>
  0 siblings, 1 reply; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-13 20:19 UTC (permalink / raw)
  To: Mike Turquette
  Cc: Grant Likely, Rob Herring, Alexandre Belloni, Antoine Tenart,
	devicetree, linux-arm-kernel, linux-kernel

On 05/13/2014 09:49 PM, Mike Turquette wrote:
> Quoting Sebastian Hesselbarth (2014-05-11 13:24:34)
>> Currently, most DT clock drivers pick a unique node name to allow unique
>> clock names. As ePAPR recommends node names to be generic, we therefore
>> provide a helper to generate a unique clock name from the DT node name
>> plus reg property or a magic number instead. This is basically the same
>> we already do for proper devices and may vanish as soon as there is some
>> (early) device support for clocks available.
>>
>> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
[...]
>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
>> index dff0373f53c1..b449a635dbfa 100644
>> --- a/drivers/clk/clk.c
>> +++ b/drivers/clk/clk.c
>> @@ -17,6 +17,7 @@
>>  #include <linux/list.h>
>>  #include <linux/slab.h>
>>  #include <linux/of.h>
>> +#include <linux/of_address.h>
>>  #include <linux/device.h>
>>  #include <linux/init.h>
>>  #include <linux/sched.h>
>> @@ -2543,6 +2544,34 @@ const char *of_clk_get_parent_name(struct device_node *np, int index)
>>  }
>>  EXPORT_SYMBOL_GPL(of_clk_get_parent_name);
>>  
>> +/**
>> + * of_clk_create_name() - Allocate and create a unique clock name
>> + * @np: Device node pointer of the clock node
>> + *
>> + * This will allocate and create a unique clock name based on the
>> + * reg property value. As a last resort, it will use the node name
>> + * followed by a unique number. The caller has to deallocate the
>> + * buffer.
>> + */
>> +char *of_clk_create_name(struct device_node *np)
>> +{
>> +       static atomic_t clk_no_reg_magic;
>> +       const __be32 *reg;
>> +       u64 addr;
>> +       int magic;
>> +
>> +       reg = of_get_property(np, "reg", NULL);
>> +       if (reg) {
>> +               addr = of_translate_address(np, reg);
>> +               return kasprintf(GFP_KERNEL, "%llx.%s",
>> +                                (unsigned long long)addr, np->name);
>> +       }
>> +
>> +       magic = atomic_add_return(1, &clk_no_reg_magic);
>> +       return kasprintf(GFP_KERNEL, "%s.%d", np->name, magic);
> 
> For the case where we the reg property is present we use reg.name, but
> for the case were the reg property is missing we use name.magic. Is it
> intentional to switch the string and integer pairs?
> 
> Doing so avoids the case where magic might collide with a simple bus
> clock (e.g. 'clk@1'), but I wanted to double check that it was
> intentional.

Mike,

yes it is intentional and copies what is done for platform_device names.

Unfortunately, as much as I prefer this patch someday, it doesn't work
with the rest of the helpers as expected. While this can generate unique
and generic clock names, especially of_clk_get_parent_name() picks
either an clock-output-names named clock _or_ the node name ignoring the
above auto-generated name of course.

If you agree with the general approach here, we should still postpone
this for the next cycle when I have more time to look at the details.
I prefer to rename the nodes and use clock-output-names where required
for the Berlin clock nodes now.

Sebastian

>> +}
>> +EXPORT_SYMBOL_GPL(of_clk_create_name);
>> +
>>  struct clock_provider {
>>         of_clk_init_cb_t clk_init_cb;
>>         struct device_node *np;
>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>> index 511917416fb0..c6f3ca1cd81c 100644
>> --- a/include/linux/clk-provider.h
>> +++ b/include/linux/clk-provider.h
>> @@ -514,6 +514,7 @@ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
>>  struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
>>  int of_clk_get_parent_count(struct device_node *np);
>>  const char *of_clk_get_parent_name(struct device_node *np, int index);
>> +char *of_clk_create_name(struct device_node *np);
>>  
>>  void of_clk_init(const struct of_device_id *matches);
>>  
>> @@ -543,6 +544,10 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
>>  {
>>         return NULL;
>>  }
>> +static inline char *of_clk_create_name(struct device_node *np)
>> +{
>> +       return NULL;
>> +}
>>  #define of_clk_init(matches) \
>>         { while (0); }
>>  #endif /* CONFIG_OF */
>> -- 
>> 1.9.1
>>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/8] clk: add helper for unique DT clock names
       [not found]       ` <20140513205111.5943.12709@quantum>
@ 2014-05-13 21:25         ` Sebastian Hesselbarth
  0 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-13 21:25 UTC (permalink / raw)
  To: Mike Turquette
  Cc: Grant Likely, Rob Herring, Alexandre Belloni, Antoine Tenart,
	devicetree, linux-arm-kernel, linux-kernel

On 05/13/2014 10:51 PM, Mike Turquette wrote:
> Quoting Sebastian Hesselbarth (2014-05-13 13:19:58)
>> On 05/13/2014 09:49 PM, Mike Turquette wrote:
>>> Quoting Sebastian Hesselbarth (2014-05-11 13:24:34)
>>>> Currently, most DT clock drivers pick a unique node name to allow unique
>>>> clock names. As ePAPR recommends node names to be generic, we therefore
>>>> provide a helper to generate a unique clock name from the DT node name
>>>> plus reg property or a magic number instead. This is basically the same
>>>> we already do for proper devices and may vanish as soon as there is some
>>>> (early) device support for clocks available.
>>>>
>>>> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
>> [...]
>>>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
>>>> index dff0373f53c1..b449a635dbfa 100644
>>>> --- a/drivers/clk/clk.c
>>>> +++ b/drivers/clk/clk.c
>>>> @@ -17,6 +17,7 @@
>>>>  #include <linux/list.h>
>>>>  #include <linux/slab.h>
>>>>  #include <linux/of.h>
>>>> +#include <linux/of_address.h>
>>>>  #include <linux/device.h>
>>>>  #include <linux/init.h>
>>>>  #include <linux/sched.h>
>>>> @@ -2543,6 +2544,34 @@ const char *of_clk_get_parent_name(struct device_node *np, int index)
>>>>  }
>>>>  EXPORT_SYMBOL_GPL(of_clk_get_parent_name);
>>>>  
>>>> +/**
>>>> + * of_clk_create_name() - Allocate and create a unique clock name
>>>> + * @np: Device node pointer of the clock node
>>>> + *
>>>> + * This will allocate and create a unique clock name based on the
>>>> + * reg property value. As a last resort, it will use the node name
>>>> + * followed by a unique number. The caller has to deallocate the
>>>> + * buffer.
>>>> + */
>>>> +char *of_clk_create_name(struct device_node *np)
>>>> +{
>>>> +       static atomic_t clk_no_reg_magic;
>>>> +       const __be32 *reg;
>>>> +       u64 addr;
>>>> +       int magic;
>>>> +
>>>> +       reg = of_get_property(np, "reg", NULL);
>>>> +       if (reg) {
>>>> +               addr = of_translate_address(np, reg);
>>>> +               return kasprintf(GFP_KERNEL, "%llx.%s",
>>>> +                                (unsigned long long)addr, np->name);
>>>> +       }
>>>> +
>>>> +       magic = atomic_add_return(1, &clk_no_reg_magic);
>>>> +       return kasprintf(GFP_KERNEL, "%s.%d", np->name, magic);
>>>
>>> For the case where we the reg property is present we use reg.name, but
>>> for the case were the reg property is missing we use name.magic. Is it
>>> intentional to switch the string and integer pairs?
>>>
>>> Doing so avoids the case where magic might collide with a simple bus
>>> clock (e.g. 'clk@1'), but I wanted to double check that it was
>>> intentional.
>>
>> Mike,
>>
>> yes it is intentional and copies what is done for platform_device names.
>>
>> Unfortunately, as much as I prefer this patch someday, it doesn't work
>> with the rest of the helpers as expected. While this can generate unique
>> and generic clock names, especially of_clk_get_parent_name() picks
>> either an clock-output-names named clock _or_ the node name ignoring the
>> above auto-generated name of course.
>>
>> If you agree with the general approach here, we should still postpone
>> this for the next cycle when I have more time to look at the details.
>> I prefer to rename the nodes and use clock-output-names where required
>> for the Berlin clock nodes now.
> 
> Yes, that sounds fine. I'd also like the DT maintainers to take a look
> at this and weigh in.

Ok, great! So, I drop the of_clk_create_name() for the Berlin clock
drivers now and send a v2 with some bugs fixed. I also received the
requested BG2Q dtsi changes and tests from Alexandre.

Will pick up the DT clock naming issues next cycle then. Would be good
to get some remarks from the DT maintainers in the meantime.

Sebastian

>>>> +}
>>>> +EXPORT_SYMBOL_GPL(of_clk_create_name);
>>>> +
>>>>  struct clock_provider {
>>>>         of_clk_init_cb_t clk_init_cb;
>>>>         struct device_node *np;
>>>> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
>>>> index 511917416fb0..c6f3ca1cd81c 100644
>>>> --- a/include/linux/clk-provider.h
>>>> +++ b/include/linux/clk-provider.h
>>>> @@ -514,6 +514,7 @@ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
>>>>  struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
>>>>  int of_clk_get_parent_count(struct device_node *np);
>>>>  const char *of_clk_get_parent_name(struct device_node *np, int index);
>>>> +char *of_clk_create_name(struct device_node *np);
>>>>  
>>>>  void of_clk_init(const struct of_device_id *matches);
>>>>  
>>>> @@ -543,6 +544,10 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
>>>>  {
>>>>         return NULL;
>>>>  }
>>>> +static inline char *of_clk_create_name(struct device_node *np)
>>>> +{
>>>> +       return NULL;
>>>> +}
>>>>  #define of_clk_init(matches) \
>>>>         { while (0); }
>>>>  #endif /* CONFIG_OF */
>>>> -- 
>>>> 1.9.1
>>>>
>>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/8] clk: berlin: add core clock driver for BG2/BG2CD
  2014-05-11 20:24 ` [PATCH 6/8] clk: berlin: add core clock driver for BG2/BG2CD Sebastian Hesselbarth
@ 2014-05-14 11:43   ` Alexandre Belloni
  2014-05-14 11:48     ` Sebastian Hesselbarth
  0 siblings, 1 reply; 40+ messages in thread
From: Alexandre Belloni @ 2014-05-14 11:43 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Antoine Tenart, Mike Turquette, linux-kernel, linux-arm-kernel

On 11/05/2014 at 22:24:39 +0200, Sebastian Hesselbarth wrote :
> This driver deals with the core clocks found on Marvell Berlin
> BG2 and BG2CD. For the shared register dividers, make use of the
> corresponding driver and add some single clock muxes and gates for
> the rest.
> 
> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> ---
> Cc: Mike Turquette <mturquette@linaro.org>
> Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: linux-kernel@vger.kernel.org
> ---
>  drivers/clk/berlin/bg2.c | 509 +++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 509 insertions(+)
>  create mode 100644 drivers/clk/berlin/bg2.c
> 
> diff --git a/drivers/clk/berlin/bg2.c b/drivers/clk/berlin/bg2.c
> new file mode 100644
> index 000000000000..7fe04e11861b
> --- /dev/null
> +++ b/drivers/clk/berlin/bg2.c
> @@ -0,0 +1,509 @@
> +/*
> + * Copyright (c) 2014 Marvell Technology Group Ltd.
> + *
> + * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> + * Alexandre Belloni <alexandre.belloni@free-electrons.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/slab.h>
> +
> +#include "berlin2-div.h"
> +
> +/*
> + * BG2/BG2CD SoCs have the following audio/video I/O units:
> + *
> + * audiohd: HDMI TX audio
> + * audio0:  7.1ch TX
> + * audio1:  2ch TX
> + * audio2:  2ch RX
> + * audio3:  SPDIF TX
> + * video0:  HDMI video
> + * video1:  Secondary video
> + * video2:  SD auxiliary video
> + *
> + * There are no external audio clocks (ACLKI0, ACLKI1) and
> + * only one external video clock (VCLKI0).
> + *
> + * Currently missing bits and pieces:
> + * - audio_fast_pll is unknown
> + * - audiohd_pll is unknown
> + * - video0_pll is unknown
> + * - audio[023], audiohd parent pll is assumed to be audio_fast_pll
> + *
> + */
> +
> +struct bg2_gate_data {
> +	const char *name;
> +	const char *parent_name;
> +	u8 bit_idx;
> +	unsigned long flags;
> +};
> +
> +#define REG_CLKENABLE		0x00
> +#define REG_CLKSELECT0		0x04
> +#define REG_CLKSELECT1		0x08
> +#define REG_CLKSELECT2		0x0c
> +#define REG_CLKSELECT3		0x10
> +#define REG_CLKSWITCH0		0x14
> +#define REG_CLKSWITCH1		0x18
> +
> +enum {
> +	/* clock divider cells */
> +	SYS, CPU, DRMFIGO, CFG, GFX, ZSP, PERIF, PCUBE, VSCOPE, NFC_ECC,
> +	VPP, APP, AUDIO0, AUDIO2, AUDIO3, AUDIO1,
> +	/* clock gates */
> +	GETH0, GETH1, SATA, AHBAPB, USB0, USB1, PBRIDGE, SDIO0, SDIO1,
> +	NFC, SMEMC, AUDIOHD, VIDEO0, VIDEO1, VIDEO2,
> +	MAX_CLKS
> +};
> +

Shouldn't you reuse the CLKID_* that you are introducing in
dt-bindings/clock/berlin2.h in a following patch there ?
That would prevent inconsistencies.

> +enum { REFCLK, SYSPLL, MEMPLL, CPUPLL };
> +static const char *refclk_names[] = { "refclk", "syspll", "mempll", "cpupll" };
> +
> +enum { CH1, CH2, CH3, CH4, CH5, CH6, CH7, CH8 };
> +static const char *avplla_names[] = {
> +	"avpll_a1", "avpll_a2", "avpll_a3", "avpll_a4",
> +	"avpll_a5", "avpll_a6", "avpll_a7", "avpll_a8"
> +};
> +static const char *avpllb_names[] = {
> +	"avpll_b1", "avpll_b2", "avpll_b3", "avpll_b4",
> +	"avpll_b5", "avpll_b6", "avpll_b7", "avpll_a8"
> +};
> +static const char *video_ext0_name = "video_ext0";
> +
> +static DEFINE_SPINLOCK(lock);
> +static struct clk *clks[MAX_CLKS];
> +static struct clk_onecell_data clk_data;
> +
> +static const struct berlin2_div_data bg2_divs[] __initconst = {
> +	{
> +		.name = "sys",
> +		.flags = CLK_IGNORE_UNUSED,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 0),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "cpu",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "drmfigo",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 16),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 17),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 20),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "cfg",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 1),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 23),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 26),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "gfx",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 4),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 29),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 0),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "zsp",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 5),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 3),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 6),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "perif",
> +		.flags = CLK_IGNORE_UNUSED,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 6),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 9),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 12),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "pcube",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 2),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 15),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 18),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "vscope",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 3),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 21),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 24),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "nfc_ecc",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 18),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 27),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 0),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "vpp",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 21),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT2, 3),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 6),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 4),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 5),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 6),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "app",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 20),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT2, 9),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 12),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 7),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 8),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 9),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "audio0",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 22),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 17),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 10),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 11),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE,
> +	},
> +	{
> +		.name = "audio2",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 24),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 20),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 14),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 15),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE,
> +	},
> +	{
> +		.name = "audio3",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 25),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 23),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 16),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 17),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE,
> +	},
> +	{
> +		.name = "audio1",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 23),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT3, 0),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 12),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 13),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE,
> +	},
> +};
> +
> +static const struct bg2_gate_data bg2_gates[] __initconst = {
> +	{ "geth0",	"perif",	7 },
> +	{ "geth1",	"perif",	8 },
> +	{ "sata",	"perif",	9 },
> +	{ "ahbapb",	"perif",	10, CLK_IGNORE_UNUSED },
> +	{ "usb0",	"perif",	11 },
> +	{ "usb1",	"perif",	12 },
> +	{ "pbridge",	"perif",	13, CLK_IGNORE_UNUSED },
> +	{ "sdio0",	"perif",	14 },
> +	{ "sdio1",	"perif",	15 },
> +	{ "nfc",	"perif",	17 },
> +	{ "smemc",	"perif",	19 },
> +	{ "audiohd",	"audiohd_pll",	26 },
> +	{ "video0",	"video0_in",	27 },
> +	{ "video1",	"video1_in",	28 },
> +	{ "video2",	"video2_in",	29 },
> +};
> +
> +static int __init collect_refclks(struct device_node *np)
> +{
> +	struct clk *iclk;
> +	int n;
> +
> +	/* overwrite default clock names with DT provided ones */
> +	/* reference clocks */
> +	for (n = 0; n < ARRAY_SIZE(refclk_names); n++) {
> +		iclk = of_clk_get_by_name(np, refclk_names[n]);
> +		if (!IS_ERR(iclk)) {
> +			refclk_names[n] = __clk_get_name(iclk);
> +			clk_put(iclk);
> +		}
> +	}
> +
> +	/* AVPLL_A inputs */
> +	for (n = 0; n < ARRAY_SIZE(avplla_names); n++) {
> +		iclk = of_clk_get_by_name(np, avplla_names[n]);
> +		if (!IS_ERR(iclk)) {
> +			avplla_names[n] = __clk_get_name(iclk);
> +			clk_put(iclk);
> +		}
> +	}
> +
> +	/* AVPLL_B inputs */
> +	for (n = 0; n < ARRAY_SIZE(avpllb_names); n++) {
> +		iclk = of_clk_get_by_name(np, avpllb_names[n]);
> +		if (!IS_ERR(iclk)) {
> +			avpllb_names[n] = __clk_get_name(iclk);
> +			clk_put(iclk);
> +		}
> +	}
> +
> +	/* video_ext0 input */
> +	iclk = of_clk_get_by_name(np, video_ext0_name);
> +	if (!IS_ERR(iclk)) {
> +		video_ext0_name = __clk_get_name(iclk);
> +		clk_put(iclk);
> +	}
> +
> +	return 0;
> +}
> +
> +static void __init berlin2_core_clock_of_setup(struct device_node *np)
> +{
> +	const struct berlin2_div_data *data;
> +	const char *parent_names[9];
> +	void __iomem *base;
> +	struct clk *clk;
> +	int n;
> +
> +	if (collect_refclks(np))
> +		return;
> +
> +	base = of_iomap(np, 0);
> +	if (!base) {
> +		pr_err("%s: Unable to map register base\n", np->full_name);
> +		return;
> +	}
> +
> +	/* reference clock bypass switches */
> +	parent_names[0] = refclk_names[SYSPLL];
> +	parent_names[1] = refclk_names[REFCLK];
> +	clk = clk_register_mux(NULL, "syspll_in", parent_names, 2, 0,
> +			       base + REG_CLKSWITCH0, 0, 1, 0, &lock);
> +	if (IS_ERR(clk))
> +		goto core_clock_fail;
> +	refclk_names[SYSPLL] = __clk_get_name(clk);
> +
> +	parent_names[0] = refclk_names[MEMPLL];
> +	parent_names[1] = refclk_names[REFCLK];
> +	clk = clk_register_mux(NULL, "mempll_in", parent_names, 2, 0,
> +			       base + REG_CLKSWITCH0, 1, 1, 0, &lock);
> +	if (IS_ERR(clk))
> +		goto core_clock_fail;
> +	refclk_names[MEMPLL] = __clk_get_name(clk);
> +
> +	parent_names[0] = refclk_names[CPUPLL];
> +	parent_names[1] = refclk_names[REFCLK];
> +	clk = clk_register_mux(NULL, "cpupll_in", parent_names, 2, 0,
> +			       base + REG_CLKSWITCH0, 2, 1, 0, &lock);
> +	if (IS_ERR(clk))
> +		goto core_clock_fail;
> +	refclk_names[CPUPLL] = __clk_get_name(clk);
> +
> +	/* clock muxes */
> +	parent_names[0] = avpllb_names[CH3];
> +	parent_names[1] = avplla_names[CH3];
> +	clk = clk_register_mux(NULL, "audio1_pll", parent_names, 2, 0,
> +			       base + REG_CLKSELECT2, 29, 1, 0, &lock);
> +	if (IS_ERR(clk))
> +		goto core_clock_fail;
> +
> +	parent_names[0] = "video0_pll";
> +	parent_names[1] = video_ext0_name;
> +	clk = clk_register_mux(NULL, "video0_in", parent_names, 2, 0,
> +			       base + REG_CLKSELECT3, 4, 1, 0, &lock);
> +	if (IS_ERR(clk))
> +		goto core_clock_fail;
> +
> +	parent_names[0] = "video1_pll";
> +	parent_names[1] = video_ext0_name;
> +	clk = clk_register_mux(NULL, "video1_in", parent_names, 2, 0,
> +			       base + REG_CLKSELECT3, 6, 1, 0, &lock);
> +	if (IS_ERR(clk))
> +		goto core_clock_fail;
> +
> +	parent_names[0] = avplla_names[CH2];
> +	parent_names[1] = avpllb_names[CH2];
> +	clk = clk_register_mux(NULL, "video1_pll", parent_names, 2, 0,
> +			       base + REG_CLKSELECT3, 7, 1, 0, &lock);
> +	if (IS_ERR(clk))
> +		goto core_clock_fail;
> +
> +	parent_names[0] = "video2_pll";
> +	parent_names[1] = video_ext0_name;
> +	clk = clk_register_mux(NULL, "video2_in", parent_names, 2, 0,
> +			       base + REG_CLKSELECT3, 9, 1, 0, &lock);
> +	if (IS_ERR(clk))
> +		goto core_clock_fail;
> +
> +	parent_names[0] = avpllb_names[CH1];
> +	parent_names[1] = avplla_names[CH5];
> +	clk = clk_register_mux(NULL, "video2_pll", parent_names, 2, 0,
> +			       base + REG_CLKSELECT3, 10, 1, 0, &lock);
> +	if (IS_ERR(clk))
> +		goto core_clock_fail;
> +
> +	/* clock divider cells */
> +	parent_names[1] = avpllb_names[CH4];
> +	parent_names[2] = avpllb_names[CH5];
> +	parent_names[3] = avpllb_names[CH6];
> +	parent_names[4] = avpllb_names[CH7];
> +
> +	parent_names[0] = refclk_names[SYSPLL];
> +	data = &bg2_divs[SYS];
> +	clks[SYS] = berlin2_div_register(&data->map, base, data->name,
> +			 data->div_flags, parent_names, 5, data->flags, &lock);
> +
> +	parent_names[0] = refclk_names[CPUPLL];
> +	parent_names[5] = refclk_names[MEMPLL];
> +	data = &bg2_divs[CPU];
> +	clks[CPU] = berlin2_div_register(&data->map, base, data->name,
> +			 data->div_flags, parent_names, 6, data->flags, &lock);
> +
> +	parent_names[0] = refclk_names[SYSPLL];
> +	for (n = DRMFIGO; n <= APP; n++) {
> +		data = &bg2_divs[n];
> +		clks[n] = berlin2_div_register(&data->map, base, data->name,
> +			 data->div_flags, parent_names, 5, data->flags, &lock);
> +	}
> +
> +	parent_names[0] = "audio_fast_pll";
> +	for (n = AUDIO0; n <= AUDIO3; n++) {
> +		data = &bg2_divs[n];
> +		clks[n] = berlin2_div_register(&data->map, base, data->name,
> +			 data->div_flags, parent_names, 1, data->flags, &lock);
> +	}
> +
> +	parent_names[0] = "audio1_pll";
> +	data = &bg2_divs[AUDIO1];
> +	clks[AUDIO1] = berlin2_div_register(&data->map, base, data->name,
> +			 data->div_flags, parent_names, 1, data->flags, &lock);
> +
> +	/* clock gate cells */
> +	for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) {
> +		const struct bg2_gate_data *gd = &bg2_gates[n];
> +
> +		clks[GETH0 + n] = clk_register_gate(NULL, gd->name,
> +			    gd->parent_name, gd->flags, base + REG_CLKENABLE,
> +			    gd->bit_idx, 0, &lock);
> +	}
> +
> +	/* check for errors on leaf clocks */
> +	for (n = 0; n < MAX_CLKS; n++) {
> +		if (!IS_ERR(clks[n]))
> +			continue;
> +
> +		pr_err("%s: Unable to register leaf clock %d\n",
> +		       np->full_name, n);
> +		goto core_clock_fail;
> +	}
> +
> +	/* register clk-provider */
> +	clk_data.clks = clks;
> +	clk_data.clk_num = MAX_CLKS;
> +	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
> +	return;
> +
> +core_clock_fail:
> +	iounmap(base);
> +}
> +CLK_OF_DECLARE(berlin2_coreclk, "marvell,berlin2-core-clocks",
> +	       berlin2_core_clock_of_setup);
> -- 
> 1.9.1
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/8] clk: berlin: add core clock driver for BG2/BG2CD
  2014-05-14 11:43   ` Alexandre Belloni
@ 2014-05-14 11:48     ` Sebastian Hesselbarth
  0 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-14 11:48 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: Antoine Tenart, Mike Turquette, linux-kernel, linux-arm-kernel

On 05/14/2014 01:43 PM, Alexandre Belloni wrote:
> On 11/05/2014 at 22:24:39 +0200, Sebastian Hesselbarth wrote :
>> This driver deals with the core clocks found on Marvell Berlin
>> BG2 and BG2CD. For the shared register dividers, make use of the
>> corresponding driver and add some single clock muxes and gates for
>> the rest.
>>
>> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
[...]
>> diff --git a/drivers/clk/berlin/bg2.c b/drivers/clk/berlin/bg2.c
>> new file mode 100644
>> index 000000000000..7fe04e11861b
>> --- /dev/null
>> +++ b/drivers/clk/berlin/bg2.c
>> @@ -0,0 +1,509 @@
>> +/*
>> + * Copyright (c) 2014 Marvell Technology Group Ltd.
>> + *
>> + * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
>> + * Alexandre Belloni <alexandre.belloni@free-electrons.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms and conditions of the GNU General Public License,
>> + * version 2, as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>> + * more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/io.h>
>> +#include <linux/kernel.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/slab.h>
>> +
>> +#include "berlin2-div.h"
>> +
>> +/*
>> + * BG2/BG2CD SoCs have the following audio/video I/O units:
>> + *
>> + * audiohd: HDMI TX audio
>> + * audio0:  7.1ch TX
>> + * audio1:  2ch TX
>> + * audio2:  2ch RX
>> + * audio3:  SPDIF TX
>> + * video0:  HDMI video
>> + * video1:  Secondary video
>> + * video2:  SD auxiliary video
>> + *
>> + * There are no external audio clocks (ACLKI0, ACLKI1) and
>> + * only one external video clock (VCLKI0).
>> + *
>> + * Currently missing bits and pieces:
>> + * - audio_fast_pll is unknown
>> + * - audiohd_pll is unknown
>> + * - video0_pll is unknown
>> + * - audio[023], audiohd parent pll is assumed to be audio_fast_pll
>> + *
>> + */
>> +
>> +struct bg2_gate_data {
>> +	const char *name;
>> +	const char *parent_name;
>> +	u8 bit_idx;
>> +	unsigned long flags;
>> +};
>> +
>> +#define REG_CLKENABLE		0x00
>> +#define REG_CLKSELECT0		0x04
>> +#define REG_CLKSELECT1		0x08
>> +#define REG_CLKSELECT2		0x0c
>> +#define REG_CLKSELECT3		0x10
>> +#define REG_CLKSWITCH0		0x14
>> +#define REG_CLKSWITCH1		0x18
>> +
>> +enum {
>> +	/* clock divider cells */
>> +	SYS, CPU, DRMFIGO, CFG, GFX, ZSP, PERIF, PCUBE, VSCOPE, NFC_ECC,
>> +	VPP, APP, AUDIO0, AUDIO2, AUDIO3, AUDIO1,
>> +	/* clock gates */
>> +	GETH0, GETH1, SATA, AHBAPB, USB0, USB1, PBRIDGE, SDIO0, SDIO1,
>> +	NFC, SMEMC, AUDIOHD, VIDEO0, VIDEO1, VIDEO2,
>> +	MAX_CLKS
>> +};
>> +
>
> Shouldn't you reuse the CLKID_* that you are introducing in
> dt-bindings/clock/berlin2.h in a following patch there ?
> That would prevent inconsistencies.

I didn't follow the discussion of whether it is reasonable to
include dt-bindings/foo.h into driver code. But a quick git grep
reveals at least some drivers do it.

So, yes, if that is still valid, I fix it up to reuse the dt-binding
include here.

Sebastian


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v2 00/10] Marvell Berlin full clock support
  2014-05-11 20:24 [PATCH 0/8] Marvell Berlin full clock support Sebastian Hesselbarth
                   ` (7 preceding siblings ...)
  2014-05-11 20:24 ` [PATCH 8/8] ARM: dts: berlin: convert BG2 " Sebastian Hesselbarth
@ 2014-05-14 20:15 ` Sebastian Hesselbarth
  2014-05-14 20:15   ` [PATCH v2 01/10] dt-binding: clk: add clock binding docs for Marvell Berlin2 SoCs Sebastian Hesselbarth
                     ` (9 more replies)
  8 siblings, 10 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-14 20:15 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Mike Turquette, Alexandre Belloni, Jisheng Zhang,
	devicetree, linux-doc, linux-arm-kernel, linux-kernel

This is version 2 of a patch set to bring proper DT based clocks to
Marvell Berlin SoCs.

The overall changes are:

* Dropped of_clk_create_name() helper
Booting into an initramfs rootfs revealed that the unique clock names
created with that helper clash with the way of_clk_get_parent_name()
resolves the clock specifier to get the correct clock name. Anyway,
I still consider the helper a good idea and postpone it to the next
cycle when I have more time to look at the details.

* Added BG2Q core clock driver and dtsi changes
Alexandre just provided them, so I added them to this patch set.

The single patch overview now is:

Patch 1 adds the whole binding documentation for all clock related IP
found on BG2, BG2CD, and BG2Q.

Patch 2 adds corresponding dt-binding includes for the core clock
indices to be used in both DT and the driver.

Patches 3, 4, and 5 add clock drivers for the Audio/Video PLL, simple
PLLs, and complex clock divider cells found on Berlin SoCs. Where
required, currently known differences between BG2/BG2CD and BG2Q are
taken care of.

Patches 6 and 7 add core clock drivers for the remaining clocks of
BG2/BG2CD and BG2Q. The register set dealing with it, is shared among
input and bypass muxes, clock dividers and clock gates.

Patches 8, 9, and 10 finally convert the DT SoC includes for BG2,
BG2CD, and BG2Q to make use of the new clock related DT nodes.

Alexandre Belloni (4):
  clk: berlin: add driver for BG2x simple PLLs
  clk: berlin: add driver for BG2x complex divider cells
  clk: berlin: add core clock driver for BG2Q
  ARM: dts: berlin: convert BG2Q to DT clock nodes

Sebastian Hesselbarth (6):
  dt-binding: clk: add clock binding docs for Marvell Berlin2 SoCs
  clk: berlin: add binding include for BG2/BG2CD clock ids
  clk: berlin: add driver for BG2x audio/video PLL
  clk: berlin: add core clock driver for BG2/BG2CD
  ARM: dts: berlin: convert BG2CD to DT clock nodes
  ARM: dts: berlin: convert BG2 to DT clock nodes

 .../devicetree/bindings/clock/berlin2-clock.txt    | 195 ++++++++
 arch/arm/boot/dts/berlin2.dtsi                     | 207 +++++++--
 arch/arm/boot/dts/berlin2cd.dtsi                   | 205 +++++++--
 arch/arm/boot/dts/berlin2q.dtsi                    |  80 +++-
 drivers/clk/Makefile                               |   1 +
 drivers/clk/berlin/Makefile                        |   4 +
 drivers/clk/berlin/berlin2-avpll.c                 | 368 +++++++++++++++
 drivers/clk/berlin/berlin2-div.c                   | 324 +++++++++++++
 drivers/clk/berlin/berlin2-div.h                   |  80 ++++
 drivers/clk/berlin/berlin2-pll.c                   | 168 +++++++
 drivers/clk/berlin/bg2.c                           | 502 +++++++++++++++++++++
 drivers/clk/berlin/bg2q.c                          | 269 +++++++++++
 include/dt-bindings/clock/berlin2.h                |  35 ++
 include/dt-bindings/clock/berlin2q.h               |  28 ++
 14 files changed, 2385 insertions(+), 81 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/berlin2-clock.txt
 create mode 100644 drivers/clk/berlin/Makefile
 create mode 100644 drivers/clk/berlin/berlin2-avpll.c
 create mode 100644 drivers/clk/berlin/berlin2-div.c
 create mode 100644 drivers/clk/berlin/berlin2-div.h
 create mode 100644 drivers/clk/berlin/berlin2-pll.c
 create mode 100644 drivers/clk/berlin/bg2.c
 create mode 100644 drivers/clk/berlin/bg2q.c
 create mode 100644 include/dt-bindings/clock/berlin2.h
 create mode 100644 include/dt-bindings/clock/berlin2q.h

---
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Cc: devicetree@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
-- 
1.9.1


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v2 01/10] dt-binding: clk: add clock binding docs for Marvell Berlin2 SoCs
  2014-05-14 20:15 ` [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
@ 2014-05-14 20:15   ` Sebastian Hesselbarth
  2014-05-14 20:15   ` [PATCH v2 02/10] clk: berlin: add binding include for BG2/BG2CD clock ids Sebastian Hesselbarth
                     ` (8 subsequent siblings)
  9 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-14 20:15 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Alexandre Belloni, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Randy Dunlap, Mike Turquette,
	Jisheng Zhang, devicetree, linux-doc, linux-arm-kernel,
	linux-kernel

This adds mandatory device tree binding documentation for the clock related
IP found on Marvell Berlin2 (BG2, BG2CD, and BG2Q) SoCs.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
Changelog:
v1->v2:
- typo fixed (Reported by Alexandre Belloni)
- added BG2Q core clock indices

Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Cc: devicetree@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 .../devicetree/bindings/clock/berlin2-clock.txt    | 195 +++++++++++++++++++++
 1 file changed, 195 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/berlin2-clock.txt

diff --git a/Documentation/devicetree/bindings/clock/berlin2-clock.txt b/Documentation/devicetree/bindings/clock/berlin2-clock.txt
new file mode 100644
index 000000000000..6ca380cf6e4f
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/berlin2-clock.txt
@@ -0,0 +1,195 @@
+* Marvell Berlin2 clock bindings
+
+Marvell Berlin2 (BG2, BG2CD, BG2Q) share the same IP for PLLs and clocks,
+with some minor differences in features and register layout. The below
+describes the individual clock related IP:
+
+* Audio/Video PLL
+
+The Audio/Video PLL (AVPLL) is a dual-VCO PLL with 8 channels each. Each
+of the VCOs can sythesize a single VCO frequency based on a single input
+reference clock. Each of the 8 channels then, can derive an output clock
+from that VCO frequency by various dividers/multipliers.
+
+Required properties:
+- compatible: shall be "marvell,berlin2-avpll"
+- reg: address and length of the corresponding AVPLL registers
+- #clock-cells: shall be set to 2
+- clocks: single clock specifier referencing the AVPLL input clock
+
+To ease match-up with the desired AVPLL output clock, clock specifiers
+referencing AVPLL clocks shall contain two cells. The first refers to
+the VCO (0=AVPLL_A, 1=AVPLL_B) while the second refers to the corresponding
+channel starting with 1. For example, to reference AVPLL_B3 the clock
+specifier shall be: <&avpll 1 3>.
+
+Example:
+
+avpll: pll@ea0040 {
+	compatible = "marvell,berlin2-avpll";
+	#clock-cells = <2>;
+	reg = <0xea0050 0x100>;
+	clocks = <&refclk>;
+};
+
+* Simple PLLs
+
+Simple PLLs are memory mapped PLLs that can sythesize a single output clock
+based on a single input reference clock.
+
+Required properties:
+- compatible: shall be one of the following:
+	"marvell,berlin2-pll" for Berlin BG2/BG2CD PLLs
+	"marvell,berlin2q-pll" for Berlin BG2Q PLLs
+- reg: address and length of the corresponding PLL registers
+- #clock-cells: shall be set to 0
+- clocks: single clock specifier referencing the PLL input clock
+
+Example:
+
+cpupll: pll@ea003c {
+	compatible = "marvell,berlin2-pll";
+	#clock-cells = <0>;
+	reg = <0xea003c 0x14>;
+	clocks = <&refclk>;
+};
+
+* Single-register clock dividers
+
+Single-register clock dividers are complex divider cells, allowing
+to divide a reference clock with a set of fixed dividers. Also they
+comprise an input clock mux with bypass and an ouput clock gate.
+
+Required properties:
+- compatible: shall be "marvell,berlin2-clk-div"
+- reg: address and length of the corresponding DIV registers
+- #clock-cells: shall be set to 0
+- clocks: clock specifiers referencing the DIV input clocks
+- clock-names: array of strings describing the clock specifiers above.
+    Allowed clock-names are "mux_bypass" for the clock mux bypass selection
+    and "muxN" (N=0..7) for each of the 8 possible clock mux inputs.
+
+Example:
+
+gfx3dcore_clk: clock@ea022c {
+	compatible = "marvell,berlin2-clk-div";
+	#clock-cells = <0>;
+	reg = <0xea0022c 0x4>;
+	clocks = <&syspll>,
+		<&avpll AVPLL_B 4>, <&avpll AVPLL_B 5>,
+		<&avpll AVPLL_B 6>, <&avpll AVPLL_B 7>;
+	clock-names = "mux_bypass",
+		"mux0", "mux1", "mux2", "mux3";
+};
+
+* SoC-specific core clocks
+
+In addition to the above, there is a register set dealing with SoC
+specific clock dividers, muxes, and gates. There is also the complex
+divider cell used above, but instead of independent registers, they
+share a common set of registers. The core clocks are represented by
+a single DT node providing access to the remaining clocks.
+
+Required properties:
+- compatible: shall be one of
+	"marvell,berlin2-core-clocks" for BG2/BG2CD SoCs
+	"marvell,berlin2q-core-clocks" for BG2Q SoCs
+- reg: address and length of the corresponding clock registers
+- #clock-cells: shall be set to 1
+- clocks: clock specifiers referencing the core clock input clocks
+- clock-names: array of strings describing the clock specifiers above.
+    Allowed clock-names for the reference clocks are
+      "refclk", "syspll", "mempll", "cpupll"
+    also Audio/Video PLL clocks shall be named with
+      "avpll_VN" (V=0...1 for AVPLL_A and AVPLL_B, N=1..8 for the
+      corresponding reference input from AVPLL).
+
+Optional properties for BG2/BG2CD SoCs:
+- clocks/clock-names: in addition to the allowed clock names above,
+    there is an external video clock input that shall be named "video_ext0".
+
+Clocks provided by core clocks shall be referenced by a clock specifier
+indexing one of the provided clocks. A SoC-specific list of available clocks
+is below the example.
+
+Example:
+coreclk: clock@ea0150 {
+	compatible = "marvell,berlin2-core-clocks";
+	#clock-cells = <1>;
+	reg = <0xea0150 0x1c>;
+	clocks = <&refclk>, <&syspll>, <&mempll>, <&cpupll>,
+		<&avpll 0 1>, <&avpll 0 2>,
+		<&avpll 0 3>, <&avpll 0 4>,
+		<&avpll 0 5>, <&avpll 0 6>,
+		<&avpll 0 7>, <&avpll 0 8>,
+		<&avpll 1 1>, <&avpll 1 2>,
+		<&avpll 1 3>, <&avpll 1 4>,
+		<&avpll 1 5>, <&avpll 1 6>,
+		<&avpll 1 7>, <&avpll 1 8>,
+		<&externalvideoclk>;
+	clock-names = "refclk", "syspll", "mempll", "cpupll",
+		"avpll_a1", "avpll_a2", "avpll_a3", "avpll_a4",
+		"avpll_a5", "avpll_a6", "avpll_a7", "avpll_a8",
+		"avpll_b1", "avpll_b2", "avpll_b3", "avpll_b4",
+		"avpll_b5", "avpll_b6", "avpll_b7", "avpll_b8",
+		"video_ext0";
+};
+
+* BG2/BG2CD core clock indicies:
+0  - SYS
+1  - CPU
+2  - DRMFIGO
+3  - CFG
+4  - GFX
+5  - ZSP
+6  - PERIF
+7  - PCUBE
+8  - VSCOPE
+9  - NFC_ECC
+10 - VPP
+11 - APP
+12 - AUDIO0
+23 - AUDIO2
+14 - AUDIO3
+15 - AUDIO1
+16 - GETH0
+17 - GETH1
+18 - SATA
+19 - AHBAPB
+20 - USB0
+21 - USB1
+22 - PBRIDGE
+23 - SDIO0
+24 - SDIO1
+25 - NFC
+26 - SMEMC
+27 - AUDIOHD
+28 - VIDEO0
+29 - VIDEO1
+30 - VIDEO2
+
+* BG2Q core clock indicies:
+0  - SYS
+1  - DRMFIGO
+2  - CFG
+3  - GFX2D
+4  - ZSP
+5  - PERIF
+6  - PCUBE
+7  - VSCOPE
+8  - NFC_ECC
+9  - VPP
+10 - APP
+11 - GFX2DAXI
+12 - GETH0
+13 - SATA
+14 - AHBAPB
+15 - USB0
+16 - USB1
+17 - USB2
+18 - USB3
+19 - PBRIDGE
+20 - SDIO
+21 - NFC
+22 - SMEMC
+23 - PCIE
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v2 02/10] clk: berlin: add binding include for BG2/BG2CD clock ids
  2014-05-14 20:15 ` [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
  2014-05-14 20:15   ` [PATCH v2 01/10] dt-binding: clk: add clock binding docs for Marvell Berlin2 SoCs Sebastian Hesselbarth
@ 2014-05-14 20:15   ` Sebastian Hesselbarth
  2014-05-14 20:15   ` [PATCH v2 03/10] clk: berlin: add driver for BG2x audio/video PLL Sebastian Hesselbarth
                     ` (7 subsequent siblings)
  9 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-14 20:15 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Alexandre Belloni, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Mike Turquette, Jisheng Zhang,
	devicetree, linux-arm-kernel, linux-kernel

This adds a dt-binding include for Marvell Berlin BG2/BG2CD and BG2Q
core clock IDs.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
Changelog:
v1->v2:
- separate patch to make it usable in the driver (Suggested by Alexandre
  Belloni)

Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 include/dt-bindings/clock/berlin2.h  | 35 +++++++++++++++++++++++++++++++++++
 include/dt-bindings/clock/berlin2q.h | 28 ++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)
 create mode 100644 include/dt-bindings/clock/berlin2.h
 create mode 100644 include/dt-bindings/clock/berlin2q.h

diff --git a/include/dt-bindings/clock/berlin2.h b/include/dt-bindings/clock/berlin2.h
new file mode 100644
index 000000000000..dacf7edec4d3
--- /dev/null
+++ b/include/dt-bindings/clock/berlin2.h
@@ -0,0 +1,35 @@
+/*
+ * Berlin2 BG2/BG2CD clock tree IDs
+ */
+
+#define CLKID_SYS		0
+#define CLKID_CPU		1
+#define CLKID_DRMFIGO		2
+#define CLKID_CFG		3
+#define CLKID_GFX		4
+#define CLKID_ZSP		5
+#define CLKID_PERIF		6
+#define CLKID_PCUBE		7
+#define CLKID_VSCOPE		8
+#define CLKID_NFC_ECC		9
+#define CLKID_VPP		10
+#define CLKID_APP		11
+#define CLKID_AUDIO0		12
+#define CLKID_AUDIO2		23
+#define CLKID_AUDIO3		14
+#define CLKID_AUDIO1		15
+#define CLKID_GETH0		16
+#define CLKID_GETH1		17
+#define CLKID_SATA		18
+#define CLKID_AHBAPB		19
+#define CLKID_USB0		20
+#define CLKID_USB1		21
+#define CLKID_PBRIDGE		22
+#define CLKID_SDIO0		23
+#define CLKID_SDIO1		24
+#define CLKID_NFC		25
+#define CLKID_SMEMC		26
+#define CLKID_AUDIOHD		27
+#define CLKID_VIDEO0		28
+#define CLKID_VIDEO1		29
+#define CLKID_VIDEO2		30
diff --git a/include/dt-bindings/clock/berlin2q.h b/include/dt-bindings/clock/berlin2q.h
new file mode 100644
index 000000000000..069d6516ea9c
--- /dev/null
+++ b/include/dt-bindings/clock/berlin2q.h
@@ -0,0 +1,28 @@
+/*
+ * Berlin2 BG2Q clock tree IDs
+ */
+
+#define CLKID_SYS		0
+#define CLKID_DRMFIGO		1
+#define CLKID_CFG		2
+#define CLKID_GFX2D		3
+#define CLKID_ZSP		4
+#define CLKID_PERIF		5
+#define CLKID_PCUBE		6
+#define CLKID_VSCOPE		7
+#define CLKID_NFC_ECC		8
+#define CLKID_VPP		9
+#define CLKID_APP		10
+#define CLKID_GFX2DAXI		11
+#define CLKID_GETH0		12
+#define CLKID_SATA		13
+#define CLKID_AHBAPB		14
+#define CLKID_USB0		15
+#define CLKID_USB1		16
+#define CLKID_USB2		17
+#define CLKID_USB3		18
+#define CLKID_PBRIDGE		19
+#define CLKID_SDIO		20
+#define CLKID_NFC		21
+#define CLKID_SMEMC		22
+#define CLKID_PCIE		23
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v2 03/10] clk: berlin: add driver for BG2x audio/video PLL
  2014-05-14 20:15 ` [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
  2014-05-14 20:15   ` [PATCH v2 01/10] dt-binding: clk: add clock binding docs for Marvell Berlin2 SoCs Sebastian Hesselbarth
  2014-05-14 20:15   ` [PATCH v2 02/10] clk: berlin: add binding include for BG2/BG2CD clock ids Sebastian Hesselbarth
@ 2014-05-14 20:15   ` Sebastian Hesselbarth
  2014-05-14 20:15   ` [PATCH v2 04/10] clk: berlin: add driver for BG2x simple PLLs Sebastian Hesselbarth
                     ` (6 subsequent siblings)
  9 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-14 20:15 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Alexandre Belloni, Mike Turquette, Jisheng Zhang,
	linux-arm-kernel, linux-kernel

This is a driver for the dual-VCO PLL with 8 channels each found on
Marvell Berlin2 SoCs. While both VCOs share the same register set,
sometimes registers shifts for one of the VCOs is a bit off. Nothing
serious that should require a separate driver, so deal with both VCOs
in a single driver instead.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Changelog:
v1->v2:
- dropped usage of postponed of_clk_create_name()

Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 drivers/clk/Makefile               |   1 +
 drivers/clk/berlin/Makefile        |   1 +
 drivers/clk/berlin/berlin2-avpll.c | 368 +++++++++++++++++++++++++++++++++++++
 3 files changed, 370 insertions(+)
 create mode 100644 drivers/clk/berlin/Makefile
 create mode 100644 drivers/clk/berlin/berlin2-avpll.c

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 5f8a28735c96..f651b2ace915 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_COMMON_CLK_WM831X)		+= clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_XGENE)		+= clk-xgene.o
 obj-$(CONFIG_COMMON_CLK_AT91)		+= at91/
 obj-$(CONFIG_ARCH_BCM_MOBILE)		+= bcm/
+obj-$(CONFIG_ARCH_BERLIN)		+= berlin/
 obj-$(CONFIG_ARCH_HI3xxx)		+= hisilicon/
 obj-$(CONFIG_ARCH_HIP04)		+= hisilicon/
 obj-$(CONFIG_COMMON_CLK_KEYSTONE)	+= keystone/
diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile
new file mode 100644
index 000000000000..5905733fc7c7
--- /dev/null
+++ b/drivers/clk/berlin/Makefile
@@ -0,0 +1 @@
+obj-y += berlin2-avpll.o
diff --git a/drivers/clk/berlin/berlin2-avpll.c b/drivers/clk/berlin/berlin2-avpll.c
new file mode 100644
index 000000000000..a06cde9193f6
--- /dev/null
+++ b/drivers/clk/berlin/berlin2-avpll.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+/*
+ * Berlin2 AVPLL comprises two PLLs (VCOs) with 8 channels each,
+ * channel 8 is the odd-one-out and does not provide mul/div.
+ *
+ * Unfortunately, its registers are just numbered from 0-63. To
+ * get in at least some kind of structure, we split both VCOs and
+ * each of the channels into separate clock drivers.
+ *
+ * Also, here and there the VCO registers are a bit different with
+ * respect to bit shifts. Make sure to add a comment for those.
+ */
+#define NUM_VCOS	2
+#define NUM_CHANNELS	8
+
+#define AVPLL_CTRL(x)		((x) * 0x4)
+/* Second VCO starts at AVPLL_CTRL31 */
+#define VCO_OFFSET		AVPLL_CTRL(31)
+
+#define VCO_CTRL0		AVPLL_CTRL(0)
+/* VCO_B has an additional shift of 4 for its VCO_CTRL0 reg */
+#define  VCO_RESET		BIT(0)
+#define  VCO_POWERUP		BIT(1)
+#define  VCO_INTERPOL_SHIFT	2
+#define  VCO_INTERPOL_MASK	(0xf << VCO_INTERPOL_SHIFT)
+#define  VCO_REG1V45_SEL_SHIFT	6
+#define  VCO_REG1V45_SEL(x)	((x) << VCO_REG1V45_SEL_SHIFT)
+#define  VCO_REG1V45_SEL_1V40	VCO_REG1V45_SEL(0)
+#define  VCO_REG1V45_SEL_1V45	VCO_REG1V45_SEL(1)
+#define  VCO_REG1V45_SEL_1V50	VCO_REG1V45_SEL(2)
+#define  VCO_REG1V45_SEL_1V55	VCO_REG1V45_SEL(3)
+#define  VCO_REG1V45_SEL_MASK	VCO_REG1V45_SEL(3)
+#define  VCO_REG0V9_SEL_SHIFT	8
+#define  VCO_REG0V9_SEL_MASK	(0xf << VCO_REG0V9_SEL_SHIFT)
+#define  VCO_VTHCAL_SHIFT	12
+#define  VCO_VTHCAL(x)		((x) << VCO_VTHCAL_SHIFT)
+#define  VCO_VTHCAL_0V90	VCO_VTHCAL(0)
+#define  VCO_VTHCAL_0V95	VCO_VTHCAL(1)
+#define  VCO_VTHCAL_1V00	VCO_VTHCAL(2)
+#define  VCO_VTHCAL_1V05	VCO_VTHCAL(3)
+#define  VCO_VTHCAL_MASK	VCO_VTHCAL(3)
+#define  VCO_KVCOEXT_SHIFT	14
+#define  VCO_KVCOEXT_MASK	(0x3 << VCO_KVCOEXT_SHIFT)
+#define  VCO_KVCOEXT_ENABLE	BIT(17)
+#define  VCO_V2IEXT_SHIFT	18
+#define  VCO_V2IEXT_MASK	(0xf << VCO_V2IEXT_SHIFT)
+#define  VCO_V2IEXT_ENABLE	BIT(22)
+#define  VCO_SPEED_SHIFT	23
+#define  VCO_SPEED(x)		((x) << VCO_SPEED_SHIFT)
+#define  VCO_SPEED_1G08_1G21	VCO_SPEED(0)
+#define  VCO_SPEED_1G21_1G40	VCO_SPEED(1)
+#define  VCO_SPEED_1G40_1G61	VCO_SPEED(2)
+#define  VCO_SPEED_1G61_1G86	VCO_SPEED(3)
+#define  VCO_SPEED_1G86_2G00	VCO_SPEED(4)
+#define  VCO_SPEED_2G00_2G22	VCO_SPEED(5)
+#define  VCO_SPEED_2G22		VCO_SPEED(6)
+#define  VCO_SPEED_MASK		VCO_SPEED(0x7)
+#define  VCO_CLKDET_ENABLE	BIT(26)
+#define VCO_CTRL1		AVPLL_CTRL(1)
+#define  VCO_REFDIV_SHIFT	0
+#define  VCO_REFDIV(x)		((x) << VCO_REFDIV_SHIFT)
+#define  VCO_REFDIV_1		VCO_REFDIV(0)
+#define  VCO_REFDIV_2		VCO_REFDIV(1)
+#define  VCO_REFDIV_4		VCO_REFDIV(2)
+#define  VCO_REFDIV_3		VCO_REFDIV(3)
+#define  VCO_REFDIV_MASK	VCO_REFDIV(0x3f)
+#define  VCO_FBDIV_SHIFT	6
+#define  VCO_FBDIV(x)		((x) << VCO_FBDIV_SHIFT)
+#define  VCO_FBDIV_MASK		VCO_FBDIV(0xff)
+#define  VCO_ICP_SHIFT		14
+/* PLL Charge Pump Current = 10uA * (x + 1) */
+#define  VCO_ICP(x)		((x) << VCO_ICP_SHIFT)
+#define  VCO_ICP_MASK		VCO_ICP(0xf)
+#define  VCO_LOAD_CAP		BIT(18)
+#define  VCO_CALIBRATION_START	BIT(19)
+#define VCO_FREQOFFSETn(x)	AVPLL_CTRL(3 + (x))
+#define  VCO_FREQOFFSET_MASK	0x7ffff
+#define VCO_CTRL11		AVPLL_CTRL(11)
+#define VCO_CTRL12		AVPLL_CTRL(12)
+#define VCO_CTRL13		AVPLL_CTRL(13)
+#define VCO_CTRL14		AVPLL_CTRL(14)
+#define VCO_CTRL15		AVPLL_CTRL(15)
+#define VCO_SYNC1n(x)		AVPLL_CTRL(15 + (x))
+#define  VCO_SYNC1_MASK		0x1ffff
+#define VCO_SYNC2n(x)		AVPLL_CTRL(23 + (x))
+#define  VCO_SYNC2_MASK		0x1ffff
+#define VCO_CTRL30		AVPLL_CTRL(30)
+#define  VCO_DPLL_CH1_ENABLE	BIT(17)
+
+struct avpll_vco;
+struct avpll;
+
+struct avpll_channel {
+	struct clk_hw hw;
+	struct avpll_vco *vco;
+	u8 index;
+};
+
+struct avpll_vco {
+	struct clk_hw hw;
+	struct avpll_channel channel[NUM_CHANNELS];
+	struct clk *clks[NUM_CHANNELS];
+	void __iomem *base;
+	struct avpll *pll;
+	u8 index;
+};
+
+struct avpll {
+	struct avpll_vco vco[NUM_VCOS];
+	void __iomem *base;
+};
+
+#define to_avpll_vco(hw) container_of(hw, struct avpll_vco, hw)
+#define to_avpll_channel(hw) container_of(hw, struct avpll_channel, hw)
+
+static u8 vco_refdiv[] = { 1, 2, 4, 3 };
+
+static unsigned long
+avpll_vco_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct avpll_vco *vco = to_avpll_vco(hw);
+	u32 reg, refdiv;
+	u64 freq;
+
+	/* AVPLL VCO frequency: Fvco = (Fref / refdiv) * FBdiv */
+	reg = readl_relaxed(vco->base + VCO_CTRL1);
+	refdiv = (reg & VCO_REFDIV_MASK) >> VCO_REFDIV_SHIFT;
+	refdiv = vco_refdiv[refdiv];
+	freq = (reg & VCO_FBDIV_MASK) >> VCO_FBDIV_SHIFT;
+	freq *= parent_rate;
+	do_div(freq, refdiv);
+
+	return (unsigned long)freq;
+}
+
+static const struct clk_ops avpll_vco_ops = {
+	.recalc_rate	= avpll_vco_recalc_rate,
+};
+
+static const u8 div_hdmi[] = { 1, 2, 4, 6 };
+static const u8 div_av1[] = { 1, 2, 5, 5 };
+
+static unsigned long
+avpll_channel_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct avpll_channel *ch = to_avpll_channel(hw);
+	struct avpll_vco *vco = ch->vco;
+	u32 reg, divider = 1;
+	u64 freq = parent_rate;
+
+	reg = readl_relaxed(vco->base + VCO_CTRL30);
+	if ((reg & (VCO_DPLL_CH1_ENABLE << ch->index)) == 0)
+		goto skip_div;
+
+	/*
+	 * Fch = (Fref * sync2) /
+	 *    (sync1 * div_hdmi * div_av1 * div_av2 * div_av3)
+	 */
+
+	reg = readl_relaxed(vco->base + VCO_SYNC1n(ch->index));
+	/* SYNC1 for Channel 1 is shifted by 4 bits */
+	if (ch->index == 0)
+		reg >>= 4;
+	divider = reg & VCO_SYNC1_MASK;
+
+	reg = readl_relaxed(vco->base + VCO_SYNC2n(ch->index));
+	freq *= reg & VCO_SYNC2_MASK;
+
+	/* Channel 8 has no dividers */
+	if (ch->index == 7)
+		goto skip_div;
+
+	/*
+	 * HDMI divider start at VCO_CTRL11, bit 7; each 3 bits wide but
+	 * only 0-3 are valid values.
+	 */
+	reg = readl_relaxed(vco->base + VCO_CTRL11) >> 7;
+	divider *= div_hdmi[(reg >> (ch->index * 3)) & 0x3];
+
+	/*
+	 * AV1 divider start at VCO_CTRL11, bit 28; each 3 bits wide but
+	 * only 0-3 are valid values.
+	 */
+	if (ch->index == 0) {
+		reg = readl_relaxed(vco->base + VCO_CTRL11);
+		reg >>= 28;
+	} else {
+		reg = readl_relaxed(vco->base + VCO_CTRL12);
+		reg >>= (ch->index-1) * 3;
+	}
+	divider *= div_av1[reg & 0x3];
+
+	/*
+	 * AV2 divider start at VCO_CTRL12, bit 18; each 7 bits wide,
+	 * zero is not a valid value.
+	 */
+	if (ch->index < 2) {
+		reg = readl_relaxed(vco->base + VCO_CTRL12);
+		reg >>= 18 + (ch->index * 7);
+	} else if (ch->index < 7) {
+		reg = readl_relaxed(vco->base + VCO_CTRL13);
+		reg >>= (ch->index - 2) * 7;
+	} else {
+		reg = readl_relaxed(vco->base + VCO_CTRL14);
+	}
+
+	reg &= 0x7f;
+	if (reg)
+		divider *= reg;
+
+	/*
+	 * AV3 divider start at VCO_CTRL14, bit 7; each 4 bits wide,
+	 * only 0, 1 are valid values. AV3=1 divides by 1/2, AV3=0 is bypass.
+	 */
+	if (ch->index < 6) {
+		reg = readl_relaxed(vco->base + VCO_CTRL14);
+		reg >>= 7 + (ch->index * 4);
+	} else {
+		reg = readl_relaxed(vco->base + VCO_CTRL15);
+	}
+
+	if (reg & 0x1)
+		freq *= 2;
+
+skip_div:
+	do_div(freq, divider);
+	return (unsigned long)freq;
+}
+
+static const struct clk_ops avpll_channel_ops = {
+	.recalc_rate	= avpll_channel_recalc_rate,
+};
+
+/*
+ * Another nice quirk: on production SoC revisions, AVPLL_B outputs
+ * are scrambled. Use a translation table to deal with it.
+ */
+static const u8 avpllb_channel_map[] = { 0, 6, 5, 4, 3, 2, 1, 7 };
+
+struct clk *avpll_src_get(struct of_phandle_args *clkspec, void *data)
+{
+	struct avpll *pll = data;
+	unsigned int vco = clkspec->args[0];
+	unsigned int ch = clkspec->args[1] - 1;
+
+	if (vco > NUM_VCOS || ch > NUM_CHANNELS) {
+		pr_err("%s: invalid clock index %d.%d\n",
+		       __func__, vco, ch);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (vco == 1)
+		ch = avpllb_channel_map[ch];
+
+	return pll->vco[vco].clks[ch];
+}
+
+static void __init avpll_of_setup(struct device_node *np)
+{
+	struct avpll *pll;
+	struct clk_init_data init;
+	struct clk *refclk;
+	const char *refclk_name;
+	int nvco, nch;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return;
+
+	pll->base = of_iomap(np, 0);
+	if (!pll->base) {
+		pr_err("%s: Unable to map pll register\n", np->full_name);
+		kfree(pll);
+		return;
+	}
+
+	refclk = of_clk_get(np, 0);
+	if (IS_ERR(refclk)) {
+		pr_err("%s: Missing reference clock\n", np->full_name);
+		goto avpll_fail;
+	}
+	refclk_name = __clk_get_name(refclk);
+	clk_put(refclk);
+
+	for (nvco = 0; nvco < NUM_VCOS; nvco++) {
+		struct avpll_vco *vco = &pll->vco[nvco];
+		const char *vco_name =
+			kasprintf(GFP_KERNEL, "%s.vco%d", np->name, nvco);
+		struct clk *clk;
+
+		init.name = vco_name;
+		init.ops = &avpll_vco_ops;
+		init.parent_names = &refclk_name;
+		init.num_parents = 1;
+		init.flags = 0;
+
+		vco->hw.init = &init;
+		vco->base = pll->base + (nvco * VCO_OFFSET);
+		vco->pll = pll;
+		vco->index = nvco;
+
+		clk = clk_register(NULL, &vco->hw);
+		kfree(vco_name);
+		if (IS_ERR(clk)) {
+			pr_err("%s: Unable to register vco %d\n",
+			       np->full_name, nvco);
+			goto avpll_fail;
+		}
+		vco_name = __clk_get_name(clk);
+
+		for (nch = 0; nch < NUM_CHANNELS; nch++) {
+			struct avpll_channel *ch = &vco->channel[nch];
+			char *ch_name = kasprintf(GFP_KERNEL,
+						  "%s.%d", vco_name, nch);
+
+			init.name = ch_name;
+			init.ops = &avpll_channel_ops;
+			init.parent_names = &vco_name;
+			init.num_parents = 1;
+			init.flags = CLK_SET_RATE_PARENT;
+
+			ch->hw.init = &init;
+			ch->vco = vco;
+			ch->index = nch;
+
+			clk = clk_register(NULL, &ch->hw);
+			kfree(ch_name);
+			if (IS_ERR(clk)) {
+				pr_err("%s: Unable to register channel %d.%d\n",
+				       np->full_name, nvco, nch);
+				goto avpll_fail;
+			}
+			vco->clks[nch] = clk;
+		}
+	}
+
+	of_clk_add_provider(np, avpll_src_get, pll);
+	return;
+
+avpll_fail:
+	iounmap(pll->base);
+	kfree(pll);
+}
+CLK_OF_DECLARE(berlin2_avpll, "marvell,berlin2-avpll", avpll_of_setup);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v2 04/10] clk: berlin: add driver for BG2x simple PLLs
  2014-05-14 20:15 ` [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
                     ` (2 preceding siblings ...)
  2014-05-14 20:15   ` [PATCH v2 03/10] clk: berlin: add driver for BG2x audio/video PLL Sebastian Hesselbarth
@ 2014-05-14 20:15   ` Sebastian Hesselbarth
  2014-05-14 20:15   ` [PATCH v2 05/10] clk: berlin: add driver for BG2x complex divider cells Sebastian Hesselbarth
                     ` (5 subsequent siblings)
  9 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-14 20:15 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Alexandre Belloni, Mike Turquette, Jisheng Zhang,
	linux-arm-kernel, linux-kernel

From: Alexandre Belloni <alexandre.belloni@free-electrons.com>

This is a clock driver for the simple PLLs found on Berlin SoCs.
With repect to PLL registers and features, BG2/BG2CD and BG2Q are
slightly different, e.g. different allowed VCO dividers and bit
shifts.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Changelog:
v1->v2:
- dropped usage of postponed of_clk_create_name()       

Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 drivers/clk/berlin/Makefile      |   2 +-
 drivers/clk/berlin/berlin2-pll.c | 168 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 169 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/berlin/berlin2-pll.c

diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile
index 5905733fc7c7..9d3490e9782f 100644
--- a/drivers/clk/berlin/Makefile
+++ b/drivers/clk/berlin/Makefile
@@ -1 +1 @@
-obj-y += berlin2-avpll.o
+obj-y += berlin2-avpll.o berlin2-pll.o
diff --git a/drivers/clk/berlin/berlin2-pll.c b/drivers/clk/berlin/berlin2-pll.c
new file mode 100644
index 000000000000..f8ef8989ead2
--- /dev/null
+++ b/drivers/clk/berlin/berlin2-pll.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+
+struct berlin2_pll_map {
+	const u8 vcodiv[16];
+	u8 mult;
+	u8 fbdiv_shift;
+	u8 rfdiv_shift;
+	u8 divsel_shift;
+};
+
+struct berlin2_pll {
+	struct clk_hw hw;
+	void __iomem *base;
+	struct berlin2_pll_map map;
+};
+
+#define to_berlin2_pll(hw) container_of(hw, struct berlin2_pll, hw)
+
+#define SPLL_CTRL0	0x00
+#define SPLL_CTRL1	0x04
+#define SPLL_CTRL2	0x08
+#define SPLL_CTRL3	0x0c
+#define SPLL_CTRL4	0x10
+
+#define FBDIV_MASK	0x1ff
+#define RFDIV_MASK	0x1f
+#define DIVSEL_MASK	0xf
+
+/*
+ * The output frequency formula for the pll is:
+ * clkout = fbdiv / refdiv * parent / vcodiv
+ */
+static unsigned long
+berlin2_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct berlin2_pll *pll = to_berlin2_pll(hw);
+	struct berlin2_pll_map *map = &pll->map;
+	u32 val, fbdiv, rfdiv, vcodivsel, vcodiv;
+	u64 rate = parent_rate;
+
+	val = readl_relaxed(pll->base + SPLL_CTRL0);
+	fbdiv = (val >> map->fbdiv_shift) & FBDIV_MASK;
+	rfdiv = (val >> map->rfdiv_shift) & RFDIV_MASK;
+	if (rfdiv == 0) {
+		pr_warn("%s has zero rfdiv\n", __clk_get_name(hw->clk));
+		rfdiv = 1;
+	}
+
+	val = readl_relaxed(pll->base + SPLL_CTRL1);
+	vcodivsel = (val >> map->divsel_shift) & DIVSEL_MASK;
+	vcodiv = map->vcodiv[vcodivsel];
+	if (vcodiv == 0) {
+		pr_warn("%s has zero vcodiv (index %d)\n",
+			__clk_get_name(hw->clk), vcodivsel);
+		vcodiv = 1;
+	}
+
+	rate *= fbdiv * map->mult;
+	do_div(rate, rfdiv * vcodiv);
+
+	return (unsigned long)rate;
+}
+
+static const struct clk_ops berlin2_pll_ops = {
+	.recalc_rate	= berlin2_pll_recalc_rate,
+};
+
+static struct clk * __init
+berlin2_pll_register(const struct berlin2_pll_map *map,
+		     void __iomem *base, const char *name,
+		     const char *parent_name, unsigned long flags)
+{
+	struct clk_init_data init;
+	struct berlin2_pll *pll;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	/* copy pll_map to allow __initconst */
+	memcpy(&pll->map, map, sizeof(*map));
+	pll->base = base;
+	pll->hw.init = &init;
+	init.name = name;
+	init.ops = &berlin2_pll_ops;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+	init.flags = flags;
+
+	return clk_register(NULL, &pll->hw);
+}
+
+static const struct berlin2_pll_map bg2_pll_map __initconst = {
+	.vcodiv		= {10, 15, 20, 25, 30, 40, 50, 60, 80},
+	.mult		= 10,
+	.fbdiv_shift	= 6,
+	.rfdiv_shift	= 1,
+	.divsel_shift	= 7,
+};
+
+static const struct berlin2_pll_map bg2q_pll_map __initconst = {
+	.vcodiv		= {1, 0, 2, 0, 3, 4, 0, 6, 8},
+	.mult		= 1,
+	.fbdiv_shift	= 7,
+	.rfdiv_shift	= 2,
+	.divsel_shift	= 9,
+};
+
+static const struct of_device_id pll_matches[] __initconst = {
+	{ .compatible = "marvell,berlin2-pll", .data = &bg2_pll_map },
+	{ .compatible = "marvell,berlin2q-pll", .data = &bg2q_pll_map },
+	{ }
+};
+
+static void __init berlin2_pll_of_setup(struct device_node *np)
+{
+	const struct of_device_id *match = of_match_node(pll_matches, np);
+	const struct berlin2_pll_map *map = match->data;
+	void __iomem *base;
+	struct clk *refclk;
+	struct clk *pll;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("%s: Unable to map pll register\n", np->full_name);
+		return;
+	}
+
+	refclk = of_clk_get(np, 0);
+	if (IS_ERR(refclk)) {
+		pr_err("%s: Missing reference clock\n", np->full_name);
+		iounmap(base);
+		return;
+	}
+
+	pll = berlin2_pll_register(map, base, np->name,
+				   __clk_get_name(refclk), 0);
+	if (!IS_ERR(pll))
+		of_clk_add_provider(np, of_clk_src_simple_get, pll);
+
+	clk_put(refclk);
+}
+CLK_OF_DECLARE(berlin2_pll, "marvell,berlin2-pll", berlin2_pll_of_setup);
+CLK_OF_DECLARE(berlin2q_pll, "marvell,berlin2q-pll", berlin2_pll_of_setup);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v2 05/10] clk: berlin: add driver for BG2x complex divider cells
  2014-05-14 20:15 ` [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
                     ` (3 preceding siblings ...)
  2014-05-14 20:15   ` [PATCH v2 04/10] clk: berlin: add driver for BG2x simple PLLs Sebastian Hesselbarth
@ 2014-05-14 20:15   ` Sebastian Hesselbarth
  2014-05-15  7:56     ` Alexandre Belloni
  2014-05-14 20:15   ` [PATCH v2 06/10] clk: berlin: add core clock driver for BG2/BG2CD Sebastian Hesselbarth
                     ` (4 subsequent siblings)
  9 siblings, 1 reply; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-14 20:15 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Alexandre Belloni, Mike Turquette, Jisheng Zhang,
	linux-arm-kernel, linux-kernel

From: Alexandre Belloni <alexandre.belloni@free-electrons.com>

This is a driver for the complex divider cells found on Marvell Berlin2
SoCs. The cells come in two flavors: single register cells and shared
register cells. The single register cells are registered by using a DT
node, while the shared ones will be taken care of in a SoC-specific
core clock driver.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Changelog:
v1->v2:
- dropped usage of postponed of_clk_create_name()       
- fixed divide-by-3 check (!= 0 instead of == 1)
- fixed CLK_OF_DECLARE compatible to "marvell,berlin2-clk-div"
- fixed missing num_parents increment

Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 drivers/clk/berlin/Makefile      |   2 +-
 drivers/clk/berlin/berlin2-div.c | 324 +++++++++++++++++++++++++++++++++++++++
 drivers/clk/berlin/berlin2-div.h |  80 ++++++++++
 3 files changed, 405 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/berlin/berlin2-div.c
 create mode 100644 drivers/clk/berlin/berlin2-div.h

diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile
index 9d3490e9782f..f0a7dc8b5e30 100644
--- a/drivers/clk/berlin/Makefile
+++ b/drivers/clk/berlin/Makefile
@@ -1 +1 @@
-obj-y += berlin2-avpll.o berlin2-pll.o
+obj-y += berlin2-avpll.o berlin2-pll.o berlin2-div.o
diff --git a/drivers/clk/berlin/berlin2-div.c b/drivers/clk/berlin/berlin2-div.c
new file mode 100644
index 000000000000..7e5d97b170ea
--- /dev/null
+++ b/drivers/clk/berlin/berlin2-div.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "berlin2-div.h"
+
+/*
+ * Clock dividers in Berlin2 SoCs comprise a complex cell to select
+ * input pll and divider. The virtual structure as it is used in Marvell
+ * BSP code can be seen as:
+ *
+ *                      +---+
+ * pll0 --------------->| 0 |                   +---+
+ *           +---+      |(B)|--+--------------->| 0 |      +---+
+ * pll1.0 -->| 0 |  +-->| 1 |  |   +--------+   |(E)|----->| 0 |   +---+
+ * pll1.1 -->| 1 |  |   +---+  +-->|(C) 1:M |-->| 1 |      |(F)|-->|(G)|->
+ * ...    -->|(A)|--+          |   +--------+   +---+  +-->| 1 |   +---+
+ * ...    -->|   |             +-->|(D) 1:3 |----------+   +---+
+ * pll1.N -->| N |                 +---------
+ *           +---+
+ *
+ * (A) input pll clock mux controlled by               <PllSelect[1:n]>
+ * (B) input pll bypass mux controlled by              <PllSwitch>
+ * (C) programmable clock divider controlled by        <Select[1:n]>
+ * (D) constant div-by-3 clock divider
+ * (E) programmable clock divider bypass controlled by <Switch>
+ * (F) constant div-by-3 clock mux controlled by       <D3Switch>
+ * (G) clock gate controlled by                        <Enable>
+ *
+ * For whatever reason, above control signals come in two flavors:
+ * - single register dividers with all bits in one register
+ * - shared register dividers with bits spread over multiple registers
+ *   (including signals for the same cell spread over consecutive registers)
+ *
+ * Also, clock gate and pll mux is not available on every div cell, so
+ * we have to deal with those, too. We reuse common clock composite driver
+ * for it.
+ */
+
+#define PLL_SELECT_MASK	0x7
+#define DIV_SELECT_MASK	0x7
+
+struct berlin2_div {
+	struct clk_hw hw;
+	void __iomem *base;
+	struct berlin2_div_map map;
+	spinlock_t *lock;
+};
+
+#define to_berlin2_div(hw) container_of(hw, struct berlin2_div, hw)
+
+static u8 clk_div[] = { 1, 2, 4, 6, 8, 12, 1, 1 };
+
+static int berlin2_div_is_enabled(struct clk_hw *hw)
+{
+	struct berlin2_div *div = to_berlin2_div(hw);
+	struct berlin2_div_map *map = &div->map;
+	u32 reg;
+
+	if (div->lock)
+		spin_lock(div->lock);
+
+	reg = readl_relaxed(div->base + map->gate_offs);
+	reg >>= map->gate_shift;
+
+	if (div->lock)
+		spin_unlock(div->lock);
+
+	return (reg & 0x1);
+}
+
+static int berlin2_div_enable(struct clk_hw *hw)
+{
+	struct berlin2_div *div = to_berlin2_div(hw);
+	struct berlin2_div_map *map = &div->map;
+	u32 reg;
+
+	if (div->lock)
+		spin_lock(div->lock);
+
+	reg = readl_relaxed(div->base + map->gate_offs);
+	reg |= BIT(map->gate_shift);
+	writel_relaxed(reg, div->base + map->gate_offs);
+
+	if (div->lock)
+		spin_unlock(div->lock);
+
+	return 0;
+}
+
+static void berlin2_div_disable(struct clk_hw *hw)
+{
+	struct berlin2_div *div = to_berlin2_div(hw);
+	struct berlin2_div_map *map = &div->map;
+	u32 reg;
+
+	if (div->lock)
+		spin_lock(div->lock);
+
+	reg = readl_relaxed(div->base + map->gate_offs);
+	reg &= ~BIT(map->gate_shift);
+	writel_relaxed(reg, div->base + map->gate_offs);
+
+	if (div->lock)
+		spin_unlock(div->lock);
+}
+
+static int berlin2_div_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct berlin2_div *div = to_berlin2_div(hw);
+	struct berlin2_div_map *map = &div->map;
+	u32 reg;
+
+	if (div->lock)
+		spin_lock(div->lock);
+
+	/* index == 0 is PLL_SWITCH */
+	reg = readl_relaxed(div->base + map->pll_switch_offs);
+	if (index == 0)
+		reg &= ~BIT(map->pll_switch_shift);
+	else
+		reg |= BIT(map->pll_switch_shift);
+	writel_relaxed(reg, div->base + map->pll_switch_offs);
+
+	/* index > 0 is PLL_SELECT */
+	if (index > 0) {
+		reg = readl_relaxed(div->base + map->pll_select_offs);
+		reg &= ~(PLL_SELECT_MASK << map->pll_select_shift);
+		reg |= (index - 1) << map->pll_select_shift;
+		writel_relaxed(reg, div->base + map->pll_select_offs);
+	}
+
+	if (div->lock)
+		spin_unlock(div->lock);
+
+	return 0;
+}
+
+static u8 berlin2_div_get_parent(struct clk_hw *hw)
+{
+	struct berlin2_div *div = to_berlin2_div(hw);
+	struct berlin2_div_map *map = &div->map;
+	u32 reg;
+	u8 index = 0;
+
+	if (div->lock)
+		spin_lock(div->lock);
+
+	/* PLL_SWITCH == 0 is index 0 */
+	reg = readl_relaxed(div->base + map->pll_switch_offs);
+	reg &= BIT(map->pll_switch_shift);
+	if (reg) {
+		reg = readl_relaxed(div->base + map->pll_select_offs);
+		reg >>= map->pll_select_shift;
+		reg &= PLL_SELECT_MASK;
+		index = 1 + reg;
+	}
+
+	if (div->lock)
+		spin_unlock(div->lock);
+
+	return index;
+}
+
+static unsigned long berlin2_div_recalc_rate(struct clk_hw *hw,
+					     unsigned long parent_rate)
+{
+	struct berlin2_div *div = to_berlin2_div(hw);
+	struct berlin2_div_map *map = &div->map;
+	u32 divsw, div3sw, divider = 1;
+
+	if (div->lock)
+		spin_lock(div->lock);
+
+	divsw = readl_relaxed(div->base + map->div_switch_offs) &
+		(1 << map->div_switch_shift);
+	div3sw = readl_relaxed(div->base + map->div3_switch_offs) &
+		(1 << map->div3_switch_shift);
+
+	/* constant divide-by-3 (dominant) */
+	if (div3sw != 0) {
+		divider = 3;
+	/* divider can be bypassed with DIV_SWITCH == 0 */
+	} else if (divsw == 0) {
+		divider = 1;
+	/* clock divider determined by DIV_SELECT */
+	} else {
+		u32 reg;
+		reg = readl_relaxed(div->base + map->div_select_offs);
+		reg >>= map->div_select_shift;
+		reg &= DIV_SELECT_MASK;
+		divider = clk_div[reg];
+	}
+
+	if (div->lock)
+		spin_unlock(div->lock);
+
+	return parent_rate / divider;
+}
+
+static const struct clk_ops berlin2_div_rate_ops = {
+	.recalc_rate	= berlin2_div_recalc_rate,
+};
+
+static const struct clk_ops berlin2_div_gate_ops = {
+	.is_enabled	= berlin2_div_is_enabled,
+	.enable		= berlin2_div_enable,
+	.disable	= berlin2_div_disable,
+};
+
+static const struct clk_ops berlin2_div_mux_ops = {
+	.set_parent	= berlin2_div_set_parent,
+	.get_parent	= berlin2_div_get_parent,
+};
+
+struct clk * __init
+berlin2_div_register(const struct berlin2_div_map *map,
+		     void __iomem *base, const char *name, u8 div_flags,
+		     const char **parent_names, int num_parents,
+		     unsigned long flags, spinlock_t *lock)
+{
+	const struct clk_ops *mux_ops = &berlin2_div_mux_ops;
+	const struct clk_ops *rate_ops = &berlin2_div_rate_ops;
+	const struct clk_ops *gate_ops = &berlin2_div_gate_ops;
+	struct berlin2_div *div;
+
+	div = kzalloc(sizeof(*div), GFP_KERNEL);
+	if (!div)
+		return ERR_PTR(-ENOMEM);
+
+	/* copy div_map to allow __initconst */
+	memcpy(&div->map, map, sizeof(*map));
+	div->base = base;
+	div->lock = lock;
+
+	if ((div_flags & BERLIN2_DIV_HAS_GATE) == 0)
+		gate_ops = NULL;
+	if ((div_flags & BERLIN2_DIV_HAS_MUX) == 0)
+		mux_ops = NULL;
+
+	return clk_register_composite(NULL, name, parent_names, num_parents,
+				      &div->hw, mux_ops, &div->hw, rate_ops,
+				      &div->hw, gate_ops, flags);
+}
+
+static const struct berlin2_div_map berlin2_single_div_map __initconst = {
+	.gate_offs = 0,
+	.gate_shift = 0,
+	.pll_select_offs = 0,
+	.pll_select_shift = 1,
+	.pll_switch_offs = 0,
+	.pll_switch_shift = 4,
+	.div_switch_offs = 0,
+	.div_switch_shift = 5,
+	.div3_switch_offs = 0,
+	.div3_switch_shift = 6,
+	.div_select_offs = 0,
+	.div_select_shift = 7,
+};
+
+static void __init berlin2_div_of_setup(struct device_node *np)
+{
+	const char *parent_names[9] = {};
+	char *mux_name = "mux0";
+	int num_parents = 0;
+	void __iomem *base;
+	struct clk *iclk;
+	struct clk *div;
+	int n;
+
+	iclk = of_clk_get_by_name(np, "mux_bypass");
+	if (IS_ERR(iclk)) {
+		pr_err("%s: Missing mux bypass clock\n", np->full_name);
+		return;
+	}
+	parent_names[0] = __clk_get_name(iclk);
+	num_parents++;
+	clk_put(iclk);
+
+	/* collect mux input clock names */
+	for (n = 0; n < 8; n++) {
+		sprintf(mux_name, "mux%d", n);
+		iclk = of_clk_get_by_name(np, mux_name);
+		if (IS_ERR(iclk))
+			continue;
+		parent_names[1 + n] = __clk_get_name(iclk);
+		num_parents++;
+		clk_put(iclk);
+	}
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("%s: Unable to map div register\n", np->full_name);
+		return;
+	}
+
+	div = berlin2_div_register(&berlin2_single_div_map, base, np->name,
+				   BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+				   parent_names, num_parents, 0, NULL);
+	if (!IS_ERR(div))
+		of_clk_add_provider(np, of_clk_src_simple_get, div);
+}
+CLK_OF_DECLARE(berlin2_div, "marvell,berlin2-clk-div", berlin2_div_of_setup);
diff --git a/drivers/clk/berlin/berlin2-div.h b/drivers/clk/berlin/berlin2-div.h
new file mode 100644
index 000000000000..344865181712
--- /dev/null
+++ b/drivers/clk/berlin/berlin2-div.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __BERLIN2_DIV_H
+#define __BERLIN2_DIV_H
+
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+
+#define BERLIN2_DIV_HAS_GATE	BIT(0)
+#define BERLIN2_DIV_HAS_MUX	BIT(1)
+
+#define BERLIN2_PLL_SELECT(_off, _sh)	\
+	.pll_select_offs = _off,	\
+	.pll_select_shift = _sh
+
+#define BERLIN2_PLL_SWITCH(_off, _sh)	\
+	.pll_switch_offs = _off,	\
+	.pll_switch_shift = _sh
+
+#define BERLIN2_DIV_SELECT(_off, _sh)	\
+	.div_select_offs = _off,	\
+	.div_select_shift = _sh
+
+#define BERLIN2_DIV_SWITCH(_off, _sh)	\
+	.div_switch_offs = _off,	\
+	.div_switch_shift = _sh
+
+#define BERLIN2_DIV_D3SWITCH(_off, _sh)	\
+	.div3_switch_offs = _off,	\
+	.div3_switch_shift = _sh
+
+#define BERLIN2_DIV_GATE(_off, _sh)	\
+	.gate_offs = _off,		\
+	.gate_shift = _sh
+
+struct berlin2_div_map {
+	u16 pll_select_offs;
+	u16 pll_switch_offs;
+	u16 div_select_offs;
+	u16 div_switch_offs;
+	u16 div3_switch_offs;
+	u16 gate_offs;
+	u8 pll_select_shift;
+	u8 pll_switch_shift;
+	u8 div_select_shift;
+	u8 div_switch_shift;
+	u8 div3_switch_shift;
+	u8 gate_shift;
+};
+
+struct berlin2_div_data {
+	const char *name;
+	unsigned long flags;
+	struct berlin2_div_map map;
+	u8 div_flags;
+};
+
+struct clk * __init
+berlin2_div_register(const struct berlin2_div_map *map,
+	     void __iomem *base,  const char *name, u8 div_flags,
+	     const char **parent_names, int num_parents,
+	     unsigned long flags,  spinlock_t *lock);
+
+#endif /* BERLIN2_DIV_H */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v2 06/10] clk: berlin: add core clock driver for BG2/BG2CD
  2014-05-14 20:15 ` [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
                     ` (4 preceding siblings ...)
  2014-05-14 20:15   ` [PATCH v2 05/10] clk: berlin: add driver for BG2x complex divider cells Sebastian Hesselbarth
@ 2014-05-14 20:15   ` Sebastian Hesselbarth
  2014-05-15  8:09     ` Alexandre Belloni
  2014-05-14 20:15   ` [PATCH v2 07/10] clk: berlin: add core clock driver for BG2Q Sebastian Hesselbarth
                     ` (3 subsequent siblings)
  9 siblings, 1 reply; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-14 20:15 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Mike Turquette, Alexandre Belloni, Jisheng Zhang,
	linux-arm-kernel, linux-kernel

This driver deals with the core clocks found on Marvell Berlin
BG2 and BG2CD. For the shared register dividers, make use of the
corresponding driver and add some single clock muxes and gates for
the rest.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Changelog:
v1->v2:
- use dt-binding include for clock indices (Suggested by Alexandre Belloni)

Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 drivers/clk/berlin/Makefile |   2 +
 drivers/clk/berlin/bg2.c    | 502 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 504 insertions(+)
 create mode 100644 drivers/clk/berlin/bg2.c

diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile
index f0a7dc8b5e30..2b33e1e74503 100644
--- a/drivers/clk/berlin/Makefile
+++ b/drivers/clk/berlin/Makefile
@@ -1 +1,3 @@
 obj-y += berlin2-avpll.o berlin2-pll.o berlin2-div.o
+obj-$(CONFIG_MACH_BERLIN_BG2)	+= bg2.o
+obj-$(CONFIG_MACH_BERLIN_BG2CD)	+= bg2.o
diff --git a/drivers/clk/berlin/bg2.c b/drivers/clk/berlin/bg2.c
new file mode 100644
index 000000000000..16ef09491f18
--- /dev/null
+++ b/drivers/clk/berlin/bg2.c
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <dt-bindings/clock/berlin2.h>
+
+#include "berlin2-div.h"
+
+/*
+ * BG2/BG2CD SoCs have the following audio/video I/O units:
+ *
+ * audiohd: HDMI TX audio
+ * audio0:  7.1ch TX
+ * audio1:  2ch TX
+ * audio2:  2ch RX
+ * audio3:  SPDIF TX
+ * video0:  HDMI video
+ * video1:  Secondary video
+ * video2:  SD auxiliary video
+ *
+ * There are no external audio clocks (ACLKI0, ACLKI1) and
+ * only one external video clock (VCLKI0).
+ *
+ * Currently missing bits and pieces:
+ * - audio_fast_pll is unknown
+ * - audiohd_pll is unknown
+ * - video0_pll is unknown
+ * - audio[023], audiohd parent pll is assumed to be audio_fast_pll
+ *
+ */
+
+struct bg2_gate_data {
+	const char *name;
+	const char *parent_name;
+	u8 bit_idx;
+	unsigned long flags;
+};
+
+#define REG_CLKENABLE		0x00
+#define REG_CLKSELECT0		0x04
+#define REG_CLKSELECT1		0x08
+#define REG_CLKSELECT2		0x0c
+#define REG_CLKSELECT3		0x10
+#define REG_CLKSWITCH0		0x14
+#define REG_CLKSWITCH1		0x18
+
+#define	MAX_CLKS		31
+
+enum { REFCLK, SYSPLL, MEMPLL, CPUPLL };
+static const char *refclk_names[] = { "refclk", "syspll", "mempll", "cpupll" };
+
+enum { CH1, CH2, CH3, CH4, CH5, CH6, CH7, CH8 };
+static const char *avplla_names[] = {
+	"avpll_a1", "avpll_a2", "avpll_a3", "avpll_a4",
+	"avpll_a5", "avpll_a6", "avpll_a7", "avpll_a8"
+};
+static const char *avpllb_names[] = {
+	"avpll_b1", "avpll_b2", "avpll_b3", "avpll_b4",
+	"avpll_b5", "avpll_b6", "avpll_b7", "avpll_a8"
+};
+static const char *video_ext0_name = "video_ext0";
+
+static DEFINE_SPINLOCK(lock);
+static struct clk *clks[MAX_CLKS];
+static struct clk_onecell_data clk_data;
+
+static const struct berlin2_div_data bg2_divs[] __initconst = {
+	{
+		.name = "sys",
+		.flags = CLK_IGNORE_UNUSED,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 0),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "cpu",
+		.flags = 0,
+		.map = {
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8),
+		},
+		.div_flags = BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "drmfigo",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 16),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 17),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 20),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "cfg",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 1),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 23),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 26),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "gfx",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 4),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 29),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 0),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "zsp",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 5),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 3),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 6),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "perif",
+		.flags = CLK_IGNORE_UNUSED,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 6),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 9),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 12),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "pcube",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 2),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 15),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 18),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "vscope",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 3),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 21),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 24),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "nfc_ecc",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 18),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 27),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 0),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "vpp",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 21),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT2, 3),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 6),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 4),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 5),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 6),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "app",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 20),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT2, 9),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 12),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 7),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 8),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 9),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "audio0",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 22),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 17),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 10),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 11),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE,
+	},
+	{
+		.name = "audio2",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 24),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 20),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 14),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 15),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE,
+	},
+	{
+		.name = "audio3",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 25),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 23),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 16),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 17),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE,
+	},
+	{
+		.name = "audio1",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 23),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT3, 0),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 12),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 13),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE,
+	},
+};
+
+static const struct bg2_gate_data bg2_gates[] __initconst = {
+	{ "geth0",	"perif",	7 },
+	{ "geth1",	"perif",	8 },
+	{ "sata",	"perif",	9 },
+	{ "ahbapb",	"perif",	10, CLK_IGNORE_UNUSED },
+	{ "usb0",	"perif",	11 },
+	{ "usb1",	"perif",	12 },
+	{ "pbridge",	"perif",	13, CLK_IGNORE_UNUSED },
+	{ "sdio0",	"perif",	14 },
+	{ "sdio1",	"perif",	15 },
+	{ "nfc",	"perif",	17 },
+	{ "smemc",	"perif",	19 },
+	{ "audiohd",	"audiohd_pll",	26 },
+	{ "video0",	"video0_in",	27 },
+	{ "video1",	"video1_in",	28 },
+	{ "video2",	"video2_in",	29 },
+};
+
+static int __init collect_refclks(struct device_node *np)
+{
+	struct clk *iclk;
+	int n;
+
+	/* overwrite default clock names with DT provided ones */
+	/* reference clocks */
+	for (n = 0; n < ARRAY_SIZE(refclk_names); n++) {
+		iclk = of_clk_get_by_name(np, refclk_names[n]);
+		if (!IS_ERR(iclk)) {
+			refclk_names[n] = __clk_get_name(iclk);
+			clk_put(iclk);
+		}
+	}
+
+	/* AVPLL_A inputs */
+	for (n = 0; n < ARRAY_SIZE(avplla_names); n++) {
+		iclk = of_clk_get_by_name(np, avplla_names[n]);
+		if (!IS_ERR(iclk)) {
+			avplla_names[n] = __clk_get_name(iclk);
+			clk_put(iclk);
+		}
+	}
+
+	/* AVPLL_B inputs */
+	for (n = 0; n < ARRAY_SIZE(avpllb_names); n++) {
+		iclk = of_clk_get_by_name(np, avpllb_names[n]);
+		if (!IS_ERR(iclk)) {
+			avpllb_names[n] = __clk_get_name(iclk);
+			clk_put(iclk);
+		}
+	}
+
+	/* video_ext0 input */
+	iclk = of_clk_get_by_name(np, video_ext0_name);
+	if (!IS_ERR(iclk)) {
+		video_ext0_name = __clk_get_name(iclk);
+		clk_put(iclk);
+	}
+
+	return 0;
+}
+
+static void __init berlin2_core_clock_of_setup(struct device_node *np)
+{
+	const struct berlin2_div_data *data;
+	const char *parent_names[9];
+	void __iomem *base;
+	struct clk *clk;
+	int n;
+
+	if (collect_refclks(np))
+		return;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("%s: Unable to map register base\n", np->full_name);
+		return;
+	}
+
+	/* reference clock bypass switches */
+	parent_names[0] = refclk_names[SYSPLL];
+	parent_names[1] = refclk_names[REFCLK];
+	clk = clk_register_mux(NULL, "syspll_in", parent_names, 2, 0,
+			       base + REG_CLKSWITCH0, 0, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+	refclk_names[SYSPLL] = __clk_get_name(clk);
+
+	parent_names[0] = refclk_names[MEMPLL];
+	parent_names[1] = refclk_names[REFCLK];
+	clk = clk_register_mux(NULL, "mempll_in", parent_names, 2, 0,
+			       base + REG_CLKSWITCH0, 1, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+	refclk_names[MEMPLL] = __clk_get_name(clk);
+
+	parent_names[0] = refclk_names[CPUPLL];
+	parent_names[1] = refclk_names[REFCLK];
+	clk = clk_register_mux(NULL, "cpupll_in", parent_names, 2, 0,
+			       base + REG_CLKSWITCH0, 2, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+	refclk_names[CPUPLL] = __clk_get_name(clk);
+
+	/* clock muxes */
+	parent_names[0] = avpllb_names[CH3];
+	parent_names[1] = avplla_names[CH3];
+	clk = clk_register_mux(NULL, "audio1_pll", parent_names, 2, 0,
+			       base + REG_CLKSELECT2, 29, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+
+	parent_names[0] = "video0_pll";
+	parent_names[1] = video_ext0_name;
+	clk = clk_register_mux(NULL, "video0_in", parent_names, 2, 0,
+			       base + REG_CLKSELECT3, 4, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+
+	parent_names[0] = "video1_pll";
+	parent_names[1] = video_ext0_name;
+	clk = clk_register_mux(NULL, "video1_in", parent_names, 2, 0,
+			       base + REG_CLKSELECT3, 6, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+
+	parent_names[0] = avplla_names[CH2];
+	parent_names[1] = avpllb_names[CH2];
+	clk = clk_register_mux(NULL, "video1_pll", parent_names, 2, 0,
+			       base + REG_CLKSELECT3, 7, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+
+	parent_names[0] = "video2_pll";
+	parent_names[1] = video_ext0_name;
+	clk = clk_register_mux(NULL, "video2_in", parent_names, 2, 0,
+			       base + REG_CLKSELECT3, 9, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+
+	parent_names[0] = avpllb_names[CH1];
+	parent_names[1] = avplla_names[CH5];
+	clk = clk_register_mux(NULL, "video2_pll", parent_names, 2, 0,
+			       base + REG_CLKSELECT3, 10, 1, 0, &lock);
+	if (IS_ERR(clk))
+		goto core_clock_fail;
+
+	/* clock divider cells */
+	parent_names[1] = avpllb_names[CH4];
+	parent_names[2] = avpllb_names[CH5];
+	parent_names[3] = avpllb_names[CH6];
+	parent_names[4] = avpllb_names[CH7];
+
+	parent_names[0] = refclk_names[SYSPLL];
+	data = &bg2_divs[CLKID_SYS];
+	clks[CLKID_SYS] = berlin2_div_register(&data->map, base, data->name,
+		       data->div_flags, parent_names, 5, data->flags, &lock);
+
+	parent_names[0] = refclk_names[CPUPLL];
+	parent_names[5] = refclk_names[MEMPLL];
+	data = &bg2_divs[CLKID_CPU];
+	clks[CLKID_CPU] = berlin2_div_register(&data->map, base, data->name,
+			 data->div_flags, parent_names, 6, data->flags, &lock);
+
+	parent_names[0] = refclk_names[SYSPLL];
+	for (n = CLKID_DRMFIGO; n <= CLKID_APP; n++) {
+		data = &bg2_divs[n];
+		clks[n] = berlin2_div_register(&data->map, base, data->name,
+			 data->div_flags, parent_names, 5, data->flags, &lock);
+	}
+
+	parent_names[0] = "audio_fast_pll";
+	for (n = CLKID_AUDIO0; n <= CLKID_AUDIO3; n++) {
+		data = &bg2_divs[n];
+		clks[n] = berlin2_div_register(&data->map, base, data->name,
+			 data->div_flags, parent_names, 1, data->flags, &lock);
+	}
+
+	parent_names[0] = "audio1_pll";
+	data = &bg2_divs[CLKID_AUDIO1];
+	clks[CLKID_AUDIO1] = berlin2_div_register(&data->map, base, data->name,
+			 data->div_flags, parent_names, 1, data->flags, &lock);
+
+	/* clock gate cells */
+	for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) {
+		const struct bg2_gate_data *gd = &bg2_gates[n];
+
+		clks[CLKID_GETH0 + n] = clk_register_gate(NULL, gd->name,
+			    gd->parent_name, gd->flags, base + REG_CLKENABLE,
+			    gd->bit_idx, 0, &lock);
+	}
+
+	/* check for errors on leaf clocks */
+	for (n = 0; n < MAX_CLKS; n++) {
+		if (!IS_ERR(clks[n]))
+			continue;
+
+		pr_err("%s: Unable to register leaf clock %d\n",
+		       np->full_name, n);
+		goto core_clock_fail;
+	}
+
+	/* register clk-provider */
+	clk_data.clks = clks;
+	clk_data.clk_num = MAX_CLKS;
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+	return;
+
+core_clock_fail:
+	iounmap(base);
+}
+CLK_OF_DECLARE(berlin2_coreclk, "marvell,berlin2-core-clocks",
+	       berlin2_core_clock_of_setup);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v2 07/10] clk: berlin: add core clock driver for BG2Q
  2014-05-14 20:15 ` [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
                     ` (5 preceding siblings ...)
  2014-05-14 20:15   ` [PATCH v2 06/10] clk: berlin: add core clock driver for BG2/BG2CD Sebastian Hesselbarth
@ 2014-05-14 20:15   ` Sebastian Hesselbarth
  2014-05-15  7:46     ` Alexandre Belloni
  2014-05-14 20:15   ` [PATCH v2 08/10] ARM: dts: berlin: convert BG2CD to DT clock nodes Sebastian Hesselbarth
                     ` (2 subsequent siblings)
  9 siblings, 1 reply; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-14 20:15 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Alexandre Belloni, Mike Turquette, Jisheng Zhang,
	linux-arm-kernel, linux-kernel

From: Alexandre Belloni <alexandre.belloni@free-electrons.com>

This driver deals with the core clocks found on Marvell Berlin BG2Q. For the
shared register dividers, make use of the corresponding driver and add some
single clock muxes and gates for the rest.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
Changelog:
v1->v2:
- initial version

Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 drivers/clk/berlin/Makefile |   1 +
 drivers/clk/berlin/bg2q.c   | 269 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 270 insertions(+)
 create mode 100644 drivers/clk/berlin/bg2q.c

diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile
index 2b33e1e74503..2a36ab710a07 100644
--- a/drivers/clk/berlin/Makefile
+++ b/drivers/clk/berlin/Makefile
@@ -1,3 +1,4 @@
 obj-y += berlin2-avpll.o berlin2-pll.o berlin2-div.o
 obj-$(CONFIG_MACH_BERLIN_BG2)	+= bg2.o
 obj-$(CONFIG_MACH_BERLIN_BG2CD)	+= bg2.o
+obj-$(CONFIG_MACH_BERLIN_BG2Q)	+= bg2q.o
diff --git a/drivers/clk/berlin/bg2q.c b/drivers/clk/berlin/bg2q.c
new file mode 100644
index 000000000000..df5a4ce5eb87
--- /dev/null
+++ b/drivers/clk/berlin/bg2q.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2014 Marvell Technology Group Ltd.
+ *
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#include "berlin2-div.h"
+
+struct bg2_gate_data {
+	const char *name;
+	const char *parent_name;
+	u8 bit_idx;
+	unsigned long flags;
+};
+
+#define REG_CLKENABLE		0x00
+#define REG_CLKSELECT0		0x04
+#define REG_CLKSELECT1		0x08
+#define REG_CLKSELECT2		0x0c
+#define REG_CLKSWITCH0		0x10
+#define REG_CLKSWITCH1		0x14
+
+#define MAX_CLKS		24
+
+static DEFINE_SPINLOCK(lock);
+static struct clk *clks[MAX_CLKS];
+static struct clk_onecell_data clk_data;
+
+static const struct berlin2_div_data bg2q_divs[] __initconst = {
+	{
+		.name = "sys",
+		.flags = CLK_IGNORE_UNUSED,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 0),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "drmfigo",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 17),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "cfg",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 1),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 12),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 15),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 9),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 10),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 11),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "gfx2d",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 4),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 18),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 21),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "zsp",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 6),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 24),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 27),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "perif",
+		.flags = CLK_IGNORE_UNUSED,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 7),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 0),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 3),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "pcube",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 2),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 6),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 9),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "vscope",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 3),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 12),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 15),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "nfc_ecc",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 19),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 18),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 21),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "vpp",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 21),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 24),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 27),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+	{
+		.name = "app",
+		.flags = 0,
+		.map = {
+			BERLIN2_DIV_GATE(REG_CLKENABLE, 20),
+			BERLIN2_PLL_SELECT(REG_CLKSELECT2, 0),
+			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 3),
+			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1),
+			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2),
+			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3),
+		},
+		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
+	},
+};
+
+static const struct bg2_gate_data bg2q_gates[] __initconst = {
+	{ "gfx2daxi",	"perif",	5 },
+	{ "geth0",	"perif",	8 },
+	{ "sata",	"perif",	9 },
+	{ "ahbapb",	"perif",	10, CLK_IGNORE_UNUSED },
+	{ "usb0",	"perif",	11 },
+	{ "usb1",	"perif",	12 },
+	{ "usb2",	"perif",	13 },
+	{ "usb3",	"perif",	14 },
+	{ "pbridge",	"perif",	15, CLK_IGNORE_UNUSED },
+	{ "sdio",	"perif",	16 },
+	{ "nfc",	"perif",	18 },
+	{ "smemc",	"perif",	19 },
+	{ "pcie",	"perif",	22 },
+};
+
+static void __init berlin2q_core_clock_of_setup(struct device_node *np)
+{
+	const struct berlin2_div_data *data;
+	const char *parent_names[9];
+	void __iomem *base;
+	int n, nclk = 0;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("%s: Unable to map register base\n", np->full_name);
+		return;
+	}
+
+	/*
+	 * TODO: reference clock bypass switches: memPLLSWBypass, cpuPLLSWBypass
+	 * and sysPLLSWBypass are missing
+	 */
+
+	/* TODO: Once BG2Q AVPLL are added, add AVPLLB[4-7] as parents*/
+	parent_names[0] = "syspll";
+	for (n = 0; n < ARRAY_SIZE(bg2q_divs); n++) {
+		data = &bg2q_divs[n];
+		clks[n] = berlin2_div_register(&data->map, base, data->name,
+			 data->div_flags, parent_names, 5, data->flags, &lock);
+	}
+	nclk += n;
+
+	/* clock gate cells */
+	for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) {
+		const struct bg2_gate_data *gd = &bg2q_gates[n];
+
+		clks[nclk + n] = clk_register_gate(NULL, gd->name,
+			    gd->parent_name, gd->flags, base + REG_CLKENABLE,
+			    gd->bit_idx, 0, &lock);
+	}
+	nclk += n;
+
+	/* check for errors on leaf clocks */
+	for (n = 0; n < nclk; n++) {
+		if (!IS_ERR(clks[n]))
+			continue;
+
+		pr_err("%s: Unable to register leaf clock %d\n",
+		       np->full_name, n);
+		goto core_clock_fail;
+	}
+
+	/* register clk-provider */
+	clk_data.clks = clks;
+	clk_data.clk_num = MAX_CLKS;
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+	return;
+
+core_clock_fail:
+	iounmap(base);
+}
+CLK_OF_DECLARE(berlin2q_coreclk, "marvell,berlin2q-core-clocks",
+	       berlin2q_core_clock_of_setup);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v2 08/10] ARM: dts: berlin: convert BG2CD to DT clock nodes
  2014-05-14 20:15 ` [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
                     ` (6 preceding siblings ...)
  2014-05-14 20:15   ` [PATCH v2 07/10] clk: berlin: add core clock driver for BG2Q Sebastian Hesselbarth
@ 2014-05-14 20:15   ` Sebastian Hesselbarth
  2014-05-14 20:15   ` [PATCH v2 09/10] ARM: dts: berlin: convert BG2 " Sebastian Hesselbarth
  2014-05-14 20:15   ` [PATCH v2 10/10] ARM: dts: berlin: convert BG2Q " Sebastian Hesselbarth
  9 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-14 20:15 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Mike Turquette, Alexandre Belloni, Jisheng Zhang, devicetree,
	linux-arm-kernel, linux-kernel

This converts Berlin BG2CD SoC dtsi to make use of the new DT clock
nodes for Berlin SoCs. Also add a binding include to ease core clock
references.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Changelog:
v1->v2:
- dropped of_clk_create_name() usage required unique node names for
  clocks and plls
- added clock-output-names to allow fixed-factor-clock to find its
  parent name

Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 arch/arm/boot/dts/berlin2cd.dtsi | 205 +++++++++++++++++++++++++++++++++------
 1 file changed, 177 insertions(+), 28 deletions(-)

diff --git a/arch/arm/boot/dts/berlin2cd.dtsi b/arch/arm/boot/dts/berlin2cd.dtsi
index 6eb1bdae23ac..818c7557bad5 100644
--- a/arch/arm/boot/dts/berlin2cd.dtsi
+++ b/arch/arm/boot/dts/berlin2cd.dtsi
@@ -12,6 +12,7 @@
  */
 
 #include "skeleton.dtsi"
+#include <dt-bindings/clock/berlin2.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 / {
@@ -30,24 +31,18 @@
 		};
 	};
 
-	clocks {
-		smclk: sysmgr-clock {
-			compatible = "fixed-clock";
-			#clock-cells = <0>;
-			clock-frequency = <25000000>;
-		};
-
-		cfgclk: cfg-clock {
-			compatible = "fixed-clock";
-			#clock-cells = <0>;
-			clock-frequency = <75000000>;
-		};
+	refclk: oscillator {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <25000000>;
+	};
 
-		sysclk: system-clock {
-			compatible = "fixed-clock";
-			#clock-cells = <0>;
-			clock-frequency = <300000000>;
-		};
+	twdclk: twdclk {
+		compatible = "fixed-factor-clock";
+		#clock-cells = <0>;
+		clocks = <&coreclk CLKID_CPU>;
+		clock-mult = <1>;
+		clock-div = <3>;
 	};
 
 	soc {
@@ -76,7 +71,7 @@
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0xad0600 0x20>;
 			interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&sysclk>;
+			clocks = <&twdclk>;
 		};
 
 		apb@e80000 {
@@ -163,7 +158,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c00 0x14>;
 				interrupts = <8>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "okay";
 			};
@@ -172,7 +167,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c14 0x14>;
 				interrupts = <9>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "okay";
 			};
@@ -181,7 +176,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c28 0x14>;
 				interrupts = <10>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -190,7 +185,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c3c 0x14>;
 				interrupts = <11>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -199,7 +194,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c50 0x14>;
 				interrupts = <12>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -208,7 +203,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c64 0x14>;
 				interrupts = <13>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -217,7 +212,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c78 0x14>;
 				interrupts = <14>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -226,7 +221,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c8c 0x14>;
 				interrupts = <15>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -241,6 +236,160 @@
 			};
 		};
 
+		syspll: syspll@ea0014 {
+			compatible = "marvell,berlin2-pll";
+			#clock-cells = <0>;
+			reg = <0xea0014 0x14>;
+			clocks = <&refclk>;
+		};
+
+		mempll: mempll@ea0028 {
+			compatible = "marvell,berlin2-pll";
+			#clock-cells = <0>;
+			reg = <0xea0028 0x14>;
+			clocks = <&refclk>;
+		};
+
+		cpupll: cpupll@ea003c {
+			compatible = "marvell,berlin2-pll";
+			#clock-cells = <0>;
+			reg = <0xea003c 0x14>;
+			clocks = <&refclk>;
+		};
+
+		avpll: avpll@ea0040 {
+			compatible = "marvell,berlin2-avpll";
+			#clock-cells = <2>;
+			reg = <0xea0050 0x100>;
+			clocks = <&refclk>;
+		};
+
+		coreclk: core-clock@ea0150 {
+			compatible = "marvell,berlin2-core-clocks";
+			#clock-cells = <1>;
+			reg = <0xea0150 0x1c>;
+			clocks = <&refclk>, <&syspll>, <&mempll>, <&cpupll>,
+				<&avpll 0 1>, <&avpll 0 2>,
+				<&avpll 0 3>, <&avpll 0 4>,
+				<&avpll 0 5>, <&avpll 0 6>,
+				<&avpll 0 7>, <&avpll 0 8>,
+				<&avpll 1 1>, <&avpll 1 2>,
+				<&avpll 1 3>, <&avpll 1 4>,
+				<&avpll 1 5>, <&avpll 1 6>,
+				<&avpll 1 7>, <&avpll 1 8>;
+			clock-names = "refclk", "syspll", "mempll", "cpupll",
+				"avpll_a1", "avpll_a2", "avpll_a3", "avpll_a4",
+				"avpll_a5", "avpll_a6", "avpll_a7", "avpll_a8",
+				"avpll_b1", "avpll_b2", "avpll_b3", "avpll_b4",
+				"avpll_b5", "avpll_b6", "avpll_b7", "avpll_b8";
+			clock-output-names = "sys", "cpu", "drmfigo", "cfg",
+				"gfx", "zsp", "perif", "pcube", "vscope",
+				"nfc_ecc", "vpp", "app", "audio0", "audio2",
+				"audio3", "audio1", "geth0", "geth1", "sata",
+				"ahbapb", "usb0", "usb1", "pbridge", "sdio0",
+				"sdio1", "nfc", "smemc", "audiohd", "video0",
+				"video1", "video2";
+		};
+
+		gfx3dcore_clk: gfx3dcore@ea022c {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea022c 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		gfx3dsys_clk: gfx3dsys@ea0230 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0230 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		arc_clk: arc@ea0234 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0234 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		vip_clk: vip@ea0238 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0238 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		sdio0xin_clk: sdio0xin@ea023c {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea023c 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		sdio1xin_clk: sdio1xin@ea0240 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0240 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		gfx3dextra_clk: gfx3dextra@ea0244 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0244 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		gc360_clk: gc360@ea024c {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea024c 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		sdio_dllmst_clk: sdio_dllmst@ea0250 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0250 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
 		apb@fc0000 {
 			compatible = "simple-bus";
 			#address-cells = <1>;
@@ -285,7 +434,7 @@
 				reg-shift = <2>;
 				reg-io-width = <1>;
 				interrupts = <8>;
-				clocks = <&smclk>;
+				clocks = <&refclk>;
 				status = "disabled";
 			};
 
@@ -295,7 +444,7 @@
 				reg-shift = <2>;
 				reg-io-width = <1>;
 				interrupts = <9>;
-				clocks = <&smclk>;
+				clocks = <&refclk>;
 				status = "disabled";
 			};
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v2 09/10] ARM: dts: berlin: convert BG2 to DT clock nodes
  2014-05-14 20:15 ` [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
                     ` (7 preceding siblings ...)
  2014-05-14 20:15   ` [PATCH v2 08/10] ARM: dts: berlin: convert BG2CD to DT clock nodes Sebastian Hesselbarth
@ 2014-05-14 20:15   ` Sebastian Hesselbarth
  2014-05-14 20:15   ` [PATCH v2 10/10] ARM: dts: berlin: convert BG2Q " Sebastian Hesselbarth
  9 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-14 20:15 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Mike Turquette, Alexandre Belloni, Jisheng Zhang, devicetree,
	linux-arm-kernel, linux-kernel

This converts Berlin BG2 SoC dtsi to make use of the new DT clock
nodes for Berlin SoCs. While at it, also fix up twdclk which is
running at cpuclk/3 instead of sysclk.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Changelog:
v1->v2:
- dropped of_clk_create_name() usage required unique node names for
  clocks and plls 
- added clock-output-names to allow fixed-factor-clock to find its 
  parent name 

Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 arch/arm/boot/dts/berlin2.dtsi | 207 +++++++++++++++++++++++++++++++++++------
 1 file changed, 178 insertions(+), 29 deletions(-)

diff --git a/arch/arm/boot/dts/berlin2.dtsi b/arch/arm/boot/dts/berlin2.dtsi
index 57cadd31f4e1..edeecb711e97 100644
--- a/arch/arm/boot/dts/berlin2.dtsi
+++ b/arch/arm/boot/dts/berlin2.dtsi
@@ -12,6 +12,7 @@
  */
 
 #include "skeleton.dtsi"
+#include <dt-bindings/clock/berlin2.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 / {
@@ -37,24 +38,18 @@
 		};
 	};
 
-	clocks {
-		smclk: sysmgr-clock {
-			compatible = "fixed-clock";
-			#clock-cells = <0>;
-			clock-frequency = <25000000>;
-		};
-
-		cfgclk: cfg-clock {
-			compatible = "fixed-clock";
-			#clock-cells = <0>;
-			clock-frequency = <100000000>;
-		};
+	refclk: oscillator {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <25000000>;
+	};
 
-		sysclk: system-clock {
-			compatible = "fixed-clock";
-			#clock-cells = <0>;
-			clock-frequency = <400000000>;
-		};
+	twdclk: twdclk {
+		compatible = "fixed-factor-clock";
+		#clock-cells = <0>;
+		clocks = <&coreclk CLKID_CPU>;
+		clock-mult = <1>;
+		clock-div = <3>;
 	};
 
 	soc {
@@ -88,7 +83,7 @@
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0xad0600 0x20>;
 			interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&sysclk>;
+			clocks = <&twdclk>;
 		};
 
 		apb@e80000 {
@@ -175,7 +170,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c00 0x14>;
 				interrupts = <8>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "okay";
 			};
@@ -184,7 +179,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c14 0x14>;
 				interrupts = <9>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "okay";
 			};
@@ -193,7 +188,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c28 0x14>;
 				interrupts = <10>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -202,7 +197,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c3c 0x14>;
 				interrupts = <11>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -211,7 +206,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c50 0x14>;
 				interrupts = <12>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -220,7 +215,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c64 0x14>;
 				interrupts = <13>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -229,7 +224,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c78 0x14>;
 				interrupts = <14>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -238,7 +233,7 @@
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c8c 0x14>;
 				interrupts = <15>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -253,11 +248,165 @@
 			};
 		};
 
+		syspll: syspll@ea0014 {
+			compatible = "marvell,berlin2-pll";
+			#clock-cells = <0>;
+			reg = <0xea0014 0x14>;
+			clocks = <&refclk>;
+		};
+
+		mempll: mempll@ea0028 {
+			compatible = "marvell,berlin2-pll";
+			#clock-cells = <0>;
+			reg = <0xea0028 0x14>;
+			clocks = <&refclk>;
+		};
+
+		cpupll: cpupll@ea003c {
+			compatible = "marvell,berlin2-pll";
+			#clock-cells = <0>;
+			reg = <0xea003c 0x14>;
+			clocks = <&refclk>;
+		};
+
+		avpll: avpll@ea0040 {
+			compatible = "marvell,berlin2-avpll";
+			#clock-cells = <2>;
+			reg = <0xea0050 0x100>;
+			clocks = <&refclk>;
+		};
+
+		coreclk: core-clock@ea0150 {
+			compatible = "marvell,berlin2-core-clocks";
+			#clock-cells = <1>;
+			reg = <0xea0150 0x1c>;
+			clocks = <&refclk>, <&syspll>, <&mempll>, <&cpupll>,
+				<&avpll 0 1>, <&avpll 0 2>,
+				<&avpll 0 3>, <&avpll 0 4>,
+				<&avpll 0 5>, <&avpll 0 6>,
+				<&avpll 0 7>, <&avpll 0 8>,
+				<&avpll 1 1>, <&avpll 1 2>,
+				<&avpll 1 3>, <&avpll 1 4>,
+				<&avpll 1 5>, <&avpll 1 6>,
+				<&avpll 1 7>, <&avpll 1 8>;
+			clock-names = "refclk", "syspll", "mempll", "cpupll",
+				"avpll_a1", "avpll_a2", "avpll_a3", "avpll_a4",
+				"avpll_a5", "avpll_a6", "avpll_a7", "avpll_a8",
+				"avpll_b1", "avpll_b2", "avpll_b3", "avpll_b4",
+				"avpll_b5", "avpll_b6", "avpll_b7", "avpll_b8";
+			clock-output-names = "sys", "cpu", "drmfigo", "cfg",
+				"gfx", "zsp", "perif", "pcube", "vscope",
+				"nfc_ecc", "vpp", "app", "audio0", "audio2",
+				"audio3", "audio1", "geth0", "geth1", "sata",
+				"ahbapb", "usb0", "usb1", "pbridge", "sdio0",
+				"sdio1", "nfc", "smemc", "audiohd", "video0",
+				"video1", "video2";
+		};
+
 		generic-regs@ea0184 {
 			compatible = "marvell,berlin-generic-regs", "syscon";
 			reg = <0xea0184 0x10>;
 		};
 
+		gfx3dcore_clk: gfx3dcore@ea022c {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea022c 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		gfx3dsys_clk: gfx3dsys@ea0230 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0230 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		arc_clk: arc@ea0234 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0234 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		vip_clk: vip@ea0238 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0238 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		sdio0xin_clk: sdio0xin@ea023c {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea023c 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		sdio1xin_clk: sdio1xin@ea0240 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0240 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		gfx3dextra_clk: gfx3dextra@ea0244 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0244 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		gc360_clk: gc360@ea024c {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea024c 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
+		sdio_dllmst_clk: sdio_dllmst@ea0250 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0250 0x4>;
+			clocks = <&syspll>,
+				<&avpll 1 4>, <&avpll 1 5>,
+				<&avpll 1 6>, <&avpll 1 7>;
+			clock-names = "mux_bypass",
+				"mux0", "mux1", "mux2", "mux3";
+		};
+
 		apb@fc0000 {
 			compatible = "simple-bus";
 			#address-cells = <1>;
@@ -305,7 +454,7 @@
 				reg-shift = <2>;
 				reg-io-width = <1>;
 				interrupts = <8>;
-				clocks = <&smclk>;
+				clocks = <&refclk>;
 				status = "disabled";
 			};
 
@@ -315,7 +464,7 @@
 				reg-shift = <2>;
 				reg-io-width = <1>;
 				interrupts = <9>;
-				clocks = <&smclk>;
+				clocks = <&refclk>;
 				status = "disabled";
 			};
 
@@ -325,7 +474,7 @@
 				reg-shift = <2>;
 				reg-io-width = <1>;
 				interrupts = <10>;
-				clocks = <&smclk>;
+				clocks = <&refclk>;
 				status = "disabled";
 			};
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v2 10/10] ARM: dts: berlin: convert BG2Q to DT clock nodes
  2014-05-14 20:15 ` [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
                     ` (8 preceding siblings ...)
  2014-05-14 20:15   ` [PATCH v2 09/10] ARM: dts: berlin: convert BG2 " Sebastian Hesselbarth
@ 2014-05-14 20:15   ` Sebastian Hesselbarth
  9 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-14 20:15 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Alexandre Belloni, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Mike Turquette, Jisheng Zhang,
	devicetree, linux-arm-kernel, linux-kernel

From: Alexandre Belloni <alexandre.belloni@free-electrons.com>

This converts Berlin BG2Q SoC dtsi to make use of the new DT clock
nodes for Berlin SoCs.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Changelog:
v1->v2:
- initial version

Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 arch/arm/boot/dts/berlin2q.dtsi | 80 ++++++++++++++++++++++++++++-------------
 1 file changed, 56 insertions(+), 24 deletions(-)

diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi
index 52c7d644e492..8128c2b5ac07 100644
--- a/arch/arm/boot/dts/berlin2q.dtsi
+++ b/arch/arm/boot/dts/berlin2q.dtsi
@@ -6,6 +6,7 @@
  * warranty of any kind, whether express or implied.
  */
 
+#include <dt-bindings/clock/berlin2q.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 #include "skeleton.dtsi"
@@ -47,28 +48,16 @@
 		};
 	};
 
-	smclk: sysmgr-clock {
+	refclk: oscillator {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <25000000>;
 	};
 
-	cfgclk: config-clock {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <100000000>;
-	};
-
-	cpuclk: cpu-clock {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <1200000000>;
-	};
-
 	twdclk: twdclk {
 		compatible = "fixed-factor-clock";
 		#clock-cells = <0>;
-		clocks = <&cpuclk>;
+		clocks = <&cpupll>;
 		clock-mult = <1>;
 		clock-div = <3>;
 	};
@@ -106,6 +95,13 @@
 			#interrupt-cells = <3>;
 		};
 
+		cpupll: cpupll@dd0170 {
+			compatible = "marvell,berlin2q-pll";
+			clocks = <&refclk>;
+			#clock-cells = <0>;
+			reg = <0xdd0170 0x8>;
+		};
+
 		apb@e80000 {
 			compatible = "simple-bus";
 			#address-cells = <1>;
@@ -189,7 +185,7 @@
 			timer0: timer@2c00 {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c00 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				interrupts = <8>;
 			};
@@ -197,7 +193,7 @@
 			timer1: timer@2c14 {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c14 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -205,7 +201,7 @@
 			timer2: timer@2c28 {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c28 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -213,7 +209,7 @@
 			timer3: timer@2c3c {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c3c 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -221,7 +217,7 @@
 			timer4: timer@2c50 {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c50 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -229,7 +225,7 @@
 			timer5: timer@2c64 {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c64 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -237,7 +233,7 @@
 			timer6: timer@2c78 {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c78 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -245,7 +241,7 @@
 			timer7: timer@2c8c {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c8c 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&coreclk CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -290,11 +286,47 @@
 			};
 		};
 
+		syspll: syspll@ea0030 {
+			compatible = "marvell,berlin2q-pll";
+			clocks = <&refclk>;
+			#clock-cells = <0>;
+			reg = <0xea0030 0x8>;
+		};
+
+		coreclk: core-clock@ea00e8 {
+			compatible = "marvell,berlin2q-core-clocks";
+			#clock-cells = <1>;
+			reg = <0xea00e8 0x18>;
+			clocks = <&refclk>, <&syspll>;
+			clock-names = "refclk", "syspll";
+			clock-output-names = "sys", "drmfigo", "cfg",
+				"gfx2d", "zsp", "perif", "pcube", "vscope",
+				"nfc_ecc", "vpp", "app", "gfx2daxi", "geth0",
+				"ahbapb", "usb0", "usb1", "usb2", "usb3",
+				"pbridge", "sdio", "nfc", "smemc", "pcie";
+		};
+
 		generic-regs@ea0110 {
 			compatible = "marvell,berlin-generic-regs", "syscon";
 			reg = <0xea0110 0x10>;
 		};
 
+		sdio0xin_clk: sdio0xinclk@ea0158 {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea0158 0x4>;
+			clocks = <&syspll>;
+			clock-names = "mux_bypass";
+		};
+
+		sdio1xin_clk: sdio1xinclk@ea015c {
+			compatible = "marvell,berlin2-clk-div";
+			#clock-cells = <0>;
+			reg = <0xea015c 0x4>;
+			clocks = <&syspll>;
+			clock-names = "mux_bypass";
+		};
+
 		apb@fc0000 {
 			compatible = "simple-bus";
 			#address-cells = <1>;
@@ -308,7 +340,7 @@
 				reg = <0x9000 0x100>;
 				interrupt-parent = <&sic>;
 				interrupts = <8>;
-				clocks = <&smclk>;
+				clocks = <&refclk>;
 				reg-shift = <2>;
 				status = "disabled";
 			};
@@ -318,7 +350,7 @@
 				reg = <0xa000 0x100>;
 				interrupt-parent = <&sic>;
 				interrupts = <9>;
-				clocks = <&smclk>;
+				clocks = <&refclk>;
 				reg-shift = <2>;
 				status = "disabled";
 			};
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/8] clk: berlin: add clock binding docs for Marvell Berlin2 SoCs
  2014-05-11 20:24 ` [PATCH 2/8] clk: berlin: add clock binding docs for Marvell Berlin2 SoCs Sebastian Hesselbarth
  2014-05-13  8:38   ` Sebastian Hesselbarth
  2014-05-13 14:47   ` Alexandre Belloni
@ 2014-05-14 22:32   ` Mike Turquette
  2014-05-14 23:17     ` Sebastian Hesselbarth
  2 siblings, 1 reply; 40+ messages in thread
From: Mike Turquette @ 2014-05-14 22:32 UTC (permalink / raw)
  To: Sebastian Hesselbarth, Sebastian Hesselbarth
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Alexandre Belloni, Antoine Tenart, devicetree,
	linux-doc, linux-arm-kernel, linux-kernel

Quoting Sebastian Hesselbarth (2014-05-11 13:24:35)
> This adds mandatory device tree binding documentation for the clock related
> IP found on Marvell Berlin2 (BG2, BG2CD, and BG2Q) SoCs.
> 
> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> ---
> Cc: Mike Turquette <mturquette@linaro.org>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Pawel Moll <pawel.moll@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
> Cc: Kumar Gala <galak@codeaurora.org>
> Cc: Randy Dunlap <rdunlap@infradead.org>
> Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
> Cc: devicetree@vger.kernel.org
> Cc: linux-doc@vger.kernel.org
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: linux-kernel@vger.kernel.org
> ---
>  .../devicetree/bindings/clock/berlin2-clock.txt    | 169 +++++++++++++++++++++
>  1 file changed, 169 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/berlin2-clock.txt
> 
> diff --git a/Documentation/devicetree/bindings/clock/berlin2-clock.txt b/Documentation/devicetree/bindings/clock/berlin2-clock.txt
> new file mode 100644
> index 000000000000..3da87a488402
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/berlin2-clock.txt
> @@ -0,0 +1,169 @@
> +* Marvell Berlin2 clock bindings
> +
> +Marvell Berlin2 (BG2, BG2CD, BG2Q) share the same IP for PLLs and clocks,
> +with some minor differences in features and register layout. The below
> +describes the individual clock related IP:
> +
> +* Audio/Video PLL
> +
> +The Audio/Video PLL (AVPLL) is a dual-VCO PLL with 8 channels each. Each
> +of the VCOs can sythesize a single VCO frequency based on a single input
> +reference clock. Each of the 8 channels then, can derive an output clock
> +from that VCO frequency by various dividers/multipliers.
> +
> +Required properties:
> +- compatible: shall be "marvell,berlin2-avpll"
> +- reg: address and length of the corresponding AVPLL registers
> +- #clock-cells: shall be set to 2
> +- clocks: single clock specifier referencing the AVPLL input clock
> +
> +To ease match-up with the desired AVPLL output clock, clock specifiers
> +referencing AVPLL clocks shall contain two cells. The first refers to
> +the VCO (0=AVPLL_A, 1=AVPLL_B) while the second refers to the corresponding
> +channel starting with 1. For example, to reference AVPLL_B3 the clock
> +specifier shall be: <&avpll 1 3>.
> +
> +Example:
> +
> +avpll: pll@ea0040 {
> +       compatible = "marvell,berlin2-avpll";
> +       #clock-cells = <2>;
> +       reg = <0xea0050 0x100>;
> +       clocks = <&refclk>;
> +};

Hi Sebastian,

Thanks for submitting the series. It looks good. I do have some comments
about the DT bindings though. I'm encouraging new bindings (and
especially new platforms or existing platforms that are only now
converting over to CCF) to not put their per-clock data into DTS. This
has scalability problems, is unpopular with the DT crowd and sometimes
makes it hard to do things like set CLK_SET_RATE_PARENT flags for
individual clocks.

The following is a copy/paste from an email I sent earlier today[1]. Of
course per-clock data makes great sense if you have an off-SoC clock
such as a fixed-rate oscillator (e.g. the fixed-clock binding). Let me
know what you think:

I assume the rest of your clocks are part of a clock generator IP block
inside of your chip. Have you looked at the QCOM binding? It is my
favorite binding these days. Here are some highlights:

See Documentation/devicetree/bindings/clock/qcom,gcc.txt.



>From arch/arm/boot/dts/qcom-msm8974.dtsi:

gcc: clock-controller@fc400000 {
        compatible = "qcom,gcc-msm8974";
        #clock-cells = <1>;
        #reset-cells = <1>;
        reg = <0xfc400000 0x4000>;
};

...

serial@f991e000 {
        compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
        reg = <0xf991e000 0x1000>;
        interrupts = <0 108 0x0>;
        clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
        clock-names = "core", "iface";
};



>From drivers/clk/qcom/gcc-msm8974.c:

static struct clk_branch gcc_blsp1_uart2_apps_clk = {
        .halt_reg = 0x0704,
        .clkr = {
                .enable_reg = 0x0704,
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_blsp1_uart2_apps_clk",
                        .parent_names = (const char *[]){
                                "blsp1_uart2_apps_clk_src",
                        },
                        .num_parents = 1,
                        .flags = CLK_SET_RATE_PARENT,
                        .ops = &clk_branch2_ops,
                },
        },
};

Using this type of binding you only need to declare your clock generator
IP node in dts, and then define a mapping in the DT include chroot. Then
you can define your per-clock data inside of your clock driver instead
of putting all of the details inside of DT.

If you have a strong reason to do it the way that you originally posted
then let me know.

Regards,
Mike

[1] https://lkml.org/lkml/2014/5/14/598

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/8] clk: berlin: add clock binding docs for Marvell Berlin2 SoCs
  2014-05-14 22:32   ` Mike Turquette
@ 2014-05-14 23:17     ` Sebastian Hesselbarth
       [not found]       ` <20140515044106.19795.57249@quantum>
  0 siblings, 1 reply; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-14 23:17 UTC (permalink / raw)
  To: Mike Turquette
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Alexandre Belloni, Antoine Tenart, devicetree,
	linux-doc, linux-arm-kernel, linux-kernel

On 05/15/2014 12:32 AM, Mike Turquette wrote:
> Quoting Sebastian Hesselbarth (2014-05-11 13:24:35)
>> This adds mandatory device tree binding documentation for the clock related
>> IP found on Marvell Berlin2 (BG2, BG2CD, and BG2Q) SoCs.
>>
>> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
>> ---
>> Cc: Mike Turquette <mturquette@linaro.org>
>> Cc: Rob Herring <robh+dt@kernel.org>
>> Cc: Pawel Moll <pawel.moll@arm.com>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
>> Cc: Kumar Gala <galak@codeaurora.org>
>> Cc: Randy Dunlap <rdunlap@infradead.org>
>> Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
>> Cc: Antoine Tenart <antoine.tenart@free-electrons.com>
>> Cc: devicetree@vger.kernel.org
>> Cc: linux-doc@vger.kernel.org
>> Cc: linux-arm-kernel@lists.infradead.org
>> Cc: linux-kernel@vger.kernel.org
>> ---
>>  .../devicetree/bindings/clock/berlin2-clock.txt    | 169 +++++++++++++++++++++
>>  1 file changed, 169 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/clock/berlin2-clock.txt
>>
>> diff --git a/Documentation/devicetree/bindings/clock/berlin2-clock.txt b/Documentation/devicetree/bindings/clock/berlin2-clock.txt
>> new file mode 100644
>> index 000000000000..3da87a488402
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/berlin2-clock.txt
>> @@ -0,0 +1,169 @@
>> +* Marvell Berlin2 clock bindings
>> +
>> +Marvell Berlin2 (BG2, BG2CD, BG2Q) share the same IP for PLLs and clocks,
>> +with some minor differences in features and register layout. The below
>> +describes the individual clock related IP:
>> +
>> +* Audio/Video PLL
>> +
>> +The Audio/Video PLL (AVPLL) is a dual-VCO PLL with 8 channels each. Each
>> +of the VCOs can sythesize a single VCO frequency based on a single input
>> +reference clock. Each of the 8 channels then, can derive an output clock
>> +from that VCO frequency by various dividers/multipliers.
>> +
>> +Required properties:
>> +- compatible: shall be "marvell,berlin2-avpll"
>> +- reg: address and length of the corresponding AVPLL registers
>> +- #clock-cells: shall be set to 2
>> +- clocks: single clock specifier referencing the AVPLL input clock
>> +
>> +To ease match-up with the desired AVPLL output clock, clock specifiers
>> +referencing AVPLL clocks shall contain two cells. The first refers to
>> +the VCO (0=AVPLL_A, 1=AVPLL_B) while the second refers to the corresponding
>> +channel starting with 1. For example, to reference AVPLL_B3 the clock
>> +specifier shall be: <&avpll 1 3>.
>> +
>> +Example:
>> +
>> +avpll: pll@ea0040 {
>> +       compatible = "marvell,berlin2-avpll";
>> +       #clock-cells = <2>;
>> +       reg = <0xea0050 0x100>;
>> +       clocks = <&refclk>;
>> +};
> 
> Thanks for submitting the series. It looks good. I do have some comments
> about the DT bindings though. I'm encouraging new bindings (and
> especially new platforms or existing platforms that are only now
> converting over to CCF) to not put their per-clock data into DTS. This
> has scalability problems, is unpopular with the DT crowd and sometimes
> makes it hard to do things like set CLK_SET_RATE_PARENT flags for
> individual clocks.

Ok, so you are proposing the have a single node for all the SoCs
internal plls and clocks. The individual SoCs will have to deal
with the differences in a single driver, right?

> The following is a copy/paste from an email I sent earlier today[1]. Of
> course per-clock data makes great sense if you have an off-SoC clock
> such as a fixed-rate oscillator (e.g. the fixed-clock binding). Let me
> know what you think:
[...]
> Using this type of binding you only need to declare your clock generator
> IP node in dts, and then define a mapping in the DT include chroot. Then
> you can define your per-clock data inside of your clock driver instead
> of putting all of the details inside of DT.
> 
> If you have a strong reason to do it the way that you originally posted
> then let me know.

Actually, the intermediate patch set sent before this one had a single
DT clock node. The most important draw-back of a single clock node
is that Berlin's global registers are more like a register dumpster.
Vital other registers, e.g. reset, are intermixed with clock registers.

Given the lack of public datasheets (I look everything up in some
auto-generated BSP includes), I like the current approach because it
helps to get in at least some structure to the register mess ;)

Considering the postponed of_clk_create_name() helper, that would allow
us to remove at least the names from DT again. Another option would be
a syscon node for the registers, that clk, reset, pinctrl drivers can
access. But IIRC early syscon support isn't settled, yet?

So, my current idea is:
- take this as is, stabilize berlin branches for v3.16
- review of_clk_create_name() and of_clk_get_parent_name() to allow
  to remove clock-output-names properties from Berlin (and other) dtsis
- maybe switch to early syscon if it is available in v3.16

I know this would likely break DT ABI policy, but hey who else boots
mainline Linux on his Chromecast currently except me :P

Is that okay with you (and DT folks)?

Sebastian

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/8] clk: berlin: add clock binding docs for Marvell Berlin2 SoCs
       [not found]       ` <20140515044106.19795.57249@quantum>
@ 2014-05-15  6:53         ` Sebastian Hesselbarth
  2014-05-15  8:34         ` Alexandre Belloni
  1 sibling, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-15  6:53 UTC (permalink / raw)
  To: Mike Turquette
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Alexandre Belloni, Antoine Tenart, devicetree,
	linux-doc, linux-arm-kernel, linux-kernel

On 05/15/2014 06:41 AM, Mike Turquette wrote:
> Quoting Sebastian Hesselbarth (2014-05-14 16:17:52)
>> On 05/15/2014 12:32 AM, Mike Turquette wrote:
>>> Quoting Sebastian Hesselbarth (2014-05-11 13:24:35)
>>>> +avpll: pll@ea0040 {
>>>> +       compatible = "marvell,berlin2-avpll";
>>>> +       #clock-cells = <2>;
>>>> +       reg = <0xea0050 0x100>;
>>>> +       clocks = <&refclk>;
>>>> +};
>>>
>>> Thanks for submitting the series. It looks good. I do have some comments
>>> about the DT bindings though. I'm encouraging new bindings (and
>>> especially new platforms or existing platforms that are only now
>>> converting over to CCF) to not put their per-clock data into DTS. This
>>> has scalability problems, is unpopular with the DT crowd and sometimes
>>> makes it hard to do things like set CLK_SET_RATE_PARENT flags for
>>> individual clocks.
>>
>> Ok, so you are proposing the have a single node for all the SoCs
>> internal plls and clocks. The individual SoCs will have to deal
>> with the differences in a single driver, right?
> 
> To be precise, I'm talking about modeling an IP block as a single node.
> So if you have one clock generator IP block then you have one node. If
> you have more than one clock generator block then you have more than one
> node. Re-using the qcom example there are compatible strings for two
> different clock generator blocks named gcc and mmcc, respectively. So
> two DT nodes in the case for msm platforms that have one gcc instance
> and one rcg instance.

Hmm, I'd argue that you'd identify an IP block by the price tag is
carries. You can buy a single PLL but given the vast amount of different
register sets for PLLs, it is hard to identify what still count for the
same IP.

> Additionally other IP blocks may have internal clocks that can be
> modeled as part of that node. OMAP's Display SubSystem (DSS) and Image
> Signal Processor (ISP) blocks all have internal clocks that are modeled
> through the clock framework. (There are no DT bindings for that stuff,
> but the concept still applies)

Agreed. If we hit any clock mux/divider/gate in any other register set,
I wouldn't think of putting it into the core clock driver but the IP
driver instead.

>>> If you have a strong reason to do it the way that you originally posted
>>> then let me know.
>>
>> Actually, the intermediate patch set sent before this one had a single
>> DT clock node. The most important draw-back of a single clock node
>> is that Berlin's global registers are more like a register dumpster.
>> Vital other registers, e.g. reset, are intermixed with clock registers.
> 
> Yeah, this is pretty common. The compatible string should reflect the IP
> block as a whole, not just the clocks part of it. Lots of vendors have
> PRCMs or PRCMUs or CARs or whatever.
> 
> Check out the recent series to have the reset bits and regulator support
> added to the qcom binding[1]. (I'm using qcom quite a bit in my examples
> but they are not the first to add reset control to their clock driver. I
> think Tegra did it first...)

Yeah, I have to think about it a while. The register block we are
talking about contains - from what I remember from the ~20k lines
include - pinctrl, padctrl, reset, clocks, secondary cpu boot related
registers.

Maybe it is time to admit that these registers will never be split into
separate blocks but should be dealt with a single node.

>> Given the lack of public datasheets (I look everything up in some
>> auto-generated BSP includes), I like the current approach because it
>> helps to get in at least some structure to the register mess ;)
>>
>> Considering the postponed of_clk_create_name() helper, that would allow
>> us to remove at least the names from DT again. Another option would be
>> a syscon node for the registers, that clk, reset, pinctrl drivers can
>> access. But IIRC early syscon support isn't settled, yet?
> 
> Yeah, I'm not sure of the state of syscon. And modeling this stuff in
> the clock driver isn't the end of the world. There might be better
> places than drivers/clk/* for sure... I sometimes joke that the name of
> the IP block determines where the code lands. If it is Power, Reset &
> Clock Manager (several platforms use this acronym) then it can end up in
> drivers/clk or drivers/reset really easily. Same for Clock and Reset IP
> blocks (Tegra).
> 
>>
>> So, my current idea is:
>> - take this as is, stabilize berlin branches for v3.16
>> - review of_clk_create_name() and of_clk_get_parent_name() to allow
>>   to remove clock-output-names properties from Berlin (and other) dtsis
>> - maybe switch to early syscon if it is available in v3.16
>>
>> I know this would likely break DT ABI policy, but hey who else boots
>> mainline Linux on his Chromecast currently except me :P
> 
> I'm not a big fan of DT stable ABI, but if you plan on changing it for
> 3.17 why not just do it the right way the first time? And switching to
> syscon is not a hard requirement. I'm OK with you putting the reset and
> regulator stuff in the clock driver if that makes the most sense for
> your platform (especially if registers are shared and the same locks
> need to be used, etc).
> 
> What do you think?

Currently, I think that a single node for the global registers with reg
property and different nodes for clock/reset and pinctrl would be best.
I think I can workaround missing early syscon with atomic_io for now and
have a syscon provided regmap later:

global: registers@ea0000 {
	compatible = "marvell,berlin2-global-registers";
	reg = <0xea0000 0x400>;
};

pinctrl: pin-controller {
	compatible = "marvell,berlin2-pinctrl";
	...
};

clocks: clocks {
	compatible = "marvell,berlin2-clocks";
	#clock-cells = <1>;
	/* or clocks and reset FWIW */
};

or on a sub-node basis:

global: registers@ea0000 {
	compatible = "marvell,berlin2-global-registers";
	reg = <0xea0000 0x400>;
	#clock-cells = <1>;
	#reset-cells = <1>;

	pinctrl: pin-controller {
		compatible = "marvell,berlin2-pinctrl";
		...
	};
};

But I haven't made up my mind, yet.

Sebastian

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2 07/10] clk: berlin: add core clock driver for BG2Q
  2014-05-14 20:15   ` [PATCH v2 07/10] clk: berlin: add core clock driver for BG2Q Sebastian Hesselbarth
@ 2014-05-15  7:46     ` Alexandre Belloni
  0 siblings, 0 replies; 40+ messages in thread
From: Alexandre Belloni @ 2014-05-15  7:46 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Mike Turquette, Jisheng Zhang, linux-arm-kernel, linux-kernel

On 14/05/2014 at 22:15:18 +0200, Sebastian Hesselbarth wrote :
> From: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> 
> This driver deals with the core clocks found on Marvell Berlin BG2Q. For the
> shared register dividers, make use of the corresponding driver and add some
> single clock muxes and gates for the rest.
> 
> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> ---
> Changelog:
> v1->v2:
> - initial version
> 
> Cc: Mike Turquette <mturquette@linaro.org>
> Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> Cc: Jisheng Zhang <jszhang@marvell.com>
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: linux-kernel@vger.kernel.org
> ---
>  drivers/clk/berlin/Makefile |   1 +
>  drivers/clk/berlin/bg2q.c   | 269 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 270 insertions(+)
>  create mode 100644 drivers/clk/berlin/bg2q.c
> 
> diff --git a/drivers/clk/berlin/Makefile b/drivers/clk/berlin/Makefile
> index 2b33e1e74503..2a36ab710a07 100644
> --- a/drivers/clk/berlin/Makefile
> +++ b/drivers/clk/berlin/Makefile
> @@ -1,3 +1,4 @@
>  obj-y += berlin2-avpll.o berlin2-pll.o berlin2-div.o
>  obj-$(CONFIG_MACH_BERLIN_BG2)	+= bg2.o
>  obj-$(CONFIG_MACH_BERLIN_BG2CD)	+= bg2.o
> +obj-$(CONFIG_MACH_BERLIN_BG2Q)	+= bg2q.o
> diff --git a/drivers/clk/berlin/bg2q.c b/drivers/clk/berlin/bg2q.c
> new file mode 100644
> index 000000000000..df5a4ce5eb87
> --- /dev/null
> +++ b/drivers/clk/berlin/bg2q.c
> @@ -0,0 +1,269 @@
> +/*
> + * Copyright (c) 2014 Marvell Technology Group Ltd.
> + *
> + * Alexandre Belloni <alexandre.belloni@free-electrons.com>
> + * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/slab.h>
> +
> +#include "berlin2-div.h"
> +
> +struct bg2_gate_data {
> +	const char *name;
> +	const char *parent_name;
> +	u8 bit_idx;
> +	unsigned long flags;
> +};
> +
> +#define REG_CLKENABLE		0x00
> +#define REG_CLKSELECT0		0x04
> +#define REG_CLKSELECT1		0x08
> +#define REG_CLKSELECT2		0x0c
> +#define REG_CLKSWITCH0		0x10
> +#define REG_CLKSWITCH1		0x14
> +
> +#define MAX_CLKS		24
> +
> +static DEFINE_SPINLOCK(lock);
> +static struct clk *clks[MAX_CLKS];
> +static struct clk_onecell_data clk_data;
> +
> +static const struct berlin2_div_data bg2q_divs[] __initconst = {
> +	{
> +		.name = "sys",
> +		.flags = CLK_IGNORE_UNUSED,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 0),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 0),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 3),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 3),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 4),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 5),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "drmfigo",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 17),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 6),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 9),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 6),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 7),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 8),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "cfg",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 1),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 12),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 15),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 9),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 10),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 11),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "gfx2d",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 4),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 18),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 21),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 12),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 13),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 14),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "zsp",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 6),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT0, 24),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT0, 27),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 15),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 16),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 17),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "perif",
> +		.flags = CLK_IGNORE_UNUSED,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 7),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 0),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 3),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 18),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 19),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 20),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "pcube",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 2),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 6),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 9),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 21),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 22),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 23),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "vscope",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 3),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 12),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 15),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 24),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 25),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 26),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "nfc_ecc",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 19),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 18),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 21),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 27),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 28),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH0, 29),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "vpp",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 21),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT1, 24),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT1, 27),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH0, 30),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH0, 31),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 0),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +	{
> +		.name = "app",
> +		.flags = 0,
> +		.map = {
> +			BERLIN2_DIV_GATE(REG_CLKENABLE, 20),
> +			BERLIN2_PLL_SELECT(REG_CLKSELECT2, 0),
> +			BERLIN2_DIV_SELECT(REG_CLKSELECT2, 3),
> +			BERLIN2_PLL_SWITCH(REG_CLKSWITCH1, 1),
> +			BERLIN2_DIV_SWITCH(REG_CLKSWITCH1, 2),
> +			BERLIN2_DIV_D3SWITCH(REG_CLKSWITCH1, 3),
> +		},
> +		.div_flags = BERLIN2_DIV_HAS_GATE | BERLIN2_DIV_HAS_MUX,
> +	},
> +};
> +
> +static const struct bg2_gate_data bg2q_gates[] __initconst = {
> +	{ "gfx2daxi",	"perif",	5 },
> +	{ "geth0",	"perif",	8 },
> +	{ "sata",	"perif",	9 },
> +	{ "ahbapb",	"perif",	10, CLK_IGNORE_UNUSED },
> +	{ "usb0",	"perif",	11 },
> +	{ "usb1",	"perif",	12 },
> +	{ "usb2",	"perif",	13 },
> +	{ "usb3",	"perif",	14 },
> +	{ "pbridge",	"perif",	15, CLK_IGNORE_UNUSED },
> +	{ "sdio",	"perif",	16 },
> +	{ "nfc",	"perif",	18 },
> +	{ "smemc",	"perif",	19 },
> +	{ "pcie",	"perif",	22 },
> +};
> +
> +static void __init berlin2q_core_clock_of_setup(struct device_node *np)
> +{
> +	const struct berlin2_div_data *data;
> +	const char *parent_names[9];
> +	void __iomem *base;
> +	int n, nclk = 0;
> +
> +	base = of_iomap(np, 0);
> +	if (!base) {
> +		pr_err("%s: Unable to map register base\n", np->full_name);
> +		return;
> +	}
> +
> +	/*
> +	 * TODO: reference clock bypass switches: memPLLSWBypass, cpuPLLSWBypass
> +	 * and sysPLLSWBypass are missing
> +	 */
> +
> +	/* TODO: Once BG2Q AVPLL are added, add AVPLLB[4-7] as parents*/
> +	parent_names[0] = "syspll";
> +	for (n = 0; n < ARRAY_SIZE(bg2q_divs); n++) {
> +		data = &bg2q_divs[n];
> +		clks[n] = berlin2_div_register(&data->map, base, data->name,
> +			 data->div_flags, parent_names, 5, data->flags, &lock);

That one should be 1, not 5.

> +	}
> +	nclk += n;
> +
> +	/* clock gate cells */
> +	for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) {
> +		const struct bg2_gate_data *gd = &bg2q_gates[n];
> +
> +		clks[nclk + n] = clk_register_gate(NULL, gd->name,
> +			    gd->parent_name, gd->flags, base + REG_CLKENABLE,
> +			    gd->bit_idx, 0, &lock);
> +	}
> +	nclk += n;
> +
> +	/* check for errors on leaf clocks */
> +	for (n = 0; n < nclk; n++) {
> +		if (!IS_ERR(clks[n]))
> +			continue;
> +
> +		pr_err("%s: Unable to register leaf clock %d\n",
> +		       np->full_name, n);
> +		goto core_clock_fail;
> +	}
> +
> +	/* register clk-provider */
> +	clk_data.clks = clks;
> +	clk_data.clk_num = MAX_CLKS;
> +	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
> +	return;
> +
> +core_clock_fail:
> +	iounmap(base);
> +}
> +CLK_OF_DECLARE(berlin2q_coreclk, "marvell,berlin2q-core-clocks",
> +	       berlin2q_core_clock_of_setup);

-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2 05/10] clk: berlin: add driver for BG2x complex divider cells
  2014-05-14 20:15   ` [PATCH v2 05/10] clk: berlin: add driver for BG2x complex divider cells Sebastian Hesselbarth
@ 2014-05-15  7:56     ` Alexandre Belloni
  0 siblings, 0 replies; 40+ messages in thread
From: Alexandre Belloni @ 2014-05-15  7:56 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Mike Turquette, Jisheng Zhang, linux-arm-kernel, linux-kernel

On 14/05/2014 at 22:15:16 +0200, Sebastian Hesselbarth wrote :
> +static u8 berlin2_div_get_parent(struct clk_hw *hw)
> +{
> +	struct berlin2_div *div = to_berlin2_div(hw);
> +	struct berlin2_div_map *map = &div->map;
> +	u32 reg;
> +	u8 index = 0;
> +
> +	if (div->lock)
> +		spin_lock(div->lock);
> +
> +	/* PLL_SWITCH == 0 is index 0 */
> +	reg = readl_relaxed(div->base + map->pll_switch_offs);
> +	reg &= BIT(map->pll_switch_shift);
> +	if (reg) {
> +		reg = readl_relaxed(div->base + map->pll_select_offs);
> +		reg >>= map->pll_select_shift;
> +		reg &= PLL_SELECT_MASK;
> +		index = 1 + reg;

After getting more insight, I think we don't need to add 1, see my
comment on the next patchs.


-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2 06/10] clk: berlin: add core clock driver for BG2/BG2CD
  2014-05-14 20:15   ` [PATCH v2 06/10] clk: berlin: add core clock driver for BG2/BG2CD Sebastian Hesselbarth
@ 2014-05-15  8:09     ` Alexandre Belloni
  2014-05-15 15:43       ` Sebastian Hesselbarth
  0 siblings, 1 reply; 40+ messages in thread
From: Alexandre Belloni @ 2014-05-15  8:09 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Mike Turquette, Jisheng Zhang, linux-arm-kernel, linux-kernel

On 14/05/2014 at 22:15:17 +0200, Sebastian Hesselbarth wrote :
> +	/* clock divider cells */
> +	parent_names[1] = avpllb_names[CH4];
> +	parent_names[2] = avpllb_names[CH5];
> +	parent_names[3] = avpllb_names[CH6];
> +	parent_names[4] = avpllb_names[CH7];
> +
> +	parent_names[0] = refclk_names[SYSPLL];

It should actually be:

parent_names[0] = avpllb_names[CH4];
parent_names[1] = avpllb_names[CH5];
parent_names[2] = avpllb_names[CH6];
parent_names[3] = avpllb_names[CH7];
parent_names[4] = refclk_names[SYSPLL];

> +	data = &bg2_divs[CLKID_SYS];
> +	clks[CLKID_SYS] = berlin2_div_register(&data->map, base, data->name,
> +		       data->div_flags, parent_names, 5, data->flags, &lock);
> +
> +	parent_names[0] = refclk_names[CPUPLL];
> +	parent_names[5] = refclk_names[MEMPLL];

The only valid choice here should be (remember, we are not adding 1 to
the index anymore):
parent_names[4] = refclk_names[MEMPLL];

> +	data = &bg2_divs[CLKID_CPU];
> +	clks[CLKID_CPU] = berlin2_div_register(&data->map, base, data->name,
> +			 data->div_flags, parent_names, 6, data->flags, &lock);
> +

This is where it gets tricky, now we should have:
parent_names[0] = avpllb_names[CH4];
parent_names[1] = avplla_names[CH5];
parent_names[2] = avpllb_names[CH6];
parent_names[3] = avpllb_names[CH7];
parent_names[4] = refclk_names[SYSPLL];

> +	parent_names[0] = refclk_names[SYSPLL];
> +	for (n = CLKID_DRMFIGO; n <= CLKID_APP; n++) {
> +		data = &bg2_divs[n];
> +		clks[n] = berlin2_div_register(&data->map, base, data->name,
> +			 data->div_flags, parent_names, 5, data->flags, &lock);
> +	}
> +

-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/8] clk: berlin: add clock binding docs for Marvell Berlin2 SoCs
       [not found]       ` <20140515044106.19795.57249@quantum>
  2014-05-15  6:53         ` Sebastian Hesselbarth
@ 2014-05-15  8:34         ` Alexandre Belloni
  1 sibling, 0 replies; 40+ messages in thread
From: Alexandre Belloni @ 2014-05-15  8:34 UTC (permalink / raw)
  To: Mike Turquette
  Cc: Sebastian Hesselbarth, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Randy Dunlap, Antoine Tenart,
	devicetree, linux-doc, linux-arm-kernel, linux-kernel

On 14/05/2014 at 21:41:06 -0700, Mike Turquette wrote :
> > > The following is a copy/paste from an email I sent earlier today[1]. Of
> > > course per-clock data makes great sense if you have an off-SoC clock
> > > such as a fixed-rate oscillator (e.g. the fixed-clock binding). Let me
> > > know what you think:
> > [...]
> > > Using this type of binding you only need to declare your clock generator
> > > IP node in dts, and then define a mapping in the DT include chroot. Then
> > > you can define your per-clock data inside of your clock driver instead
> > > of putting all of the details inside of DT.
> > > 
> > > If you have a strong reason to do it the way that you originally posted
> > > then let me know.
> > 
> > Actually, the intermediate patch set sent before this one had a single
> > DT clock node. The most important draw-back of a single clock node
> > is that Berlin's global registers are more like a register dumpster.
> > Vital other registers, e.g. reset, are intermixed with clock registers.
> 
> Yeah, this is pretty common. The compatible string should reflect the IP
> block as a whole, not just the clocks part of it. Lots of vendors have
> PRCMs or PRCMUs or CARs or whatever.
> 
> Check out the recent series to have the reset bits and regulator support
> added to the qcom binding[1]. (I'm using qcom quite a bit in my examples
> but they are not the first to add reset control to their clock driver. I
> think Tegra did it first...)
> 
> > 
> > Given the lack of public datasheets (I look everything up in some
> > auto-generated BSP includes), I like the current approach because it
> > helps to get in at least some structure to the register mess ;)
> > 
> > Considering the postponed of_clk_create_name() helper, that would allow
> > us to remove at least the names from DT again. Another option would be
> > a syscon node for the registers, that clk, reset, pinctrl drivers can
> > access. But IIRC early syscon support isn't settled, yet?
> 
> Yeah, I'm not sure of the state of syscon. And modeling this stuff in
> the clock driver isn't the end of the world. There might be better
> places than drivers/clk/* for sure... I sometimes joke that the name of
> the IP block determines where the code lands. If it is Power, Reset &
> Clock Manager (several platforms use this acronym) then it can end up in
> drivers/clk or drivers/reset really easily. Same for Clock and Reset IP
> blocks (Tegra).
> 

So, this is called "global". On BG2/BG2CD, you have pinmuxing, a
register enabling nand power and switching the pll bypasses, all the pll
configuration, complex clocks, reset, product ID, nand write protect,
simple clocks, more resets, more clocks for which we don't have a driver
yet and finally pad control.

Now, on BG2Q, it is almost the same but between the cpupll registers and
the global registers, there is the whole APB bus, so timers, gpio
controllers, ...

I would believe that is the strong reason you are asking for.

It would also break the DT ABI (not that I care) almost each time we add
a new clock that we didn't know about.

Let me suggest something completely wild (to rephrase Thomas Petazzoni
and Kevin Hilman at ELC):

How about we have only a "marvell,berlin2", "marvell,berlin2cd" or
"marvell,berlin2q" compatible string and handle that in either
arch/arm/mach-berlin or driver/soc/mach-berlin and then use a bunch of
structures to add all the peripherals like clocks, reset, timer, gpio
controllers, pinmux, padconf...
Maybe we could call those structures "platform_data" :)


> > 
> > So, my current idea is:
> > - take this as is, stabilize berlin branches for v3.16
> > - review of_clk_create_name() and of_clk_get_parent_name() to allow
> >   to remove clock-output-names properties from Berlin (and other) dtsis
> > - maybe switch to early syscon if it is available in v3.16
> > 
> > I know this would likely break DT ABI policy, but hey who else boots
> > mainline Linux on his Chromecast currently except me :P
> 
> I'm not a big fan of DT stable ABI, but if you plan on changing it for
> 3.17 why not just do it the right way the first time? And switching to
> syscon is not a hard requirement. I'm OK with you putting the reset and
> regulator stuff in the clock driver if that makes the most sense for
> your platform (especially if registers are shared and the same locks
> need to be used, etc).
> 


-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2 06/10] clk: berlin: add core clock driver for BG2/BG2CD
  2014-05-15  8:09     ` Alexandre Belloni
@ 2014-05-15 15:43       ` Sebastian Hesselbarth
  2014-05-15 16:55         ` Alexandre Belloni
  0 siblings, 1 reply; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-15 15:43 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: Mike Turquette, Jisheng Zhang, linux-arm-kernel, linux-kernel

On 05/15/2014 10:09 AM, Alexandre Belloni wrote:
> On 14/05/2014 at 22:15:17 +0200, Sebastian Hesselbarth wrote :
>> +	/* clock divider cells */
>> +	parent_names[1] = avpllb_names[CH4];
>> +	parent_names[2] = avpllb_names[CH5];
>> +	parent_names[3] = avpllb_names[CH6];
>> +	parent_names[4] = avpllb_names[CH7];
>> +
>> +	parent_names[0] = refclk_names[SYSPLL];
>
> It should actually be:
>
> parent_names[0] = avpllb_names[CH4];
> parent_names[1] = avpllb_names[CH5];
> parent_names[2] = avpllb_names[CH6];
> parent_names[3] = avpllb_names[CH7];
> parent_names[4] = refclk_names[SYSPLL];

Given the comment to remove index 0 in the last patch, I translate that
into: "the input mux bypass is there, but {cannot,should not,we do not
want it to} be used". *sigh*

Actually, almost all of this is based on Chromecast mirrored BSP code
and I though about leaving the bypass mux in - even if it is not used
at all.

The reason is that I am _very_ tired of reading through the BSP code
and have all the things in mind where the BSP code is unclear.

>> +	data = &bg2_divs[CLKID_SYS];
>> +	clks[CLKID_SYS] = berlin2_div_register(&data->map, base, data->name,
>> +		       data->div_flags, parent_names, 5, data->flags, &lock);
>> +
>> +	parent_names[0] = refclk_names[CPUPLL];
>> +	parent_names[5] = refclk_names[MEMPLL];
>
> The only valid choice here should be (remember, we are not adding 1 to
> the index anymore):
> parent_names[4] = refclk_names[MEMPLL];

Funny to see that there ought to be a CPUPLL which isn't used by the
CPU at all. This also implies to remove CPUPLL, right?

>> +	data = &bg2_divs[CLKID_CPU];
>> +	clks[CLKID_CPU] = berlin2_div_register(&data->map, base, data->name,
>> +			 data->div_flags, parent_names, 6, data->flags, &lock);
>> +
>
> This is where it gets tricky, now we should have:
> parent_names[0] = avpllb_names[CH4];
> parent_names[1] = avplla_names[CH5];
> parent_names[2] = avpllb_names[CH6];
> parent_names[3] = avpllb_names[CH7];
> parent_names[4] = refclk_names[SYSPLL];

First I thought that it is just the default input mux clocks again..
but then I noticed that it is actually AVPLL_A5 not B5.

Ok, I admit having confirmed information is maybe better. So, you agree
that we can remove the input mux bypass on the complex divider, too?
(Including all the consequences: remove it from the divmap, driver, ...)

Sebastian

>> +	parent_names[0] = refclk_names[SYSPLL];
>> +	for (n = CLKID_DRMFIGO; n <= CLKID_APP; n++) {
>> +		data = &bg2_divs[n];
>> +		clks[n] = berlin2_div_register(&data->map, base, data->name,
>> +			 data->div_flags, parent_names, 5, data->flags, &lock);
>> +	}
>> +
>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2 06/10] clk: berlin: add core clock driver for BG2/BG2CD
  2014-05-15 15:43       ` Sebastian Hesselbarth
@ 2014-05-15 16:55         ` Alexandre Belloni
  0 siblings, 0 replies; 40+ messages in thread
From: Alexandre Belloni @ 2014-05-15 16:55 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Mike Turquette, Jisheng Zhang, linux-arm-kernel, linux-kernel

On 15/05/2014 at 17:43:03 +0200, Sebastian Hesselbarth wrote :
> On 05/15/2014 10:09 AM, Alexandre Belloni wrote:
> >On 14/05/2014 at 22:15:17 +0200, Sebastian Hesselbarth wrote :
> >>+	/* clock divider cells */
> >>+	parent_names[1] = avpllb_names[CH4];
> >>+	parent_names[2] = avpllb_names[CH5];
> >>+	parent_names[3] = avpllb_names[CH6];
> >>+	parent_names[4] = avpllb_names[CH7];
> >>+
> >>+	parent_names[0] = refclk_names[SYSPLL];
> >
> >It should actually be:
> >
> >parent_names[0] = avpllb_names[CH4];
> >parent_names[1] = avpllb_names[CH5];
> >parent_names[2] = avpllb_names[CH6];
> >parent_names[3] = avpllb_names[CH7];
> >parent_names[4] = refclk_names[SYSPLL];
> 
> Given the comment to remove index 0 in the last patch, I translate that
> into: "the input mux bypass is there, but {cannot,should not,we do not
> want it to} be used". *sigh*
> 
> Actually, almost all of this is based on Chromecast mirrored BSP code
> and I though about leaving the bypass mux in - even if it is not used
> at all.
> 
> The reason is that I am _very_ tired of reading through the BSP code
> and have all the things in mind where the BSP code is unclear.
> 

Ok, I made a mistake, I also have a hard time to picture everything
myself ;)

So, the mux is there iand can be used, hence, the parents are actually:

parent_names[0] = refclk_names[SYSPLL];
parent_names[1] = avpllb_names[CH4];
parent_names[2] = avpllb_names[CH5];
parent_names[3] = avpllb_names[CH6];
parent_names[4] = avpllb_names[CH7];
parent_names[5] = refclk_names[SYSPLL];

and disregard my comment on the previous patch.

> >>+	data = &bg2_divs[CLKID_SYS];
> >>+	clks[CLKID_SYS] = berlin2_div_register(&data->map, base, data->name,
> >>+		       data->div_flags, parent_names, 5, data->flags, &lock);
> >>+
> >>+	parent_names[0] = refclk_names[CPUPLL];
> >>+	parent_names[5] = refclk_names[MEMPLL];
> >
> >The only valid choice here should be (remember, we are not adding 1 to
> >the index anymore):
> >parent_names[4] = refclk_names[MEMPLL];

There, you actually had it right, maybe we could set parent_names[1] to
parent_names[4] to something bogus or all to refclk_names[MEMPLL].

> 
> Funny to see that there ought to be a CPUPLL which isn't used by the
> CPU at all. This also implies to remove CPUPLL, right?
> 
> >>+	data = &bg2_divs[CLKID_CPU];
> >>+	clks[CLKID_CPU] = berlin2_div_register(&data->map, base, data->name,
> >>+			 data->div_flags, parent_names, 6, data->flags, &lock);
> >>+
> >
> >This is where it gets tricky, now we should have:
> >parent_names[0] = avpllb_names[CH4];
> >parent_names[1] = avplla_names[CH5];
> >parent_names[2] = avpllb_names[CH6];
> >parent_names[3] = avpllb_names[CH7];
> >parent_names[4] = refclk_names[SYSPLL];
> 
> First I thought that it is just the default input mux clocks again..
> but then I noticed that it is actually AVPLL_A5 not B5.
> 

Here it becomes:
parent_names[0] = refclk_names[SYSPLL];
parent_names[1] = avpllb_names[CH4];
parent_names[2] = avplla_names[CH5];
parent_names[3] = avpllb_names[CH6];
parent_names[4] = avpllb_names[CH7];
parent_names[5] = refclk_names[SYSPLL];


> Ok, I admit having confirmed information is maybe better. So, you agree
> that we can remove the input mux bypass on the complex divider, too?
> (Including all the consequences: remove it from the divmap, driver, ...)
> 

No, let's keep the mux, sorry about that confusion.


-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v2 10/10] ARM: dts: berlin: convert BG2Q to DT clock nodes
  2014-05-19 16:43 [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
@ 2014-05-19 16:43 ` Sebastian Hesselbarth
  0 siblings, 0 replies; 40+ messages in thread
From: Sebastian Hesselbarth @ 2014-05-19 16:43 UTC (permalink / raw)
  To: Sebastian Hesselbarth
  Cc: Alexandre Belloni, Mike Turquette, Jisheng Zhang,
	linux-arm-kernel, linux-kernel

From: Alexandre Belloni <alexandre.belloni@free-electrons.com>

This converts Berlin BG2Q SoC dtsi to make use of the new DT clock
nodes for Berlin SoCs.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Changelog:
v1->v2:
- adapt to new single chip control node and compatible

Cc: Mike Turquette <mturquette@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
 arch/arm/boot/dts/berlin2q.dtsi | 54 +++++++++++++++--------------------------
 1 file changed, 19 insertions(+), 35 deletions(-)

diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi
index 52c7d644e492..cd3287c95f1a 100644
--- a/arch/arm/boot/dts/berlin2q.dtsi
+++ b/arch/arm/boot/dts/berlin2q.dtsi
@@ -6,6 +6,7 @@
  * warranty of any kind, whether express or implied.
  */
 
+#include <dt-bindings/clock/berlin2q.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 #include "skeleton.dtsi"
@@ -47,32 +48,12 @@
 		};
 	};
 
-	smclk: sysmgr-clock {
+	refclk: oscillator {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <25000000>;
 	};
 
-	cfgclk: config-clock {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <100000000>;
-	};
-
-	cpuclk: cpu-clock {
-		compatible = "fixed-clock";
-		#clock-cells = <0>;
-		clock-frequency = <1200000000>;
-	};
-
-	twdclk: twdclk {
-		compatible = "fixed-factor-clock";
-		#clock-cells = <0>;
-		clocks = <&cpuclk>;
-		clock-mult = <1>;
-		clock-div = <3>;
-	};
-
 	soc {
 		compatible = "simple-bus";
 		#address-cells = <1>;
@@ -95,7 +76,7 @@
 		local-timer@ad0600 {
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0xad0600 0x20>;
-			clocks = <&twdclk>;
+			clocks = <&chip CLKID_TWD>;
 			interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
@@ -189,7 +170,7 @@
 			timer0: timer@2c00 {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c00 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&chip CLKID_CFG>;
 				clock-names = "timer";
 				interrupts = <8>;
 			};
@@ -197,7 +178,7 @@
 			timer1: timer@2c14 {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c14 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&chip CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -205,7 +186,7 @@
 			timer2: timer@2c28 {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c28 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&chip CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -213,7 +194,7 @@
 			timer3: timer@2c3c {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c3c 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&chip CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -221,7 +202,7 @@
 			timer4: timer@2c50 {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c50 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&chip CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -229,7 +210,7 @@
 			timer5: timer@2c64 {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c64 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&chip CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -237,7 +218,7 @@
 			timer6: timer@2c78 {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c78 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&chip CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -245,7 +226,7 @@
 			timer7: timer@2c8c {
 				compatible = "snps,dw-apb-timer";
 				reg = <0x2c8c 0x14>;
-				clocks = <&cfgclk>;
+				clocks = <&chip CLKID_CFG>;
 				clock-names = "timer";
 				status = "disabled";
 			};
@@ -290,9 +271,12 @@
 			};
 		};
 
-		generic-regs@ea0110 {
-			compatible = "marvell,berlin-generic-regs", "syscon";
-			reg = <0xea0110 0x10>;
+		chip: chip-control@ea0000 {
+			compatible = "marvell,berlin2q-chip-ctrl";
+			#clock-cells = <1>;
+			reg = <0xea0000 0x400>, <0xdd0170 0x10>;
+			clocks = <&refclk>;
+			clock-names = "refclk";
 		};
 
 		apb@fc0000 {
@@ -308,7 +292,7 @@
 				reg = <0x9000 0x100>;
 				interrupt-parent = <&sic>;
 				interrupts = <8>;
-				clocks = <&smclk>;
+				clocks = <&refclk>;
 				reg-shift = <2>;
 				status = "disabled";
 			};
@@ -318,7 +302,7 @@
 				reg = <0xa000 0x100>;
 				interrupt-parent = <&sic>;
 				interrupts = <9>;
-				clocks = <&smclk>;
+				clocks = <&refclk>;
 				reg-shift = <2>;
 				status = "disabled";
 			};
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2014-05-19 16:43 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-11 20:24 [PATCH 0/8] Marvell Berlin full clock support Sebastian Hesselbarth
2014-05-11 20:24 ` [PATCH 1/8] clk: add helper for unique DT clock names Sebastian Hesselbarth
2014-05-13 19:49   ` Mike Turquette
2014-05-13 20:19     ` Sebastian Hesselbarth
     [not found]       ` <20140513205111.5943.12709@quantum>
2014-05-13 21:25         ` Sebastian Hesselbarth
2014-05-11 20:24 ` [PATCH 2/8] clk: berlin: add clock binding docs for Marvell Berlin2 SoCs Sebastian Hesselbarth
2014-05-13  8:38   ` Sebastian Hesselbarth
2014-05-13 14:47   ` Alexandre Belloni
2014-05-14 22:32   ` Mike Turquette
2014-05-14 23:17     ` Sebastian Hesselbarth
     [not found]       ` <20140515044106.19795.57249@quantum>
2014-05-15  6:53         ` Sebastian Hesselbarth
2014-05-15  8:34         ` Alexandre Belloni
2014-05-11 20:24 ` [PATCH 3/8] clk: berlin: add driver for BG2x audio/video PLL Sebastian Hesselbarth
2014-05-11 20:24 ` [PATCH 4/8] clk: berlin: add driver for BG2x simple PLLs Sebastian Hesselbarth
2014-05-11 20:24 ` [PATCH 5/8] clk: berlin: add driver for BG2x complex divider cells Sebastian Hesselbarth
2014-05-13  8:40   ` Sebastian Hesselbarth
2014-05-11 20:24 ` [PATCH 6/8] clk: berlin: add core clock driver for BG2/BG2CD Sebastian Hesselbarth
2014-05-14 11:43   ` Alexandre Belloni
2014-05-14 11:48     ` Sebastian Hesselbarth
2014-05-11 20:24 ` [PATCH 7/8] ARM: dts: berlin: convert BG2CD to DT clock nodes Sebastian Hesselbarth
2014-05-12 19:55   ` Sebastian Hesselbarth
2014-05-13  8:42   ` Sebastian Hesselbarth
2014-05-11 20:24 ` [PATCH 8/8] ARM: dts: berlin: convert BG2 " Sebastian Hesselbarth
2014-05-14 20:15 ` [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
2014-05-14 20:15   ` [PATCH v2 01/10] dt-binding: clk: add clock binding docs for Marvell Berlin2 SoCs Sebastian Hesselbarth
2014-05-14 20:15   ` [PATCH v2 02/10] clk: berlin: add binding include for BG2/BG2CD clock ids Sebastian Hesselbarth
2014-05-14 20:15   ` [PATCH v2 03/10] clk: berlin: add driver for BG2x audio/video PLL Sebastian Hesselbarth
2014-05-14 20:15   ` [PATCH v2 04/10] clk: berlin: add driver for BG2x simple PLLs Sebastian Hesselbarth
2014-05-14 20:15   ` [PATCH v2 05/10] clk: berlin: add driver for BG2x complex divider cells Sebastian Hesselbarth
2014-05-15  7:56     ` Alexandre Belloni
2014-05-14 20:15   ` [PATCH v2 06/10] clk: berlin: add core clock driver for BG2/BG2CD Sebastian Hesselbarth
2014-05-15  8:09     ` Alexandre Belloni
2014-05-15 15:43       ` Sebastian Hesselbarth
2014-05-15 16:55         ` Alexandre Belloni
2014-05-14 20:15   ` [PATCH v2 07/10] clk: berlin: add core clock driver for BG2Q Sebastian Hesselbarth
2014-05-15  7:46     ` Alexandre Belloni
2014-05-14 20:15   ` [PATCH v2 08/10] ARM: dts: berlin: convert BG2CD to DT clock nodes Sebastian Hesselbarth
2014-05-14 20:15   ` [PATCH v2 09/10] ARM: dts: berlin: convert BG2 " Sebastian Hesselbarth
2014-05-14 20:15   ` [PATCH v2 10/10] ARM: dts: berlin: convert BG2Q " Sebastian Hesselbarth
2014-05-19 16:43 [PATCH v2 00/10] Marvell Berlin full clock support Sebastian Hesselbarth
2014-05-19 16:43 ` [PATCH v2 10/10] ARM: dts: berlin: convert BG2Q to DT clock nodes Sebastian Hesselbarth

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).