LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH 0/7] clk: Common clock support for IMG Pistachio
@ 2015-02-25  3:56 Andrew Bresticker
  2015-02-25  3:56 ` [PATCH 1/7] clk: Add binding document for Pistachio clock controllers Andrew Bresticker
                   ` (7 more replies)
  0 siblings, 8 replies; 15+ messages in thread
From: Andrew Bresticker @ 2015-02-25  3:56 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, Ralf Baechle
  Cc: devicetree, linux-mips, linux-kernel, Andrew Bresticker,
	Ezequiel Garcia, James Hartley, James Hogan

This series adds common clock support for the IMG Pistachio SoC.
Pistachio has two clock controllers (core and peripheral) and two
general control blocks (peripheral and top) which also contain
several clock gates.  Like the recently submitted pinctrl driver [1],
this driver is written so that it's hopefully easy to add support
for future IMG SoCs.

Tested on an IMG Pistachio BuB.  Based on 4.0-rc1 + my series adding
Pistachio platform support [2], which introduces the MACH_PISTACHIO
Kconfig symbol.  A branch with this series and the dependent patches
is available at [3].  I'd like this to go through the MIPS tree with
Mike's or Stephen's ACK if possible.

Cc: Ezequiel Garcia <ezequiel.garcia@imgtec.com>
Cc: James Hartley <james.hartley@imgtec.com>
Cc: James Hogan <james.hogan@imgtec.com>

[1] https://lkml.org/lkml/2015/2/23/705
[2] https://lkml.org/lkml/2015/2/23/694
[3] https://github.com/abrestic/linux/tree/pistachio-clk-v1

Andrew Bresticker (7):
  clk: Add binding document for Pistachio clock controllers
  clk: Add basic infrastructure for Pistachio clocks
  clk: pistachio: Add PLL driver
  clk: pistachio: Register core clocks
  clk: pistachio: Register peripheral clocks
  clk: pistachio: Register system interface gate clocks
  clk: pistachio: Register external clock gates

 .../devicetree/bindings/clock/pistachio-clock.txt  | 123 +++++++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/pistachio/Makefile                     |   3 +
 drivers/clk/pistachio/clk-pistachio.c              | 329 +++++++++++++++++
 drivers/clk/pistachio/clk-pll.c                    | 401 +++++++++++++++++++++
 drivers/clk/pistachio/clk.c                        | 140 +++++++
 drivers/clk/pistachio/clk.h                        | 174 +++++++++
 include/dt-bindings/clock/pistachio-clk.h          | 183 ++++++++++
 8 files changed, 1354 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/pistachio-clock.txt
 create mode 100644 drivers/clk/pistachio/Makefile
 create mode 100644 drivers/clk/pistachio/clk-pistachio.c
 create mode 100644 drivers/clk/pistachio/clk-pll.c
 create mode 100644 drivers/clk/pistachio/clk.c
 create mode 100644 drivers/clk/pistachio/clk.h
 create mode 100644 include/dt-bindings/clock/pistachio-clk.h

-- 
2.2.0.rc0.207.ga3a616c


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

* [PATCH 1/7] clk: Add binding document for Pistachio clock controllers
  2015-02-25  3:56 [PATCH 0/7] clk: Common clock support for IMG Pistachio Andrew Bresticker
@ 2015-02-25  3:56 ` Andrew Bresticker
  2015-02-25  3:56 ` [PATCH 2/7] clk: Add basic infrastructure for Pistachio clocks Andrew Bresticker
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Andrew Bresticker @ 2015-02-25  3:56 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, Ralf Baechle
  Cc: devicetree, linux-mips, linux-kernel, Andrew Bresticker,
	Ezequiel Garcia, James Hartley, James Hogan, Damien Horsley,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala

Add a device-tree binding document describing the four clock
controllers present on the IMG Pistachio SoC.

Signed-off-by: Damien Horsley <Damien.Horsley@imgtec.com>
Signed-off-by: Andrew Bresticker <abrestic@chromium.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>
---
 .../devicetree/bindings/clock/pistachio-clock.txt  | 123 ++++++++++++++
 include/dt-bindings/clock/pistachio-clk.h          | 183 +++++++++++++++++++++
 2 files changed, 306 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/pistachio-clock.txt
 create mode 100644 include/dt-bindings/clock/pistachio-clk.h

diff --git a/Documentation/devicetree/bindings/clock/pistachio-clock.txt b/Documentation/devicetree/bindings/clock/pistachio-clock.txt
new file mode 100644
index 0000000..868db49
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/pistachio-clock.txt
@@ -0,0 +1,123 @@
+Imagination Technologies Pistachio SoC clock controllers
+========================================================
+
+Pistachio has four clock controllers (core clock, peripheral clock, peripheral
+general control, and top general control) which are instantiated individually
+from the device-tree.
+
+External clocks:
+----------------
+
+There are three external inputs to the clock controllers which should be
+defined with the following clock-output-names:
+- "xtal": External 52Mhz oscillator (required)
+- "audio_clk_in": Alternate audio reference clock (optional)
+- "enet_clk_in": Alternate ethernet PHY clock (optional)
+
+Core clock controller:
+----------------------
+
+The core clock controller generates clocks for the CPU, RPU (WiFi + BT
+co-processor), audio, and several peripherals.
+
+Required properties:
+- compatible: Must be "img,pistachio-clk".
+- reg: Must contain the base address and length of the core clock controller.
+- #clock-cells: Must be 1.  The single cell is the clock identifier.
+  See dt-bindings/clock/pistachio-clk.h for the list of valid identifiers.
+- clocks: Must contain an entry for each clock in clock-names.
+- clock-names: Must include "xtal" (see "External clocks") and
+  "audio_clk_in_gate", "enet_clk_in_gate" which are generated by the
+  top-level general control.
+
+Example:
+	clk_core: clock-controller@18144000 {
+		compatible = "img,pistachio-clk";
+		reg = <0x18144000 0x800>;
+		clocks = <&xtal>, <&cr_top EXT_CLK_AUDIO_IN>,
+			 <&cr_top EXT_CLK_ENET_IN>;
+		clock-names = "xtal", "audio_clk_in_gate", "enet_clk_in_gate";
+
+		#clock-cells = <1>;
+	};
+
+Peripheral clock controller:
+----------------------------
+
+The peripheral clock controller generates clocks for the DDR, ROM, and other
+peripherals.  The peripheral system clock ("periph_sys") generated by the core
+clock controller is the input clock to the peripheral clock controller.
+
+Required properties:
+- compatible: Must be "img,pistachio-periph-clk".
+- reg: Must contain the base address and length of the peripheral clock
+  controller.
+- #clock-cells: Must be 1.  The single cell is the clock identifier.
+  See dt-bindings/clock/pistachio-clk.h for the list of valid identifiers.
+- clocks: Must contain an entry for each clock in clock-names.
+- clock-names: Must include "periph_sys", the peripheral system clock generated
+  by the core clock controller.
+
+Example:
+	clk_periph: clock-controller@18144800 {
+		compatible = "img,pistachio-clk-periph";
+		reg = <0x18144800 0x800>;
+		clocks = <&clk_core CLK_PERIPH_SYS>;
+		clock-names = "periph_sys";
+
+		#clock-cells = <1>;
+	};
+
+Peripheral general control:
+---------------------------
+
+The peripheral general control block generates system interface clocks and
+resets for various peripherals.  It also contains miscellaneous peripheral
+control registers.  The system clock ("sys") generated by the peripheral clock
+controller is the input clock to the system clock controller.
+
+Required properties:
+- compatible: Must include "img,pistachio-periph-cr" and "syscon".
+- reg: Must contain the base address and length of the peripheral general
+  control registers.
+- #clock-cells: Must be 1.  The single cell is the clock identifier.
+  See dt-bindings/clock/pistachio-clk.h for the list of valid identifiers.
+- clocks: Must contain an entry for each clock in clock-names.
+- clock-names: Must include "sys", the system clock generated by the peripheral
+  clock controller.
+
+Example:
+	cr_periph: syscon@18144800 {
+		compatible = "img,pistachio-cr-periph", "syscon";
+		reg = <0x18148000 0x1000>;
+		clocks = <&clock_periph PERIPH_CLK_PERIPH_SYS>;
+		clock-names = "sys";
+
+		#clock-cells = <1>;
+	};
+
+Top-level general control:
+--------------------------
+
+The top-level general control block contains miscellaneous control registers and
+gates for the external clocks "audio_clk_in" and "enet_clk_in".
+
+Required properties:
+- compatible: Must include "img,pistachio-cr-top" and "syscon".
+- reg: Must contain the base address and length of the top-level
+  control registers.
+- clocks: Must contain an entry for each clock in clock-names.
+- clock-names: Two optional clocks, "audio_clk_in" and "enet_clk_in" (see
+  "External clocks").
+- #clock-cells: Must be 1.  The single cell is the clock identifier.
+  See dt-bindings/clock/pistachio-clk.h for the list of valid identifiers.
+
+Example:
+	cr_top: syscon@18144800 {
+		compatible = "img,pistachio-cr-top", "syscon";
+		reg = <0x18149000 0x200>;
+		clocks = <&audio_refclk>, <&ext_enet_in>;
+		clock-names = "audio_clk_in", "enet_clk_in";
+
+		#clock-cells = <1>;
+	};
diff --git a/include/dt-bindings/clock/pistachio-clk.h b/include/dt-bindings/clock/pistachio-clk.h
new file mode 100644
index 0000000..039f83f
--- /dev/null
+++ b/include/dt-bindings/clock/pistachio-clk.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_PISTACHIO_H
+#define _DT_BINDINGS_CLOCK_PISTACHIO_H
+
+/* PLLs */
+#define CLK_MIPS_PLL			0
+#define CLK_AUDIO_PLL			1
+#define CLK_RPU_V_PLL			2
+#define CLK_RPU_L_PLL			3
+#define CLK_SYS_PLL			4
+#define CLK_WIFI_PLL			5
+#define CLK_BT_PLL			6
+
+/* Fixed-factor clocks */
+#define CLK_WIFI_DIV4			16
+#define CLK_WIFI_DIV8			17
+
+/* Gate clocks */
+#define CLK_MIPS			32
+#define CLK_AUDIO_IN			33
+#define CLK_AUDIO			34
+#define CLK_I2S				35
+#define CLK_SPDIF			36
+#define CLK_AUDIO_DAC			37
+#define CLK_RPU_V			38
+#define CLK_RPU_L			39
+#define CLK_RPU_SLEEP			40
+#define CLK_WIFI_PLL_GATE		41
+#define CLK_RPU_CORE			42
+#define CLK_WIFI_ADC			43
+#define CLK_WIFI_DAC			44
+#define CLK_USB_PHY			45
+#define CLK_ENET_IN			46
+#define CLK_ENET			47
+#define CLK_UART0			48
+#define CLK_UART1			49
+#define CLK_PERIPH_SYS			50
+#define CLK_SPI0			51
+#define CLK_SPI1			52
+#define CLK_EVENT_TIMER			53
+#define CLK_AUX_ADC_INTERNAL		54
+#define CLK_AUX_ADC			55
+#define CLK_SD_HOST			56
+#define CLK_BT				57
+#define CLK_BT_DIV4			58
+#define CLK_BT_DIV8			59
+#define CLK_BT_1MHZ			60
+
+/* Divider clocks */
+#define CLK_MIPS_INTERNAL_DIV		64
+#define CLK_MIPS_DIV			65
+#define CLK_AUDIO_DIV			66
+#define CLK_I2S_DIV			67
+#define CLK_SPDIF_DIV			68
+#define CLK_AUDIO_DAC_DIV		69
+#define CLK_RPU_V_DIV			70
+#define CLK_RPU_L_DIV			71
+#define CLK_RPU_SLEEP_DIV		72
+#define CLK_RPU_CORE_DIV		73
+#define CLK_USB_PHY_DIV			74
+#define CLK_ENET_DIV			75
+#define CLK_UART0_INTERNAL_DIV		76
+#define CLK_UART0_DIV			77
+#define CLK_UART1_INTERNAL_DIV		78
+#define CLK_UART1_DIV			79
+#define CLK_SYS_INTERNAL_DIV		80
+#define CLK_SPI0_INTERNAL_DIV		81
+#define CLK_SPI0_DIV			82
+#define CLK_SPI1_INTERNAL_DIV		83
+#define CLK_SPI1_DIV			84
+#define CLK_EVENT_TIMER_INTERNAL_DIV	85
+#define CLK_EVENT_TIMER_DIV		86
+#define CLK_AUX_ADC_INTERNAL_DIV	87
+#define CLK_AUX_ADC_DIV			88
+#define CLK_SD_HOST_DIV			89
+#define CLK_BT_DIV			90
+#define CLK_BT_DIV4_DIV			91
+#define CLK_BT_DIV8_DIV			92
+#define CLK_BT_1MHZ_INTERNAL_DIV	93
+#define CLK_BT_1MHZ_DIV			94
+
+/* Mux clocks */
+#define CLK_AUDIO_REF_MUX		96
+#define CLK_MIPS_PLL_MUX		97
+#define CLK_AUDIO_PLL_MUX		98
+#define CLK_AUDIO_MUX			99
+#define CLK_RPU_V_PLL_MUX		100
+#define CLK_RPU_L_PLL_MUX		101
+#define CLK_RPU_L_MUX			102
+#define CLK_WIFI_PLL_MUX		103
+#define CLK_WIFI_DIV4_MUX		104
+#define CLK_WIFI_DIV8_MUX		105
+#define CLK_RPU_CORE_MUX		106
+#define CLK_SYS_PLL_MUX			107
+#define CLK_ENET_MUX			108
+#define CLK_EVENT_TIMER_MUX		109
+#define CLK_SD_HOST_MUX			110
+#define CLK_BT_PLL_MUX			111
+#define CLK_DEBUG_MUX			112
+
+#define CLK_NR_CLKS			113
+
+/* Peripheral gate clocks */
+#define PERIPH_CLK_SYS			0
+#define PERIPH_CLK_SYS_BUS		1
+#define PERIPH_CLK_DDR			2
+#define PERIPH_CLK_ROM			3
+#define PERIPH_CLK_COUNTER_FAST		4
+#define PERIPH_CLK_COUNTER_SLOW		5
+#define PERIPH_CLK_IR			6
+#define PERIPH_CLK_WD			7
+#define PERIPH_CLK_PDM			8
+#define PERIPH_CLK_PWM			9
+#define PERIPH_CLK_I2C0			10
+#define PERIPH_CLK_I2C1			11
+#define PERIPH_CLK_I2C2			12
+#define PERIPH_CLK_I2C3			13
+
+/* Peripheral divider clocks */
+#define PERIPH_CLK_ROM_DIV		32
+#define PERIPH_CLK_COUNTER_FAST_DIV	33
+#define PERIPH_CLK_COUNTER_SLOW_PRE_DIV	34
+#define PERIPH_CLK_COUNTER_SLOW_DIV	35
+#define PERIPH_CLK_IR_PRE_DIV		36
+#define PERIPH_CLK_IR_DIV		37
+#define PERIPH_CLK_WD_PRE_DIV		38
+#define PERIPH_CLK_WD_DIV		39
+#define PERIPH_CLK_PDM_PRE_DIV		40
+#define PERIPH_CLK_PDM_DIV		41
+#define PERIPH_CLK_PWM_PRE_DIV		42
+#define PERIPH_CLK_PWM_DIV		43
+#define PERIPH_CLK_I2C0_PRE_DIV		44
+#define PERIPH_CLK_I2C0_DIV		45
+#define PERIPH_CLK_I2C1_PRE_DIV		46
+#define PERIPH_CLK_I2C1_DIV		47
+#define PERIPH_CLK_I2C2_PRE_DIV		48
+#define PERIPH_CLK_I2C2_DIV		49
+#define PERIPH_CLK_I2C3_PRE_DIV		50
+#define PERIPH_CLK_I2C3_DIV		51
+
+#define PERIPH_CLK_NR_CLKS		52
+
+/* System gate clocks */
+#define SYS_CLK_I2C0			0
+#define SYS_CLK_I2C1			1
+#define SYS_CLK_I2C2			2
+#define SYS_CLK_I2C3			3
+#define SYS_CLK_I2S_IN			4
+#define SYS_CLK_PAUD_OUT		5
+#define SYS_CLK_SPDIF_OUT		6
+#define SYS_CLK_SPI0_MASTER		7
+#define SYS_CLK_SPI0_SLAVE		8
+#define SYS_CLK_PWM			9
+#define SYS_CLK_UART0			10
+#define SYS_CLK_UART1			11
+#define SYS_CLK_SPI1			12
+#define SYS_CLK_MDC			13
+#define SYS_CLK_SD_HOST			14
+#define SYS_CLK_ENET			15
+#define SYS_CLK_IR			16
+#define SYS_CLK_WD			17
+#define SYS_CLK_TIMER			18
+#define SYS_CLK_I2S_OUT			24
+#define SYS_CLK_SPDIF_IN		25
+#define SYS_CLK_EVENT_TIMER		26
+#define SYS_CLK_HASH			27
+
+#define SYS_CLK_NR_CLKS			28
+
+/* Gates for external input clocks */
+#define EXT_CLK_AUDIO_IN		0
+#define EXT_CLK_ENET_IN			1
+
+#define EXT_CLK_NR_CLKS			2
+
+#endif /* _DT_BINDINGS_CLOCK_PISTACHIO_H */
-- 
2.2.0.rc0.207.ga3a616c


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

* [PATCH 2/7] clk: Add basic infrastructure for Pistachio clocks
  2015-02-25  3:56 [PATCH 0/7] clk: Common clock support for IMG Pistachio Andrew Bresticker
  2015-02-25  3:56 ` [PATCH 1/7] clk: Add binding document for Pistachio clock controllers Andrew Bresticker
@ 2015-02-25  3:56 ` Andrew Bresticker
  2015-03-30 23:59   ` Stephen Boyd
  2015-02-25  3:56 ` [PATCH 3/7] clk: pistachio: Add PLL driver Andrew Bresticker
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 15+ messages in thread
From: Andrew Bresticker @ 2015-02-25  3:56 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, Ralf Baechle
  Cc: devicetree, linux-mips, linux-kernel, Andrew Bresticker,
	Ezequiel Garcia, James Hartley, James Hogan

Add helpers for registering clocks and clock providers on Pistachio.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/clk/Makefile           |   1 +
 drivers/clk/pistachio/Makefile |   1 +
 drivers/clk/pistachio/clk.c    | 140 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/pistachio/clk.h    | 124 ++++++++++++++++++++++++++++++++++++
 4 files changed, 266 insertions(+)
 create mode 100644 drivers/clk/pistachio/Makefile
 create mode 100644 drivers/clk/pistachio/clk.c
 create mode 100644 drivers/clk/pistachio/clk.h

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index d478ceb..e43ff53 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_ARCH_MMP)			+= mmp/
 endif
 obj-$(CONFIG_PLAT_ORION)		+= mvebu/
 obj-$(CONFIG_ARCH_MXS)			+= mxs/
+obj-$(CONFIG_MACH_PISTACHIO)		+= pistachio/
 obj-$(CONFIG_COMMON_CLK_PXA)		+= pxa/
 obj-$(CONFIG_COMMON_CLK_QCOM)		+= qcom/
 obj-$(CONFIG_ARCH_ROCKCHIP)		+= rockchip/
diff --git a/drivers/clk/pistachio/Makefile b/drivers/clk/pistachio/Makefile
new file mode 100644
index 0000000..fc216ad
--- /dev/null
+++ b/drivers/clk/pistachio/Makefile
@@ -0,0 +1 @@
+obj-y	+= clk.o
diff --git a/drivers/clk/pistachio/clk.c b/drivers/clk/pistachio/clk.c
new file mode 100644
index 0000000..85faa83
--- /dev/null
+++ b/drivers/clk/pistachio/clk.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+struct pistachio_clk_provider *
+pistachio_clk_alloc_provider(struct device_node *node, unsigned int num_clks)
+{
+	struct pistachio_clk_provider *p;
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return p;
+
+	p->clk_data.clks = kcalloc(num_clks, sizeof(struct clk *), GFP_KERNEL);
+	if (!p->clk_data.clks)
+		goto free_provider;
+	p->clk_data.clk_num = num_clks;
+	p->node = node;
+	p->base = of_iomap(node, 0);
+	if (!p->base) {
+		pr_err("Failed to map clock provider registers\n");
+		goto free_clks;
+	}
+
+	return p;
+
+free_clks:
+	kfree(p->clk_data.clks);
+free_provider:
+	kfree(p);
+	return NULL;
+}
+
+void pistachio_clk_register_provider(struct pistachio_clk_provider *p)
+{
+	unsigned int i;
+
+	for (i = 0; i < p->clk_data.clk_num; i++) {
+		if (IS_ERR(p->clk_data.clks[i]))
+			pr_warn("Failed to register clock %d: %ld\n", i,
+				PTR_ERR(p->clk_data.clks[i]));
+	}
+
+	of_clk_add_provider(p->node, of_clk_src_onecell_get, &p->clk_data);
+}
+
+void pistachio_clk_register_gate(struct pistachio_clk_provider *p,
+				 struct pistachio_gate *gate,
+				 unsigned int num)
+{
+	struct clk *clk;
+	unsigned int i;
+
+	for (i = 0; i < num; i++) {
+		clk = clk_register_gate(NULL, gate[i].name, gate[i].parent,
+					CLK_SET_RATE_PARENT,
+					p->base + gate[i].reg, gate[i].shift,
+					0, NULL);
+		p->clk_data.clks[gate[i].id] = clk;
+	}
+}
+
+void pistachio_clk_register_mux(struct pistachio_clk_provider *p,
+				struct pistachio_mux *mux,
+				unsigned int num)
+{
+	struct clk *clk;
+	unsigned int i;
+
+	for (i = 0; i < num; i++) {
+		clk = clk_register_mux(NULL, mux[i].name, mux[i].parents,
+				       mux[i].num_parents,
+				       CLK_SET_RATE_NO_REPARENT,
+				       p->base + mux[i].reg, mux[i].shift,
+				       get_count_order(mux[i].num_parents),
+				       0, NULL);
+		p->clk_data.clks[mux[i].id] = clk;
+	}
+}
+
+void pistachio_clk_register_div(struct pistachio_clk_provider *p,
+				struct pistachio_div *div,
+				unsigned int num)
+{
+	struct clk *clk;
+	unsigned int i;
+
+	for (i = 0; i < num; i++) {
+		clk = clk_register_divider(NULL, div[i].name, div[i].parent,
+					   0, p->base + div[i].reg, 0,
+					   div[i].width, div[i].div_flags,
+					   NULL);
+		p->clk_data.clks[div[i].id] = clk;
+	}
+}
+
+void pistachio_clk_register_fixed_factor(struct pistachio_clk_provider *p,
+					 struct pistachio_fixed_factor *ff,
+					 unsigned int num)
+{
+	struct clk *clk;
+	unsigned int i;
+
+	for (i = 0; i < num; i++) {
+		clk = clk_register_fixed_factor(NULL, ff[i].name, ff[i].parent,
+						0, 1, ff[i].div);
+		p->clk_data.clks[ff[i].id] = clk;
+	}
+}
+
+void pistachio_clk_force_enable(struct pistachio_clk_provider *p,
+				unsigned int *clk_ids, unsigned int num)
+{
+	unsigned int i;
+	int err;
+
+	for (i = 0; i < num; i++) {
+		struct clk *clk = p->clk_data.clks[clk_ids[i]];
+
+		if (IS_ERR(clk))
+			continue;
+
+		err = clk_prepare_enable(clk);
+		if (err)
+			pr_err("Failed to enable clock %s: %d\n",
+			       __clk_get_name(clk), err);
+	}
+}
diff --git a/drivers/clk/pistachio/clk.h b/drivers/clk/pistachio/clk.h
new file mode 100644
index 0000000..e735107
--- /dev/null
+++ b/drivers/clk/pistachio/clk.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __PISTACHIO_CLK_H
+#define __PISTACHIO_CLK_H
+
+#include <linux/clk-provider.h>
+
+struct pistachio_gate {
+	unsigned int id;
+	unsigned long reg;
+	unsigned int shift;
+	const char *name;
+	const char *parent;
+};
+
+#define GATE(_id, _name, _pname, _reg, _shift)	\
+	{					\
+		.id	= _id,			\
+		.reg	= _reg,			\
+		.shift	= _shift,		\
+		.name	= _name,		\
+		.parent = _pname,		\
+	}
+
+struct pistachio_mux {
+	unsigned int id;
+	unsigned long reg;
+	unsigned int shift;
+	unsigned int num_parents;
+	const char *name;
+	const char **parents;
+};
+
+#define PNAME(x) static const char *x[] __initconst
+
+#define MUX(_id, _name, _pnames, _reg, _shift)			\
+	{							\
+		.id		= _id,				\
+		.reg		= _reg,				\
+		.shift		= _shift,			\
+		.name		= _name,			\
+		.parents	= _pnames,			\
+		.num_parents	= ARRAY_SIZE(_pnames)		\
+	}
+
+
+struct pistachio_div {
+	unsigned int id;
+	unsigned long reg;
+	unsigned int width;
+	unsigned int div_flags;
+	const char *name;
+	const char *parent;
+};
+
+#define DIV(_id, _name, _pname, _reg, _width)			\
+	{							\
+		.id		= _id,				\
+		.reg		= _reg,				\
+		.width		= _width,			\
+		.div_flags	= 0,				\
+		.name		= _name,			\
+		.parent		= _pname,			\
+	}
+
+#define DIV_F(_id, _name, _pname, _reg, _width, _div_flags)	\
+	{							\
+		.id		= _id,				\
+		.reg		= _reg,				\
+		.width		= _width,			\
+		.div_flags	= _div_flags,			\
+		.name		= _name,			\
+		.parent		= _pname,			\
+	}
+
+struct pistachio_fixed_factor {
+	unsigned int id;
+	unsigned int div;
+	const char *name;
+	const char *parent;
+};
+
+#define FIXED_FACTOR(_id, _name, _pname, _div)			\
+	{							\
+		.id		= _id,				\
+		.div		= _div,				\
+		.name		= _name,			\
+		.parent		= _pname,			\
+	}
+
+struct pistachio_clk_provider {
+	struct device_node *node;
+	void __iomem *base;
+	struct clk_onecell_data clk_data;
+};
+
+extern struct pistachio_clk_provider *
+pistachio_clk_alloc_provider(struct device_node *node, unsigned int num_clks);
+extern void pistachio_clk_register_provider(struct pistachio_clk_provider *p);
+
+extern void pistachio_clk_register_gate(struct pistachio_clk_provider *p,
+					struct pistachio_gate *gate,
+					unsigned int num);
+extern void pistachio_clk_register_mux(struct pistachio_clk_provider *p,
+				       struct pistachio_mux *mux,
+				       unsigned int num);
+extern void pistachio_clk_register_div(struct pistachio_clk_provider *p,
+				       struct pistachio_div *div,
+				       unsigned int num);
+extern void
+pistachio_clk_register_fixed_factor(struct pistachio_clk_provider *p,
+				    struct pistachio_fixed_factor *ff,
+				    unsigned int num);
+
+extern void pistachio_clk_force_enable(struct pistachio_clk_provider *p,
+				       unsigned int *clk_ids, unsigned int num);
+
+#endif
-- 
2.2.0.rc0.207.ga3a616c


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

* [PATCH 3/7] clk: pistachio: Add PLL driver
  2015-02-25  3:56 [PATCH 0/7] clk: Common clock support for IMG Pistachio Andrew Bresticker
  2015-02-25  3:56 ` [PATCH 1/7] clk: Add binding document for Pistachio clock controllers Andrew Bresticker
  2015-02-25  3:56 ` [PATCH 2/7] clk: Add basic infrastructure for Pistachio clocks Andrew Bresticker
@ 2015-02-25  3:56 ` Andrew Bresticker
  2015-02-25  3:56 ` [PATCH 4/7] clk: pistachio: Register core clocks Andrew Bresticker
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Andrew Bresticker @ 2015-02-25  3:56 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, Ralf Baechle
  Cc: devicetree, linux-mips, linux-kernel, Andrew Bresticker,
	Ezequiel Garcia, James Hartley, James Hogan

Add a driver for the integer (GF40LP_LAINT) and fractional (GF40LP_FRAC)
PLLs present on Pistachio.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/clk/pistachio/Makefile  |   1 +
 drivers/clk/pistachio/clk-pll.c | 401 ++++++++++++++++++++++++++++++++++++++++
 drivers/clk/pistachio/clk.h     |  50 +++++
 3 files changed, 452 insertions(+)
 create mode 100644 drivers/clk/pistachio/clk-pll.c

diff --git a/drivers/clk/pistachio/Makefile b/drivers/clk/pistachio/Makefile
index fc216ad..a93490d 100644
--- a/drivers/clk/pistachio/Makefile
+++ b/drivers/clk/pistachio/Makefile
@@ -1 +1,2 @@
 obj-y	+= clk.o
+obj-y	+= clk-pll.o
diff --git a/drivers/clk/pistachio/clk-pll.c b/drivers/clk/pistachio/clk-pll.c
new file mode 100644
index 0000000..de53756
--- /dev/null
+++ b/drivers/clk/pistachio/clk-pll.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+#define PLL_STATUS			0x0
+#define PLL_STATUS_LOCK			BIT(0)
+
+#define PLL_CTRL1			0x4
+#define PLL_CTRL1_REFDIV_SHIFT		0
+#define PLL_CTRL1_REFDIV_MASK		0x3f
+#define PLL_CTRL1_FBDIV_SHIFT		6
+#define PLL_CTRL1_FBDIV_MASK		0xfff
+#define PLL_INT_CTRL1_POSTDIV1_SHIFT	18
+#define PLL_INT_CTRL1_POSTDIV1_MASK	0x7
+#define PLL_INT_CTRL1_POSTDIV2_SHIFT	21
+#define PLL_INT_CTRL1_POSTDIV2_MASK	0x7
+#define PLL_INT_CTRL1_PD		BIT(24)
+#define PLL_INT_CTRL1_DSMPD		BIT(25)
+#define PLL_INT_CTRL1_FOUTPOSTDIVPD	BIT(26)
+#define PLL_INT_CTRL1_FOUTVCOPD		BIT(27)
+
+#define PLL_CTRL2			0x8
+#define PLL_FRAC_CTRL2_FRAC_SHIFT	0
+#define PLL_FRAC_CTRL2_FRAC_MASK	0xffffff
+#define PLL_FRAC_CTRL2_POSTDIV1_SHIFT	24
+#define PLL_FRAC_CTRL2_POSTDIV1_MASK	0x7
+#define PLL_FRAC_CTRL2_POSTDIV2_SHIFT	27
+#define PLL_FRAC_CTRL2_POSTDIV2_MASK	0x7
+#define PLL_INT_CTRL2_BYPASS		BIT(28)
+
+#define PLL_CTRL3			0xc
+#define PLL_FRAC_CTRL3_PD		BIT(0)
+#define PLL_FRAC_CTRL3_DACPD		BIT(1)
+#define PLL_FRAC_CTRL3_DSMPD		BIT(2)
+#define PLL_FRAC_CTRL3_FOUTPOSTDIVPD	BIT(3)
+#define PLL_FRAC_CTRL3_FOUT4PHASEPD	BIT(4)
+#define PLL_FRAC_CTRL3_FOUTVCOPD	BIT(5)
+
+#define PLL_CTRL4			0x10
+#define PLL_FRAC_CTRL4_BYPASS		BIT(28)
+
+struct pistachio_clk_pll {
+	struct clk_hw hw;
+	void __iomem *base;
+	struct pistachio_pll_rate_table *rates;
+	unsigned int nr_rates;
+};
+
+static inline u32 pll_readl(struct pistachio_clk_pll *pll, u32 reg)
+{
+	return readl(pll->base + reg);
+}
+
+static inline void pll_writel(struct pistachio_clk_pll *pll, u32 val, u32 reg)
+{
+	writel(val, pll->base + reg);
+}
+
+static inline u32 do_div_round_closest(u64 dividend, u32 divisor)
+{
+	dividend += divisor / 2;
+	do_div(dividend, divisor);
+
+	return dividend;
+}
+
+static inline struct pistachio_clk_pll *to_pistachio_pll(struct clk_hw *hw)
+{
+	return container_of(hw, struct pistachio_clk_pll, hw);
+}
+
+static struct pistachio_pll_rate_table *
+pll_get_params(struct pistachio_clk_pll *pll, unsigned long fref,
+	       unsigned long fout)
+{
+	unsigned int i;
+
+	for (i = 0; i < pll->nr_rates; i++) {
+		if (pll->rates[i].fref == fref && pll->rates[i].fout == fout)
+			return &pll->rates[i];
+	}
+
+	return NULL;
+}
+
+static long pll_round_rate(struct clk_hw *hw, unsigned long rate,
+			   unsigned long *parent_rate)
+{
+	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
+	unsigned int i;
+
+	for (i = 0; i < pll->nr_rates; i++) {
+		if (i > 0 && pll->rates[i].fref == *parent_rate &&
+		    pll->rates[i].fout <= rate)
+			return pll->rates[i - 1].fout;
+	}
+
+	return pll->rates[0].fout;
+}
+
+static int pll_gf40lp_frac_enable(struct clk_hw *hw)
+{
+	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
+	u32 val;
+
+	val = pll_readl(pll, PLL_CTRL3);
+	val &= ~(PLL_FRAC_CTRL3_PD | PLL_FRAC_CTRL3_DACPD |
+		 PLL_FRAC_CTRL3_DSMPD | PLL_FRAC_CTRL3_FOUTPOSTDIVPD |
+		 PLL_FRAC_CTRL3_FOUT4PHASEPD | PLL_FRAC_CTRL3_FOUTVCOPD);
+	pll_writel(pll, val, PLL_CTRL3);
+
+	val = pll_readl(pll, PLL_CTRL4);
+	val &= ~PLL_FRAC_CTRL4_BYPASS;
+	pll_writel(pll, val, PLL_CTRL4);
+
+	return 0;
+}
+
+static void pll_gf40lp_frac_disable(struct clk_hw *hw)
+{
+	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
+	u32 val;
+
+	val = pll_readl(pll, PLL_CTRL3);
+	val |= PLL_FRAC_CTRL3_PD;
+	pll_writel(pll, val, PLL_CTRL3);
+}
+
+static int pll_gf40lp_frac_is_enabled(struct clk_hw *hw)
+{
+	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
+
+	return !(pll_readl(pll, PLL_CTRL3) & PLL_FRAC_CTRL3_PD);
+}
+
+static int pll_gf40lp_frac_set_rate(struct clk_hw *hw, unsigned long rate,
+				    unsigned long parent_rate)
+{
+	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
+	struct pistachio_pll_rate_table *params;
+	bool was_enabled;
+	u32 val;
+
+	params = pll_get_params(pll, parent_rate, rate);
+	if (!params)
+		return -EINVAL;
+
+	was_enabled = pll_gf40lp_frac_is_enabled(hw);
+	if (!was_enabled)
+		pll_gf40lp_frac_enable(hw);
+
+	val = pll_readl(pll, PLL_CTRL1);
+	val &= ~((PLL_CTRL1_REFDIV_MASK << PLL_CTRL1_REFDIV_SHIFT) |
+		 (PLL_CTRL1_FBDIV_MASK << PLL_CTRL1_FBDIV_SHIFT));
+	val |= (params->refdiv << PLL_CTRL1_REFDIV_SHIFT) |
+		(params->fbdiv << PLL_CTRL1_FBDIV_SHIFT);
+	pll_writel(pll, val, PLL_CTRL1);
+
+	val = pll_readl(pll, PLL_CTRL2);
+	val &= ~((PLL_FRAC_CTRL2_FRAC_MASK << PLL_FRAC_CTRL2_FRAC_SHIFT) |
+		 (PLL_FRAC_CTRL2_POSTDIV1_MASK <<
+		  PLL_FRAC_CTRL2_POSTDIV1_SHIFT) |
+		 (PLL_FRAC_CTRL2_POSTDIV2_MASK <<
+		  PLL_FRAC_CTRL2_POSTDIV2_SHIFT));
+	val |= (params->frac << PLL_FRAC_CTRL2_FRAC_SHIFT) |
+		(params->postdiv1 << PLL_FRAC_CTRL2_POSTDIV1_SHIFT) |
+		(params->postdiv2 << PLL_FRAC_CTRL2_POSTDIV2_SHIFT);
+	pll_writel(pll, val, PLL_CTRL2);
+
+	while (!(pll_readl(pll, PLL_STATUS) & PLL_STATUS_LOCK))
+		cpu_relax();
+
+	if (!was_enabled)
+		pll_gf40lp_frac_disable(hw);
+
+	return 0;
+}
+
+static unsigned long pll_gf40lp_frac_recalc_rate(struct clk_hw *hw,
+						 unsigned long parent_rate)
+{
+	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
+	u32 val, prediv, fbdiv, frac, postdiv1, postdiv2;
+	u64 rate = parent_rate;
+
+	val = pll_readl(pll, PLL_CTRL1);
+	prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK;
+	fbdiv = (val >> PLL_CTRL1_FBDIV_SHIFT) & PLL_CTRL1_FBDIV_MASK;
+
+	val = pll_readl(pll, PLL_CTRL2);
+	postdiv1 = (val >> PLL_FRAC_CTRL2_POSTDIV1_SHIFT) &
+		PLL_FRAC_CTRL2_POSTDIV1_MASK;
+	postdiv2 = (val >> PLL_FRAC_CTRL2_POSTDIV2_SHIFT) &
+		PLL_FRAC_CTRL2_POSTDIV2_MASK;
+	frac = (val >> PLL_FRAC_CTRL2_FRAC_SHIFT) & PLL_FRAC_CTRL2_FRAC_MASK;
+
+	rate *= (fbdiv << 24) + frac;
+	rate = do_div_round_closest(rate, (prediv * postdiv1 * postdiv2) << 24);
+
+	return rate;
+}
+
+static struct clk_ops pll_gf40lp_frac_ops = {
+	.enable = pll_gf40lp_frac_enable,
+	.disable = pll_gf40lp_frac_disable,
+	.is_enabled = pll_gf40lp_frac_is_enabled,
+	.recalc_rate = pll_gf40lp_frac_recalc_rate,
+	.round_rate = pll_round_rate,
+	.set_rate = pll_gf40lp_frac_set_rate,
+};
+
+static struct clk_ops pll_gf40lp_frac_fixed_ops = {
+	.enable = pll_gf40lp_frac_enable,
+	.disable = pll_gf40lp_frac_disable,
+	.is_enabled = pll_gf40lp_frac_is_enabled,
+	.recalc_rate = pll_gf40lp_frac_recalc_rate,
+};
+
+static int pll_gf40lp_laint_enable(struct clk_hw *hw)
+{
+	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
+	u32 val;
+
+	val = pll_readl(pll, PLL_CTRL1);
+	val &= ~(PLL_INT_CTRL1_PD | PLL_INT_CTRL1_DSMPD |
+		 PLL_INT_CTRL1_FOUTPOSTDIVPD | PLL_INT_CTRL1_FOUTVCOPD);
+	pll_writel(pll, val, PLL_CTRL1);
+
+	val = pll_readl(pll, PLL_CTRL2);
+	val &= ~PLL_INT_CTRL2_BYPASS;
+	pll_writel(pll, val, PLL_CTRL2);
+
+	return 0;
+}
+
+static void pll_gf40lp_laint_disable(struct clk_hw *hw)
+{
+	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
+	u32 val;
+
+	val = pll_readl(pll, PLL_CTRL1);
+	val |= PLL_INT_CTRL1_PD;
+	pll_writel(pll, val, PLL_CTRL1);
+}
+
+static int pll_gf40lp_laint_is_enabled(struct clk_hw *hw)
+{
+	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
+
+	return !(pll_readl(pll, PLL_CTRL1) & PLL_INT_CTRL1_PD);
+}
+
+static int pll_gf40lp_laint_set_rate(struct clk_hw *hw, unsigned long rate,
+				     unsigned long parent_rate)
+{
+	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
+	struct pistachio_pll_rate_table *params;
+	bool was_enabled;
+	u32 val;
+
+	params = pll_get_params(pll, parent_rate, rate);
+	if (!params)
+		return -EINVAL;
+
+	was_enabled = pll_gf40lp_laint_is_enabled(hw);
+	if (!was_enabled)
+		pll_gf40lp_laint_enable(hw);
+
+	val = pll_readl(pll, PLL_CTRL1);
+	val &= ~((PLL_CTRL1_REFDIV_MASK << PLL_CTRL1_REFDIV_SHIFT) |
+		 (PLL_CTRL1_FBDIV_MASK << PLL_CTRL1_FBDIV_SHIFT) |
+		 (PLL_INT_CTRL1_POSTDIV1_MASK << PLL_INT_CTRL1_POSTDIV1_SHIFT) |
+		 (PLL_INT_CTRL1_POSTDIV2_MASK << PLL_INT_CTRL1_POSTDIV2_SHIFT));
+	val |= (params->refdiv << PLL_CTRL1_REFDIV_SHIFT) |
+		(params->fbdiv << PLL_CTRL1_FBDIV_SHIFT) |
+		(params->postdiv1 << PLL_INT_CTRL1_POSTDIV1_SHIFT) |
+		(params->postdiv2 << PLL_INT_CTRL1_POSTDIV2_SHIFT);
+	pll_writel(pll, val, PLL_CTRL1);
+
+	while (!(pll_readl(pll, PLL_STATUS) & PLL_STATUS_LOCK))
+		cpu_relax();
+
+	if (!was_enabled)
+		pll_gf40lp_laint_disable(hw);
+
+	return 0;
+}
+
+static unsigned long pll_gf40lp_laint_recalc_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	struct pistachio_clk_pll *pll = to_pistachio_pll(hw);
+	u32 val, prediv, fbdiv, postdiv1, postdiv2;
+	u64 rate = parent_rate;
+
+	val = pll_readl(pll, PLL_CTRL1);
+	prediv = (val >> PLL_CTRL1_REFDIV_SHIFT) & PLL_CTRL1_REFDIV_MASK;
+	fbdiv = (val >> PLL_CTRL1_FBDIV_SHIFT) & PLL_CTRL1_FBDIV_MASK;
+	postdiv1 = (val >> PLL_INT_CTRL1_POSTDIV1_SHIFT) &
+		PLL_INT_CTRL1_POSTDIV1_MASK;
+	postdiv2 = (val >> PLL_INT_CTRL1_POSTDIV2_SHIFT) &
+		PLL_INT_CTRL1_POSTDIV2_MASK;
+
+	rate *= fbdiv;
+	rate = do_div_round_closest(rate, prediv * postdiv1 * postdiv2);
+
+	return rate;
+}
+
+static struct clk_ops pll_gf40lp_laint_ops = {
+	.enable = pll_gf40lp_laint_enable,
+	.disable = pll_gf40lp_laint_disable,
+	.is_enabled = pll_gf40lp_laint_is_enabled,
+	.recalc_rate = pll_gf40lp_laint_recalc_rate,
+	.round_rate = pll_round_rate,
+	.set_rate = pll_gf40lp_laint_set_rate,
+};
+
+static struct clk_ops pll_gf40lp_laint_fixed_ops = {
+	.enable = pll_gf40lp_laint_enable,
+	.disable = pll_gf40lp_laint_disable,
+	.is_enabled = pll_gf40lp_laint_is_enabled,
+	.recalc_rate = pll_gf40lp_laint_recalc_rate,
+};
+
+static struct clk *pll_register(const char *name, const char *parent_name,
+				unsigned long flags, void __iomem *base,
+				enum pistachio_pll_type type,
+				struct pistachio_pll_rate_table *rates,
+				unsigned int nr_rates)
+{
+	struct pistachio_clk_pll *pll;
+	struct clk_init_data init;
+	struct clk *clk;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.flags = flags | CLK_GET_RATE_NOCACHE;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	switch (type) {
+	case PLL_GF40LP_FRAC:
+		if (rates)
+			init.ops = &pll_gf40lp_frac_ops;
+		else
+			init.ops = &pll_gf40lp_frac_fixed_ops;
+		break;
+	case PLL_GF40LP_LAINT:
+		if (rates)
+			init.ops = &pll_gf40lp_laint_ops;
+		else
+			init.ops = &pll_gf40lp_laint_fixed_ops;
+		break;
+	default:
+		pr_err("Unrecognized PLL type %u\n", type);
+		kfree(pll);
+		return ERR_PTR(-EINVAL);
+	}
+
+	pll->hw.init = &init;
+	pll->base = base;
+	pll->rates = rates;
+	pll->nr_rates = nr_rates;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
+
+void pistachio_clk_register_pll(struct pistachio_clk_provider *p,
+				struct pistachio_pll *pll,
+				unsigned int num)
+{
+	struct clk *clk;
+	unsigned int i;
+
+	for (i = 0; i < num; i++) {
+		clk = pll_register(pll[i].name, pll[i].parent,
+				   0, p->base + pll[i].reg_base,
+				   pll[i].type, pll[i].rates,
+				   pll[i].nr_rates);
+		p->clk_data.clks[pll[i].id] = clk;
+	}
+}
diff --git a/drivers/clk/pistachio/clk.h b/drivers/clk/pistachio/clk.h
index e735107..52fabbc 100644
--- a/drivers/clk/pistachio/clk.h
+++ b/drivers/clk/pistachio/clk.h
@@ -94,6 +94,53 @@ struct pistachio_fixed_factor {
 		.parent		= _pname,			\
 	}
 
+struct pistachio_pll_rate_table {
+	unsigned long fref;
+	unsigned long fout;
+	unsigned int refdiv;
+	unsigned int fbdiv;
+	unsigned int postdiv1;
+	unsigned int postdiv2;
+	unsigned int frac;
+};
+
+enum pistachio_pll_type {
+	PLL_GF40LP_LAINT,
+	PLL_GF40LP_FRAC,
+};
+
+struct pistachio_pll {
+	unsigned int id;
+	unsigned long reg_base;
+	enum pistachio_pll_type type;
+	struct pistachio_pll_rate_table *rates;
+	unsigned int nr_rates;
+	const char *name;
+	const char *parent;
+};
+
+#define PLL(_id, _name, _pname, _type, _reg, _rates)		\
+	{							\
+		.id		= _id,				\
+		.reg_base	= _reg,				\
+		.type		= _type,			\
+		.rates		= _rates,			\
+		.nr_rates	= ARRAY_SIZE(_rates),		\
+		.name		= _name,			\
+		.parent		= _pname,			\
+	}
+
+#define PLL_FIXED(_id, _name, _pname, _type, _reg)		\
+	{							\
+		.id		= _id,				\
+		.reg_base	= _reg,				\
+		.type		= _type,			\
+		.rates		= NULL,				\
+		.nr_rates	= 0,				\
+		.name		= _name,			\
+		.parent		= _pname,			\
+	}
+
 struct pistachio_clk_provider {
 	struct device_node *node;
 	void __iomem *base;
@@ -117,6 +164,9 @@ extern void
 pistachio_clk_register_fixed_factor(struct pistachio_clk_provider *p,
 				    struct pistachio_fixed_factor *ff,
 				    unsigned int num);
+extern void pistachio_clk_register_pll(struct pistachio_clk_provider *p,
+				       struct pistachio_pll *pll,
+				       unsigned int num);
 
 extern void pistachio_clk_force_enable(struct pistachio_clk_provider *p,
 				       unsigned int *clk_ids, unsigned int num);
-- 
2.2.0.rc0.207.ga3a616c


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

* [PATCH 4/7] clk: pistachio: Register core clocks
  2015-02-25  3:56 [PATCH 0/7] clk: Common clock support for IMG Pistachio Andrew Bresticker
                   ` (2 preceding siblings ...)
  2015-02-25  3:56 ` [PATCH 3/7] clk: pistachio: Add PLL driver Andrew Bresticker
@ 2015-02-25  3:56 ` Andrew Bresticker
  2015-02-25  3:56 ` [PATCH 5/7] clk: pistachio: Register peripheral clocks Andrew Bresticker
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Andrew Bresticker @ 2015-02-25  3:56 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, Ralf Baechle
  Cc: devicetree, linux-mips, linux-kernel, Andrew Bresticker,
	Ezequiel Garcia, James Hartley, James Hogan, Damien Horsley

Register the clocks generated by the core clock controller.
This includes the 7 PLLs and clocks for the CPU, RPU co-processor,
audio, WiFi, bluetooth, and several other peripherals.

The MIPS and PERIPH_SYS clocks must remain enabled at all times.

Signed-off-by: Damien Horsley <Damien.Horsley@imgtec.com>
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/clk/pistachio/Makefile        |   1 +
 drivers/clk/pistachio/clk-pistachio.c | 199 ++++++++++++++++++++++++++++++++++
 2 files changed, 200 insertions(+)
 create mode 100644 drivers/clk/pistachio/clk-pistachio.c

diff --git a/drivers/clk/pistachio/Makefile b/drivers/clk/pistachio/Makefile
index a93490d..f1e151f 100644
--- a/drivers/clk/pistachio/Makefile
+++ b/drivers/clk/pistachio/Makefile
@@ -1,2 +1,3 @@
 obj-y	+= clk.o
 obj-y	+= clk-pll.o
+obj-y	+= clk-pistachio.o
diff --git a/drivers/clk/pistachio/clk-pistachio.c b/drivers/clk/pistachio/clk-pistachio.c
new file mode 100644
index 0000000..12a45e2
--- /dev/null
+++ b/drivers/clk/pistachio/clk-pistachio.c
@@ -0,0 +1,199 @@
+/*
+ * Pistachio SoC clock controllers
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include <dt-bindings/clock/pistachio-clk.h>
+
+#include "clk.h"
+
+static struct pistachio_gate pistachio_gates[] __initdata = {
+	GATE(CLK_MIPS, "mips", "mips_div", 0x104, 0),
+	GATE(CLK_AUDIO_IN, "audio_in", "audio_clk_in_gate", 0x104, 1),
+	GATE(CLK_AUDIO, "audio", "audio_div", 0x104, 2),
+	GATE(CLK_I2S, "i2s", "i2s_div", 0x104, 3),
+	GATE(CLK_SPDIF, "spdif", "spdif_div", 0x104, 4),
+	GATE(CLK_AUDIO_DAC, "audio_dac", "audio_dac_div", 0x104, 5),
+	GATE(CLK_RPU_V, "rpu_v", "rpu_v_div", 0x104, 6),
+	GATE(CLK_RPU_L, "rpu_l", "rpu_l_div", 0x104, 7),
+	GATE(CLK_RPU_SLEEP, "rpu_sleep", "rpu_sleep_div", 0x104, 8),
+	GATE(CLK_WIFI_PLL_GATE, "wifi_pll_gate", "wifi_pll_mux", 0x104, 9),
+	GATE(CLK_RPU_CORE, "rpu_core", "rpu_core_div", 0x104, 10),
+	GATE(CLK_WIFI_ADC, "wifi_adc", "wifi_div8_mux", 0x104, 11),
+	GATE(CLK_WIFI_DAC, "wifi_dac", "wifi_div4_mux", 0x104, 12),
+	GATE(CLK_USB_PHY, "usb_phy", "usb_phy_div", 0x104, 13),
+	GATE(CLK_ENET_IN, "enet_in", "enet_clk_in_gate", 0x104, 14),
+	GATE(CLK_ENET, "enet", "enet_div", 0x104, 15),
+	GATE(CLK_UART0, "uart0", "uart0_div", 0x104, 16),
+	GATE(CLK_UART1, "uart1", "uart1_div", 0x104, 17),
+	GATE(CLK_PERIPH_SYS, "periph_sys", "sys_internal_div", 0x104, 18),
+	GATE(CLK_SPI0, "spi0", "spi0_div", 0x104, 19),
+	GATE(CLK_SPI1, "spi1", "spi1_div", 0x104, 20),
+	GATE(CLK_EVENT_TIMER, "event_timer", "event_timer_div", 0x104, 21),
+	GATE(CLK_AUX_ADC_INTERNAL, "aux_adc_internal", "sys_internal_div",
+	     0x104, 22),
+	GATE(CLK_AUX_ADC, "aux_adc", "aux_adc_div", 0x104, 23),
+	GATE(CLK_SD_HOST, "sd_host", "sd_host_div", 0x104, 24),
+	GATE(CLK_BT, "bt", "bt_div", 0x104, 25),
+	GATE(CLK_BT_DIV4, "bt_div4", "bt_div4_div", 0x104, 26),
+	GATE(CLK_BT_DIV8, "bt_div8", "bt_div8_div", 0x104, 27),
+	GATE(CLK_BT_1MHZ, "bt_1mhz", "bt_1mhz_div", 0x104, 28),
+};
+
+static struct pistachio_fixed_factor pistachio_ffs[] __initdata = {
+	FIXED_FACTOR(CLK_WIFI_DIV4, "wifi_div4", "wifi_pll", 4),
+	FIXED_FACTOR(CLK_WIFI_DIV8, "wifi_div8", "wifi_pll", 8),
+};
+
+static struct pistachio_div pistachio_divs[] __initdata = {
+	DIV(CLK_MIPS_INTERNAL_DIV, "mips_internal_div", "mips_pll_mux",
+	    0x204, 2),
+	DIV(CLK_MIPS_DIV, "mips_div", "mips_internal_div", 0x208, 8),
+	DIV_F(CLK_AUDIO_DIV, "audio_div", "audio_mux",
+		0x20c, 8, CLK_DIVIDER_ROUND_CLOSEST),
+	DIV_F(CLK_I2S_DIV, "i2s_div", "audio_pll_mux",
+		0x210, 8, CLK_DIVIDER_ROUND_CLOSEST),
+	DIV_F(CLK_SPDIF_DIV, "spdif_div", "audio_pll_mux",
+		0x214, 8, CLK_DIVIDER_ROUND_CLOSEST),
+	DIV_F(CLK_AUDIO_DAC_DIV, "audio_dac_div", "audio_pll_mux",
+		0x218, 8, CLK_DIVIDER_ROUND_CLOSEST),
+	DIV(CLK_RPU_V_DIV, "rpu_v_div", "rpu_v_pll_mux", 0x21c, 2),
+	DIV(CLK_RPU_L_DIV, "rpu_l_div", "rpu_l_mux", 0x220, 2),
+	DIV(CLK_RPU_SLEEP_DIV, "rpu_sleep_div", "xtal", 0x224, 10),
+	DIV(CLK_RPU_CORE_DIV, "rpu_core_div", "rpu_core_mux", 0x228, 3),
+	DIV(CLK_USB_PHY_DIV, "usb_phy_div", "sys_internal_div", 0x22c, 6),
+	DIV(CLK_ENET_DIV, "enet_div", "enet_mux", 0x230, 6),
+	DIV_F(CLK_UART0_INTERNAL_DIV, "uart0_internal_div", "sys_pll_mux",
+	      0x234, 3, CLK_DIVIDER_ROUND_CLOSEST),
+	DIV_F(CLK_UART0_DIV, "uart0_div", "uart0_internal_div", 0x238, 10,
+	      CLK_DIVIDER_ROUND_CLOSEST),
+	DIV_F(CLK_UART1_INTERNAL_DIV, "uart1_internal_div", "sys_pll_mux",
+	      0x23c, 3, CLK_DIVIDER_ROUND_CLOSEST),
+	DIV_F(CLK_UART1_DIV, "uart1_div", "uart1_internal_div", 0x240, 10,
+	      CLK_DIVIDER_ROUND_CLOSEST),
+	DIV(CLK_SYS_INTERNAL_DIV, "sys_internal_div", "sys_pll_mux", 0x244, 3),
+	DIV(CLK_SPI0_INTERNAL_DIV, "spi0_internal_div", "sys_pll_mux",
+	    0x248, 3),
+	DIV(CLK_SPI0_DIV, "spi0_div", "spi0_internal_div", 0x24c, 7),
+	DIV(CLK_SPI1_INTERNAL_DIV, "spi1_internal_div", "sys_pll_mux",
+	    0x250, 3),
+	DIV(CLK_SPI1_DIV, "spi1_div", "spi1_internal_div", 0x254, 7),
+	DIV(CLK_EVENT_TIMER_INTERNAL_DIV, "event_timer_internal_div",
+	    "event_timer_mux", 0x258, 3),
+	DIV(CLK_EVENT_TIMER_DIV, "event_timer_div", "event_timer_internal_div",
+	    0x25c, 12),
+	DIV(CLK_AUX_ADC_INTERNAL_DIV, "aux_adc_internal_div",
+	    "aux_adc_internal", 0x260, 3),
+	DIV(CLK_AUX_ADC_DIV, "aux_adc_div", "aux_adc_internal_div", 0x264, 10),
+	DIV(CLK_SD_HOST_DIV, "sd_host_div", "sd_host_mux", 0x268, 6),
+	DIV(CLK_BT_DIV, "bt_div", "bt_pll_mux", 0x26c, 6),
+	DIV(CLK_BT_DIV4_DIV, "bt_div4_div", "bt_pll_mux", 0x270, 6),
+	DIV(CLK_BT_DIV8_DIV, "bt_div8_div", "bt_pll_mux", 0x274, 6),
+	DIV(CLK_BT_1MHZ_INTERNAL_DIV, "bt_1mhz_internal_div", "bt_pll_mux",
+	    0x278, 3),
+	DIV(CLK_BT_1MHZ_DIV, "bt_1mhz_div", "bt_1mhz_internal_div", 0x27c, 10),
+};
+
+PNAME(mux_xtal_audio_refclk) = { "xtal", "audio_clk_in_gate" };
+PNAME(mux_xtal_mips) = { "xtal", "mips_pll" };
+PNAME(mux_xtal_audio) = { "xtal", "audio_pll", "audio_in" };
+PNAME(mux_audio_debug) = { "audio_pll_mux", "debug_mux" };
+PNAME(mux_xtal_rpu_v) = { "xtal", "rpu_v_pll" };
+PNAME(mux_xtal_rpu_l) = { "xtal", "rpu_l_pll" };
+PNAME(mux_rpu_l_mips) = { "rpu_l_pll_mux", "mips_pll_mux" };
+PNAME(mux_xtal_wifi) = { "xtal", "wifi_pll" };
+PNAME(mux_xtal_wifi_div4) = { "xtal", "wifi_div4" };
+PNAME(mux_xtal_wifi_div8) = { "xtal", "wifi_div8" };
+PNAME(mux_wifi_div4_rpu_l) = { "wifi_pll_gate", "wifi_div4_mux",
+			       "rpu_l_pll_mux" };
+PNAME(mux_xtal_sys) = { "xtal", "sys_pll" };
+PNAME(mux_sys_enet) = { "sys_internal_div", "enet_in" };
+PNAME(mux_audio_sys) = { "audio_pll_mux", "sys_internal_div" };
+PNAME(mux_sys_bt) = { "sys_internal_div", "bt_pll_mux" };
+PNAME(mux_xtal_bt) = { "xtal", "bt_pll" };
+
+static struct pistachio_mux pistachio_muxes[] __initdata = {
+	MUX(CLK_AUDIO_REF_MUX, "audio_refclk_mux", mux_xtal_audio_refclk,
+	    0x200, 0),
+	MUX(CLK_MIPS_PLL_MUX, "mips_pll_mux", mux_xtal_mips, 0x200, 1),
+	MUX(CLK_AUDIO_PLL_MUX, "audio_pll_mux", mux_xtal_audio, 0x200, 2),
+	MUX(CLK_AUDIO_MUX, "audio_mux", mux_audio_debug, 0x200, 4),
+	MUX(CLK_RPU_V_PLL_MUX, "rpu_v_pll_mux", mux_xtal_rpu_v, 0x200, 5),
+	MUX(CLK_RPU_L_PLL_MUX, "rpu_l_pll_mux", mux_xtal_rpu_l, 0x200, 6),
+	MUX(CLK_RPU_L_MUX, "rpu_l_mux", mux_rpu_l_mips, 0x200, 7),
+	MUX(CLK_WIFI_PLL_MUX, "wifi_pll_mux", mux_xtal_wifi, 0x200, 8),
+	MUX(CLK_WIFI_DIV4_MUX, "wifi_div4_mux", mux_xtal_wifi_div4, 0x200, 9),
+	MUX(CLK_WIFI_DIV8_MUX, "wifi_div8_mux", mux_xtal_wifi_div8, 0x200, 10),
+	MUX(CLK_RPU_CORE_MUX, "rpu_core_mux", mux_wifi_div4_rpu_l, 0x200, 11),
+	MUX(CLK_SYS_PLL_MUX, "sys_pll_mux", mux_xtal_sys, 0x200, 13),
+	MUX(CLK_ENET_MUX, "enet_mux", mux_sys_enet, 0x200, 14),
+	MUX(CLK_EVENT_TIMER_MUX, "event_timer_mux", mux_audio_sys, 0x200, 15),
+	MUX(CLK_SD_HOST_MUX, "sd_host_mux", mux_sys_bt, 0x200, 16),
+	MUX(CLK_BT_PLL_MUX, "bt_pll_mux", mux_xtal_bt, 0x200, 17),
+};
+
+static struct pistachio_pll pistachio_plls[] __initdata = {
+	PLL_FIXED(CLK_MIPS_PLL, "mips_pll", "xtal", PLL_GF40LP_LAINT, 0x0),
+	PLL_FIXED(CLK_AUDIO_PLL, "audio_pll", "audio_refclk_mux",
+		  PLL_GF40LP_FRAC, 0xc),
+	PLL_FIXED(CLK_RPU_V_PLL, "rpu_v_pll", "xtal", PLL_GF40LP_LAINT, 0x20),
+	PLL_FIXED(CLK_RPU_L_PLL, "rpu_l_pll", "xtal", PLL_GF40LP_LAINT, 0x2c),
+	PLL_FIXED(CLK_SYS_PLL, "sys_pll", "xtal", PLL_GF40LP_FRAC, 0x38),
+	PLL_FIXED(CLK_WIFI_PLL, "wifi_pll", "xtal", PLL_GF40LP_FRAC, 0x4c),
+	PLL_FIXED(CLK_BT_PLL, "bt_pll", "xtal", PLL_GF40LP_LAINT, 0x60),
+};
+
+PNAME(mux_debug) = { "mips_pll_mux", "rpu_v_pll_mux",
+		     "rpu_l_pll_mux", "sys_pll_mux",
+		     "wifi_pll_mux", "bt_pll_mux" };
+static u32 mux_debug_idx[] = { 0x0, 0x1, 0x2, 0x4, 0x8, 0x10 };
+
+static unsigned int pistachio_critical_clks[] __initdata = {
+	CLK_MIPS,
+	CLK_PERIPH_SYS,
+};
+
+static void __init pistachio_clk_init(struct device_node *np)
+{
+	struct pistachio_clk_provider *p;
+	struct clk *debug_clk;
+
+	p = pistachio_clk_alloc_provider(np, CLK_NR_CLKS);
+	if (!p)
+		return;
+
+	pistachio_clk_register_pll(p, pistachio_plls,
+				   ARRAY_SIZE(pistachio_plls));
+	pistachio_clk_register_mux(p, pistachio_muxes,
+				   ARRAY_SIZE(pistachio_muxes));
+	pistachio_clk_register_div(p, pistachio_divs,
+				   ARRAY_SIZE(pistachio_divs));
+	pistachio_clk_register_fixed_factor(p, pistachio_ffs,
+					    ARRAY_SIZE(pistachio_ffs));
+	pistachio_clk_register_gate(p, pistachio_gates,
+				    ARRAY_SIZE(pistachio_gates));
+
+	debug_clk = clk_register_mux_table(NULL, "debug_mux", mux_debug,
+					   ARRAY_SIZE(mux_debug),
+					   CLK_SET_RATE_NO_REPARENT,
+					   p->base + 0x200, 18, 0x1f, 0,
+					   mux_debug_idx, NULL);
+	p->clk_data.clks[CLK_DEBUG_MUX] = debug_clk;
+
+	pistachio_clk_register_provider(p);
+
+	pistachio_clk_force_enable(p, pistachio_critical_clks,
+				   ARRAY_SIZE(pistachio_critical_clks));
+}
+CLK_OF_DECLARE(pistachio_clk, "img,pistachio-clk", pistachio_clk_init);
-- 
2.2.0.rc0.207.ga3a616c


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

* [PATCH 5/7] clk: pistachio: Register peripheral clocks
  2015-02-25  3:56 [PATCH 0/7] clk: Common clock support for IMG Pistachio Andrew Bresticker
                   ` (3 preceding siblings ...)
  2015-02-25  3:56 ` [PATCH 4/7] clk: pistachio: Register core clocks Andrew Bresticker
@ 2015-02-25  3:56 ` Andrew Bresticker
  2015-02-25  3:56 ` [PATCH 6/7] clk: pistachio: Register system interface gate clocks Andrew Bresticker
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Andrew Bresticker @ 2015-02-25  3:56 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, Ralf Baechle
  Cc: devicetree, linux-mips, linux-kernel, Andrew Bresticker,
	Ezequiel Garcia, James Hartley, James Hogan, Damien Horsley

Register the clocks generated by the peripheral clock controller.
This includes the clocks for several peripherals, including I2C,
PWM, watchdog, and timer.

Signed-off-by: Damien Horsley <Damien.Horsley@imgtec.com>
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/clk/pistachio/clk-pistachio.c | 67 +++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/drivers/clk/pistachio/clk-pistachio.c b/drivers/clk/pistachio/clk-pistachio.c
index 12a45e2..0eabb54 100644
--- a/drivers/clk/pistachio/clk-pistachio.c
+++ b/drivers/clk/pistachio/clk-pistachio.c
@@ -197,3 +197,70 @@ static void __init pistachio_clk_init(struct device_node *np)
 				   ARRAY_SIZE(pistachio_critical_clks));
 }
 CLK_OF_DECLARE(pistachio_clk, "img,pistachio-clk", pistachio_clk_init);
+
+static struct pistachio_gate pistachio_periph_gates[] __initdata = {
+	GATE(PERIPH_CLK_SYS, "sys", "periph_sys", 0x100, 0),
+	GATE(PERIPH_CLK_SYS_BUS, "bus_sys", "periph_sys", 0x100, 1),
+	GATE(PERIPH_CLK_DDR, "ddr", "periph_sys", 0x100, 2),
+	GATE(PERIPH_CLK_ROM, "rom", "rom_div", 0x100, 3),
+	GATE(PERIPH_CLK_COUNTER_FAST, "counter_fast", "counter_fast_div",
+	     0x100, 4),
+	GATE(PERIPH_CLK_COUNTER_SLOW, "counter_slow", "counter_slow_div",
+	     0x100, 5),
+	GATE(PERIPH_CLK_IR, "ir", "ir_div", 0x100, 6),
+	GATE(PERIPH_CLK_WD, "wd", "wd_div", 0x100, 7),
+	GATE(PERIPH_CLK_PDM, "pdm", "pdm_div", 0x100, 8),
+	GATE(PERIPH_CLK_PWM, "pwm", "pwm_div", 0x100, 9),
+	GATE(PERIPH_CLK_I2C0, "i2c0", "i2c0_div", 0x100, 10),
+	GATE(PERIPH_CLK_I2C1, "i2c1", "i2c1_div", 0x100, 11),
+	GATE(PERIPH_CLK_I2C2, "i2c2", "i2c2_div", 0x100, 12),
+	GATE(PERIPH_CLK_I2C3, "i2c3", "i2c3_div", 0x100, 13),
+};
+
+static struct pistachio_div pistachio_periph_divs[] __initdata = {
+	DIV(PERIPH_CLK_ROM_DIV, "rom_div", "periph_sys", 0x10c, 7),
+	DIV(PERIPH_CLK_COUNTER_FAST_DIV, "counter_fast_div", "periph_sys",
+	    0x110, 7),
+	DIV(PERIPH_CLK_COUNTER_SLOW_PRE_DIV, "counter_slow_pre_div",
+	    "periph_sys", 0x114, 7),
+	DIV(PERIPH_CLK_COUNTER_SLOW_DIV, "counter_slow_div",
+	    "counter_slow_pre_div", 0x118, 7),
+	DIV_F(PERIPH_CLK_IR_PRE_DIV, "ir_pre_div", "periph_sys", 0x11c, 7,
+	      CLK_DIVIDER_ROUND_CLOSEST),
+	DIV_F(PERIPH_CLK_IR_DIV, "ir_div", "ir_pre_div", 0x120, 7,
+	      CLK_DIVIDER_ROUND_CLOSEST),
+	DIV_F(PERIPH_CLK_WD_PRE_DIV, "wd_pre_div", "periph_sys", 0x124, 7,
+	      CLK_DIVIDER_ROUND_CLOSEST),
+	DIV_F(PERIPH_CLK_WD_DIV, "wd_div", "wd_pre_div", 0x128, 7,
+	      CLK_DIVIDER_ROUND_CLOSEST),
+	DIV(PERIPH_CLK_PDM_PRE_DIV, "pdm_pre_div", "periph_sys", 0x12c, 7),
+	DIV(PERIPH_CLK_PDM_DIV, "pdm_div", "pdm_pre_div", 0x130, 7),
+	DIV(PERIPH_CLK_PWM_PRE_DIV, "pwm_pre_div", "periph_sys", 0x134, 7),
+	DIV(PERIPH_CLK_PWM_DIV, "pwm_div", "pwm_pre_div", 0x138, 7),
+	DIV(PERIPH_CLK_I2C0_PRE_DIV, "i2c0_pre_div", "periph_sys", 0x13c, 7),
+	DIV(PERIPH_CLK_I2C0_DIV, "i2c0_div", "i2c0_pre_div", 0x140, 7),
+	DIV(PERIPH_CLK_I2C1_PRE_DIV, "i2c1_pre_div", "periph_sys", 0x144, 7),
+	DIV(PERIPH_CLK_I2C1_DIV, "i2c1_div", "i2c1_pre_div", 0x148, 7),
+	DIV(PERIPH_CLK_I2C2_PRE_DIV, "i2c2_pre_div", "periph_sys", 0x14c, 7),
+	DIV(PERIPH_CLK_I2C2_DIV, "i2c2_div", "i2c2_pre_div", 0x150, 7),
+	DIV(PERIPH_CLK_I2C3_PRE_DIV, "i2c3_pre_div", "periph_sys", 0x154, 7),
+	DIV(PERIPH_CLK_I2C3_DIV, "i2c3_div", "i2c3_pre_div", 0x158, 7),
+};
+
+static void __init pistachio_clk_periph_init(struct device_node *np)
+{
+	struct pistachio_clk_provider *p;
+
+	p = pistachio_clk_alloc_provider(np, PERIPH_CLK_NR_CLKS);
+	if (!p)
+		return;
+
+	pistachio_clk_register_div(p, pistachio_periph_divs,
+				   ARRAY_SIZE(pistachio_periph_divs));
+	pistachio_clk_register_gate(p, pistachio_periph_gates,
+				    ARRAY_SIZE(pistachio_periph_gates));
+
+	pistachio_clk_register_provider(p);
+}
+CLK_OF_DECLARE(pistachio_clk_periph, "img,pistachio-clk-periph",
+	       pistachio_clk_periph_init);
-- 
2.2.0.rc0.207.ga3a616c


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

* [PATCH 6/7] clk: pistachio: Register system interface gate clocks
  2015-02-25  3:56 [PATCH 0/7] clk: Common clock support for IMG Pistachio Andrew Bresticker
                   ` (4 preceding siblings ...)
  2015-02-25  3:56 ` [PATCH 5/7] clk: pistachio: Register peripheral clocks Andrew Bresticker
@ 2015-02-25  3:56 ` Andrew Bresticker
  2015-02-25  3:56 ` [PATCH 7/7] clk: pistachio: Register external clock gates Andrew Bresticker
  2015-03-31  0:01 ` [PATCH 0/7] clk: Common clock support for IMG Pistachio Stephen Boyd
  7 siblings, 0 replies; 15+ messages in thread
From: Andrew Bresticker @ 2015-02-25  3:56 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, Ralf Baechle
  Cc: devicetree, linux-mips, linux-kernel, Andrew Bresticker,
	Ezequiel Garcia, James Hartley, James Hogan, Damien Horsley

Register the system interface gate clocks provided by the peripheral
general control block.  These clocks gate register access for various
peripherals.

Signed-off-by: Damien Horsley <Damien.Horsley@imgtec.com>
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/clk/pistachio/clk-pistachio.c | 42 +++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/drivers/clk/pistachio/clk-pistachio.c b/drivers/clk/pistachio/clk-pistachio.c
index 0eabb54..3351808 100644
--- a/drivers/clk/pistachio/clk-pistachio.c
+++ b/drivers/clk/pistachio/clk-pistachio.c
@@ -264,3 +264,45 @@ static void __init pistachio_clk_periph_init(struct device_node *np)
 }
 CLK_OF_DECLARE(pistachio_clk_periph, "img,pistachio-clk-periph",
 	       pistachio_clk_periph_init);
+
+static struct pistachio_gate pistachio_sys_gates[] __initdata = {
+	GATE(SYS_CLK_I2C0, "i2c0_sys", "sys", 0x8, 0),
+	GATE(SYS_CLK_I2C1, "i2c1_sys", "sys", 0x8, 1),
+	GATE(SYS_CLK_I2C2, "i2c2_sys", "sys", 0x8, 2),
+	GATE(SYS_CLK_I2C3, "i2c3_sys", "sys", 0x8, 3),
+	GATE(SYS_CLK_I2S_IN, "i2s_in_sys", "sys", 0x8, 4),
+	GATE(SYS_CLK_PAUD_OUT, "paud_out_sys", "sys", 0x8, 5),
+	GATE(SYS_CLK_SPDIF_OUT, "spdif_out_sys", "sys", 0x8, 6),
+	GATE(SYS_CLK_SPI0_MASTER, "spi0_master_sys", "sys", 0x8, 7),
+	GATE(SYS_CLK_SPI0_SLAVE, "spi0_slave_sys", "sys", 0x8, 8),
+	GATE(SYS_CLK_PWM, "pwm_sys", "sys", 0x8, 9),
+	GATE(SYS_CLK_UART0, "uart0_sys", "sys", 0x8, 10),
+	GATE(SYS_CLK_UART1, "uart1_sys", "sys", 0x8, 11),
+	GATE(SYS_CLK_SPI1, "spi1_sys", "sys", 0x8, 12),
+	GATE(SYS_CLK_MDC, "mdc_sys", "sys", 0x8, 13),
+	GATE(SYS_CLK_SD_HOST, "sd_host_sys", "sys", 0x8, 14),
+	GATE(SYS_CLK_ENET, "enet_sys", "sys", 0x8, 15),
+	GATE(SYS_CLK_IR, "ir_sys", "sys", 0x8, 16),
+	GATE(SYS_CLK_WD, "wd_sys", "sys", 0x8, 17),
+	GATE(SYS_CLK_TIMER, "timer_sys", "sys", 0x8, 18),
+	GATE(SYS_CLK_I2S_OUT, "i2s_out_sys", "sys", 0x8, 24),
+	GATE(SYS_CLK_SPDIF_IN, "spdif_in_sys", "sys", 0x8, 25),
+	GATE(SYS_CLK_EVENT_TIMER, "event_timer_sys", "sys", 0x8, 26),
+	GATE(SYS_CLK_HASH, "hash_sys", "sys", 0x8, 27),
+};
+
+static void __init pistachio_cr_periph_init(struct device_node *np)
+{
+	struct pistachio_clk_provider *p;
+
+	p = pistachio_clk_alloc_provider(np, SYS_CLK_NR_CLKS);
+	if (!p)
+		return;
+
+	pistachio_clk_register_gate(p, pistachio_sys_gates,
+				    ARRAY_SIZE(pistachio_sys_gates));
+
+	pistachio_clk_register_provider(p);
+}
+CLK_OF_DECLARE(pistachio_cr_periph, "img,pistachio-cr-periph",
+	       pistachio_cr_periph_init);
-- 
2.2.0.rc0.207.ga3a616c


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

* [PATCH 7/7] clk: pistachio: Register external clock gates
  2015-02-25  3:56 [PATCH 0/7] clk: Common clock support for IMG Pistachio Andrew Bresticker
                   ` (5 preceding siblings ...)
  2015-02-25  3:56 ` [PATCH 6/7] clk: pistachio: Register system interface gate clocks Andrew Bresticker
@ 2015-02-25  3:56 ` Andrew Bresticker
  2015-03-31  0:01 ` [PATCH 0/7] clk: Common clock support for IMG Pistachio Stephen Boyd
  7 siblings, 0 replies; 15+ messages in thread
From: Andrew Bresticker @ 2015-02-25  3:56 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, Ralf Baechle
  Cc: devicetree, linux-mips, linux-kernel, Andrew Bresticker,
	Ezequiel Garcia, James Hartley, James Hogan, Damien Horsley

Register the clock gates for the external audio and ethernet
reference clocks provided by the top-level general control block.

Signed-off-by: Damien Horsley <Damien.Horsley@imgtec.com>
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/clk/pistachio/clk-pistachio.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/clk/pistachio/clk-pistachio.c b/drivers/clk/pistachio/clk-pistachio.c
index 3351808..8c0fe88 100644
--- a/drivers/clk/pistachio/clk-pistachio.c
+++ b/drivers/clk/pistachio/clk-pistachio.c
@@ -306,3 +306,24 @@ static void __init pistachio_cr_periph_init(struct device_node *np)
 }
 CLK_OF_DECLARE(pistachio_cr_periph, "img,pistachio-cr-periph",
 	       pistachio_cr_periph_init);
+
+static struct pistachio_gate pistachio_ext_gates[] __initdata = {
+	GATE(EXT_CLK_ENET_IN, "enet_clk_in_gate", "enet_clk_in", 0x58, 5),
+	GATE(EXT_CLK_AUDIO_IN, "audio_clk_in_gate", "audio_clk_in", 0x58, 8)
+};
+
+static void __init pistachio_cr_top_init(struct device_node *np)
+{
+	struct pistachio_clk_provider *p;
+
+	p = pistachio_clk_alloc_provider(np, EXT_CLK_NR_CLKS);
+	if (!p)
+		return;
+
+	pistachio_clk_register_gate(p, pistachio_ext_gates,
+				    ARRAY_SIZE(pistachio_ext_gates));
+
+	pistachio_clk_register_provider(p);
+}
+CLK_OF_DECLARE(pistachio_cr_top, "img,pistachio-cr-top",
+	       pistachio_cr_top_init);
-- 
2.2.0.rc0.207.ga3a616c


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

* Re: [PATCH 2/7] clk: Add basic infrastructure for Pistachio clocks
  2015-02-25  3:56 ` [PATCH 2/7] clk: Add basic infrastructure for Pistachio clocks Andrew Bresticker
@ 2015-03-30 23:59   ` Stephen Boyd
  2015-03-31  0:15     ` Andrew Bresticker
  0 siblings, 1 reply; 15+ messages in thread
From: Stephen Boyd @ 2015-03-30 23:59 UTC (permalink / raw)
  To: Andrew Bresticker, Mike Turquette, Ralf Baechle
  Cc: devicetree, linux-mips, linux-kernel, Ezequiel Garcia,
	James Hartley, James Hogan

On 02/24/15 19:56, Andrew Bresticker wrote:
> +
> +void pistachio_clk_force_enable(struct pistachio_clk_provider *p,
> +				unsigned int *clk_ids, unsigned int num)
> +{
> +	unsigned int i;
> +	int err;
> +
> +	for (i = 0; i < num; i++) {
> +		struct clk *clk = p->clk_data.clks[clk_ids[i]];
> +
> +		if (IS_ERR(clk))
> +			continue;
> +
> +		err = clk_prepare_enable(clk);
> +		if (err)
> +			pr_err("Failed to enable clock %s: %d\n",
> +			       __clk_get_name(clk), err);
> +	}
> +}
>

Is this to workaround some problems in the framework where clocks are
turned off? Or is it that these clocks are already on before we boot
Linux and we need to make sure the framework knows that?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH 0/7] clk: Common clock support for IMG Pistachio
  2015-02-25  3:56 [PATCH 0/7] clk: Common clock support for IMG Pistachio Andrew Bresticker
                   ` (6 preceding siblings ...)
  2015-02-25  3:56 ` [PATCH 7/7] clk: pistachio: Register external clock gates Andrew Bresticker
@ 2015-03-31  0:01 ` Stephen Boyd
  7 siblings, 0 replies; 15+ messages in thread
From: Stephen Boyd @ 2015-03-31  0:01 UTC (permalink / raw)
  To: Andrew Bresticker, Mike Turquette, Ralf Baechle
  Cc: devicetree, linux-mips, linux-kernel, Ezequiel Garcia,
	James Hartley, James Hogan

On 02/24/15 19:56, Andrew Bresticker wrote:
> This series adds common clock support for the IMG Pistachio SoC.
> Pistachio has two clock controllers (core and peripheral) and two
> general control blocks (peripheral and top) which also contain
> several clock gates.  Like the recently submitted pinctrl driver [1],
> this driver is written so that it's hopefully easy to add support
> for future IMG SoCs.
>
> Tested on an IMG Pistachio BuB.  Based on 4.0-rc1 + my series adding
> Pistachio platform support [2], which introduces the MACH_PISTACHIO
> Kconfig symbol.  A branch with this series and the dependent patches
> is available at [3].  I'd like this to go through the MIPS tree with
> Mike's or Stephen's ACK if possible.
>
>

Minor comment on patch 2, but otherwise

Acked-by: Stephen Boyd <sboyd@codeaurora.org>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH 2/7] clk: Add basic infrastructure for Pistachio clocks
  2015-03-30 23:59   ` Stephen Boyd
@ 2015-03-31  0:15     ` Andrew Bresticker
  2015-03-31  1:21       ` Stephen Boyd
  2015-03-31  1:36       ` Michael Turquette
  0 siblings, 2 replies; 15+ messages in thread
From: Andrew Bresticker @ 2015-03-31  0:15 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Mike Turquette, Ralf Baechle, devicetree, Linux-MIPS,
	linux-kernel, Ezequiel Garcia, James Hartley, James Hogan

On Mon, Mar 30, 2015 at 4:59 PM, Stephen Boyd <sboyd@codeaurora.org> wrote:
> On 02/24/15 19:56, Andrew Bresticker wrote:
>> +
>> +void pistachio_clk_force_enable(struct pistachio_clk_provider *p,
>> +                             unsigned int *clk_ids, unsigned int num)
>> +{
>> +     unsigned int i;
>> +     int err;
>> +
>> +     for (i = 0; i < num; i++) {
>> +             struct clk *clk = p->clk_data.clks[clk_ids[i]];
>> +
>> +             if (IS_ERR(clk))
>> +                     continue;
>> +
>> +             err = clk_prepare_enable(clk);
>> +             if (err)
>> +                     pr_err("Failed to enable clock %s: %d\n",
>> +                            __clk_get_name(clk), err);
>> +     }
>> +}
>>
>
> Is this to workaround some problems in the framework where clocks are
> turned off? Or is it that these clocks are already on before we boot
> Linux and we need to make sure the framework knows that?

It's the former.  These clocks are enabled at POR and may only be
gated as the final step to entering suspend, so they must remain on at
runtime.  The issue we were running into was that consumers of these
critical clocks or their descendants would enable/disable their clocks
during boot or runtime PM and cause these clocks to get disabled.
Bumping up the prepare/enable count of these critical clocks seemed
like the best way to handle this - is there a more preferred way?
FWIW, this is also how the Tegra and Rockchip drivers handled this
problem.

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

* Re: [PATCH 2/7] clk: Add basic infrastructure for Pistachio clocks
  2015-03-31  0:15     ` Andrew Bresticker
@ 2015-03-31  1:21       ` Stephen Boyd
  2015-03-31  1:36         ` Andrew Bresticker
  2015-03-31  1:36       ` Michael Turquette
  1 sibling, 1 reply; 15+ messages in thread
From: Stephen Boyd @ 2015-03-31  1:21 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: Mike Turquette, Ralf Baechle, devicetree, Linux-MIPS,
	linux-kernel, Ezequiel Garcia, James Hartley, James Hogan

On 03/30/15 17:15, Andrew Bresticker wrote:
> On Mon, Mar 30, 2015 at 4:59 PM, Stephen Boyd <sboyd@codeaurora.org> wrote:
>> On 02/24/15 19:56, Andrew Bresticker wrote:
>>> +
>>> +void pistachio_clk_force_enable(struct pistachio_clk_provider *p,
>>> +                             unsigned int *clk_ids, unsigned int num)
>>> +{
>>> +     unsigned int i;
>>> +     int err;
>>> +
>>> +     for (i = 0; i < num; i++) {
>>> +             struct clk *clk = p->clk_data.clks[clk_ids[i]];
>>> +
>>> +             if (IS_ERR(clk))
>>> +                     continue;
>>> +
>>> +             err = clk_prepare_enable(clk);
>>> +             if (err)
>>> +                     pr_err("Failed to enable clock %s: %d\n",
>>> +                            __clk_get_name(clk), err);
>>> +     }
>>> +}
>>>
>> Is this to workaround some problems in the framework where clocks are
>> turned off? Or is it that these clocks are already on before we boot
>> Linux and we need to make sure the framework knows that?
> It's the former.  These clocks are enabled at POR and may only be
> gated as the final step to entering suspend, so they must remain on at
> runtime.  The issue we were running into was that consumers of these
> critical clocks or their descendants would enable/disable their clocks
> during boot or runtime PM and cause these clocks to get disabled.
> Bumping up the prepare/enable count of these critical clocks seemed
> like the best way to handle this - is there a more preferred way?
> FWIW, this is also how the Tegra and Rockchip drivers handled this
> problem.

Ideally clock providers just provide clocks and don't actually call
clock consumer APIs. I don't see where these clocks are disabled in this
series. Is it just because suspend isn't done right now so there isn't a
place to hook the disable part? I hope that it's a 1:1 relation between
the clocks that are turned on here and the clocks that are turned off
during suspend.

I have a slightly similar problem on my hardware. Consider the case
where the bootloader has left on the display and audio clocks and they
share a common parent PLL. When the kernel boots up, all it knows is
that the display clock and audio clock share a common PLL and the rate
they're running at. If the audio driver probes first, calls clk_enable()
on the audio clock (almost a no-op except for the fact that we call the
.enable op when it's already on) and then calls clk_disable() on the
audio clock when it's done we'll also turn off the shared PLL.
Unfortunately it's also being used by the display clock for the display
driver that hasn't probed yet and so the display stops working and it
may show an artifact or black screen.

Other cases are where certain clocks should never be turned off because
they're used by some non-linux entity (dram controller for example) and
we don't have a place to put the clk_prepare_enable() besides in the
clock driver itself. In these cases, it may be better to tell the
framework that a clock should always be on. I think this case is what
Lee Jones is working on here[1].

Do you fall into one of these two cases? It isn't clear to me how
suspend is special and needs to be dealt with differently. Why wouldn't
these clocks be always on?

[1] https://lkml.org/lkml/2015/2/27/548

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH 2/7] clk: Add basic infrastructure for Pistachio clocks
  2015-03-31  1:21       ` Stephen Boyd
@ 2015-03-31  1:36         ` Andrew Bresticker
  0 siblings, 0 replies; 15+ messages in thread
From: Andrew Bresticker @ 2015-03-31  1:36 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Mike Turquette, Ralf Baechle, devicetree, Linux-MIPS,
	linux-kernel, Ezequiel Garcia, James Hartley, James Hogan

On Mon, Mar 30, 2015 at 6:21 PM, Stephen Boyd <sboyd@codeaurora.org> wrote:
> On 03/30/15 17:15, Andrew Bresticker wrote:
>> On Mon, Mar 30, 2015 at 4:59 PM, Stephen Boyd <sboyd@codeaurora.org> wrote:
>>> On 02/24/15 19:56, Andrew Bresticker wrote:
>>>> +
>>>> +void pistachio_clk_force_enable(struct pistachio_clk_provider *p,
>>>> +                             unsigned int *clk_ids, unsigned int num)
>>>> +{
>>>> +     unsigned int i;
>>>> +     int err;
>>>> +
>>>> +     for (i = 0; i < num; i++) {
>>>> +             struct clk *clk = p->clk_data.clks[clk_ids[i]];
>>>> +
>>>> +             if (IS_ERR(clk))
>>>> +                     continue;
>>>> +
>>>> +             err = clk_prepare_enable(clk);
>>>> +             if (err)
>>>> +                     pr_err("Failed to enable clock %s: %d\n",
>>>> +                            __clk_get_name(clk), err);
>>>> +     }
>>>> +}
>>>>
>>> Is this to workaround some problems in the framework where clocks are
>>> turned off? Or is it that these clocks are already on before we boot
>>> Linux and we need to make sure the framework knows that?
>> It's the former.  These clocks are enabled at POR and may only be
>> gated as the final step to entering suspend, so they must remain on at
>> runtime.  The issue we were running into was that consumers of these
>> critical clocks or their descendants would enable/disable their clocks
>> during boot or runtime PM and cause these clocks to get disabled.
>> Bumping up the prepare/enable count of these critical clocks seemed
>> like the best way to handle this - is there a more preferred way?
>> FWIW, this is also how the Tegra and Rockchip drivers handled this
>> problem.
>
> Ideally clock providers just provide clocks and don't actually call
> clock consumer APIs. I don't see where these clocks are disabled in this
> series. Is it just because suspend isn't done right now so there isn't a
> place to hook the disable part? I hope that it's a 1:1 relation between
> the clocks that are turned on here and the clocks that are turned off
> during suspend.

Suspend hasn't been hooked up yet and it's still a long ways off.

> I have a slightly similar problem on my hardware. Consider the case
> where the bootloader has left on the display and audio clocks and they
> share a common parent PLL. When the kernel boots up, all it knows is
> that the display clock and audio clock share a common PLL and the rate
> they're running at. If the audio driver probes first, calls clk_enable()
> on the audio clock (almost a no-op except for the fact that we call the
> .enable op when it's already on) and then calls clk_disable() on the
> audio clock when it's done we'll also turn off the shared PLL.
> Unfortunately it's also being used by the display clock for the display
> driver that hasn't probed yet and so the display stops working and it
> may show an artifact or black screen.
>
> Other cases are where certain clocks should never be turned off because
> they're used by some non-linux entity (dram controller for example) and
> we don't have a place to put the clk_prepare_enable() besides in the
> clock driver itself. In these cases, it may be better to tell the
> framework that a clock should always be on. I think this case is what
> Lee Jones is working on here[1].
>
> Do you fall into one of these two cases? It isn't clear to me how
> suspend is special and needs to be dealt with differently. Why wouldn't
> these clocks be always on?

These clocks fall into the latter case in that there's really no good
place to put the clk_prepare_enable() calls, so it looks like I want
to use what Lee is proposing.

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

* Re: [PATCH 2/7] clk: Add basic infrastructure for Pistachio clocks
  2015-03-31  0:15     ` Andrew Bresticker
  2015-03-31  1:21       ` Stephen Boyd
@ 2015-03-31  1:36       ` Michael Turquette
  2015-03-31  1:49         ` Andrew Bresticker
  1 sibling, 1 reply; 15+ messages in thread
From: Michael Turquette @ 2015-03-31  1:36 UTC (permalink / raw)
  To: Andrew Bresticker, Stephen Boyd
  Cc: Ralf Baechle, devicetree, Linux-MIPS, linux-kernel,
	Ezequiel Garcia, James Hartley, James Hogan

Quoting Andrew Bresticker (2015-03-30 17:15:43)
> On Mon, Mar 30, 2015 at 4:59 PM, Stephen Boyd <sboyd@codeaurora.org> wrote:
> > On 02/24/15 19:56, Andrew Bresticker wrote:
> >> +
> >> +void pistachio_clk_force_enable(struct pistachio_clk_provider *p,
> >> +                             unsigned int *clk_ids, unsigned int num)
> >> +{
> >> +     unsigned int i;
> >> +     int err;
> >> +
> >> +     for (i = 0; i < num; i++) {
> >> +             struct clk *clk = p->clk_data.clks[clk_ids[i]];
> >> +
> >> +             if (IS_ERR(clk))
> >> +                     continue;
> >> +
> >> +             err = clk_prepare_enable(clk);
> >> +             if (err)
> >> +                     pr_err("Failed to enable clock %s: %d\n",
> >> +                            __clk_get_name(clk), err);
> >> +     }
> >> +}
> >>
> >
> > Is this to workaround some problems in the framework where clocks are
> > turned off? Or is it that these clocks are already on before we boot
> > Linux and we need to make sure the framework knows that?
> 
> It's the former.  These clocks are enabled at POR and may only be
> gated as the final step to entering suspend, so they must remain on at
> runtime.  The issue we were running into was that consumers of these
> critical clocks or their descendants would enable/disable their clocks
> during boot or runtime PM and cause these clocks to get disabled.
> Bumping up the prepare/enable count of these critical clocks seemed
> like the best way to handle this - is there a more preferred way?
> FWIW, this is also how the Tegra and Rockchip drivers handled this
> problem.

Hi Andrew,

Why are your drivers allowed to disable clocks which must not be
disabled? (you mentioned boot and runtime pm)

Is this the case that a critical clock is not directly disabled, but a
parent of that critical clock is and it is gated as a result?

Regards,
Mike

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

* Re: [PATCH 2/7] clk: Add basic infrastructure for Pistachio clocks
  2015-03-31  1:36       ` Michael Turquette
@ 2015-03-31  1:49         ` Andrew Bresticker
  0 siblings, 0 replies; 15+ messages in thread
From: Andrew Bresticker @ 2015-03-31  1:49 UTC (permalink / raw)
  To: Michael Turquette
  Cc: Stephen Boyd, Ralf Baechle, devicetree, Linux-MIPS, linux-kernel,
	Ezequiel Garcia, James Hartley, James Hogan

Hi Mike,

On Mon, Mar 30, 2015 at 6:36 PM, Michael Turquette
<mturquette@linaro.org> wrote:
> Quoting Andrew Bresticker (2015-03-30 17:15:43)
>> On Mon, Mar 30, 2015 at 4:59 PM, Stephen Boyd <sboyd@codeaurora.org> wrote:
>> > On 02/24/15 19:56, Andrew Bresticker wrote:
>> >> +
>> >> +void pistachio_clk_force_enable(struct pistachio_clk_provider *p,
>> >> +                             unsigned int *clk_ids, unsigned int num)
>> >> +{
>> >> +     unsigned int i;
>> >> +     int err;
>> >> +
>> >> +     for (i = 0; i < num; i++) {
>> >> +             struct clk *clk = p->clk_data.clks[clk_ids[i]];
>> >> +
>> >> +             if (IS_ERR(clk))
>> >> +                     continue;
>> >> +
>> >> +             err = clk_prepare_enable(clk);
>> >> +             if (err)
>> >> +                     pr_err("Failed to enable clock %s: %d\n",
>> >> +                            __clk_get_name(clk), err);
>> >> +     }
>> >> +}
>> >>
>> >
>> > Is this to workaround some problems in the framework where clocks are
>> > turned off? Or is it that these clocks are already on before we boot
>> > Linux and we need to make sure the framework knows that?
>>
>> It's the former.  These clocks are enabled at POR and may only be
>> gated as the final step to entering suspend, so they must remain on at
>> runtime.  The issue we were running into was that consumers of these
>> critical clocks or their descendants would enable/disable their clocks
>> during boot or runtime PM and cause these clocks to get disabled.
>> Bumping up the prepare/enable count of these critical clocks seemed
>> like the best way to handle this - is there a more preferred way?
>> FWIW, this is also how the Tegra and Rockchip drivers handled this
>> problem.
>
> Hi Andrew,
>
> Why are your drivers allowed to disable clocks which must not be
> disabled? (you mentioned boot and runtime pm)

The issue is that they do not directly consume a critical clock, but
rather a descendant of the critical clock and thus could cause the
critical clock to be disabled.  For example, the periph_sys clock is
one of these critical clocks and it is the parent of various
peripheral clocks, like the watchdog, I2C, PWM, etc.  If the I2C
driver enables and disables it's clock during probe(), and nothing
else has caused the periph_sys clock to be enabled, the disable() call
will cause periph_sys to become disabled since its enable count drops
to 0.

Now this could be solved if there was a driver to directly consume
these clocks and keep them enabled, but, like Stephen mentioned, there
really isn't a proper driver for that.  So it looks like I want
something like the always-on feature Lee is trying to introduce.

Thanks,
Andrew

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

end of thread, other threads:[~2015-03-31  1:49 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-25  3:56 [PATCH 0/7] clk: Common clock support for IMG Pistachio Andrew Bresticker
2015-02-25  3:56 ` [PATCH 1/7] clk: Add binding document for Pistachio clock controllers Andrew Bresticker
2015-02-25  3:56 ` [PATCH 2/7] clk: Add basic infrastructure for Pistachio clocks Andrew Bresticker
2015-03-30 23:59   ` Stephen Boyd
2015-03-31  0:15     ` Andrew Bresticker
2015-03-31  1:21       ` Stephen Boyd
2015-03-31  1:36         ` Andrew Bresticker
2015-03-31  1:36       ` Michael Turquette
2015-03-31  1:49         ` Andrew Bresticker
2015-02-25  3:56 ` [PATCH 3/7] clk: pistachio: Add PLL driver Andrew Bresticker
2015-02-25  3:56 ` [PATCH 4/7] clk: pistachio: Register core clocks Andrew Bresticker
2015-02-25  3:56 ` [PATCH 5/7] clk: pistachio: Register peripheral clocks Andrew Bresticker
2015-02-25  3:56 ` [PATCH 6/7] clk: pistachio: Register system interface gate clocks Andrew Bresticker
2015-02-25  3:56 ` [PATCH 7/7] clk: pistachio: Register external clock gates Andrew Bresticker
2015-03-31  0:01 ` [PATCH 0/7] clk: Common clock support for IMG Pistachio Stephen Boyd

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).