linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv4 1/6] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA
@ 2013-05-24 15:41 dinguyen at altera.com
  2013-05-24 15:41 ` [PATCHv4 2/6] ARM: socfpga: dts: Add gate-clock bindings dinguyen at altera.com
                   ` (4 more replies)
  0 siblings, 5 replies; 13+ messages in thread
From: dinguyen at altera.com @ 2013-05-24 15:41 UTC (permalink / raw)
  To: linux-arm-kernel

From: Dinh Nguyen <dinguyen@altera.com>

Add entry for 2nd GMAC controller. Add the correct clocks for the GMAC.

Signed-off-by: Dinh Nguyen <dinguyen@altera.com>
Reviewed-by: Pavel Machek <pavel@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Olof Johansson <olof@lixom.net>
Cc: Pavel Machek <pavel@denx.de>
CC: <linux@arm.linux.org.uk>

v2:
- Moved "disabled" status to dtsi file
---
 arch/arm/boot/dts/socfpga.dtsi         |   18 ++++++++++++++++--
 arch/arm/boot/dts/socfpga_cyclone5.dts |   13 +++++++++++++
 arch/arm/boot/dts/socfpga_vt.dts       |    5 +++++
 3 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi
index 16a6e13..02bb425 100644
--- a/arch/arm/boot/dts/socfpga.dtsi
+++ b/arch/arm/boot/dts/socfpga.dtsi
@@ -23,6 +23,7 @@
 
 	aliases {
 		ethernet0 = &gmac0;
+		ethernet1 = &gmac1;
 		serial0 = &uart0;
 		serial1 = &uart1;
 		timer0 = &timer0;
@@ -238,13 +239,26 @@
 				};
 			};
 
-		gmac0: stmmac at ff700000 {
+		gmac0: ethernet at ff700000 {
 			compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac";
 			reg = <0xff700000 0x2000>;
 			interrupts = <0 115 4>;
 			interrupt-names = "macirq";
 			mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */
-			phy-mode = "gmii";
+			clocks = <&emac0_clk>;
+			clock-names = "stmmaceth";
+			status = "disabled";
+		};
+
+		gmac1: ethernet at ff702000 {
+			compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac";
+			reg = <0xff702000 0x2000>;
+			interrupts = <0 120 4>;
+			interrupt-names = "macirq";
+			mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */
+			clocks = <&emac1_clk>;
+			clock-names = "stmmaceth";
+			status = "disabled";
 		};
 
 		L2: l2-cache at fffef000 {
diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dts b/arch/arm/boot/dts/socfpga_cyclone5.dts
index 2495958..973999d 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5.dts
@@ -32,6 +32,13 @@
 		reg = <0x0 0x40000000>; /* 1GB */
 	};
 
+	aliases {
+		/* this allow the ethaddr uboot environmnet variable contents
+		 * to be added to the gmac1 device tree blob.
+		 */
+		ethernet0 = &gmac1;
+	};
+
 	soc {
 		clkmgr at ffd04000 {
 			clocks {
@@ -41,6 +48,12 @@
 			};
 		};
 
+		ethernet at ff702000 {
+			phy-mode = "rgmii";
+			phy-addr = <0xffffffff>; /* probe for phy addr */
+			status = "okay";
+		};
+
 		timer0 at ffc08000 {
 			clock-frequency = <100000000>;
 		};
diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts
index 0bf035d..d1ec0ca 100644
--- a/arch/arm/boot/dts/socfpga_vt.dts
+++ b/arch/arm/boot/dts/socfpga_vt.dts
@@ -41,6 +41,11 @@
 			};
 		};
 
+		ethernet at ff700000 {
+			phy-mode = "gmii";
+			status = "okay";
+		};
+
 		timer0 at ffc08000 {
 			clock-frequency = <7000000>;
 		};
-- 
1.7.9.5

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

* [PATCHv4 2/6] ARM: socfpga: dts: Add gate-clock bindings
  2013-05-24 15:41 [PATCHv4 1/6] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA dinguyen at altera.com
@ 2013-05-24 15:41 ` dinguyen at altera.com
  2013-05-24 15:41 ` [PATCHv4 3/6] ARM: socfpga: Add support to gate peripheral clocks dinguyen at altera.com
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: dinguyen at altera.com @ 2013-05-24 15:41 UTC (permalink / raw)
  To: linux-arm-kernel

From: Dinh Nguyen <dinguyen@altera.com>

Add bindings for "socfpga-gate-clk" clocks. These clocks directly feed
the peripherals.

Signed-off-by: Dinh Nguyen <dinguyen@altera.com>
Reviewed-by: Pavel Machek <pavel@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Olof Johansson <olof@lixom.net>
Cc: Pavel Machek <pavel@denx.de>
CC: <linux@arm.linux.org.uk>
---
 .../devicetree/bindings/clock/altr_socfpga.txt     |    7 +
 arch/arm/boot/dts/socfpga.dtsi                     |  199 ++++++++++++++++++++
 2 files changed, 206 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/altr_socfpga.txt b/Documentation/devicetree/bindings/clock/altr_socfpga.txt
index bd0c841..0045433 100644
--- a/Documentation/devicetree/bindings/clock/altr_socfpga.txt
+++ b/Documentation/devicetree/bindings/clock/altr_socfpga.txt
@@ -9,6 +9,9 @@ Required properties:
 	"altr,socfpga-pll-clock" - for a PLL clock
 	"altr,socfpga-perip-clock" - The peripheral clock divided from the
 		PLL clock.
+	"altr,socfpga-gate-clk" - Clocks that directly feed peripherals and
+		can get gated.
+
 - reg : shall be the control register offset from CLOCK_MANAGER's base for the clock.
 - clocks : shall be the input parent clock phandle for the clock. This is
 	either an oscillator or a pll output.
@@ -16,3 +19,7 @@ Required properties:
 
 Optional properties:
 - fixed-divider : If clocks have a fixed divider value, use this property.
+- clk-gate : For "socfpga-gate-clk", clk-gate contains the gating register
+        and the bit index.
+- div-reg : For "socfpga-gate-clk", div-reg contains the divider register, bit shift,
+        and width.
diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi
index 02bb425..bee62a2 100644
--- a/arch/arm/boot/dts/socfpga.dtsi
+++ b/arch/arm/boot/dts/socfpga.dtsi
@@ -95,6 +95,12 @@
 						compatible = "fixed-clock";
 					};
 
+					f2s_periph_ref_clk: f2s_periph_ref_clk {
+						#clock-cells = <0>;
+						compatible = "fixed-clock";
+						clock-frequency = <10000000>;
+					};
+
 					main_pll: main_pll {
 						#address-cells = <1>;
 						#size-cells = <0>;
@@ -236,6 +242,199 @@
 							reg = <0xD4>;
 						};
 					};
+
+				mpu_periph_clk: mpu_periph_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&mpuclk>;
+					fixed-divider = <4>;
+					};
+
+				mpu_l2_ram_clk: mpu_l2_ram_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&mpuclk>;
+					fixed-divider = <2>;
+					};
+
+				l4_main_clk: l4_main_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&mainclk>;
+					clk-gate = <0x60 0>;
+					};
+
+				l3_main_clk: l3_main_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&mainclk>;
+					};
+
+				l3_mp_clk: l3_mp_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&mainclk>;
+					div-reg = <0x64 0 2>;
+					clk-gate = <0x60 1>;
+					};
+
+				l3_sp_clk: l3_sp_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&mainclk>;
+					div-reg = <0x64 2 2>;
+				};
+
+				l4_mp_clk: l4_mp_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&mainclk>, <&per_base_clk>;
+					div-reg = <0x64 4 3>;
+					clk-gate = <0x60 2>;
+					};
+
+				l4_sp_clk: l4_sp_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&mainclk>, <&per_base_clk>;
+					div-reg = <0x64 7 3>;
+					clk-gate = <0x60 3>;
+					};
+
+				dbg_at_clk: dbg_at_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&dbg_base_clk>;
+					div-reg = <0x68 0 2>;
+					clk-gate = <0x60 4>;
+					};
+
+				dbg_clk: dbg_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&dbg_base_clk>;
+					div-reg = <0x68 2 2>;
+					clk-gate = <0x60 5>;
+					};
+
+				dbg_trace_clk: dbg_trace_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&dbg_base_clk>;
+					div-reg = <0x6C 0 3>;
+					clk-gate = <0x60 6>;
+					};
+
+				dbg_timer_clk: dbg_timer_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&dbg_base_clk>;
+					clk-gate = <0x60 7>;
+					};
+
+				cfg_clk: cfg_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&cfg_s2f_usr0_clk>;
+					clk-gate = <0x60 8>;
+					};
+
+				s2f_user0_clk: s2f_user0_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&cfg_s2f_usr0_clk>;
+					clk-gate = <0x60 9>;
+					};
+
+				emac_0_clk: emac_0_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&emac0_clk>;
+					clk-gate = <0xa0 0>;
+					};
+
+				emac_1_clk: emac_1_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&emac1_clk>;
+					clk-gate = <0xa0 1>;
+					};
+
+				usb_mp_clk: usb_mp_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&per_base_clk>;
+					clk-gate = <0xa0 2>;
+					div-reg = <0xa4 0 3>;
+					};
+
+				spi_m_clk: spi_m_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&per_base_clk>;
+					clk-gate = <0xa0 3>;
+					div-reg = <0xa4 3 3>;
+					};
+
+				can0_clk: can0_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&per_base_clk>;
+					clk-gate = <0xa0 4>;
+					div-reg = <0xa4 6 3>;
+					};
+
+				can1_clk: can1_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&per_base_clk>;
+					clk-gate = <0xa0 5>;
+					div-reg = <0xa4 9 3>;
+					};
+
+				gpio_db_clk: gpio_db_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&per_base_clk>;
+					clk-gate = <0xa0 6>;
+					div-reg = <0xa8 0 24>;
+					};
+
+				s2f_user1_clk: s2f_user1_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&s2f_usr1_clk>;
+					clk-gate = <0xa0 7>;
+					};
+
+				sdmmc_clk: sdmmc_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&f2s_periph_ref_clk>, <&main_nand_sdmmc_clk>, <&per_nand_mmc_clk>;
+					clk-gate = <0xa0 8>;
+					};
+
+				nand_x_clk: nand_x_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&f2s_periph_ref_clk>, <&main_nand_sdmmc_clk>, <&per_nand_mmc_clk>;
+					clk-gate = <0xa0 9>;
+					};
+
+				nand_clk: nand_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&f2s_periph_ref_clk>, <&main_nand_sdmmc_clk>, <&per_nand_mmc_clk>;
+					clk-gate = <0xa0 10>;
+					fixed-divider = <4>;
+					};
+
+				qspi_clk: qspi_clk {
+					#clock-cells = <0>;
+					compatible = "altr,socfpga-gate-clk";
+					clocks = <&f2s_periph_ref_clk>, <&main_qspi_clk>, <&per_qspi_clk>;
+					clk-gate = <0xa0 11>;
+					};
 				};
 			};
 
-- 
1.7.9.5

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

* [PATCHv4 3/6] ARM: socfpga: Add support to gate peripheral clocks
  2013-05-24 15:41 [PATCHv4 1/6] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA dinguyen at altera.com
  2013-05-24 15:41 ` [PATCHv4 2/6] ARM: socfpga: dts: Add gate-clock bindings dinguyen at altera.com
@ 2013-05-24 15:41 ` dinguyen at altera.com
  2013-05-30 19:42   ` Mike Turquette
  2013-05-24 15:41 ` [PATCHv4 4/6] ARM: socfpga: Add syscon to be part of socfpga dinguyen at altera.com
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 13+ messages in thread
From: dinguyen at altera.com @ 2013-05-24 15:41 UTC (permalink / raw)
  To: linux-arm-kernel

From: Dinh Nguyen <dinguyen@altera.com>

Add support to gate the clocks that directly feed peripherals. For clocks
with multiple parents, add the ability to determine the correct parent,
and also set parents. Also add support to calculate and set the clocks'
rate.

Signed-off-by: Dinh Nguyen <dinguyen@altera.com>
Reviewed-by: Pavel Machek <pavel@denx.de>
CC: Mike Turquette <mturquette@linaro.org>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Olof Johansson <olof@lixom.net>
Cc: Pavel Machek <pavel@denx.de>
CC: <linux@arm.linux.org.uk>

v3:
- Addressed comments from Pavel

v2:
- Fix space/indent errors
- Add streq for strcmp == 0
---
 drivers/clk/socfpga/clk.c |  194 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 185 insertions(+), 9 deletions(-)

diff --git a/drivers/clk/socfpga/clk.c b/drivers/clk/socfpga/clk.c
index bd11315..5bb848c 100644
--- a/drivers/clk/socfpga/clk.c
+++ b/drivers/clk/socfpga/clk.c
@@ -24,15 +24,17 @@
 #include <linux/of.h>
 
 /* Clock Manager offsets */
-#define CLKMGR_CTRL    0x0
-#define CLKMGR_BYPASS 0x4
+#define CLKMGR_CTRL	0x0
+#define CLKMGR_BYPASS	0x4
+#define CLKMGR_L4SRC	0x70
+#define CLKMGR_PERPLL_SRC	0xAC
 
 /* Clock bypass bits */
-#define MAINPLL_BYPASS (1<<0)
-#define SDRAMPLL_BYPASS (1<<1)
-#define SDRAMPLL_SRC_BYPASS (1<<2)
-#define PERPLL_BYPASS (1<<3)
-#define PERPLL_SRC_BYPASS (1<<4)
+#define MAINPLL_BYPASS		(1<<0)
+#define SDRAMPLL_BYPASS		(1<<1)
+#define SDRAMPLL_SRC_BYPASS	(1<<2)
+#define PERPLL_BYPASS		(1<<3)
+#define PERPLL_SRC_BYPASS	(1<<4)
 
 #define SOCFPGA_PLL_BG_PWRDWN		0
 #define SOCFPGA_PLL_EXT_ENA		1
@@ -41,6 +43,17 @@
 #define SOCFPGA_PLL_DIVF_SHIFT	3
 #define SOCFPGA_PLL_DIVQ_MASK		0x003F0000
 #define SOCFPGA_PLL_DIVQ_SHIFT	16
+#define SOCFGPA_MAX_PARENTS	3
+
+#define SOCFPGA_L4_MP_CLK		"l4_mp_clk"
+#define SOCFPGA_L4_SP_CLK		"l4_sp_clk"
+#define SOCFPGA_NAND_CLK		"nand_clk"
+#define SOCFPGA_NAND_X_CLK		"nand_x_clk"
+#define SOCFPGA_MMC_CLK			"mmc_clk"
+#define SOCFPGA_DB_CLK			"gpio_db_clk"
+
+#define div_mask(width)	((1 << (width)) - 1)
+#define streq(a, b) (strcmp((a), (b)) == 0)
 
 extern void __iomem *clk_mgr_base_addr;
 
@@ -49,6 +62,9 @@ struct socfpga_clk {
 	char *parent_name;
 	char *clk_name;
 	u32 fixed_div;
+	void __iomem *div_reg;
+	u32 width;	/* only valid if div_reg != 0 */
+	u32 shift;	/* only valid if div_reg != 0 */
 };
 #define to_socfpga_clk(p) container_of(p, struct socfpga_clk, hw.hw)
 
@@ -132,8 +148,9 @@ static __init struct clk *socfpga_clk_init(struct device_node *node,
 
 	socfpga_clk->hw.hw.init = &init;
 
-	if (strcmp(clk_name, "main_pll") || strcmp(clk_name, "periph_pll") ||
-			strcmp(clk_name, "sdram_pll")) {
+	if (streq(clk_name, "main_pll") ||
+		streq(clk_name, "periph_pll") ||
+		streq(clk_name, "sdram_pll")) {
 		socfpga_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA;
 		clk_pll_ops.enable = clk_gate_ops.enable;
 		clk_pll_ops.disable = clk_gate_ops.disable;
@@ -148,6 +165,159 @@ static __init struct clk *socfpga_clk_init(struct device_node *node,
 	return clk;
 }
 
+static u8 socfpga_clk_get_parent(struct clk_hw *hwclk)
+{
+	u32 l4_src;
+	u32 perpll_src;
+
+	if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
+		l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
+		return l4_src &= 0x1;
+	}
+	if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
+		l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
+		return !!(l4_src & 2);
+	}
+
+	perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
+	if (streq(hwclk->init->name, SOCFPGA_MMC_CLK))
+		return perpll_src &= 0x3;
+	if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
+			streq(hwclk->init->name, SOCFPGA_NAND_X_CLK))
+			return (perpll_src >> 2) & 3;
+
+	/* QSPI clock */
+	return (perpll_src >> 4) & 3;
+
+}
+
+static int socfpga_clk_set_parent(struct clk_hw *hwclk, u8 parent)
+{
+	u32 src_reg;
+
+	if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
+		src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
+		src_reg &= ~0x1;
+		src_reg |= parent;
+		writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
+	} else if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
+		src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
+		src_reg &= ~0x2;
+		src_reg |= (parent << 1);
+		writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
+	} else {
+		src_reg = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
+		if (streq(hwclk->init->name, SOCFPGA_MMC_CLK)) {
+			src_reg &= ~0x3;
+			src_reg |= parent;
+		} else if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
+			streq(hwclk->init->name, SOCFPGA_NAND_X_CLK)) {
+			src_reg &= ~0xC;
+			src_reg |= (parent << 2);
+		} else {/* QSPI clock */
+			src_reg &= ~0x30;
+			src_reg |= (parent << 4);
+		}
+		writel(src_reg, clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
+	}
+
+	return 0;
+}
+
+static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
+	unsigned long parent_rate)
+{
+	struct socfpga_clk *socfpgaclk = to_socfpga_clk(hwclk);
+	u32 div = 1, val;
+
+	if (socfpgaclk->fixed_div)
+		div = socfpgaclk->fixed_div;
+	else if (socfpgaclk->div_reg) {
+		val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
+		val &= div_mask(socfpgaclk->width);
+		if (streq(hwclk->init->name, SOCFPGA_DB_CLK))
+			div = val + 1;
+		else
+			div = (1 << val);
+	}
+
+	return parent_rate / div;
+}
+
+static struct clk_ops gateclk_ops = {
+	.recalc_rate = socfpga_clk_recalc_rate,
+	.get_parent = socfpga_clk_get_parent,
+	.set_parent = socfpga_clk_set_parent,
+};
+
+static void __init socfpga_gate_clk_init(struct device_node *node,
+	const struct clk_ops *ops)
+{
+	u32 clk_gate[2];
+	u32 div_reg[3];
+	u32 fixed_div;
+	struct clk *clk;
+	struct socfpga_clk *socfpga_clk;
+	const char *clk_name = node->name;
+	const char *parent_name[SOCFGPA_MAX_PARENTS];
+	struct clk_init_data init;
+	int rc;
+	int i = 0;
+
+	socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
+	if (WARN_ON(!socfpga_clk))
+		return;
+
+	rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2);
+	if (rc)
+		clk_gate[0] = 0;
+
+	if (clk_gate[0]) {
+		socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0];
+		socfpga_clk->hw.bit_idx = clk_gate[1];
+
+		gateclk_ops.enable = clk_gate_ops.enable;
+		gateclk_ops.disable = clk_gate_ops.disable;
+	}
+
+	rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
+	if (rc)
+		socfpga_clk->fixed_div = 0;
+	else
+		socfpga_clk->fixed_div = fixed_div;
+
+	rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
+	if (!rc) {
+		socfpga_clk->div_reg = clk_mgr_base_addr + div_reg[0];
+		socfpga_clk->shift = div_reg[1];
+		socfpga_clk->width = div_reg[2];
+	} else {
+		socfpga_clk->div_reg = 0;
+	}
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	init.name = clk_name;
+	init.ops = ops;
+	init.flags = 0;
+	while (i < SOCFGPA_MAX_PARENTS && (parent_name[i] =
+			of_clk_get_parent_name(node, i)) != NULL)
+		i++;
+
+	init.parent_names = parent_name;
+	init.num_parents = i;
+	socfpga_clk->hw.hw.init = &init;
+
+	clk = clk_register(NULL, &socfpga_clk->hw.hw);
+	if (WARN_ON(IS_ERR(clk))) {
+		kfree(socfpga_clk);
+		return;
+	}
+	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	if (WARN_ON(rc))
+		return;
+}
+
 static void __init socfpga_pll_init(struct device_node *node)
 {
 	socfpga_clk_init(node, &clk_pll_ops);
@@ -160,6 +330,12 @@ static void __init socfpga_periph_init(struct device_node *node)
 }
 CLK_OF_DECLARE(socfpga_periph, "altr,socfpga-perip-clk", socfpga_periph_init);
 
+static void __init socfpga_gate_init(struct device_node *node)
+{
+	socfpga_gate_clk_init(node, &gateclk_ops);
+}
+CLK_OF_DECLARE(socfpga_gate, "altr,socfpga-gate-clk", socfpga_gate_init);
+
 void __init socfpga_init_clocks(void)
 {
 	struct clk *clk;
-- 
1.7.9.5

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

* [PATCHv4 4/6] ARM: socfpga: Add syscon to be part of socfpga
  2013-05-24 15:41 [PATCHv4 1/6] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA dinguyen at altera.com
  2013-05-24 15:41 ` [PATCHv4 2/6] ARM: socfpga: dts: Add gate-clock bindings dinguyen at altera.com
  2013-05-24 15:41 ` [PATCHv4 3/6] ARM: socfpga: Add support to gate peripheral clocks dinguyen at altera.com
@ 2013-05-24 15:41 ` dinguyen at altera.com
  2013-05-24 15:41 ` [PATCHv4 5/6] ARM: socfpga: dts: Add support for SD/MMC dinguyen at altera.com
  2013-05-24 15:41 ` [PATCHv4 6/6] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA dinguyen at altera.com
  4 siblings, 0 replies; 13+ messages in thread
From: dinguyen at altera.com @ 2013-05-24 15:41 UTC (permalink / raw)
  To: linux-arm-kernel

From: Dinh Nguyen <dinguyen@altera.com>

SOCFPGA has a system manager register block can be accessed by using
the syscon driver.

Signed-off-by: Dinh Nguyen <dinguyen@altera.com>
Cc: Pavel Machek <pavel@denx.de>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Olof Johansson <olof@lixom.net>
Cc: <linux@arm.linux.org.uk>
---
 arch/arm/mach-socfpga/Kconfig |    1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig
index 566e804..07dff6f 100644
--- a/arch/arm/mach-socfpga/Kconfig
+++ b/arch/arm/mach-socfpga/Kconfig
@@ -13,5 +13,6 @@ config ARCH_SOCFPGA
 	select GPIO_PL061 if GPIOLIB
 	select HAVE_ARM_SCU
 	select HAVE_SMP
+	select MFD_SYSCON
 	select SPARSE_IRQ
 	select USE_OF
-- 
1.7.9.5

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

* [PATCHv4 5/6] ARM: socfpga: dts: Add support for SD/MMC
  2013-05-24 15:41 [PATCHv4 1/6] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA dinguyen at altera.com
                   ` (2 preceding siblings ...)
  2013-05-24 15:41 ` [PATCHv4 4/6] ARM: socfpga: Add syscon to be part of socfpga dinguyen at altera.com
@ 2013-05-24 15:41 ` dinguyen at altera.com
  2013-05-24 15:41 ` [PATCHv4 6/6] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA dinguyen at altera.com
  4 siblings, 0 replies; 13+ messages in thread
From: dinguyen at altera.com @ 2013-05-24 15:41 UTC (permalink / raw)
  To: linux-arm-kernel

From: Dinh Nguyen <dinguyen@altera.com>

Add bindings for SD/MMC for SOCFPGA.
Add "syscon" to the "altr,sys-mgr" binding.

Signed-off-by: Dinh Nguyen <dinguyen@altera.com>
Reviewed-by: Pavel Machek <pavel@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Olof Johansson <olof@lixom.net>
Cc: Pavel Machek <pavel@denx.de>
CC: <linux@arm.linux.org.uk>

v2:
- Add "syscon" to "altr,sys-mgr"
- Remove pwr-en field
---
 .../devicetree/bindings/mmc/socfpga-dw-mshc.txt    |   60 ++++++++++++++++++++
 arch/arm/boot/dts/socfpga.dtsi                     |   13 ++++-
 arch/arm/boot/dts/socfpga_cyclone5.dts             |   13 +++++
 arch/arm/boot/dts/socfpga_vt.dts                   |   12 ++++
 4 files changed, 97 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt

diff --git a/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt
new file mode 100644
index 0000000..9d7062c
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt
@@ -0,0 +1,60 @@
+* Altera SOCFPGA specific extensions to the Synopsis Designware Mobile
+  Storage Host Controller
+
+Required Properties:
+
+* compatible: should be
+	- "altr,socfpga-dw-mshc": for controllers with Altera SOCFPGA
+	  specific extentions.
+
+* altr,dw-mshc-ciu-div: Specifies the divider value for the card interface
+  unit (ciu) clock. The value should be (n-1). For Altera's SOCFPGA, the divider
+  value is fixed at 3, which mean parent_clock/4.
+
+* altr,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
+  in transmit mode and CIU clock phase shift value in receive mode for single
+  data rate mode operation. Refer notes below for the order of the cells and the
+  valid values.
+
+  Notes for the sdr-timing values:
+
+    The order of the cells should be
+      - First Cell: CIU clock phase shift value for RX mode, smplsel bits in
+	the system manager SDMMC control group.
+      - Second Cell: CIU clock phase shift value for TX mode, drvsel bits in
+	the system manager SDMMC control group.
+
+    Valid values for SDR CIU clock timing for SOCFPGA:
+      - valid value for tx phase shift and rx phase shift is 0 to 7.
+
+Required properties for a slot:
+
+* bus-width: Data width for card slot. 4-bit or 8-bit data.
+
+Example:
+
+  The MSHC controller node can be split into two portions, SoC specific and
+  board specific portions as listed below.
+
+	dwmmc0 at ff704000 {
+		compatible = "altr,socfpga-dw-mshc";
+		reg = <0xff704000 0x1000>;
+		interrupts = <0 139 4>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	dwmmc0 at ff704000 {
+		num-slots = <1>;
+		supports-highspeed;
+		broken-cd;
+		fifo-depth = <0x400>;
+		altr,dw-mshc-ciu-div = <3>;
+      		altr,dw-mshc-sdr-timing = <0 3>;
+
+		slot at 0 {
+			reg = <0>;
+			bus-width = <4>;
+		};
+	};
+
diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi
index bee62a2..dbf7f22 100644
--- a/arch/arm/boot/dts/socfpga.dtsi
+++ b/arch/arm/boot/dts/socfpga.dtsi
@@ -468,6 +468,17 @@
 			cache-level = <2>;
 		};
 
+		mmc: dwmmc0 at ff704000 {
+			compatible = "altr,socfpga-dw-mshc";
+			reg = <0xff704000 0x1000>;
+			interrupts = <0 139 4>;
+			fifo-depth = <0x400>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clocks = <&l4_mp_clk>, <&sdmmc_clk>;
+			clock-names = "biu", "ciu";
+		};
+
 		/* Local timer */
 		timer at fffec600 {
 			compatible = "arm,cortex-a9-twd-timer";
@@ -521,7 +532,7 @@
 			};
 
 		sysmgr at ffd08000 {
-				compatible = "altr,sys-mgr";
+				compatible = "altr,sys-mgr", "syscon";
 				reg = <0xffd08000 0x4000>;
 			};
 	};
diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dts b/arch/arm/boot/dts/socfpga_cyclone5.dts
index 973999d..1853cb1 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5.dts
@@ -54,6 +54,19 @@
 			status = "okay";
 		};
 
+		dwmmc0 at ff704000 {
+			num-slots = <1>;
+			supports-highspeed;
+			broken-cd;
+			altr,dw-mshc-ciu-div = <3>;
+			altr,dw-mshc-sdr-timing = <0 3>;
+
+			slot at 0 {
+				reg = <0>;
+				bus-width = <4>;
+			};
+		};
+
 		timer0 at ffc08000 {
 			clock-frequency = <100000000>;
 		};
diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts
index d1ec0ca..d93deb0 100644
--- a/arch/arm/boot/dts/socfpga_vt.dts
+++ b/arch/arm/boot/dts/socfpga_vt.dts
@@ -46,6 +46,18 @@
 			status = "okay";
 		};
 
+		dwmmc0 at ff704000 {
+			num-slots = <1>;
+			supports-highspeed;
+			broken-cd;
+			altr,dw-mshc-ciu-div = <3>;
+
+			slot at 0 {
+				reg = <0>;
+				bus-width = <4>;
+			};
+		};
+
 		timer0 at ffc08000 {
 			clock-frequency = <7000000>;
 		};
-- 
1.7.9.5

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

* [PATCHv4 6/6] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
  2013-05-24 15:41 [PATCHv4 1/6] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA dinguyen at altera.com
                   ` (3 preceding siblings ...)
  2013-05-24 15:41 ` [PATCHv4 5/6] ARM: socfpga: dts: Add support for SD/MMC dinguyen at altera.com
@ 2013-05-24 15:41 ` dinguyen at altera.com
  2013-05-24 17:10   ` Arnd Bergmann
  4 siblings, 1 reply; 13+ messages in thread
From: dinguyen at altera.com @ 2013-05-24 15:41 UTC (permalink / raw)
  To: linux-arm-kernel

From: Dinh Nguyen <dinguyen@altera.com>

Add platform specific functionality for the DW SD/MMC driver for
SoCFPGA. Move SDMMC_CMD_USE_HOLD_REG to dw_mmc.h so other platforms
can use this define.

Signed-off-by: Dinh Nguyen <dinguyen@altera.com>
CC: Seungwon Jeon <tgih.jun@samsung.com>
CC: Jaehoon Chung <jh80.chung@samsung.com>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Olof Johansson <olof@lixom.net>
CC: Pavel Machek <pavel@denx.de>
CC: linux-mmc at vger.kernel.org

v4:
- Fix up SYSMGR_SDMMC_CTRL_SET macro

v3:
- Addressed comments from Seugwon, Jaehoon, and Pavel
- Use clk_disable_unprepare/clk_prepare_enable

v2:
- Use syscon and regmap
- Avoid divide by zero
- Remove the need to set PWR_EN
---
 drivers/mmc/host/Kconfig          |    8 +++
 drivers/mmc/host/Makefile         |    1 +
 drivers/mmc/host/dw_mmc-exynos.c  |    2 -
 drivers/mmc/host/dw_mmc-socfpga.c |  138 +++++++++++++++++++++++++++++++++++++
 drivers/mmc/host/dw_mmc.h         |    1 +
 5 files changed, 148 insertions(+), 2 deletions(-)
 create mode 100644 drivers/mmc/host/dw_mmc-socfpga.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 9ab8f8d..1be2289 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -556,6 +556,14 @@ config MMC_DW_EXYNOS
 	  Synopsys DesignWare Memory Card Interface driver. Select this option
 	  for platforms based on Exynos4 and Exynos5 SoC's.
 
+config MMC_DW_SOCFPGA
+	tristate "SOCFPGA specific extensions for Synopsys DW Memory Card Interface"
+	depends on MMC_DW
+	select MMC_DW_PLTFM
+	help
+	  This selects support for Altera SoCFPGA specific extensions to the
+	  Synopsys DesignWare Memory Card Interface driver.
+
 config MMC_DW_PCI
 	tristate "Synopsys Designware MCI support on PCI bus"
 	depends on MMC_DW && PCI
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index cd32280..67718c1 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_SDH_BFIN)		+= bfin_sdh.o
 obj-$(CONFIG_MMC_DW)		+= dw_mmc.o
 obj-$(CONFIG_MMC_DW_PLTFM)	+= dw_mmc-pltfm.o
 obj-$(CONFIG_MMC_DW_EXYNOS)	+= dw_mmc-exynos.o
+obj-$(CONFIG_MMC_DW_SOCFPGA)	+= dw_mmc-socfpga.o
 obj-$(CONFIG_MMC_DW_PCI)	+= dw_mmc-pci.o
 obj-$(CONFIG_MMC_SH_MMCIF)	+= sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)	+= jz4740_mmc.o
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index f013e7e..866edef 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -31,8 +31,6 @@
 					SDMMC_CLKSEL_CCLK_DRIVE(y) |	\
 					SDMMC_CLKSEL_CCLK_DIVIDER(z))
 
-#define SDMMC_CMD_USE_HOLD_REG		BIT(29)
-
 #define EXYNOS4210_FIXED_CIU_CLK_DIV	2
 #define EXYNOS4412_FIXED_CIU_CLK_DIV	4
 
diff --git a/drivers/mmc/host/dw_mmc-socfpga.c b/drivers/mmc/host/dw_mmc-socfpga.c
new file mode 100644
index 0000000..4c19fd8
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-socfpga.c
@@ -0,0 +1,138 @@
+/*
+ * Altera SoCFPGA Specific Extensions for Synopsys DW Multimedia Card Interface driver
+ *
+ *  Copyright (C) 2012, Samsung Electronics Co., Ltd.
+ *  Copyright (C) 2013 Altera Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Taken from dw_mmc-exynos.c
+ */
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/dw_mmc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+
+#define SYSMGR_SDMMCGRP_CTRL_OFFSET		0x108
+#define DRV_CLK_PHASE_SHIFT_SEL_MASK	0x7
+#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel)          \
+	((((smplsel) & 0x7) << 3) | (((drvsel) & 0x7) << 0))
+
+/* SOCFPGA implementation specific driver private data */
+struct dw_mci_socfpga_priv_data {
+	u8	ciu_div; /* card interface unit divisor */
+	u32	hs_timing; /* bitmask for CIU clock phase shift */
+	struct regmap   *sysreg; /* regmap for system manager register */
+};
+
+static int dw_mci_socfpga_priv_init(struct dw_mci *host)
+{
+	struct dw_mci_socfpga_priv_data *priv;
+
+	priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(host->dev, "mem alloc failed for private data\n");
+		return -ENOMEM;
+	}
+
+	priv->sysreg = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
+	if (IS_ERR(priv->sysreg)) {
+		dev_err(host->dev, "regmap for altr,sys-mgr lookup failed.\n");
+		return PTR_ERR(priv->sysreg);
+	}
+	host->priv = priv;
+
+	return 0;
+}
+
+static int dw_mci_socfpga_setup_clock(struct dw_mci *host)
+{
+	struct dw_mci_socfpga_priv_data *priv = host->priv;
+
+	clk_disable_unprepare(host->ciu_clk);
+	regmap_write(priv->sysreg, SYSMGR_SDMMCGRP_CTRL_OFFSET, priv->hs_timing);
+	clk_prepare_enable(host->ciu_clk);
+
+	host->bus_hz /= (priv->ciu_div + 1);
+	return 0;
+}
+
+static void dw_mci_socfpga_prepare_command(struct dw_mci *host, u32 *cmdr)
+{
+	struct dw_mci_socfpga_priv_data *priv = host->priv;
+
+	if (priv->hs_timing & DRV_CLK_PHASE_SHIFT_SEL_MASK)
+		*cmdr |= SDMMC_CMD_USE_HOLD_REG;
+}
+
+static int dw_mci_socfpga_parse_dt(struct dw_mci *host)
+{
+	struct dw_mci_socfpga_priv_data *priv = host->priv;
+	struct device_node *np = host->dev->of_node;
+	u32 timing[2];
+	u32 div = 0;
+	int ret;
+
+	ret = of_property_read_u32(np, "altr,dw-mshc-ciu-div", &div);
+	if (ret)
+		dev_info(host->dev, "No dw-mshc-ciu-div specified, assuming 1");
+	priv->ciu_div = div;
+
+	ret = of_property_read_u32_array(np,
+			"altr,dw-mshc-sdr-timing", timing, 2);
+	if (ret)
+		return ret;
+
+	priv->hs_timing = SYSMGR_SDMMC_CTRL_SET(timing[0], timing[1]);
+	return 0;
+}
+
+static const struct dw_mci_drv_data socfpga_drv_data = {
+	.init			= dw_mci_socfpga_priv_init,
+	.setup_clock		= dw_mci_socfpga_setup_clock,
+	.prepare_command	= dw_mci_socfpga_prepare_command,
+	.parse_dt		= dw_mci_socfpga_parse_dt,
+};
+
+static const struct of_device_id dw_mci_socfpga_match[] = {
+	{ .compatible = "altr,socfpga-dw-mshc",
+			.data = &socfpga_drv_data, },
+	{},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_socfpga_match);
+
+int dw_mci_socfpga_probe(struct platform_device *pdev)
+{
+	const struct dw_mci_drv_data *drv_data;
+	const struct of_device_id *match;
+
+	match = of_match_node(dw_mci_socfpga_match, pdev->dev.of_node);
+	drv_data = match->data;
+	return dw_mci_pltfm_register(pdev, drv_data);
+}
+
+static struct platform_driver dw_mci_socfpga_pltfm_driver = {
+	.probe		= dw_mci_socfpga_probe,
+	.remove		= __exit_p(dw_mci_pltfm_remove),
+	.driver		= {
+		.name		= "dwmmc_socfpga",
+		.of_match_table	= of_match_ptr(dw_mci_socfpga_match),
+		.pm		= &dw_mci_pltfm_pmops,
+	},
+};
+
+module_platform_driver(dw_mci_socfpga_pltfm_driver);
+
+MODULE_DESCRIPTION("Altera SOCFPGA Specific DW-MSHC Driver Extension");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:dwmmc-socfpga");
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 0b74189..3700cb2 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -111,6 +111,7 @@
 #define SDMMC_INT_ERROR			0xbfc2
 /* Command register defines */
 #define SDMMC_CMD_START			BIT(31)
+#define SDMMC_CMD_USE_HOLD_REG	BIT(29)
 #define SDMMC_CMD_CCS_EXP		BIT(23)
 #define SDMMC_CMD_CEATA_RD		BIT(22)
 #define SDMMC_CMD_UPD_CLK		BIT(21)
-- 
1.7.9.5

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

* [PATCHv4 6/6] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
  2013-05-24 15:41 ` [PATCHv4 6/6] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA dinguyen at altera.com
@ 2013-05-24 17:10   ` Arnd Bergmann
  2013-05-24 17:12     ` Arnd Bergmann
  0 siblings, 1 reply; 13+ messages in thread
From: Arnd Bergmann @ 2013-05-24 17:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 24 May 2013, dinguyen at altera.com wrote:
> 
> From: Dinh Nguyen <dinguyen@altera.com>
> 
> Add platform specific functionality for the DW SD/MMC driver for
> SoCFPGA. Move SDMMC_CMD_USE_HOLD_REG to dw_mmc.h so other platforms
> can use this define.

No objections to the patch, but you seem to be missing a  binding document,
which is mandatory to describe the properties you add.

It also seems odd to have this in the series for the ethernet driver.

	Arnd

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

* [PATCHv4 6/6] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
  2013-05-24 17:10   ` Arnd Bergmann
@ 2013-05-24 17:12     ` Arnd Bergmann
  2013-05-24 18:03       ` Dinh Nguyen
  0 siblings, 1 reply; 13+ messages in thread
From: Arnd Bergmann @ 2013-05-24 17:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 24 May 2013, Arnd Bergmann wrote:

> It also seems odd to have this in the series for the ethernet driver.

After I sent it I realized that your patches are actually for different
parts of the system, they were just all replies to the same first patch.

It's usually helpful to add a [PATCH 0/6] message that explains the
overall intention and who you expect to pick up the patches, to avoid
the confusion I had.

	Arnd

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

* [PATCHv4 6/6] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
  2013-05-24 17:12     ` Arnd Bergmann
@ 2013-05-24 18:03       ` Dinh Nguyen
  2013-05-24 18:58         ` Arnd Bergmann
  0 siblings, 1 reply; 13+ messages in thread
From: Dinh Nguyen @ 2013-05-24 18:03 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arnd,

On Fri, 2013-05-24 at 19:12 +0200, Arnd Bergmann wrote:
> On Friday 24 May 2013, Arnd Bergmann wrote:
> 
> > It also seems odd to have this in the series for the ethernet driver.
> 
> After I sent it I realized that your patches are actually for different
> parts of the system, they were just all replies to the same first patch.
> 
> It's usually helpful to add a [PATCH 0/6] message that explains the
> overall intention and who you expect to pick up the patches, to avoid
> the confusion I had.

I apologize for that. Will make sure to include a [PATCH 0/6] message in
the future.

Dinh
> 
> 	Arnd
> 

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

* [PATCHv4 6/6] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
  2013-05-24 18:03       ` Dinh Nguyen
@ 2013-05-24 18:58         ` Arnd Bergmann
  2013-05-26 18:11           ` Pavel Machek
  0 siblings, 1 reply; 13+ messages in thread
From: Arnd Bergmann @ 2013-05-24 18:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 24 May 2013, Dinh Nguyen wrote:
> I apologize for that. Will make sure to include a [PATCH 0/6] message in
> the future.

No worries, I actually saw now that my only other comment was also
wrong, as you have the binding I was looking for in patch 5/6.

	Arnd

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

* [PATCHv4 6/6] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
  2013-05-24 18:58         ` Arnd Bergmann
@ 2013-05-26 18:11           ` Pavel Machek
  0 siblings, 0 replies; 13+ messages in thread
From: Pavel Machek @ 2013-05-26 18:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri 2013-05-24 20:58:34, Arnd Bergmann wrote:
> On Friday 24 May 2013, Dinh Nguyen wrote:
> > I apologize for that. Will make sure to include a [PATCH 0/6] message in
> > the future.
> 
> No worries, I actually saw now that my only other comment was also
> wrong, as you have the binding I was looking for in patch 5/6.

Could you take the series through your tree?

Patches 1,2,4,5/6 are mostly local to arch/arm, 3/6 is stuff Dinh is
listed as a maintainer for, and 6/6 is fairly socfpga-specific,
too. (I guess Dinh could add MAINTAINERs entry for that...).

Thanks,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* [PATCHv4 3/6] ARM: socfpga: Add support to gate peripheral clocks
  2013-05-24 15:41 ` [PATCHv4 3/6] ARM: socfpga: Add support to gate peripheral clocks dinguyen at altera.com
@ 2013-05-30 19:42   ` Mike Turquette
  2013-05-30 21:33     ` Dinh Nguyen
  0 siblings, 1 reply; 13+ messages in thread
From: Mike Turquette @ 2013-05-30 19:42 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting dinguyen at altera.com (2013-05-24 08:41:17)
> From: Dinh Nguyen <dinguyen@altera.com>
> 
> Add support to gate the clocks that directly feed peripherals. For clocks
> with multiple parents, add the ability to determine the correct parent,
> and also set parents. Also add support to calculate and set the clocks'
> rate.
> 
> Signed-off-by: Dinh Nguyen <dinguyen@altera.com>
> Reviewed-by: Pavel Machek <pavel@denx.de>
> CC: Mike Turquette <mturquette@linaro.org>
> CC: Arnd Bergmann <arnd@arndb.de>
> CC: Olof Johansson <olof@lixom.net>
> Cc: Pavel Machek <pavel@denx.de>
> CC: <linux@arm.linux.org.uk>
> 

Looks OK to me.  Lots of conditionals in socfpga_gate_clk_init, which
some day might be better to break out into separate clk types.  Not a
big deal for now:

Acked-by: Mike Turquette <mturquette@linaro.org>

> v3:
> - Addressed comments from Pavel
> 
> v2:
> - Fix space/indent errors
> - Add streq for strcmp == 0
> ---
>  drivers/clk/socfpga/clk.c |  194 ++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 185 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/clk/socfpga/clk.c b/drivers/clk/socfpga/clk.c
> index bd11315..5bb848c 100644
> --- a/drivers/clk/socfpga/clk.c
> +++ b/drivers/clk/socfpga/clk.c
> @@ -24,15 +24,17 @@
>  #include <linux/of.h>
>  
>  /* Clock Manager offsets */
> -#define CLKMGR_CTRL    0x0
> -#define CLKMGR_BYPASS 0x4
> +#define CLKMGR_CTRL    0x0
> +#define CLKMGR_BYPASS  0x4
> +#define CLKMGR_L4SRC   0x70
> +#define CLKMGR_PERPLL_SRC      0xAC
>  
>  /* Clock bypass bits */
> -#define MAINPLL_BYPASS (1<<0)
> -#define SDRAMPLL_BYPASS (1<<1)
> -#define SDRAMPLL_SRC_BYPASS (1<<2)
> -#define PERPLL_BYPASS (1<<3)
> -#define PERPLL_SRC_BYPASS (1<<4)
> +#define MAINPLL_BYPASS         (1<<0)
> +#define SDRAMPLL_BYPASS                (1<<1)
> +#define SDRAMPLL_SRC_BYPASS    (1<<2)
> +#define PERPLL_BYPASS          (1<<3)
> +#define PERPLL_SRC_BYPASS      (1<<4)
>  
>  #define SOCFPGA_PLL_BG_PWRDWN          0
>  #define SOCFPGA_PLL_EXT_ENA            1
> @@ -41,6 +43,17 @@
>  #define SOCFPGA_PLL_DIVF_SHIFT 3
>  #define SOCFPGA_PLL_DIVQ_MASK          0x003F0000
>  #define SOCFPGA_PLL_DIVQ_SHIFT 16
> +#define SOCFGPA_MAX_PARENTS    3
> +
> +#define SOCFPGA_L4_MP_CLK              "l4_mp_clk"
> +#define SOCFPGA_L4_SP_CLK              "l4_sp_clk"
> +#define SOCFPGA_NAND_CLK               "nand_clk"
> +#define SOCFPGA_NAND_X_CLK             "nand_x_clk"
> +#define SOCFPGA_MMC_CLK                        "mmc_clk"
> +#define SOCFPGA_DB_CLK                 "gpio_db_clk"
> +
> +#define div_mask(width)        ((1 << (width)) - 1)
> +#define streq(a, b) (strcmp((a), (b)) == 0)
>  
>  extern void __iomem *clk_mgr_base_addr;
>  
> @@ -49,6 +62,9 @@ struct socfpga_clk {
>         char *parent_name;
>         char *clk_name;
>         u32 fixed_div;
> +       void __iomem *div_reg;
> +       u32 width;      /* only valid if div_reg != 0 */
> +       u32 shift;      /* only valid if div_reg != 0 */
>  };
>  #define to_socfpga_clk(p) container_of(p, struct socfpga_clk, hw.hw)
>  
> @@ -132,8 +148,9 @@ static __init struct clk *socfpga_clk_init(struct device_node *node,
>  
>         socfpga_clk->hw.hw.init = &init;
>  
> -       if (strcmp(clk_name, "main_pll") || strcmp(clk_name, "periph_pll") ||
> -                       strcmp(clk_name, "sdram_pll")) {
> +       if (streq(clk_name, "main_pll") ||
> +               streq(clk_name, "periph_pll") ||
> +               streq(clk_name, "sdram_pll")) {
>                 socfpga_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA;
>                 clk_pll_ops.enable = clk_gate_ops.enable;
>                 clk_pll_ops.disable = clk_gate_ops.disable;
> @@ -148,6 +165,159 @@ static __init struct clk *socfpga_clk_init(struct device_node *node,
>         return clk;
>  }
>  
> +static u8 socfpga_clk_get_parent(struct clk_hw *hwclk)
> +{
> +       u32 l4_src;
> +       u32 perpll_src;
> +
> +       if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
> +               l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
> +               return l4_src &= 0x1;
> +       }
> +       if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
> +               l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
> +               return !!(l4_src & 2);
> +       }
> +
> +       perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
> +       if (streq(hwclk->init->name, SOCFPGA_MMC_CLK))
> +               return perpll_src &= 0x3;
> +       if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
> +                       streq(hwclk->init->name, SOCFPGA_NAND_X_CLK))
> +                       return (perpll_src >> 2) & 3;
> +
> +       /* QSPI clock */
> +       return (perpll_src >> 4) & 3;
> +
> +}
> +
> +static int socfpga_clk_set_parent(struct clk_hw *hwclk, u8 parent)
> +{
> +       u32 src_reg;
> +
> +       if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
> +               src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
> +               src_reg &= ~0x1;
> +               src_reg |= parent;
> +               writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
> +       } else if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
> +               src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
> +               src_reg &= ~0x2;
> +               src_reg |= (parent << 1);
> +               writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
> +       } else {
> +               src_reg = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
> +               if (streq(hwclk->init->name, SOCFPGA_MMC_CLK)) {
> +                       src_reg &= ~0x3;
> +                       src_reg |= parent;
> +               } else if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
> +                       streq(hwclk->init->name, SOCFPGA_NAND_X_CLK)) {
> +                       src_reg &= ~0xC;
> +                       src_reg |= (parent << 2);
> +               } else {/* QSPI clock */
> +                       src_reg &= ~0x30;
> +                       src_reg |= (parent << 4);
> +               }
> +               writel(src_reg, clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
> +       }
> +
> +       return 0;
> +}
> +
> +static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
> +       unsigned long parent_rate)
> +{
> +       struct socfpga_clk *socfpgaclk = to_socfpga_clk(hwclk);
> +       u32 div = 1, val;
> +
> +       if (socfpgaclk->fixed_div)
> +               div = socfpgaclk->fixed_div;
> +       else if (socfpgaclk->div_reg) {
> +               val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
> +               val &= div_mask(socfpgaclk->width);
> +               if (streq(hwclk->init->name, SOCFPGA_DB_CLK))
> +                       div = val + 1;
> +               else
> +                       div = (1 << val);
> +       }
> +
> +       return parent_rate / div;
> +}
> +
> +static struct clk_ops gateclk_ops = {
> +       .recalc_rate = socfpga_clk_recalc_rate,
> +       .get_parent = socfpga_clk_get_parent,
> +       .set_parent = socfpga_clk_set_parent,
> +};
> +
> +static void __init socfpga_gate_clk_init(struct device_node *node,
> +       const struct clk_ops *ops)
> +{
> +       u32 clk_gate[2];
> +       u32 div_reg[3];
> +       u32 fixed_div;
> +       struct clk *clk;
> +       struct socfpga_clk *socfpga_clk;
> +       const char *clk_name = node->name;
> +       const char *parent_name[SOCFGPA_MAX_PARENTS];
> +       struct clk_init_data init;
> +       int rc;
> +       int i = 0;
> +
> +       socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
> +       if (WARN_ON(!socfpga_clk))
> +               return;
> +
> +       rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2);
> +       if (rc)
> +               clk_gate[0] = 0;
> +
> +       if (clk_gate[0]) {
> +               socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0];
> +               socfpga_clk->hw.bit_idx = clk_gate[1];
> +
> +               gateclk_ops.enable = clk_gate_ops.enable;
> +               gateclk_ops.disable = clk_gate_ops.disable;
> +       }
> +
> +       rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
> +       if (rc)
> +               socfpga_clk->fixed_div = 0;
> +       else
> +               socfpga_clk->fixed_div = fixed_div;
> +
> +       rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
> +       if (!rc) {
> +               socfpga_clk->div_reg = clk_mgr_base_addr + div_reg[0];
> +               socfpga_clk->shift = div_reg[1];
> +               socfpga_clk->width = div_reg[2];
> +       } else {
> +               socfpga_clk->div_reg = 0;
> +       }
> +
> +       of_property_read_string(node, "clock-output-names", &clk_name);
> +
> +       init.name = clk_name;
> +       init.ops = ops;
> +       init.flags = 0;
> +       while (i < SOCFGPA_MAX_PARENTS && (parent_name[i] =
> +                       of_clk_get_parent_name(node, i)) != NULL)
> +               i++;
> +
> +       init.parent_names = parent_name;
> +       init.num_parents = i;
> +       socfpga_clk->hw.hw.init = &init;
> +
> +       clk = clk_register(NULL, &socfpga_clk->hw.hw);
> +       if (WARN_ON(IS_ERR(clk))) {
> +               kfree(socfpga_clk);
> +               return;
> +       }
> +       rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +       if (WARN_ON(rc))
> +               return;
> +}
> +
>  static void __init socfpga_pll_init(struct device_node *node)
>  {
>         socfpga_clk_init(node, &clk_pll_ops);
> @@ -160,6 +330,12 @@ static void __init socfpga_periph_init(struct device_node *node)
>  }
>  CLK_OF_DECLARE(socfpga_periph, "altr,socfpga-perip-clk", socfpga_periph_init);
>  
> +static void __init socfpga_gate_init(struct device_node *node)
> +{
> +       socfpga_gate_clk_init(node, &gateclk_ops);
> +}
> +CLK_OF_DECLARE(socfpga_gate, "altr,socfpga-gate-clk", socfpga_gate_init);
> +
>  void __init socfpga_init_clocks(void)
>  {
>         struct clk *clk;
> -- 
> 1.7.9.5

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

* [PATCHv4 3/6] ARM: socfpga: Add support to gate peripheral clocks
  2013-05-30 19:42   ` Mike Turquette
@ 2013-05-30 21:33     ` Dinh Nguyen
  0 siblings, 0 replies; 13+ messages in thread
From: Dinh Nguyen @ 2013-05-30 21:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 2013-05-30 at 12:42 -0700, Mike Turquette wrote:
> Quoting dinguyen at altera.com (2013-05-24 08:41:17)
> > From: Dinh Nguyen <dinguyen@altera.com>
> > 
> > Add support to gate the clocks that directly feed peripherals. For clocks
> > with multiple parents, add the ability to determine the correct parent,
> > and also set parents. Also add support to calculate and set the clocks'
> > rate.
> > 
> > Signed-off-by: Dinh Nguyen <dinguyen@altera.com>
> > Reviewed-by: Pavel Machek <pavel@denx.de>
> > CC: Mike Turquette <mturquette@linaro.org>
> > CC: Arnd Bergmann <arnd@arndb.de>
> > CC: Olof Johansson <olof@lixom.net>
> > Cc: Pavel Machek <pavel@denx.de>
> > CC: <linux@arm.linux.org.uk>
> > 
> 
> Looks OK to me.  Lots of conditionals in socfpga_gate_clk_init, which
> some day might be better to break out into separate clk types.  Not a
> big deal for now:
> 
> Acked-by: Mike Turquette <mturquette@linaro.org>

Thanks Mike.

Arnd, if you don't have any other comments, can you or Olof please apply
this series? Or I can send a new set with Mike's Ack?

Dinh
> 
> > v3:
> > - Addressed comments from Pavel
> > 
> > v2:
> > - Fix space/indent errors
> > - Add streq for strcmp == 0
> > ---
> >  drivers/clk/socfpga/clk.c |  194 ++++++++++++++++++++++++++++++++++++++++++---
> >  1 file changed, 185 insertions(+), 9 deletions(-)
> > 
> > diff --git a/drivers/clk/socfpga/clk.c b/drivers/clk/socfpga/clk.c
> > index bd11315..5bb848c 100644
> > --- a/drivers/clk/socfpga/clk.c
> > +++ b/drivers/clk/socfpga/clk.c
> > @@ -24,15 +24,17 @@
> >  #include <linux/of.h>
> >  
> >  /* Clock Manager offsets */
> > -#define CLKMGR_CTRL    0x0
> > -#define CLKMGR_BYPASS 0x4
> > +#define CLKMGR_CTRL    0x0
> > +#define CLKMGR_BYPASS  0x4
> > +#define CLKMGR_L4SRC   0x70
> > +#define CLKMGR_PERPLL_SRC      0xAC
> >  
> >  /* Clock bypass bits */
> > -#define MAINPLL_BYPASS (1<<0)
> > -#define SDRAMPLL_BYPASS (1<<1)
> > -#define SDRAMPLL_SRC_BYPASS (1<<2)
> > -#define PERPLL_BYPASS (1<<3)
> > -#define PERPLL_SRC_BYPASS (1<<4)
> > +#define MAINPLL_BYPASS         (1<<0)
> > +#define SDRAMPLL_BYPASS                (1<<1)
> > +#define SDRAMPLL_SRC_BYPASS    (1<<2)
> > +#define PERPLL_BYPASS          (1<<3)
> > +#define PERPLL_SRC_BYPASS      (1<<4)
> >  
> >  #define SOCFPGA_PLL_BG_PWRDWN          0
> >  #define SOCFPGA_PLL_EXT_ENA            1
> > @@ -41,6 +43,17 @@
> >  #define SOCFPGA_PLL_DIVF_SHIFT 3
> >  #define SOCFPGA_PLL_DIVQ_MASK          0x003F0000
> >  #define SOCFPGA_PLL_DIVQ_SHIFT 16
> > +#define SOCFGPA_MAX_PARENTS    3
> > +
> > +#define SOCFPGA_L4_MP_CLK              "l4_mp_clk"
> > +#define SOCFPGA_L4_SP_CLK              "l4_sp_clk"
> > +#define SOCFPGA_NAND_CLK               "nand_clk"
> > +#define SOCFPGA_NAND_X_CLK             "nand_x_clk"
> > +#define SOCFPGA_MMC_CLK                        "mmc_clk"
> > +#define SOCFPGA_DB_CLK                 "gpio_db_clk"
> > +
> > +#define div_mask(width)        ((1 << (width)) - 1)
> > +#define streq(a, b) (strcmp((a), (b)) == 0)
> >  
> >  extern void __iomem *clk_mgr_base_addr;
> >  
> > @@ -49,6 +62,9 @@ struct socfpga_clk {
> >         char *parent_name;
> >         char *clk_name;
> >         u32 fixed_div;
> > +       void __iomem *div_reg;
> > +       u32 width;      /* only valid if div_reg != 0 */
> > +       u32 shift;      /* only valid if div_reg != 0 */
> >  };
> >  #define to_socfpga_clk(p) container_of(p, struct socfpga_clk, hw.hw)
> >  
> > @@ -132,8 +148,9 @@ static __init struct clk *socfpga_clk_init(struct device_node *node,
> >  
> >         socfpga_clk->hw.hw.init = &init;
> >  
> > -       if (strcmp(clk_name, "main_pll") || strcmp(clk_name, "periph_pll") ||
> > -                       strcmp(clk_name, "sdram_pll")) {
> > +       if (streq(clk_name, "main_pll") ||
> > +               streq(clk_name, "periph_pll") ||
> > +               streq(clk_name, "sdram_pll")) {
> >                 socfpga_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA;
> >                 clk_pll_ops.enable = clk_gate_ops.enable;
> >                 clk_pll_ops.disable = clk_gate_ops.disable;
> > @@ -148,6 +165,159 @@ static __init struct clk *socfpga_clk_init(struct device_node *node,
> >         return clk;
> >  }
> >  
> > +static u8 socfpga_clk_get_parent(struct clk_hw *hwclk)
> > +{
> > +       u32 l4_src;
> > +       u32 perpll_src;
> > +
> > +       if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
> > +               l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
> > +               return l4_src &= 0x1;
> > +       }
> > +       if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
> > +               l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
> > +               return !!(l4_src & 2);
> > +       }
> > +
> > +       perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
> > +       if (streq(hwclk->init->name, SOCFPGA_MMC_CLK))
> > +               return perpll_src &= 0x3;
> > +       if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
> > +                       streq(hwclk->init->name, SOCFPGA_NAND_X_CLK))
> > +                       return (perpll_src >> 2) & 3;
> > +
> > +       /* QSPI clock */
> > +       return (perpll_src >> 4) & 3;
> > +
> > +}
> > +
> > +static int socfpga_clk_set_parent(struct clk_hw *hwclk, u8 parent)
> > +{
> > +       u32 src_reg;
> > +
> > +       if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
> > +               src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
> > +               src_reg &= ~0x1;
> > +               src_reg |= parent;
> > +               writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
> > +       } else if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
> > +               src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
> > +               src_reg &= ~0x2;
> > +               src_reg |= (parent << 1);
> > +               writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC);
> > +       } else {
> > +               src_reg = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
> > +               if (streq(hwclk->init->name, SOCFPGA_MMC_CLK)) {
> > +                       src_reg &= ~0x3;
> > +                       src_reg |= parent;
> > +               } else if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
> > +                       streq(hwclk->init->name, SOCFPGA_NAND_X_CLK)) {
> > +                       src_reg &= ~0xC;
> > +                       src_reg |= (parent << 2);
> > +               } else {/* QSPI clock */
> > +                       src_reg &= ~0x30;
> > +                       src_reg |= (parent << 4);
> > +               }
> > +               writel(src_reg, clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
> > +       unsigned long parent_rate)
> > +{
> > +       struct socfpga_clk *socfpgaclk = to_socfpga_clk(hwclk);
> > +       u32 div = 1, val;
> > +
> > +       if (socfpgaclk->fixed_div)
> > +               div = socfpgaclk->fixed_div;
> > +       else if (socfpgaclk->div_reg) {
> > +               val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
> > +               val &= div_mask(socfpgaclk->width);
> > +               if (streq(hwclk->init->name, SOCFPGA_DB_CLK))
> > +                       div = val + 1;
> > +               else
> > +                       div = (1 << val);
> > +       }
> > +
> > +       return parent_rate / div;
> > +}
> > +
> > +static struct clk_ops gateclk_ops = {
> > +       .recalc_rate = socfpga_clk_recalc_rate,
> > +       .get_parent = socfpga_clk_get_parent,
> > +       .set_parent = socfpga_clk_set_parent,
> > +};
> > +
> > +static void __init socfpga_gate_clk_init(struct device_node *node,
> > +       const struct clk_ops *ops)
> > +{
> > +       u32 clk_gate[2];
> > +       u32 div_reg[3];
> > +       u32 fixed_div;
> > +       struct clk *clk;
> > +       struct socfpga_clk *socfpga_clk;
> > +       const char *clk_name = node->name;
> > +       const char *parent_name[SOCFGPA_MAX_PARENTS];
> > +       struct clk_init_data init;
> > +       int rc;
> > +       int i = 0;
> > +
> > +       socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
> > +       if (WARN_ON(!socfpga_clk))
> > +               return;
> > +
> > +       rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2);
> > +       if (rc)
> > +               clk_gate[0] = 0;
> > +
> > +       if (clk_gate[0]) {
> > +               socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0];
> > +               socfpga_clk->hw.bit_idx = clk_gate[1];
> > +
> > +               gateclk_ops.enable = clk_gate_ops.enable;
> > +               gateclk_ops.disable = clk_gate_ops.disable;
> > +       }
> > +
> > +       rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
> > +       if (rc)
> > +               socfpga_clk->fixed_div = 0;
> > +       else
> > +               socfpga_clk->fixed_div = fixed_div;
> > +
> > +       rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
> > +       if (!rc) {
> > +               socfpga_clk->div_reg = clk_mgr_base_addr + div_reg[0];
> > +               socfpga_clk->shift = div_reg[1];
> > +               socfpga_clk->width = div_reg[2];
> > +       } else {
> > +               socfpga_clk->div_reg = 0;
> > +       }
> > +
> > +       of_property_read_string(node, "clock-output-names", &clk_name);
> > +
> > +       init.name = clk_name;
> > +       init.ops = ops;
> > +       init.flags = 0;
> > +       while (i < SOCFGPA_MAX_PARENTS && (parent_name[i] =
> > +                       of_clk_get_parent_name(node, i)) != NULL)
> > +               i++;
> > +
> > +       init.parent_names = parent_name;
> > +       init.num_parents = i;
> > +       socfpga_clk->hw.hw.init = &init;
> > +
> > +       clk = clk_register(NULL, &socfpga_clk->hw.hw);
> > +       if (WARN_ON(IS_ERR(clk))) {
> > +               kfree(socfpga_clk);
> > +               return;
> > +       }
> > +       rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
> > +       if (WARN_ON(rc))
> > +               return;
> > +}
> > +
> >  static void __init socfpga_pll_init(struct device_node *node)
> >  {
> >         socfpga_clk_init(node, &clk_pll_ops);
> > @@ -160,6 +330,12 @@ static void __init socfpga_periph_init(struct device_node *node)
> >  }
> >  CLK_OF_DECLARE(socfpga_periph, "altr,socfpga-perip-clk", socfpga_periph_init);
> >  
> > +static void __init socfpga_gate_init(struct device_node *node)
> > +{
> > +       socfpga_gate_clk_init(node, &gateclk_ops);
> > +}
> > +CLK_OF_DECLARE(socfpga_gate, "altr,socfpga-gate-clk", socfpga_gate_init);
> > +
> >  void __init socfpga_init_clocks(void)
> >  {
> >         struct clk *clk;
> > -- 
> > 1.7.9.5
> 

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

end of thread, other threads:[~2013-05-30 21:33 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-24 15:41 [PATCHv4 1/6] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA dinguyen at altera.com
2013-05-24 15:41 ` [PATCHv4 2/6] ARM: socfpga: dts: Add gate-clock bindings dinguyen at altera.com
2013-05-24 15:41 ` [PATCHv4 3/6] ARM: socfpga: Add support to gate peripheral clocks dinguyen at altera.com
2013-05-30 19:42   ` Mike Turquette
2013-05-30 21:33     ` Dinh Nguyen
2013-05-24 15:41 ` [PATCHv4 4/6] ARM: socfpga: Add syscon to be part of socfpga dinguyen at altera.com
2013-05-24 15:41 ` [PATCHv4 5/6] ARM: socfpga: dts: Add support for SD/MMC dinguyen at altera.com
2013-05-24 15:41 ` [PATCHv4 6/6] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA dinguyen at altera.com
2013-05-24 17:10   ` Arnd Bergmann
2013-05-24 17:12     ` Arnd Bergmann
2013-05-24 18:03       ` Dinh Nguyen
2013-05-24 18:58         ` Arnd Bergmann
2013-05-26 18:11           ` Pavel Machek

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