* [PATCH 2/5] ARM: socfpga: dts: Add gate-clock bindings
2013-05-14 22:52 [PATCH 1/5] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA dinguyen at altera.com
@ 2013-05-14 22:52 ` dinguyen at altera.com
2013-05-15 13:06 ` Pavel Machek
2013-05-14 22:52 ` [PATCH 3/5] ARM: socfpga: Add support to gate peripheral clocks dinguyen at altera.com
` (4 subsequent siblings)
5 siblings, 1 reply; 18+ messages in thread
From: dinguyen at altera.com @ 2013-05-14 22:52 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>
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 c42f835..ee8d1f1 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] 18+ messages in thread* [PATCH 3/5] ARM: socfpga: Add support to gate peripheral clocks
2013-05-14 22:52 [PATCH 1/5] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA dinguyen at altera.com
2013-05-14 22:52 ` [PATCH 2/5] ARM: socfpga: dts: Add gate-clock bindings dinguyen at altera.com
@ 2013-05-14 22:52 ` dinguyen at altera.com
2013-05-15 13:58 ` Pavel Machek
2013-05-14 22:52 ` [PATCH 4/5] ARM: socfpga: dts: Add support for SD/MMC dinguyen at altera.com
` (3 subsequent siblings)
5 siblings, 1 reply; 18+ messages in thread
From: dinguyen at altera.com @ 2013-05-14 22:52 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>
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>
---
drivers/clk/socfpga/clk.c | 182 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 180 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/socfpga/clk.c b/drivers/clk/socfpga/clk.c
index bd11315..a0551f2 100644
--- a/drivers/clk/socfpga/clk.c
+++ b/drivers/clk/socfpga/clk.c
@@ -26,6 +26,8 @@
/* Clock Manager offsets */
#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)
@@ -41,6 +43,16 @@
#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)
extern void __iomem *clk_mgr_base_addr;
@@ -49,6 +61,9 @@ struct socfpga_clk {
char *parent_name;
char *clk_name;
u32 fixed_div;
+ void __iomem *div_reg;
+ u32 width;
+ u32 shift;
};
#define to_socfpga_clk(p) container_of(p, struct socfpga_clk, hw.hw)
@@ -132,8 +147,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 (strcmp(clk_name, "main_pll") == 0 ||
+ strcmp(clk_name, "periph_pll") == 0 ||
+ strcmp(clk_name, "sdram_pll") == 0) {
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 +164,162 @@ 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;
+ u8 parent;
+
+ if (strcmp(hwclk->init->name, SOCFPGA_L4_MP_CLK) == 0) {
+ l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
+ l4_src &= 0x1;
+ parent = l4_src;
+ } else if (strcmp(hwclk->init->name, SOCFPGA_L4_SP_CLK) == 0) {
+ l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
+ l4_src = ((l4_src & 0x2) >> 1);
+ parent = l4_src;
+ } else {
+ perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
+ if (strcmp(hwclk->init->name, SOCFPGA_MMC_CLK) == 0)
+ perpll_src &= 0x3;
+ else if (strcmp(hwclk->init->name, SOCFPGA_NAND_CLK) == 0 ||
+ strcmp(hwclk->init->name, SOCFPGA_NAND_X_CLK) == 0)
+ perpll_src = ((perpll_src & 0xC) >> 2);
+ else /*QSPI clock */
+ perpll_src = ((perpll_src & 0x30) >> 4);
+ parent = perpll_src;
+ }
+
+ return parent;
+}
+
+static int socfpga_clk_set_parent(struct clk_hw *hwclk, u8 parent)
+{
+ u32 src_reg;
+
+ if (strcmp(hwclk->init->name, SOCFPGA_L4_MP_CLK) == 0) {
+ 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 (strcmp(hwclk->init->name, SOCFPGA_L4_SP_CLK) == 0) {
+ 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 (strcmp(hwclk->init->name, SOCFPGA_MMC_CLK) == 0) {
+ src_reg &= ~0x3;
+ src_reg |= parent;
+ } else if (strcmp(hwclk->init->name, SOCFPGA_NAND_CLK) == 0 ||
+ strcmp(hwclk->init->name, SOCFPGA_NAND_X_CLK) == 0) {
+ 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 (strcmp(hwclk->init->name, SOCFPGA_DB_CLK) == 0)
+ 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;
+
+ rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
+ if (rc)
+ socfpga_clk->fixed_div = 0;
+ else
+ socfpga_clk->fixed_div = fixed_div;
+
+ 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_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 +332,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] 18+ messages in thread* [PATCH 3/5] ARM: socfpga: Add support to gate peripheral clocks
2013-05-14 22:52 ` [PATCH 3/5] ARM: socfpga: Add support to gate peripheral clocks dinguyen at altera.com
@ 2013-05-15 13:58 ` Pavel Machek
0 siblings, 0 replies; 18+ messages in thread
From: Pavel Machek @ 2013-05-15 13:58 UTC (permalink / raw)
To: linux-arm-kernel
Hi!
> 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>
> 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>
> @@ -132,8 +147,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 (strcmp(clk_name, "main_pll") == 0 ||
> + strcmp(clk_name, "periph_pll") == 0 ||
> + strcmp(clk_name, "sdram_pll") == 0) {
> 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;
Perhaps do
#define streq(a, b) (strcmp((a), (b)) == 0)
and use that to simplify the conditions?
Actually, here are suggested cleanups. Note that there are two FIXMEs
-- I could not understand why the code is safe, and that the BUG_ON()s
are commented on. AFAICT I got them correct, but for some reason they
seem to trigger.
Thanks,
Pavel
diff --git a/drivers/clk/socfpga/clk.c b/drivers/clk/socfpga/clk.c
index a0551f2..ddb340d 100644
--- a/drivers/clk/socfpga/clk.c
+++ b/drivers/clk/socfpga/clk.c
@@ -24,17 +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
@@ -45,14 +45,16 @@
#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_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 SOCFPGA_QSPI_CLK "qspi_clk"
#define div_mask(width) ((1 << (width)) - 1)
+#define streq(a, b) (strcmp((a), (b)) == 0)
extern void __iomem *clk_mgr_base_addr;
@@ -62,8 +64,8 @@ struct socfpga_clk {
char *clk_name;
u32 fixed_div;
void __iomem *div_reg;
- u32 width;
- u32 shift;
+ 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)
@@ -145,11 +147,12 @@ static __init struct clk *socfpga_clk_init(struct device_node *node,
init.parent_names = &parent_name;
init.num_parents = 1;
+ // FIXME: assigning automatic variable ptr into malloced structure?
socfpga_clk->hw.hw.init = &init;
- if (strcmp(clk_name, "main_pll") == 0 ||
- strcmp(clk_name, "periph_pll") == 0 ||
- strcmp(clk_name, "sdram_pll") == 0) {
+ 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;
@@ -168,61 +171,57 @@ static u8 socfpga_clk_get_parent(struct clk_hw *hwclk)
{
u32 l4_src;
u32 perpll_src;
- u8 parent;
- if (strcmp(hwclk->init->name, SOCFPGA_L4_MP_CLK) == 0) {
+ if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) {
l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
- l4_src &= 0x1;
- parent = l4_src;
- } else if (strcmp(hwclk->init->name, SOCFPGA_L4_SP_CLK) == 0) {
+ return l4_src & 1;
+ }
+ if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) {
l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC);
- l4_src = ((l4_src & 0x2) >> 1);
- parent = l4_src;
- } else {
- perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC);
- if (strcmp(hwclk->init->name, SOCFPGA_MMC_CLK) == 0)
- perpll_src &= 0x3;
- else if (strcmp(hwclk->init->name, SOCFPGA_NAND_CLK) == 0 ||
- strcmp(hwclk->init->name, SOCFPGA_NAND_X_CLK) == 0)
- perpll_src = ((perpll_src & 0xC) >> 2);
- else /*QSPI clock */
- perpll_src = ((perpll_src & 0x30) >> 4);
- parent = perpll_src;
+ 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 & 3;
+ if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
+ streq(hwclk->init->name, SOCFPGA_NAND_X_CLK))
+ return (perpll_src >> 2) & 3;
+
+ /* else QSPI clock */
+// BUG_ON(!streq(hwclk->init->name, SOCFPGA_QSPI_CLK));
+ return (perpll_src >> 4) & 3;
+}
- return parent;
+static int clrsetbits(u32 adr, u32 clr, u32 set)
+{
+ u32 reg;
+
+ reg = readl(adr);
+ reg &= ~clr;
+ reg |= set;
+ writel(reg, adr);
+ return 0;
}
static int socfpga_clk_set_parent(struct clk_hw *hwclk, u8 parent)
{
- u32 src_reg;
-
- if (strcmp(hwclk->init->name, SOCFPGA_L4_MP_CLK) == 0) {
- 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 (strcmp(hwclk->init->name, SOCFPGA_L4_SP_CLK) == 0) {
- 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 (strcmp(hwclk->init->name, SOCFPGA_MMC_CLK) == 0) {
- src_reg &= ~0x3;
- src_reg |= parent;
- } else if (strcmp(hwclk->init->name, SOCFPGA_NAND_CLK) == 0 ||
- strcmp(hwclk->init->name, SOCFPGA_NAND_X_CLK) == 0) {
- 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);
- }
+// BUG_ON(parent & ~3);
+
+ if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK))
+ return clrsetbits(clk_mgr_base_addr + CLKMGR_L4SRC, 1, parent);
+ if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK))
+ return clrsetbits(clk_mgr_base_addr + CLKMGR_L4SRC, 2, parent << 1);
+ if (streq(hwclk->init->name, SOCFPGA_MMC_CLK))
+ return clrsetbits(clk_mgr_base_addr + CLKMGR_PERPLL_SRC, 3, parent);
+ if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) ||
+ streq(hwclk->init->name, SOCFPGA_NAND_X_CLK))
+ return clrsetbits(clk_mgr_base_addr + CLKMGR_PERPLL_SRC, 0xC, parent << 2);
+
+ /* else QSPI clock */
+// BUG_ON(!streq(hwclk->init->name, SOCFPGA_QSPI_CLK));
+
+ clrsetbits(clk_mgr_base_addr + CLKMGR_PERPLL_SRC, 0x30, parent << 4);
return 0;
}
@@ -237,7 +236,7 @@ static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
else if (socfpgaclk->div_reg) {
val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
val &= div_mask(socfpgaclk->width);
- if (strcmp(hwclk->init->name, SOCFPGA_DB_CLK) == 0)
+ if (streq(hwclk->init->name, SOCFPGA_DB_CLK))
div = val + 1;
else
div = (1 << val);
@@ -273,13 +272,6 @@ static void __init socfpga_gate_clk_init(struct device_node *node,
rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2);
if (rc)
clk_gate[0] = 0;
-
- rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
- if (rc)
- socfpga_clk->fixed_div = 0;
- else
- socfpga_clk->fixed_div = fixed_div;
-
if (clk_gate[0]) {
socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0];
socfpga_clk->hw.bit_idx = clk_gate[1];
@@ -288,6 +280,12 @@ static void __init socfpga_gate_clk_init(struct device_node *node,
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];
@@ -302,12 +300,17 @@ static void __init socfpga_gate_clk_init(struct device_node *node,
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)
+ while (i < SOCFGPA_MAX_PARENTS) {
+ char *name = of_clk_get_parent_name(node, i);
+ parent_name[i] = name;
+ if (name == NULL)
+ break;
i++;
+ }
init.parent_names = parent_name;
init.num_parents = i;
+ // FIXME: assigning automatic variable ptr into malloced structure?
socfpga_clk->hw.hw.init = &init;
clk = clk_register(NULL, &socfpga_clk->hw.hw);
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 4/5] ARM: socfpga: dts: Add support for SD/MMC
2013-05-14 22:52 [PATCH 1/5] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA dinguyen at altera.com
2013-05-14 22:52 ` [PATCH 2/5] ARM: socfpga: dts: Add gate-clock bindings dinguyen at altera.com
2013-05-14 22:52 ` [PATCH 3/5] ARM: socfpga: Add support to gate peripheral clocks dinguyen at altera.com
@ 2013-05-14 22:52 ` dinguyen at altera.com
2013-05-15 13:05 ` Pavel Machek
2013-05-14 22:52 ` [PATCH 5/5] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA dinguyen at altera.com
` (2 subsequent siblings)
5 siblings, 1 reply; 18+ messages in thread
From: dinguyen at altera.com @ 2013-05-14 22:52 UTC (permalink / raw)
To: linux-arm-kernel
From: Dinh Nguyen <dinguyen@altera.com>
Add bindings for SD/MMC for SOCFPGA.
Signed-off-by: Dinh Nguyen <dinguyen@altera.com>
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/mmc/socfpga-dw-mshc.txt | 59 ++++++++++++++++++++
arch/arm/boot/dts/socfpga.dtsi | 11 ++++
arch/arm/boot/dts/socfpga_cyclone5.dts | 13 +++++
arch/arm/boot/dts/socfpga_vt.dts | 13 +++++
4 files changed, 96 insertions(+)
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..f4fda57
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt
@@ -0,0 +1,59 @@
+* 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. For Altera's SOCFPGA, the divider value is fixed at 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 = <4>;
+ 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 ee8d1f1..6138edf 100644
--- a/arch/arm/boot/dts/socfpga.dtsi
+++ b/arch/arm/boot/dts/socfpga.dtsi
@@ -466,6 +466,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";
diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dts b/arch/arm/boot/dts/socfpga_cyclone5.dts
index ece1a87..dcb8c3a 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5.dts
@@ -57,6 +57,19 @@
phy-addr = <0xffffffff>; /* probe for phy addr */
};
+ dwmmc0 at ff704000 {
+ num-slots = <1>;
+ supports-highspeed;
+ broken-cd;
+ altr,dw-mshc-ciu-div = <4>;
+ 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 f728471..1aec566 100644
--- a/arch/arm/boot/dts/socfpga_vt.dts
+++ b/arch/arm/boot/dts/socfpga_vt.dts
@@ -49,6 +49,19 @@
status = "disabled";
};
+ dwmmc0 at ff704000 {
+ num-slots = <1>;
+ supports-highspeed;
+ broken-cd;
+ altr,dw-mshc-ciu-div = <4>;
+ pwr-en = <1>;
+
+ slot at 0 {
+ reg = <0>;
+ bus-width = <4>;
+ };
+ };
+
timer0 at ffc08000 {
clock-frequency = <7000000>;
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 4/5] ARM: socfpga: dts: Add support for SD/MMC
2013-05-14 22:52 ` [PATCH 4/5] ARM: socfpga: dts: Add support for SD/MMC dinguyen at altera.com
@ 2013-05-15 13:05 ` Pavel Machek
0 siblings, 0 replies; 18+ messages in thread
From: Pavel Machek @ 2013-05-15 13:05 UTC (permalink / raw)
To: linux-arm-kernel
Hi!
> From: Dinh Nguyen <dinguyen@altera.com>
>
> Add bindings for SD/MMC for SOCFPGA.
>
> Signed-off-by: Dinh Nguyen <dinguyen@altera.com>
> CC: Arnd Bergmann <arnd@arndb.de>
> CC: Olof Johansson <olof@lixom.net>
> CC: Pavel Machek <pavel@denx.de>
> CC: <linux@arm.linux.org.uk>
git says:
[pavel at pollux linux]$ cat /tmp/delme | git apply
<stdin>:136: space before tab in indent.
altr,dw-mshc-sdr-timing = <0 3>;
<stdin>:143: new blank line at EOF.
+
warning: 2 lines add whitespace errors.
[pavel at pollux linux]$
Is this patch series expected to be enough to get MMC to work? I
applied all 5 patches, and it detects the controller, but mmcblkX
devices do not show up.
Synopsys Designware Multimedia Card Interface Driver
dwmmc_socfpga ff704000.dwmmc0: couldn't determine pwr-en, assuming
pwr-en = 0
dwmmc_socfpga ff704000.dwmmc0: Using internal DMA controller.
dwmmc_socfpga ff704000.dwmmc0: Version ID is 240a
dwmmc_socfpga ff704000.dwmmc0: DW MMC controller at irq 171, 32 bit
host data width, 1024 deep fifo
mmc_host mmc0: Bus speed (slot 0) = 100000000Hz (slot req 400000Hz,
actual 400000HZ div = 125)
...
VFS: Unable to mount root fs via NFS, trying floppy.
VFS: Cannot open root device "nfs" or unknown-block(2,0): error -6
Please append a correct "root=" boot option; here are the available
partitions:
Kernel panic - not syncing: VFS: Unable to mount root fs on
unknown-block(2,0)
It should be configured in:
CONFIG_MMC_BLOCK=y
CONFIG_MMC_BLOCK_MINORS=8
CONFIG_MMC_BLOCK_BOUNCE=y
.
Otherwise, it looks good.
Reviewed-by: Pavel Machek <pavel@denx.de>
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] 18+ messages in thread
* [PATCH 5/5] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
2013-05-14 22:52 [PATCH 1/5] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA dinguyen at altera.com
` (2 preceding siblings ...)
2013-05-14 22:52 ` [PATCH 4/5] ARM: socfpga: dts: Add support for SD/MMC dinguyen at altera.com
@ 2013-05-14 22:52 ` dinguyen at altera.com
2013-05-15 4:28 ` Jaehoon Chung
2013-05-15 13:25 ` Arnd Bergmann
2013-05-15 12:43 ` [PATCH 1/5] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA Pavel Machek
2013-05-15 13:19 ` Arnd Bergmann
5 siblings, 2 replies; 18+ messages in thread
From: dinguyen at altera.com @ 2013-05-14 22:52 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
---
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 | 141 +++++++++++++++++++++++++++++++++++++
drivers/mmc/host/dw_mmc.h | 1 +
5 files changed, 151 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..7eb3163
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-socfpga.c
@@ -0,0 +1,141 @@
+/*
+ * 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/mmc/host.h>
+#include <linux/mmc/dw_mmc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.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) \
+ ((((drvsel) << 0) & 0x7) | (((smplsel) << 3) & 0x38))
+
+extern void __iomem *sys_manager_base_addr;
+
+/* SOCFPGA implementation specific driver private data */
+struct dw_mci_socfpga_priv_data {
+ u8 ciu_div;
+ u32 hs_timing;
+};
+
+static int dw_mci_socfpga_priv_init(struct dw_mci *host)
+{
+ struct dw_mci_socfpga_priv_data *priv;
+ struct device *dev = host->dev;
+ int pwr_en;
+
+ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(host->dev, "mem alloc failed for private data\n");
+ return -ENOMEM;
+ }
+
+ host->priv = priv;
+
+ if (of_property_read_u32(dev->of_node, "pwr-en", &pwr_en)) {
+ dev_info(dev, "couldn't determine pwr-en, assuming pwr-en = 0\n");
+ pwr_en = 0;
+ }
+
+ /* Set PWREN bit */
+ mci_writel(host, PWREN, pwr_en);
+
+ return 0;
+}
+
+static int dw_mci_socfpga_setup_clock(struct dw_mci *host)
+{
+ struct dw_mci_socfpga_priv_data *priv = host->priv;
+
+ clk_disable(host->ciu_clk);
+ writel(priv->hs_timing, sys_manager_base_addr +
+ SYSMGR_SDMMCGRP_CTRL_OFFSET);
+ clk_enable(host->ciu_clk);
+
+ host->bus_hz /= priv->ciu_div;
+ 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;
+
+ of_property_read_u32(np, "altr,dw-mshc-ciu-div", &div);
+ 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] 18+ messages in thread* [PATCH 5/5] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
2013-05-14 22:52 ` [PATCH 5/5] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA dinguyen at altera.com
@ 2013-05-15 4:28 ` Jaehoon Chung
2013-05-15 16:27 ` Dinh Nguyen
2013-05-15 13:25 ` Arnd Bergmann
1 sibling, 1 reply; 18+ messages in thread
From: Jaehoon Chung @ 2013-05-15 4:28 UTC (permalink / raw)
To: linux-arm-kernel
On 05/15/2013 07:52 AM, 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.
>
> 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
> ---
> 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 | 141 +++++++++++++++++++++++++++++++++++++
> drivers/mmc/host/dw_mmc.h | 1 +
> 5 files changed, 151 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
SOCFPGA? I think good that should be changed more generic.
> + 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..7eb3163
> --- /dev/null
> +++ b/drivers/mmc/host/dw_mmc-socfpga.c
> @@ -0,0 +1,141 @@
> +/*
> + * 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/mmc/host.h>
> +#include <linux/mmc/dw_mmc.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +
> +#include "dw_mmc.h"
> +#include "dw_mmc-pltfm.h"
> +
> +#define SYSMGR_SDMMCGRP_CTRL_OFFSET 0x108
Is it vendor specific register offset?
> +#define DRV_CLK_PHASE_SHIFT_SEL_MASK 0x7
> +#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \
> + ((((drvsel) << 0) & 0x7) | (((smplsel) << 3) & 0x38))
Change more readable. ((drvsel & 0x7) << 0 | (smplsel & 0x7) << 3)?
> +
> +extern void __iomem *sys_manager_base_addr;
> +
> +/* SOCFPGA implementation specific driver private data */
> +struct dw_mci_socfpga_priv_data {
> + u8 ciu_div;
> + u32 hs_timing;
> +};
> +
> +static int dw_mci_socfpga_priv_init(struct dw_mci *host)
> +{
> + struct dw_mci_socfpga_priv_data *priv;
> + struct device *dev = host->dev;
> + int pwr_en;
> +
> + priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv) {
> + dev_err(host->dev, "mem alloc failed for private data\n");
> + return -ENOMEM;
> + }
> +
> + host->priv = priv;
> +
> + if (of_property_read_u32(dev->of_node, "pwr-en", &pwr_en)) {
> + dev_info(dev, "couldn't determine pwr-en, assuming pwr-en = 0\n");
> + pwr_en = 0;
> + }
> +
> + /* Set PWREN bit */
> + mci_writel(host, PWREN, pwr_en);
What is this setting? In dw-mmc.c, PWREN register should be set.
> +
> + return 0;
> +}
> +
> +static int dw_mci_socfpga_setup_clock(struct dw_mci *host)
> +{
> + struct dw_mci_socfpga_priv_data *priv = host->priv;
> +
> + clk_disable(host->ciu_clk);
> + writel(priv->hs_timing, sys_manager_base_addr +
> + SYSMGR_SDMMCGRP_CTRL_OFFSET);
> + clk_enable(host->ciu_clk);
Why do you use the clk_disable/enable at this point?
> +
> + host->bus_hz /= priv->ciu_div;
Didn't consider the "divide by zero"?
> + 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;
> +
> + of_property_read_u32(np, "altr,dw-mshc-ciu-div", &div);
> + 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)
>
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH 5/5] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
2013-05-15 4:28 ` Jaehoon Chung
@ 2013-05-15 16:27 ` Dinh Nguyen
0 siblings, 0 replies; 18+ messages in thread
From: Dinh Nguyen @ 2013-05-15 16:27 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
On 05/14/2013 11:28 PM, Jaehoon Chung wrote:
> On 05/15/2013 07:52 AM, 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.
>>
>> 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
>> ---
>> 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 | 141 +++++++++++++++++++++++++++++++++++++
>> drivers/mmc/host/dw_mmc.h | 1 +
>> 5 files changed, 151 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
> SOCFPGA? I think good that should be changed more generic.
Not sure what you mean? SOCFPGA is the name of new ARM SOCs from Altera.
>> + 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..7eb3163
>> --- /dev/null
>> +++ b/drivers/mmc/host/dw_mmc-socfpga.c
>> @@ -0,0 +1,141 @@
>> +/*
>> + * 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/mmc/host.h>
>> +#include <linux/mmc/dw_mmc.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +
>> +#include "dw_mmc.h"
>> +#include "dw_mmc-pltfm.h"
>> +
>> +#define SYSMGR_SDMMCGRP_CTRL_OFFSET 0x108
> Is it vendor specific register offset?
>> +#define DRV_CLK_PHASE_SHIFT_SEL_MASK 0x7
>> +#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \
>> + ((((drvsel) << 0) & 0x7) | (((smplsel) << 3) & 0x38))
> Change more readable. ((drvsel & 0x7) << 0 | (smplsel & 0x7) << 3)?
>> +
>> +extern void __iomem *sys_manager_base_addr;
>> +
>> +/* SOCFPGA implementation specific driver private data */
>> +struct dw_mci_socfpga_priv_data {
>> + u8 ciu_div;
>> + u32 hs_timing;
>> +};
>> +
>> +static int dw_mci_socfpga_priv_init(struct dw_mci *host)
>> +{
>> + struct dw_mci_socfpga_priv_data *priv;
>> + struct device *dev = host->dev;
>> + int pwr_en;
>> +
>> + priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
>> + if (!priv) {
>> + dev_err(host->dev, "mem alloc failed for private data\n");
>> + return -ENOMEM;
>> + }
>> +
>> + host->priv = priv;
>> +
>> + if (of_property_read_u32(dev->of_node, "pwr-en", &pwr_en)) {
>> + dev_info(dev, "couldn't determine pwr-en, assuming pwr-en = 0\n");
>> + pwr_en = 0;
>> + }
>> +
>> + /* Set PWREN bit */
>> + mci_writel(host, PWREN, pwr_en);
> What is this setting? In dw-mmc.c, PWREN register should be set.
Ah..it was there before 3.9...I will adjust accordingly.
>> +
>> + return 0;
>> +}
>> +
>> +static int dw_mci_socfpga_setup_clock(struct dw_mci *host)
>> +{
>> + struct dw_mci_socfpga_priv_data *priv = host->priv;
>> +
>> + clk_disable(host->ciu_clk);
>> + writel(priv->hs_timing, sys_manager_base_addr +
>> + SYSMGR_SDMMCGRP_CTRL_OFFSET);
>> + clk_enable(host->ciu_clk);
> Why do you use the clk_disable/enable at this point?
Our implementation of the controller requires us to disable the clock
when we adjust the timing parameter.
>> +
>> + host->bus_hz /= priv->ciu_div;
> Didn't consider the "divide by zero"?
Will fix..
Thanks alot for the review.
Dinh
>> + 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;
>> +
>> + of_property_read_u32(np, "altr,dw-mshc-ciu-div", &div);
>> + 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)
>>
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 5/5] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
2013-05-14 22:52 ` [PATCH 5/5] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA dinguyen at altera.com
2013-05-15 4:28 ` Jaehoon Chung
@ 2013-05-15 13:25 ` Arnd Bergmann
2013-05-15 16:40 ` Dinh Nguyen
1 sibling, 1 reply; 18+ messages in thread
From: Arnd Bergmann @ 2013-05-15 13:25 UTC (permalink / raw)
To: linux-arm-kernel
On Wednesday 15 May 2013, dinguyen at altera.com wrote:
> +
> +#define SYSMGR_SDMMCGRP_CTRL_OFFSET 0x108
> +#define DRV_CLK_PHASE_SHIFT_SEL_MASK 0x7
> +#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \
> + ((((drvsel) << 0) & 0x7) | (((smplsel) << 3) & 0x38))
> +
> +extern void __iomem *sys_manager_base_addr;
This is not acceptable, you cannot just reference external symbols
from one driver in another, without a proper interface.
Please explain what the functionality is that you need here, then
we can help you find the proper interface. My guess is that you
need either the functionality provided by drivers/reset/
or drivers/mfd/syscon.c.
> + if (of_property_read_u32(dev->of_node, "pwr-en", &pwr_en)) {
> + dev_info(dev, "couldn't determine pwr-en, assuming pwr-en = 0\n");
> + pwr_en = 0;
> + }
> +
> + /* Set PWREN bit */
> + mci_writel(host, PWREN, pwr_en);
If you add new properties, you have to document them in
Documentations/devicetree/bindings/*.
What is the requirement for this property? Is there no way to
automatically power the card on/off using the normal
dw_mci_set_ios function?
The rest of this patch looks ok to me.
Arnd
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH 5/5] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
2013-05-15 13:25 ` Arnd Bergmann
@ 2013-05-15 16:40 ` Dinh Nguyen
2013-05-15 17:11 ` Arnd Bergmann
0 siblings, 1 reply; 18+ messages in thread
From: Dinh Nguyen @ 2013-05-15 16:40 UTC (permalink / raw)
To: linux-arm-kernel
Hi Arnd,
Thanks for the review.
On 05/15/2013 08:25 AM, Arnd Bergmann wrote:
> On Wednesday 15 May 2013, dinguyen at altera.com wrote:
>> +
>> +#define SYSMGR_SDMMCGRP_CTRL_OFFSET 0x108
>> +#define DRV_CLK_PHASE_SHIFT_SEL_MASK 0x7
>> +#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \
>> + ((((drvsel) << 0) & 0x7) | (((smplsel) << 3) & 0x38))
>> +
>> +extern void __iomem *sys_manager_base_addr;
>
> This is not acceptable, you cannot just reference external symbols
> from one driver in another, without a proper interface.
>
> Please explain what the functionality is that you need here, then
> we can help you find the proper interface. My guess is that you
> need either the functionality provided by drivers/reset/
> or drivers/mfd/syscon.c.
Our implementation has the timing controls for the SD/MMC controller in
another custom IP block(system manager). sys_manager_base_addr was
mapped in mach-socfpga/socfpga.c. I saw the same approach with
drivers/clk(clk_mgr_base_addr), so I thought it would be ok with this
driver. Please advise on another way to do this...
>
>> + if (of_property_read_u32(dev->of_node, "pwr-en", &pwr_en)) {
>> + dev_info(dev, "couldn't determine pwr-en, assuming pwr-en = 0\n");
>> + pwr_en = 0;
>> + }
>> +
>> + /* Set PWREN bit */
>> + mci_writel(host, PWREN, pwr_en);
>
> If you add new properties, you have to document them in
> Documentations/devicetree/bindings/*.
>
> What is the requirement for this property? Is there no way to
> automatically power the card on/off using the normal
> dw_mci_set_ios function?
Apologies...it wasn't there in 3.8. I will fix...
Thanks,
Dinh
>
> The rest of this patch looks ok to me.
>
> Arnd
>
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH 5/5] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
2013-05-15 16:40 ` Dinh Nguyen
@ 2013-05-15 17:11 ` Arnd Bergmann
2013-05-15 19:18 ` Dinh Nguyen
0 siblings, 1 reply; 18+ messages in thread
From: Arnd Bergmann @ 2013-05-15 17:11 UTC (permalink / raw)
To: linux-arm-kernel
On Wednesday 15 May 2013 11:40:12 Dinh Nguyen wrote:
> On 05/15/2013 08:25 AM, Arnd Bergmann wrote:
> > On Wednesday 15 May 2013, dinguyen at altera.com wrote:
> >> +
> >> +#define SYSMGR_SDMMCGRP_CTRL_OFFSET 0x108
> >> +#define DRV_CLK_PHASE_SHIFT_SEL_MASK 0x7
> >> +#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \
> >> + ((((drvsel) << 0) & 0x7) | (((smplsel) << 3) & 0x38))
> >> +
> >> +extern void __iomem *sys_manager_base_addr;
> >
> > This is not acceptable, you cannot just reference external symbols
> > from one driver in another, without a proper interface.
> >
> > Please explain what the functionality is that you need here, then
> > we can help you find the proper interface. My guess is that you
> > need either the functionality provided by drivers/reset/
> > or drivers/mfd/syscon.c.
>
> Our implementation has the timing controls for the SD/MMC controller in
> another custom IP block(system manager). sys_manager_base_addr was
> mapped in mach-socfpga/socfpga.c. I saw the same approach with
> drivers/clk(clk_mgr_base_addr), so I thought it would be ok with this
> driver. Please advise on another way to do this...
The clock code is tied more more closely to the platform code, so I
was turning a blind eye on that one, under the assumption that it
was only used there.
Arnd
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 5/5] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
2013-05-15 17:11 ` Arnd Bergmann
@ 2013-05-15 19:18 ` Dinh Nguyen
0 siblings, 0 replies; 18+ messages in thread
From: Dinh Nguyen @ 2013-05-15 19:18 UTC (permalink / raw)
To: linux-arm-kernel
Hi Arnd,
On 05/15/2013 12:11 PM, Arnd Bergmann wrote:
> On Wednesday 15 May 2013 11:40:12 Dinh Nguyen wrote:
>> On 05/15/2013 08:25 AM, Arnd Bergmann wrote:
>>> On Wednesday 15 May 2013, dinguyen at altera.com wrote:
>>>> +
>>>> +#define SYSMGR_SDMMCGRP_CTRL_OFFSET 0x108
>>>> +#define DRV_CLK_PHASE_SHIFT_SEL_MASK 0x7
>>>> +#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \
>>>> + ((((drvsel) << 0) & 0x7) | (((smplsel) << 3) & 0x38))
>>>> +
>>>> +extern void __iomem *sys_manager_base_addr;
>>>
>>> This is not acceptable, you cannot just reference external symbols
>>> from one driver in another, without a proper interface.
>>>
>>> Please explain what the functionality is that you need here, then
>>> we can help you find the proper interface. My guess is that you
>>> need either the functionality provided by drivers/reset/
>>> or drivers/mfd/syscon.c.
>>
>> Our implementation has the timing controls for the SD/MMC controller in
>> another custom IP block(system manager). sys_manager_base_addr was
>> mapped in mach-socfpga/socfpga.c. I saw the same approach with
>> drivers/clk(clk_mgr_base_addr), so I thought it would be ok with this
>> driver. Please advise on another way to do this...
>
> The clock code is tied more more closely to the platform code, so I
> was turning a blind eye on that one, under the assumption that it
> was only used there.
I think I can use the syscon interface for this. Thanks for the pointer.
I kinda thought that these dw_mmc-<platform> is platform specific
enough, but I will go the syscon route.
Dinh
>
> Arnd
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 1/5] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA
2013-05-14 22:52 [PATCH 1/5] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA dinguyen at altera.com
` (3 preceding siblings ...)
2013-05-14 22:52 ` [PATCH 5/5] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA dinguyen at altera.com
@ 2013-05-15 12:43 ` Pavel Machek
2013-05-15 16:44 ` Dinh Nguyen
2013-05-15 13:19 ` Arnd Bergmann
5 siblings, 1 reply; 18+ messages in thread
From: Pavel Machek @ 2013-05-15 12:43 UTC (permalink / raw)
To: linux-arm-kernel
On Tue 2013-05-14 17:52:31, dinguyen at altera.com wrote:
> 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>
> 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 good.
Reviewed-by: Pavel Machek <pavel@denx.de>
...but, this patch is not enough to get ethernet to work with
3.10-rc1, right? I hoped that applying 1-3 of the series would get me
ethernet, but no :-(.
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] 18+ messages in thread* [PATCH 1/5] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA
2013-05-15 12:43 ` [PATCH 1/5] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA Pavel Machek
@ 2013-05-15 16:44 ` Dinh Nguyen
0 siblings, 0 replies; 18+ messages in thread
From: Dinh Nguyen @ 2013-05-15 16:44 UTC (permalink / raw)
To: linux-arm-kernel
Hi Pavel,
Thanks for the review...
On 05/15/2013 07:43 AM, Pavel Machek wrote:
> On Tue 2013-05-14 17:52:31, dinguyen at altera.com wrote:
>> 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>
>> 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 good.
>
> Reviewed-by: Pavel Machek <pavel@denx.de>
>
> ...but, this patch is not enough to get ethernet to work with
> 3.10-rc1, right? I hoped that applying 1-3 of the series would get me
> ethernet, but no :-(.
Yes, this fixes a build error for socfpga_defconfig in 3.10-rc1. I'll
send a patch to enable ethernet after these patches are accepted.
Dinh
>
> Thanks,
> Pavel
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 1/5] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA
2013-05-14 22:52 [PATCH 1/5] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA dinguyen at altera.com
` (4 preceding siblings ...)
2013-05-15 12:43 ` [PATCH 1/5] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA Pavel Machek
@ 2013-05-15 13:19 ` Arnd Bergmann
2013-05-15 16:44 ` Dinh Nguyen
5 siblings, 1 reply; 18+ messages in thread
From: Arnd Bergmann @ 2013-05-15 13:19 UTC (permalink / raw)
To: linux-arm-kernel
On Wednesday 15 May 2013, dinguyen at altera.com wrote:
> };
>
> + ethernet at ff700000 {
> + phy-mode = "gmii";
> + };
> +
> + ethernet at ff702000 {
> + status = "disabled";
> + };
By convention, please mark the controllers as "disabled" in the main .dtsi file
and only enable them in the board specific files when used, rather than the
other way round.
Arnd
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH 1/5] ARM: socfpga: dts: Add ethernet bindings for SOCFPGA
2013-05-15 13:19 ` Arnd Bergmann
@ 2013-05-15 16:44 ` Dinh Nguyen
0 siblings, 0 replies; 18+ messages in thread
From: Dinh Nguyen @ 2013-05-15 16:44 UTC (permalink / raw)
To: linux-arm-kernel
Hi Arnd,
On 05/15/2013 08:19 AM, Arnd Bergmann wrote:
> On Wednesday 15 May 2013, dinguyen at altera.com wrote:
>> };
>>
>> + ethernet at ff700000 {
>> + phy-mode = "gmii";
>> + };
>> +
>> + ethernet at ff702000 {
>> + status = "disabled";
>> + };
>
> By convention, please mark the controllers as "disabled" in the main .dtsi file
> and only enable them in the board specific files when used, rather than the
> other way round.
Thanks for the review. Will fix.
Dinh
>
> Arnd
>
^ permalink raw reply [flat|nested] 18+ messages in thread