All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/7] arm: add basic support for Rockchip Cortex-A9 SoCs
@ 2013-06-11 11:28 ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:28 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mike Turquette, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

Third version of basic Rockchip A9 support.

The biggest change is probably the missing pinctrl driver which already found
its way into the pinctrl tree from Linus Walleij as part of the pinconfig
generalisation and should find its way into the mainline kernel from there.
But startup of rk3066-based boards will even suceed without the pinctrl driver
present, as the bootloader sets up the most basic pins like uarts too.


Changes since v2:
- use common (pending review) HIWORD_MASK clock flag from Haojian Zhuang and me
- pinctrl driver is already in the pinctrl tree
- add core-periph clock that supplies the twd
- split "mmc: dw_mmc-pltfm: add Rockchip variant" into move and feature parts
  as suggested by Andy Shevchenko

Changes since v1:
- addressed Linus Walleij's comments to the pinctrl driver, including the
  move to generic pinconfig (hopefully I did catch all)
- renamed the clocks to use the SoC name of the initial user
  as suggested by Olof Johansson
- fixed the uart address, found by Arnd Bergmann
- address Arnd's comments on the board file (use of_clk_init and friends,
  remove map_io, use real soc names)
- removed Makefile.boot as suggested by Thomas Petazzoni


Dependencies:
- the 3 clock changes of "support Hisilicon SoC" from Haojian Zhuang
- "mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA" from Dinh Nguyen that
  moves the SDMMC_CMD_USE_HOLD_REG constant into the common header, which is
  required on these Rockchip SoCs 
- series "dw_apb_timer: osc as sched_clock, clocks and clocksource_of support"


Heiko Stuebner (7):
  clk: divider: add flag to limit possible dividers to even numbers
  mmc: dw_mmc-pltfm: remove static from dw_mci_pltfm_remove
  mmc: dw_mmc-pltfm: move probe and remove below dt match table
  mmc: dw_mmc-pltfm: add Rockchip variant
  clk: add basic Rockchip rk3066a clock support
  arm: add debug uarts for rockchip rk29xx and rk3xxx series
  arm: add basic support for Rockchip RK3066a boards

 arch/arm/Kconfig                        |    2 +
 arch/arm/Kconfig.debug                  |   34 +++
 arch/arm/Makefile                       |    1 +
 arch/arm/boot/dts/rk3066a-clocks.dtsi   |  467 +++++++++++++++++++++++++++++++
 arch/arm/boot/dts/rk3066a.dtsi          |  390 ++++++++++++++++++++++++++
 arch/arm/include/debug/rockchip.S       |   42 +++
 arch/arm/mach-rockchip/Kconfig          |   16 +
 arch/arm/mach-rockchip/Makefile         |    1 +
 arch/arm/mach-rockchip/rockchip.c       |   54 ++++
 drivers/clk/Makefile                    |    1 +
 drivers/clk/clk-divider.c               |   14 +-
 drivers/clk/rockchip/Makefile           |    6 +
 drivers/clk/rockchip/clk-rockchip-pll.c |  131 +++++++++
 drivers/clk/rockchip/clk-rockchip-pll.h |   19 ++
 drivers/clk/rockchip/clk-rockchip.c     |  330 ++++++++++++++++++++++
 drivers/mmc/host/dw_mmc-pltfm.c         |   47 +++-
 include/linux/clk-provider.h            |    2 +
 17 files changed, 1541 insertions(+), 16 deletions(-)
 create mode 100644 arch/arm/boot/dts/rk3066a-clocks.dtsi
 create mode 100644 arch/arm/boot/dts/rk3066a.dtsi
 create mode 100644 arch/arm/include/debug/rockchip.S
 create mode 100644 arch/arm/mach-rockchip/Kconfig
 create mode 100644 arch/arm/mach-rockchip/Makefile
 create mode 100644 arch/arm/mach-rockchip/rockchip.c
 create mode 100644 drivers/clk/rockchip/Makefile
 create mode 100644 drivers/clk/rockchip/clk-rockchip-pll.c
 create mode 100644 drivers/clk/rockchip/clk-rockchip-pll.h
 create mode 100644 drivers/clk/rockchip/clk-rockchip.c

-- 
1.7.2.3


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

* [PATCH v3 0/7] arm: add basic support for Rockchip Cortex-A9 SoCs
@ 2013-06-11 11:28 ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:28 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Mike Turquette, Seungwon Jeon, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Jaehoon Chung,
	Andy Shevchenko, Grant Likely, Russell King, Chris Ball,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

Third version of basic Rockchip A9 support.

The biggest change is probably the missing pinctrl driver which already found
its way into the pinctrl tree from Linus Walleij as part of the pinconfig
generalisation and should find its way into the mainline kernel from there.
But startup of rk3066-based boards will even suceed without the pinctrl driver
present, as the bootloader sets up the most basic pins like uarts too.


Changes since v2:
- use common (pending review) HIWORD_MASK clock flag from Haojian Zhuang and me
- pinctrl driver is already in the pinctrl tree
- add core-periph clock that supplies the twd
- split "mmc: dw_mmc-pltfm: add Rockchip variant" into move and feature parts
  as suggested by Andy Shevchenko

Changes since v1:
- addressed Linus Walleij's comments to the pinctrl driver, including the
  move to generic pinconfig (hopefully I did catch all)
- renamed the clocks to use the SoC name of the initial user
  as suggested by Olof Johansson
- fixed the uart address, found by Arnd Bergmann
- address Arnd's comments on the board file (use of_clk_init and friends,
  remove map_io, use real soc names)
- removed Makefile.boot as suggested by Thomas Petazzoni


Dependencies:
- the 3 clock changes of "support Hisilicon SoC" from Haojian Zhuang
- "mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA" from Dinh Nguyen that
  moves the SDMMC_CMD_USE_HOLD_REG constant into the common header, which is
  required on these Rockchip SoCs 
- series "dw_apb_timer: osc as sched_clock, clocks and clocksource_of support"


Heiko Stuebner (7):
  clk: divider: add flag to limit possible dividers to even numbers
  mmc: dw_mmc-pltfm: remove static from dw_mci_pltfm_remove
  mmc: dw_mmc-pltfm: move probe and remove below dt match table
  mmc: dw_mmc-pltfm: add Rockchip variant
  clk: add basic Rockchip rk3066a clock support
  arm: add debug uarts for rockchip rk29xx and rk3xxx series
  arm: add basic support for Rockchip RK3066a boards

 arch/arm/Kconfig                        |    2 +
 arch/arm/Kconfig.debug                  |   34 +++
 arch/arm/Makefile                       |    1 +
 arch/arm/boot/dts/rk3066a-clocks.dtsi   |  467 +++++++++++++++++++++++++++++++
 arch/arm/boot/dts/rk3066a.dtsi          |  390 ++++++++++++++++++++++++++
 arch/arm/include/debug/rockchip.S       |   42 +++
 arch/arm/mach-rockchip/Kconfig          |   16 +
 arch/arm/mach-rockchip/Makefile         |    1 +
 arch/arm/mach-rockchip/rockchip.c       |   54 ++++
 drivers/clk/Makefile                    |    1 +
 drivers/clk/clk-divider.c               |   14 +-
 drivers/clk/rockchip/Makefile           |    6 +
 drivers/clk/rockchip/clk-rockchip-pll.c |  131 +++++++++
 drivers/clk/rockchip/clk-rockchip-pll.h |   19 ++
 drivers/clk/rockchip/clk-rockchip.c     |  330 ++++++++++++++++++++++
 drivers/mmc/host/dw_mmc-pltfm.c         |   47 +++-
 include/linux/clk-provider.h            |    2 +
 17 files changed, 1541 insertions(+), 16 deletions(-)
 create mode 100644 arch/arm/boot/dts/rk3066a-clocks.dtsi
 create mode 100644 arch/arm/boot/dts/rk3066a.dtsi
 create mode 100644 arch/arm/include/debug/rockchip.S
 create mode 100644 arch/arm/mach-rockchip/Kconfig
 create mode 100644 arch/arm/mach-rockchip/Makefile
 create mode 100644 arch/arm/mach-rockchip/rockchip.c
 create mode 100644 drivers/clk/rockchip/Makefile
 create mode 100644 drivers/clk/rockchip/clk-rockchip-pll.c
 create mode 100644 drivers/clk/rockchip/clk-rockchip-pll.h
 create mode 100644 drivers/clk/rockchip/clk-rockchip.c

-- 
1.7.2.3

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

* [PATCH v3 0/7] arm: add basic support for Rockchip Cortex-A9 SoCs
@ 2013-06-11 11:28 ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:28 UTC (permalink / raw)
  To: linux-arm-kernel

Third version of basic Rockchip A9 support.

The biggest change is probably the missing pinctrl driver which already found
its way into the pinctrl tree from Linus Walleij as part of the pinconfig
generalisation and should find its way into the mainline kernel from there.
But startup of rk3066-based boards will even suceed without the pinctrl driver
present, as the bootloader sets up the most basic pins like uarts too.


Changes since v2:
- use common (pending review) HIWORD_MASK clock flag from Haojian Zhuang and me
- pinctrl driver is already in the pinctrl tree
- add core-periph clock that supplies the twd
- split "mmc: dw_mmc-pltfm: add Rockchip variant" into move and feature parts
  as suggested by Andy Shevchenko

Changes since v1:
- addressed Linus Walleij's comments to the pinctrl driver, including the
  move to generic pinconfig (hopefully I did catch all)
- renamed the clocks to use the SoC name of the initial user
  as suggested by Olof Johansson
- fixed the uart address, found by Arnd Bergmann
- address Arnd's comments on the board file (use of_clk_init and friends,
  remove map_io, use real soc names)
- removed Makefile.boot as suggested by Thomas Petazzoni


Dependencies:
- the 3 clock changes of "support Hisilicon SoC" from Haojian Zhuang
- "mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA" from Dinh Nguyen that
  moves the SDMMC_CMD_USE_HOLD_REG constant into the common header, which is
  required on these Rockchip SoCs 
- series "dw_apb_timer: osc as sched_clock, clocks and clocksource_of support"


Heiko Stuebner (7):
  clk: divider: add flag to limit possible dividers to even numbers
  mmc: dw_mmc-pltfm: remove static from dw_mci_pltfm_remove
  mmc: dw_mmc-pltfm: move probe and remove below dt match table
  mmc: dw_mmc-pltfm: add Rockchip variant
  clk: add basic Rockchip rk3066a clock support
  arm: add debug uarts for rockchip rk29xx and rk3xxx series
  arm: add basic support for Rockchip RK3066a boards

 arch/arm/Kconfig                        |    2 +
 arch/arm/Kconfig.debug                  |   34 +++
 arch/arm/Makefile                       |    1 +
 arch/arm/boot/dts/rk3066a-clocks.dtsi   |  467 +++++++++++++++++++++++++++++++
 arch/arm/boot/dts/rk3066a.dtsi          |  390 ++++++++++++++++++++++++++
 arch/arm/include/debug/rockchip.S       |   42 +++
 arch/arm/mach-rockchip/Kconfig          |   16 +
 arch/arm/mach-rockchip/Makefile         |    1 +
 arch/arm/mach-rockchip/rockchip.c       |   54 ++++
 drivers/clk/Makefile                    |    1 +
 drivers/clk/clk-divider.c               |   14 +-
 drivers/clk/rockchip/Makefile           |    6 +
 drivers/clk/rockchip/clk-rockchip-pll.c |  131 +++++++++
 drivers/clk/rockchip/clk-rockchip-pll.h |   19 ++
 drivers/clk/rockchip/clk-rockchip.c     |  330 ++++++++++++++++++++++
 drivers/mmc/host/dw_mmc-pltfm.c         |   47 +++-
 include/linux/clk-provider.h            |    2 +
 17 files changed, 1541 insertions(+), 16 deletions(-)
 create mode 100644 arch/arm/boot/dts/rk3066a-clocks.dtsi
 create mode 100644 arch/arm/boot/dts/rk3066a.dtsi
 create mode 100644 arch/arm/include/debug/rockchip.S
 create mode 100644 arch/arm/mach-rockchip/Kconfig
 create mode 100644 arch/arm/mach-rockchip/Makefile
 create mode 100644 arch/arm/mach-rockchip/rockchip.c
 create mode 100644 drivers/clk/rockchip/Makefile
 create mode 100644 drivers/clk/rockchip/clk-rockchip-pll.c
 create mode 100644 drivers/clk/rockchip/clk-rockchip-pll.h
 create mode 100644 drivers/clk/rockchip/clk-rockchip.c

-- 
1.7.2.3

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

* [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
  2013-06-11 11:28 ` Heiko Stübner
  (?)
@ 2013-06-11 11:29   ` Heiko Stübner
  -1 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:29 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mike Turquette, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
that use the regular mechanisms for storage but allow only even
dividers and 1 to be used.

Therefore add a flag that lets _is_valid_div limit the valid dividers
to these values. _get_maxdiv is also adapted to return even values
for the CLK_DIVIDER_ONE_BASED case.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/clk-divider.c    |   14 ++++++++++++--
 include/linux/clk-provider.h |    2 ++
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index ce5cfe9..bdee7cf 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -45,8 +45,16 @@ static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
 
 static unsigned int _get_maxdiv(struct clk_divider *divider)
 {
-	if (divider->flags & CLK_DIVIDER_ONE_BASED)
-		return div_mask(divider);
+	if (divider->flags & CLK_DIVIDER_ONE_BASED) {
+		unsigned int div = div_mask(divider);
+
+		/* decrease to even number */
+		if (divider->flags & CLK_DIVIDER_EVEN)
+			div--;
+
+		return div;
+	}
+
 	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
 		return 1 << div_mask(divider);
 	if (divider->table)
@@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
 		return is_power_of_2(div);
 	if (divider->table)
 		return _is_valid_table_div(divider->table, div);
+	if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) != 0)
+		return false;
 	return true;
 }
 
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 1ec14a7..bd52e52 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -266,6 +266,7 @@ struct clk_div_table {
  *   of this register, and mask of divider bits are in higher 16-bit of this
  *   register.  While setting the divider bits, higher 16-bit should also be
  *   updated to indicate changing divider bits.
+ * CLK_DIVIDER_EVEN - only allow even divider values
  */
 struct clk_divider {
 	struct clk_hw	hw;
@@ -281,6 +282,7 @@ struct clk_divider {
 #define CLK_DIVIDER_POWER_OF_TWO	BIT(1)
 #define CLK_DIVIDER_ALLOW_ZERO		BIT(2)
 #define CLK_DIVIDER_HIWORD_MASK		BIT(3)
+#define CLK_DIVIDER_EVEN		BIT(4)
 
 extern const struct clk_ops clk_divider_ops;
 struct clk *clk_register_divider(struct device *dev, const char *name,
-- 
1.7.2.3


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

* [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
@ 2013-06-11 11:29   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:29 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mike Turquette, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
that use the regular mechanisms for storage but allow only even
dividers and 1 to be used.

Therefore add a flag that lets _is_valid_div limit the valid dividers
to these values. _get_maxdiv is also adapted to return even values
for the CLK_DIVIDER_ONE_BASED case.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/clk-divider.c    |   14 ++++++++++++--
 include/linux/clk-provider.h |    2 ++
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index ce5cfe9..bdee7cf 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -45,8 +45,16 @@ static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
 
 static unsigned int _get_maxdiv(struct clk_divider *divider)
 {
-	if (divider->flags & CLK_DIVIDER_ONE_BASED)
-		return div_mask(divider);
+	if (divider->flags & CLK_DIVIDER_ONE_BASED) {
+		unsigned int div = div_mask(divider);
+
+		/* decrease to even number */
+		if (divider->flags & CLK_DIVIDER_EVEN)
+			div--;
+
+		return div;
+	}
+
 	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
 		return 1 << div_mask(divider);
 	if (divider->table)
@@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
 		return is_power_of_2(div);
 	if (divider->table)
 		return _is_valid_table_div(divider->table, div);
+	if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) != 0)
+		return false;
 	return true;
 }
 
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 1ec14a7..bd52e52 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -266,6 +266,7 @@ struct clk_div_table {
  *   of this register, and mask of divider bits are in higher 16-bit of this
  *   register.  While setting the divider bits, higher 16-bit should also be
  *   updated to indicate changing divider bits.
+ * CLK_DIVIDER_EVEN - only allow even divider values
  */
 struct clk_divider {
 	struct clk_hw	hw;
@@ -281,6 +282,7 @@ struct clk_divider {
 #define CLK_DIVIDER_POWER_OF_TWO	BIT(1)
 #define CLK_DIVIDER_ALLOW_ZERO		BIT(2)
 #define CLK_DIVIDER_HIWORD_MASK		BIT(3)
+#define CLK_DIVIDER_EVEN		BIT(4)
 
 extern const struct clk_ops clk_divider_ops;
 struct clk *clk_register_divider(struct device *dev, const char *name,
-- 
1.7.2.3

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

* [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
@ 2013-06-11 11:29   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:29 UTC (permalink / raw)
  To: linux-arm-kernel

SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
that use the regular mechanisms for storage but allow only even
dividers and 1 to be used.

Therefore add a flag that lets _is_valid_div limit the valid dividers
to these values. _get_maxdiv is also adapted to return even values
for the CLK_DIVIDER_ONE_BASED case.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/clk-divider.c    |   14 ++++++++++++--
 include/linux/clk-provider.h |    2 ++
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index ce5cfe9..bdee7cf 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -45,8 +45,16 @@ static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
 
 static unsigned int _get_maxdiv(struct clk_divider *divider)
 {
-	if (divider->flags & CLK_DIVIDER_ONE_BASED)
-		return div_mask(divider);
+	if (divider->flags & CLK_DIVIDER_ONE_BASED) {
+		unsigned int div = div_mask(divider);
+
+		/* decrease to even number */
+		if (divider->flags & CLK_DIVIDER_EVEN)
+			div--;
+
+		return div;
+	}
+
 	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
 		return 1 << div_mask(divider);
 	if (divider->table)
@@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
 		return is_power_of_2(div);
 	if (divider->table)
 		return _is_valid_table_div(divider->table, div);
+	if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) != 0)
+		return false;
 	return true;
 }
 
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 1ec14a7..bd52e52 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -266,6 +266,7 @@ struct clk_div_table {
  *   of this register, and mask of divider bits are in higher 16-bit of this
  *   register.  While setting the divider bits, higher 16-bit should also be
  *   updated to indicate changing divider bits.
+ * CLK_DIVIDER_EVEN - only allow even divider values
  */
 struct clk_divider {
 	struct clk_hw	hw;
@@ -281,6 +282,7 @@ struct clk_divider {
 #define CLK_DIVIDER_POWER_OF_TWO	BIT(1)
 #define CLK_DIVIDER_ALLOW_ZERO		BIT(2)
 #define CLK_DIVIDER_HIWORD_MASK		BIT(3)
+#define CLK_DIVIDER_EVEN		BIT(4)
 
 extern const struct clk_ops clk_divider_ops;
 struct clk *clk_register_divider(struct device *dev, const char *name,
-- 
1.7.2.3

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

* [PATCH v3 2/7] mmc: dw_mmc-pltfm: remove static from dw_mci_pltfm_remove
  2013-06-11 11:28 ` Heiko Stübner
  (?)
@ 2013-06-11 11:29   ` Heiko Stübner
  -1 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:29 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mike Turquette, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

dw_mci_pltfm_remove gets exported and used by dw_mmc-exynos, so should
not be static.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/host/dw_mmc-pltfm.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 37873f1..0048da8 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -68,7 +68,7 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
 	return dw_mci_pltfm_register(pdev, NULL);
 }
 
-static int dw_mci_pltfm_remove(struct platform_device *pdev)
+int dw_mci_pltfm_remove(struct platform_device *pdev)
 {
 	struct dw_mci *host = platform_get_drvdata(pdev);
 
-- 
1.7.2.3


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

* [PATCH v3 2/7] mmc: dw_mmc-pltfm: remove static from dw_mci_pltfm_remove
@ 2013-06-11 11:29   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:29 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mike Turquette, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

dw_mci_pltfm_remove gets exported and used by dw_mmc-exynos, so should
not be static.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/host/dw_mmc-pltfm.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 37873f1..0048da8 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -68,7 +68,7 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
 	return dw_mci_pltfm_register(pdev, NULL);
 }
 
-static int dw_mci_pltfm_remove(struct platform_device *pdev)
+int dw_mci_pltfm_remove(struct platform_device *pdev)
 {
 	struct dw_mci *host = platform_get_drvdata(pdev);
 
-- 
1.7.2.3

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

* [PATCH v3 2/7] mmc: dw_mmc-pltfm: remove static from dw_mci_pltfm_remove
@ 2013-06-11 11:29   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:29 UTC (permalink / raw)
  To: linux-arm-kernel

dw_mci_pltfm_remove gets exported and used by dw_mmc-exynos, so should
not be static.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Seungwon Jeon <tgih.jun@samsung.com>
---
 drivers/mmc/host/dw_mmc-pltfm.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 37873f1..0048da8 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -68,7 +68,7 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
 	return dw_mci_pltfm_register(pdev, NULL);
 }
 
-static int dw_mci_pltfm_remove(struct platform_device *pdev)
+int dw_mci_pltfm_remove(struct platform_device *pdev)
 {
 	struct dw_mci *host = platform_get_drvdata(pdev);
 
-- 
1.7.2.3

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

* [PATCH v3 3/7] mmc: dw_mmc-pltfm: move probe and remove below dt match table
  2013-06-11 11:28 ` Heiko Stübner
  (?)
@ 2013-06-11 11:30   ` Heiko Stübner
  -1 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:30 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mike Turquette, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

In a subsquent patch probe will need to do some handling of data from
the dt match table. So to prevent the need for forward declarations,
move probe and remove below the match table.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/mmc/host/dw_mmc-pltfm.c |   28 ++++++++++++++--------------
 1 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 0048da8..9b05381 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -63,20 +63,6 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
 }
 EXPORT_SYMBOL_GPL(dw_mci_pltfm_register);
 
-static int dw_mci_pltfm_probe(struct platform_device *pdev)
-{
-	return dw_mci_pltfm_register(pdev, NULL);
-}
-
-int dw_mci_pltfm_remove(struct platform_device *pdev)
-{
-	struct dw_mci *host = platform_get_drvdata(pdev);
-
-	dw_mci_remove(host);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
-
 #ifdef CONFIG_PM_SLEEP
 /*
  * TODO: we should probably disable the clock to the card in the suspend path.
@@ -118,6 +104,20 @@ static const struct of_device_id dw_mci_pltfm_match[] = {
 };
 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
 
+static int dw_mci_pltfm_probe(struct platform_device *pdev)
+{
+	return dw_mci_pltfm_register(pdev, NULL);
+}
+
+int dw_mci_pltfm_remove(struct platform_device *pdev)
+{
+	struct dw_mci *host = platform_get_drvdata(pdev);
+
+	dw_mci_remove(host);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
+
 static struct platform_driver dw_mci_pltfm_driver = {
 	.probe		= dw_mci_pltfm_probe,
 	.remove		= dw_mci_pltfm_remove,
-- 
1.7.2.3


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

* [PATCH v3 3/7] mmc: dw_mmc-pltfm: move probe and remove below dt match table
@ 2013-06-11 11:30   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:30 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mike Turquette, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

In a subsquent patch probe will need to do some handling of data from
the dt match table. So to prevent the need for forward declarations,
move probe and remove below the match table.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/mmc/host/dw_mmc-pltfm.c |   28 ++++++++++++++--------------
 1 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 0048da8..9b05381 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -63,20 +63,6 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
 }
 EXPORT_SYMBOL_GPL(dw_mci_pltfm_register);
 
-static int dw_mci_pltfm_probe(struct platform_device *pdev)
-{
-	return dw_mci_pltfm_register(pdev, NULL);
-}
-
-int dw_mci_pltfm_remove(struct platform_device *pdev)
-{
-	struct dw_mci *host = platform_get_drvdata(pdev);
-
-	dw_mci_remove(host);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
-
 #ifdef CONFIG_PM_SLEEP
 /*
  * TODO: we should probably disable the clock to the card in the suspend path.
@@ -118,6 +104,20 @@ static const struct of_device_id dw_mci_pltfm_match[] = {
 };
 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
 
+static int dw_mci_pltfm_probe(struct platform_device *pdev)
+{
+	return dw_mci_pltfm_register(pdev, NULL);
+}
+
+int dw_mci_pltfm_remove(struct platform_device *pdev)
+{
+	struct dw_mci *host = platform_get_drvdata(pdev);
+
+	dw_mci_remove(host);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
+
 static struct platform_driver dw_mci_pltfm_driver = {
 	.probe		= dw_mci_pltfm_probe,
 	.remove		= dw_mci_pltfm_remove,
-- 
1.7.2.3

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

* [PATCH v3 3/7] mmc: dw_mmc-pltfm: move probe and remove below dt match table
@ 2013-06-11 11:30   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

In a subsquent patch probe will need to do some handling of data from
the dt match table. So to prevent the need for forward declarations,
move probe and remove below the match table.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/mmc/host/dw_mmc-pltfm.c |   28 ++++++++++++++--------------
 1 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 0048da8..9b05381 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -63,20 +63,6 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
 }
 EXPORT_SYMBOL_GPL(dw_mci_pltfm_register);
 
-static int dw_mci_pltfm_probe(struct platform_device *pdev)
-{
-	return dw_mci_pltfm_register(pdev, NULL);
-}
-
-int dw_mci_pltfm_remove(struct platform_device *pdev)
-{
-	struct dw_mci *host = platform_get_drvdata(pdev);
-
-	dw_mci_remove(host);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
-
 #ifdef CONFIG_PM_SLEEP
 /*
  * TODO: we should probably disable the clock to the card in the suspend path.
@@ -118,6 +104,20 @@ static const struct of_device_id dw_mci_pltfm_match[] = {
 };
 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
 
+static int dw_mci_pltfm_probe(struct platform_device *pdev)
+{
+	return dw_mci_pltfm_register(pdev, NULL);
+}
+
+int dw_mci_pltfm_remove(struct platform_device *pdev)
+{
+	struct dw_mci *host = platform_get_drvdata(pdev);
+
+	dw_mci_remove(host);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
+
 static struct platform_driver dw_mci_pltfm_driver = {
 	.probe		= dw_mci_pltfm_probe,
 	.remove		= dw_mci_pltfm_remove,
-- 
1.7.2.3

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

* [PATCH v3 4/7] mmc: dw_mmc-pltfm: add Rockchip variant
  2013-06-11 11:28 ` Heiko Stübner
  (?)
@ 2013-06-11 11:30   ` Heiko Stübner
  -1 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:30 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mike Turquette, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

Cortex-A9 SoCs from Rockchip use a slightly modified variant of dw_mmc
controllers that seems to require the SDMMC_CMD_USE_HOLD_REG bit to
always be set.

There also seem to be no other modifications (additional register etc)
present, so to keep the footprint low, add this small variant to the
pltfm driver.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/mmc/host/dw_mmc-pltfm.c |   21 ++++++++++++++++++++-
 1 files changed, 20 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 9b05381..cbbbcf3 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -24,6 +24,15 @@
 
 #include "dw_mmc.h"
 
+static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
+{
+	*cmdr |= SDMMC_CMD_USE_HOLD_REG;
+}
+
+static const struct dw_mci_drv_data rockchip_drv_data = {
+	.prepare_command	= dw_mci_rockchip_prepare_command,
+};
+
 int dw_mci_pltfm_register(struct platform_device *pdev,
 				const struct dw_mci_drv_data *drv_data)
 {
@@ -100,13 +109,23 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
 
 static const struct of_device_id dw_mci_pltfm_match[] = {
 	{ .compatible = "snps,dw-mshc", },
+	{ .compatible = "rockchip,cortex-a9-dw-mshc",
+		.data = &rockchip_drv_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
 
 static int dw_mci_pltfm_probe(struct platform_device *pdev)
 {
-	return dw_mci_pltfm_register(pdev, NULL);
+	const struct dw_mci_drv_data *drv_data = NULL;
+	const struct of_device_id *match;
+
+	if (pdev->dev.of_node) {
+		match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
+		drv_data = match->data;
+	}
+
+	return dw_mci_pltfm_register(pdev, drv_data);
 }
 
 int dw_mci_pltfm_remove(struct platform_device *pdev)
-- 
1.7.2.3


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

* [PATCH v3 4/7] mmc: dw_mmc-pltfm: add Rockchip variant
@ 2013-06-11 11:30   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:30 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mike Turquette, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

Cortex-A9 SoCs from Rockchip use a slightly modified variant of dw_mmc
controllers that seems to require the SDMMC_CMD_USE_HOLD_REG bit to
always be set.

There also seem to be no other modifications (additional register etc)
present, so to keep the footprint low, add this small variant to the
pltfm driver.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/mmc/host/dw_mmc-pltfm.c |   21 ++++++++++++++++++++-
 1 files changed, 20 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 9b05381..cbbbcf3 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -24,6 +24,15 @@
 
 #include "dw_mmc.h"
 
+static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
+{
+	*cmdr |= SDMMC_CMD_USE_HOLD_REG;
+}
+
+static const struct dw_mci_drv_data rockchip_drv_data = {
+	.prepare_command	= dw_mci_rockchip_prepare_command,
+};
+
 int dw_mci_pltfm_register(struct platform_device *pdev,
 				const struct dw_mci_drv_data *drv_data)
 {
@@ -100,13 +109,23 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
 
 static const struct of_device_id dw_mci_pltfm_match[] = {
 	{ .compatible = "snps,dw-mshc", },
+	{ .compatible = "rockchip,cortex-a9-dw-mshc",
+		.data = &rockchip_drv_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
 
 static int dw_mci_pltfm_probe(struct platform_device *pdev)
 {
-	return dw_mci_pltfm_register(pdev, NULL);
+	const struct dw_mci_drv_data *drv_data = NULL;
+	const struct of_device_id *match;
+
+	if (pdev->dev.of_node) {
+		match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
+		drv_data = match->data;
+	}
+
+	return dw_mci_pltfm_register(pdev, drv_data);
 }
 
 int dw_mci_pltfm_remove(struct platform_device *pdev)
-- 
1.7.2.3


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

* [PATCH v3 4/7] mmc: dw_mmc-pltfm: add Rockchip variant
@ 2013-06-11 11:30   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

Cortex-A9 SoCs from Rockchip use a slightly modified variant of dw_mmc
controllers that seems to require the SDMMC_CMD_USE_HOLD_REG bit to
always be set.

There also seem to be no other modifications (additional register etc)
present, so to keep the footprint low, add this small variant to the
pltfm driver.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/mmc/host/dw_mmc-pltfm.c |   21 ++++++++++++++++++++-
 1 files changed, 20 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 9b05381..cbbbcf3 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -24,6 +24,15 @@
 
 #include "dw_mmc.h"
 
+static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
+{
+	*cmdr |= SDMMC_CMD_USE_HOLD_REG;
+}
+
+static const struct dw_mci_drv_data rockchip_drv_data = {
+	.prepare_command	= dw_mci_rockchip_prepare_command,
+};
+
 int dw_mci_pltfm_register(struct platform_device *pdev,
 				const struct dw_mci_drv_data *drv_data)
 {
@@ -100,13 +109,23 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
 
 static const struct of_device_id dw_mci_pltfm_match[] = {
 	{ .compatible = "snps,dw-mshc", },
+	{ .compatible = "rockchip,cortex-a9-dw-mshc",
+		.data = &rockchip_drv_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
 
 static int dw_mci_pltfm_probe(struct platform_device *pdev)
 {
-	return dw_mci_pltfm_register(pdev, NULL);
+	const struct dw_mci_drv_data *drv_data = NULL;
+	const struct of_device_id *match;
+
+	if (pdev->dev.of_node) {
+		match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
+		drv_data = match->data;
+	}
+
+	return dw_mci_pltfm_register(pdev, drv_data);
 }
 
 int dw_mci_pltfm_remove(struct platform_device *pdev)
-- 
1.7.2.3

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

* [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support
@ 2013-06-11 11:31   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:31 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mike Turquette, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

This adds basic support for clocks on Rockchip rk3066 SoCs.
The clock handling thru small dt nodes is heavily inspired by the
sunxi clk code.

The plls are currently read-only, as their setting needs more
investigation. This also results in slow cpu speeds, as the apll starts
at a default of 600mhz.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/boot/dts/rk3066a-clocks.dtsi   |  467 +++++++++++++++++++++++++++++++
 drivers/clk/Makefile                    |    1 +
 drivers/clk/rockchip/Makefile           |    6 +
 drivers/clk/rockchip/clk-rockchip-pll.c |  131 +++++++++
 drivers/clk/rockchip/clk-rockchip-pll.h |   19 ++
 drivers/clk/rockchip/clk-rockchip.c     |  330 ++++++++++++++++++++++
 6 files changed, 954 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/boot/dts/rk3066a-clocks.dtsi
 create mode 100644 drivers/clk/rockchip/Makefile
 create mode 100644 drivers/clk/rockchip/clk-rockchip-pll.c
 create mode 100644 drivers/clk/rockchip/clk-rockchip-pll.h
 create mode 100644 drivers/clk/rockchip/clk-rockchip.c

diff --git a/arch/arm/boot/dts/rk3066a-clocks.dtsi b/arch/arm/boot/dts/rk3066a-clocks.dtsi
new file mode 100644
index 0000000..d797710
--- /dev/null
+++ b/arch/arm/boot/dts/rk3066a-clocks.dtsi
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	clocks {
+		compatible = "rockchip,clocks";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		/*
+		 * This is a dummy clock, to be used as placeholder on
+		 * other mux clocks when a specific parent clock is not
+		 * yet implemented. It should be dropped when the driver
+		 * is complete.
+		 */
+		dummy: dummy {
+			compatible = "fixed-clock";
+			clock-frequency = <0>;
+			#clock-cells = <0>;
+		};
+
+		xin24m: xin24m {
+			compatible = "fixed-clock";
+			clock-frequency = <24000000>;
+			#clock-cells = <0>;
+		};
+
+		apll: apll@20000000 {
+			compatible = "rockchip,rk3066a-apll";
+			reg = <0x20000000 0x10>,
+			      <0x20000040 0x04>;
+			clocks = <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		dpll: dpll@20000000 {
+			compatible = "rockchip,rk3066a-dpll";
+			reg = <0x20000010 0x10>,
+			      <0x20000040 0x04>;
+			clocks = <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		cpll: cpll@20000000 {
+			compatible = "rockchip,rk3066a-cpll";
+			reg = <0x20000020 0x10>,
+			      <0x20000040 0x04>;
+			clocks = <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		gpll: gpll@20000000 {
+			compatible = "rockchip,rk3066a-gpll";
+			reg = <0x20000030 0x10>,
+			      <0x20000040 0x04>;
+			clocks = <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		mux_aclk_periph: mux-aclk-periph@2000006c {
+			compatible = "rockchip,rk2928-gpll-cpll-bit15-mux";
+			reg = <0x2000006c 0x04>;
+			clocks = <&gpll>, <&cpll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart_pll: mux-uart_pll@20000074 {
+			compatible = "rockchip,rk2928-gpll-cpll-bit15-mux";
+			reg = <0x20000074 0x04>;
+			clocks = <&gpll>, <&cpll>;
+			#clock-cells = <0>;
+		};
+
+		div_uart0: div-uart0@20000078 {
+			compatible = "rockchip,rk2928-uart-divider";
+			reg = <0x20000078 0x04>;
+			clocks = <&mux_uart_pll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart0: mux-uart0@20000078 {
+			compatible = "rockchip,rk2928-uart-mux";
+			reg = <0x20000078 0x04>;
+			clocks = <&clk_gates1 8>, <&dummy>, <&xin24m>; /* dummy is uart0_frac_div */
+			#clock-cells = <0>;
+		};
+
+		div_uart1: div-uart1@2000007c {
+			compatible = "rockchip,rk2928-uart-divider";
+			reg = <0x2000007c 0x04>;
+			clocks = <&mux_uart_pll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart1: mux-uart1@2000007c {
+			compatible = "rockchip,rk2928-uart-mux";
+			reg = <0x2000007c 0x04>;
+			clocks = <&clk_gates1 10>, <&dummy>, <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		div_uart2: div-uart2@20000080 {
+			compatible = "rockchip,rk2928-uart-divider";
+			reg = <0x20000080 0x04>;
+			clocks = <&mux_uart_pll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart2: mux-uart2@20000080 {
+			compatible = "rockchip,rk2928-uart-mux";
+			reg = <0x20000080 0x04>;
+			clocks = <&clk_gates1 12>, <&dummy>, <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		div_uart3: div-uart3@20000084 {
+			compatible = "rockchip,rk2928-uart-divider";
+			reg = <0x20000084 0x04>;
+			clocks = <&mux_uart_pll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart3: mux-uart3@20000084 {
+			compatible = "rockchip,rk2928-uart-mux";
+			reg = <0x20000084 0x04>;
+			clocks = <&clk_gates1 14>, <&dummy>, <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		mux_cpu: mux-cpu@20000044 {
+			compatible = "rockchip,rk3066-cpu-mux";
+			reg = <0x20000044 0x4>;
+			clocks = <&apll>, <&dummy> /* cpu_gpll_path */;
+			#clock-cells = <0>;
+		};
+
+		div_cpu: div-cpu@20000044 {
+			compatible = "rockchip,rk3066a-cpu-divider";
+			reg = <0x20000044 0x4>;
+			clocks = <&mux_cpu>;
+			#clock-cells = <0>;
+		};
+
+		div_core_periph: div-core-periph@20000044 {
+			compatible = "rockchip,rk3066a-core-periph-divider";
+			reg = <0x20000044 0x4>;
+			clocks = <&div_cpu>;
+			#clock-cells = <0>;
+		};
+
+		div_aclk_cpu: div-aclk-cpu@20000048 {
+			compatible = "rockchip,rk3066a-aclk-cpu-divider";
+			reg = <0x20000048 0x4>;
+			clocks = <&div_cpu>;
+			#clock-cells = <0>;
+		};
+
+		div_aclk_periph: div-aclk-periph@2000006c {
+			compatible = "rockchip,rk2928-aclk-periph-divider";
+			reg = <0x2000006c 0x4>;
+			clocks = <&mux_aclk_periph>;
+			#clock-cells = <0>;
+		};
+
+		div_hclk_periph: div-hclk-periph@2000006c {
+			compatible = "rockchip,rk2928-hclk-divider";
+			reg = <0x2000006c 0x4>;
+			clocks = <&clk_gates2 1>;
+			#clock-cells = <0>;
+		};
+
+		div_pclk_periph: div-pclk-periph@2000006c {
+			compatible = "rockchip,rk2928-pclk-divider";
+			reg = <0x2000006c 0x4>;
+			clocks = <&clk_gates2 1>;
+			#clock-cells = <0>;
+		};
+
+		div_hclk_cpu: div-hclk-cpu@20000048 {
+			compatible = "rockchip,rk2928-hclk-divider";
+			reg = <0x20000048 0x4>;
+			clocks = <&clk_gates0 3>;
+			#clock-cells = <0>;
+		};
+
+		div_pclk_cpu: div-pclk-cpu@20000048 {
+			compatible = "rockchip,rk2928-pclk-divider";
+			reg = <0x20000048 0x4>;
+			clocks = <&clk_gates0 3>;
+			#clock-cells = <0>;
+		};
+
+		div_mmc0: div-mmc0@20000070 {
+			compatible = "rockchip,rk2928-mmc-divider";
+			reg = <0x20000070 0x4>;
+			clocks = <&clk_gates2 2>;
+			#clock-cells = <0>;
+		};
+
+		div_mmc1: div-mmc1@20000074 {
+			compatible = "rockchip,rk2928-mmc-divider";
+			reg = <0x20000074 0x4>;
+			clocks = <&clk_gates2 2>;
+			#clock-cells = <0>;
+		};
+
+		clk_gates0: gate-clk@200000d0 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000d0 0x4>;
+			clocks = <&dummy>, <&dummy>,
+				 <&dummy>, <&div_aclk_cpu>,
+				 <&div_hclk_cpu>, <&div_pclk_cpu>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>;
+
+			clock-output-names =
+				"gate_core_periph", "gate_cpu_gpll",
+				"gate_ddrphy", "gate_aclk_cpu",
+				"gate_hclk_cpu", "gate_pclk_cpu",
+				"gate_atclk_cpu", "gate_i2s0",
+				"gate_i2s0_frac", "gate_i2s1",
+				"gate_i2s1_frac", "gate_i2s2",
+				"gate_i2s2_frac", "gate_spdif",
+				"gate_spdif_frac", "gate_testclk";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates1: gate-clk@200000d4 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000d4 0x4>;
+			clocks = <&xin24m>, <&xin24m>,
+				 <&xin24m>, <&dummy>,
+				 <&dummy>, <&xin24m>,
+				 <&xin24m>, <&dummy>,
+				 <&div_uart0>, <&dummy>,
+				 <&div_uart1>, <&dummy>,
+				 <&div_uart2>, <&dummy>,
+				 <&div_uart3>, <&dummy>;
+
+			clock-output-names =
+				"gate_timer0", "gate_timer1",
+				"gate_timer2", "gate_jtag",
+				"gate_aclk_lcdc1_src", "gate_otgphy0",
+				"gate_otgphy1", "gate_ddr_gpll",
+				"gate_uart0", "gate_frac_uart0",
+				"gate_uart1", "gate_frac_uart1",
+				"gate_uart2", "gate_frac_uart2",
+				"gate_uart3", "gate_frac_uart3";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates2: gate-clk@200000d8 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000d8 0x4>;
+			clocks = <&clk_gates2 1>, <&div_aclk_periph>,
+				 <&div_hclk_periph>, <&div_pclk_periph>,
+				 <&dummy>, <&dummy>,
+				 <&clk_gates2 3>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&div_mmc0>,
+				 <&dummy>, <&div_mmc1>,
+				 <&dummy>, <&dummy>;
+
+			clock-output-names =
+				"gate_periph_src", "gate_aclk_periph",
+				"gate_hclk_periph", "gate_pclk_periph",
+				"gate_smc", "gate_mac",
+				"gate_hsadc", "gate_hsadc_frac",
+				"gate_saradc", "gate_spi0",
+				"gate_spi1", "gate_mmc0",
+				"gate_mac_lbtest", "gate_mmc1",
+				"gate_emmc", "gate_tsadc";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates3: gate-clk@200000dc {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000dc 0x4>;
+			clocks = <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>;
+
+			clock-output-names =
+				"gate_aclk_lcdc0_src", "gate_dclk_lcdc0",
+				"gate_dclk_lcdc1", "gate_pclkin_cif0",
+				"gate_pclkin_cif1", "reserved",
+				"reserved", "gate_cif0_out",
+				"gate_cif1_out", "gate_aclk_vepu",
+				"gate_hclk_vepu", "gate_aclk_vdpu",
+				"gate_hclk_vdpu", "gate_gpu_src",
+				"reserved", "gate_xin27m";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates4: gate-clk@200000e0 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000e0 0x4>;
+			clocks = <&clk_gates2 2>, <&clk_gates2 3>,
+				 <&clk_gates2 1>, <&clk_gates2 1>,
+				 <&clk_gates2 1>, <&clk_gates2 2>,
+				 <&clk_gates2 2>, <&clk_gates2 2>,
+				 <&clk_gates0 4>, <&clk_gates0 4>,
+				 <&clk_gates0 3>, <&clk_gates0 3>,
+				 <&clk_gates0 3>, <&clk_gates2 3>,
+				 <&clk_gates0 4>;
+
+			clock-output-names =
+				"gate_hclk_peri_axi_matrix", "gate_pclk_peri_axi_matrix",
+				"gate_aclk_cpu_peri", "gate_aclk_peri_axi_matrix",
+				"gate_aclk_pei_niu", "gate_hclk_usb_peri",
+				"gate_hclk_peri_ahb_arbi", "gate_hclk_emem_peri",
+				"gate_hclk_cpubus", "gate_hclk_ahb2apb",
+				"gate_aclk_strc_sys", "gate_aclk_l2mem_con",
+				"gate_aclk_intmem", "gate_pclk_tsadc",
+				"gate_hclk_hdmi";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates5: gate-clk@200000e4 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000e4 0x4>;
+			clocks = <&clk_gates0 3>, <&clk_gates2 1>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates0 4>, <&clk_gates0 5>,
+				 <&clk_gates2 1>, <&clk_gates2 2>,
+				 <&clk_gates2 2>, <&clk_gates2 2>,
+				 <&clk_gates2 2>, <&clk_gates4 5>,
+				 <&clk_gates4 5>, <&dummy>;
+
+			clock-output-names =
+				"gate_aclk_dmac1", "gate_aclk_dmac2",
+				"gate_pclk_efuse", "gate_pclk_tzpc",
+				"gate_pclk_grf", "gate_pclk_pmu",
+				"gate_hclk_rom", "gate_pclk_ddrupctl",
+				"gate_aclk_smc", "gate_hclk_nandc",
+				"gate_hclk_mmc0", "gate_hclk_mmc1",
+				"gate_hclk_emmc", "gate_hclk_otg0",
+				"gate_hclk_otg1", "gate_aclk_gpu";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates6: gate-clk@200000e8 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000e8 0x4>;
+			clocks = <&clk_gates3 0>, <&clk_gates0 4>,
+				 <&clk_gates0 4>, <&clk_gates1 4>,
+				 <&clk_gates0 4>, <&clk_gates3 0>,
+				 <&clk_gates0 4>, <&clk_gates1 4>,
+				 <&clk_gates3 0>, <&clk_gates0 4>,
+				 <&clk_gates0 4>, <&clk_gates1 4>,
+				 <&clk_gates0 4>, <&clk_gates3 0>,
+				 <&dummy>, <&dummy>;
+
+			clock-output-names =
+				"gate_aclk_lcdc0", "gate_hclk_lcdc0",
+				"gate_hclk_lcdc1", "gate_aclk_lcdc1",
+				"gate_hclk_cif0", "gate_aclk_cif0",
+				"gate_hclk_cif1", "gate_aclk_cif1",
+				"gate_aclk_ipp", "gate_hclk_ipp",
+				"gate_hclk_rga", "gate_aclk_rga",
+				"gate_hclk_vio_bus", "gate_aclk_vio0",
+				"gate_aclk_vcodec", "gate_shclk_vio_h2h";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates7: gate-clk@200000ec {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000ec 0x4>;
+			clocks = <&clk_gates2 2>, <&clk_gates0 4>,
+				 <&clk_gates0 4>, <&clk_gates0 4>,
+				 <&clk_gates0 4>, <&clk_gates2 2>,
+				 <&clk_gates2 2>, <&clk_gates0 5>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates0 5>, <&clk_gates2 3>,
+				 <&clk_gates2 3>, <&clk_gates2 3>,
+				 <&clk_gates2 3>, <&clk_gates2 3>;
+
+			clock-output-names =
+				"gate_hclk_emac", "gate_hclk_spdif",
+				"gate_hclk_i2s0_2ch", "gate_hclk_i2s1_2ch",
+				"gate_hclk_i2s_8ch", "gate_hclk_hsadc",
+				"gate_hclk_pidf", "gate_pclk_timer0",
+				"gate_pclk_timer1", "gate_pclk_timer2",
+				"gate_pclk_pwm01", "gate_pclk_pwm23",
+				"gate_pclk_spi0", "gate_pclk_spi1",
+				"gate_pclk_saradc", "gate_pclk_wdt";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates8: gate-clk@200000f0 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000f0 0x4>;
+			clocks = <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates2 3>, <&clk_gates2 3>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates2 3>, <&clk_gates2 3>,
+				 <&clk_gates2 3>, <&clk_gates0 5>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates2 3>, <&clk_gates2 3>,
+				 <&dummy>, <&clk_gates0 5>;
+
+			clock-output-names =
+				"gate_pclk_uart0", "gate_pclk_uart1",
+				"gate_pclk_uart2", "gate_pclk_uart3",
+				"gate_pclk_i2c0", "gate_pclk_i2c1",
+				"gate_pclk_i2c2", "gate_pclk_i2c3",
+				"gate_pclk_i2c4", "gate_pclk_gpio0",
+				"gate_pclk_gpio1", "gate_pclk_gpio2",
+				"gate_pclk_gpio3", "gate_pclk_gpio4",
+				"reserved", "gate_pclk_gpio6";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates9: gate-clk@200000f4 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000f4 0x4>;
+			clocks = <&dummy>, <&clk_gates0 5>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&clk_gates1 4>,
+				 <&clk_gates0 5>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>;
+
+			clock-output-names =
+				"gate_clk_core_dbg", "gate_pclk_dbg",
+				"gate_clk_trace", "gate_atclk",
+				"gate_clk_l2c", "gate_aclk_vio1",
+				"gate_pclk_publ", "gate_aclk_intmem0",
+				"gate_aclk_intmem1", "gate_aclk_intmem2",
+				"gate_aclk_intmem3";
+
+			#clock-cells = <1>;
+		};
+	};
+
+};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f51b52b..2e2e957 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -25,6 +25,7 @@ ifeq ($(CONFIG_COMMON_CLK), y)
 obj-$(CONFIG_ARCH_MMP)		+= mmp/
 endif
 obj-$(CONFIG_MACH_LOONGSON1)	+= clk-ls1x.o
+obj-$(CONFIG_ARCH_ROCKCHIP)	+= rockchip/
 obj-$(CONFIG_ARCH_SUNXI)	+= sunxi/
 obj-$(CONFIG_ARCH_U8500)	+= ux500/
 obj-$(CONFIG_ARCH_VT8500)	+= clk-vt8500.o
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
new file mode 100644
index 0000000..e0fbafb
--- /dev/null
+++ b/drivers/clk/rockchip/Makefile
@@ -0,0 +1,6 @@
+#
+# Rockchip Clock specific Makefile
+#
+
+obj-y	+= clk-rockchip.o
+obj-y	+= clk-rockchip-pll.o
diff --git a/drivers/clk/rockchip/clk-rockchip-pll.c b/drivers/clk/rockchip/clk-rockchip-pll.c
new file mode 100644
index 0000000..4456445
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rockchip-pll.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/div64.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-private.h>
+
+#define RK3X_PLL_MODE_MASK		0x3
+#define RK3X_PLL_MODE_SLOW		0x0
+#define RK3X_PLL_MODE_NORM		0x1
+#define RK3X_PLL_MODE_DEEP		0x2
+
+#define RK3X_PLLCON0_OD_MASK		0xf
+#define RK3X_PLLCON0_OD_SHIFT		0
+#define RK3X_PLLCON0_NR_MASK		0x3f
+#define RK3X_PLLCON0_NR_SHIFT		8
+
+#define RK3X_PLLCON1_NF_MASK		0x1fff
+#define RK3X_PLLCON1_NF_SHIFT		0
+
+#define RK3X_PLLCON3_REST		(1 << 5)
+#define RK3X_PLLCON3_BYPASS		(1 << 0)
+
+struct rockchip_clk_pll {
+	struct clk_hw		hw;
+	void __iomem		*reg_base;
+	void __iomem		*reg_mode;
+	unsigned int		shift_mode;
+	spinlock_t		*lock;
+};
+
+#define to_clk_pll(_hw) container_of(_hw, struct rockchip_clk_pll, hw)
+
+static unsigned long rk3x_generic_pll_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct rockchip_clk_pll *pll = to_clk_pll(hw);
+	u32 pll_con0 = readl_relaxed(pll->reg_base);
+	u32 pll_con1 = readl_relaxed(pll->reg_base + 0x4);
+	u32 pll_con3 = readl_relaxed(pll->reg_base + 0xc);
+	u32 mode_con = readl_relaxed(pll->reg_mode) >> pll->shift_mode;
+	u64 pll_nf;
+	u64 pll_nr;
+	u64 pll_no;
+	u64 rate64;
+
+	if (pll_con3 & RK3X_PLLCON3_BYPASS) {
+		pr_debug("%s: pll %s is bypassed\n", __func__,
+			__clk_get_name(hw->clk));
+		return parent_rate;
+	}
+
+	mode_con &= RK3X_PLL_MODE_MASK;
+	if (mode_con != RK3X_PLL_MODE_NORM) {
+		pr_debug("%s: pll %s not in normal mode: %d\n", __func__,
+			__clk_get_name(hw->clk), mode_con);
+		return parent_rate;
+	}
+
+	pll_nf = (pll_con1 >> RK3X_PLLCON1_NF_SHIFT);
+	pll_nf &= RK3X_PLLCON1_NF_MASK;
+	pll_nf++;
+	rate64 = (u64)parent_rate * pll_nf;
+
+	pll_nr = (pll_con0 >> RK3X_PLLCON0_NR_SHIFT);
+	pll_nr &= RK3X_PLLCON0_NR_MASK;
+	pll_nr++;
+	do_div(rate64, pll_nr);
+
+	pll_no = (pll_con0 >> RK3X_PLLCON0_OD_SHIFT);
+	pll_no &= RK3X_PLLCON0_OD_MASK;
+	pll_no++;
+	do_div(rate64, pll_no);
+
+	return (unsigned long)rate64;
+}
+
+static const struct clk_ops rk3x_generic_pll_clk_ops = {
+	.recalc_rate = rk3x_generic_pll_recalc_rate,
+};
+
+struct clk * __init rockchip_clk_register_rk3x_pll(const char *name,
+			const char *pname, void __iomem *reg_base,
+			void __iomem *reg_mode, unsigned int shift_mode,
+			spinlock_t *lock)
+{
+	struct rockchip_clk_pll *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll) {
+		pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+		return NULL;
+	}
+
+	init.name = name;
+	init.ops = &rk3x_generic_pll_clk_ops;
+	init.flags = CLK_GET_RATE_NOCACHE;
+	init.parent_names = &pname;
+	init.num_parents = 1;
+
+	pll->hw.init = &init;
+	pll->reg_base = reg_base;
+	pll->reg_mode = reg_mode;
+	pll->shift_mode = shift_mode;
+	pll->lock = lock;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: failed to register pll clock %s\n", __func__,
+				name);
+		kfree(pll);
+	}
+
+	return clk;
+}
diff --git a/drivers/clk/rockchip/clk-rockchip-pll.h b/drivers/clk/rockchip/clk-rockchip-pll.h
new file mode 100644
index 0000000..a63288a
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rockchip-pll.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+extern struct clk * __init rockchip_clk_register_rk3x_pll(const char *name,
+			const char *pname, const void __iomem *reg_base,
+			const void __iomem *reg_mode, unsigned int shift_mode,
+			spinlock_t *lock);
diff --git a/drivers/clk/rockchip/clk-rockchip.c b/drivers/clk/rockchip/clk-rockchip.c
new file mode 100644
index 0000000..660b00f
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rockchip.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "clk-rockchip-pll.h"
+
+static DEFINE_SPINLOCK(clk_lock);
+
+struct rockchip_pll_data {
+	int mode_shift;
+};
+
+struct rockchip_pll_data rk3066a_apll_data = {
+	.mode_shift = 0,
+};
+
+struct rockchip_pll_data rk3066a_dpll_data = {
+	.mode_shift = 4,
+};
+
+struct rockchip_pll_data rk3066a_cpll_data = {
+	.mode_shift = 8,
+};
+
+struct rockchip_pll_data rk3066a_gpll_data = {
+	.mode_shift = 12,
+};
+
+/* Matches for plls */
+static const __initconst struct of_device_id clk_pll_match[] = {
+	{ .compatible = "rockchip,rk3066a-apll", .data = &rk3066a_apll_data },
+	{ .compatible = "rockchip,rk3066a-dpll", .data = &rk3066a_dpll_data },
+	{ .compatible = "rockchip,rk3066a-cpll", .data = &rk3066a_cpll_data },
+	{ .compatible = "rockchip,rk3066a-gpll", .data = &rk3066a_gpll_data },
+	{}
+};
+
+static void __init rockchip_pll_setup(struct device_node *node,
+				      struct rockchip_pll_data *data)
+{
+	struct clk *clk;
+	const char *clk_name = node->name;
+	const char *clk_parent;
+	void __iomem *reg_base;
+	void __iomem *reg_mode;
+	u32 rate;
+
+	reg_base = of_iomap(node, 0);
+	reg_mode = of_iomap(node, 1);
+
+	clk_parent = of_clk_get_parent_name(node, 0);
+
+	pr_debug("%s: adding %s as child of %s\n",
+		__func__, clk_name, clk_parent);
+
+	clk = rockchip_clk_register_rk3x_pll(clk_name, clk_parent, reg_base,
+					     reg_mode, data->mode_shift,
+					     &clk_lock);
+	if (clk) {
+		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+		/* optionally set a target frequency for the pll */
+		if (!of_property_read_u32(node, "clock-frequency", &rate))
+			clk_set_rate(clk, rate);
+	}
+}
+
+/*
+ * Mux clocks
+ */
+
+struct rockchip_mux_data {
+	int shift;
+	int width;
+};
+
+#define RK_MUX(n, s, w)					\
+static const __initconst struct rockchip_mux_data n = {	\
+	.shift = s,					\
+	.width = w,					\
+}
+
+RK_MUX(gpll_cpll_15_mux_data, 15, 1);
+RK_MUX(uart_mux_data, 8, 2);
+RK_MUX(cpu_mux_data, 8, 1);
+
+static const __initconst struct of_device_id clk_mux_match[] = {
+	{ .compatible = "rockchip,rk2928-gpll-cpll-bit15-mux",
+		.data = &gpll_cpll_15_mux_data },
+	{ .compatible = "rockchip,rk2928-uart-mux",
+		.data = &uart_mux_data },
+	{ .compatible = "rockchip,rk3066-cpu-mux",
+		.data = &cpu_mux_data },
+	{}
+};
+
+static void __init rockchip_mux_clk_setup(struct device_node *node,
+					  struct rockchip_mux_data *data)
+{
+	struct clk *clk;
+	const char *clk_name = node->name;
+	void __iomem *reg;
+	int max_parents = (1 << data->width);
+	const char *parents[max_parents];
+	int flags;
+	int i = 0;
+
+	reg = of_iomap(node, 0);
+
+	while (i < max_parents &&
+	       (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
+		i++;
+
+	flags = CLK_MUX_HIWORD_MASK;
+
+	clk = clk_register_mux(NULL, clk_name, parents, i, 0,
+			       reg, data->shift, data->width,
+			       flags, &clk_lock);
+	if (clk)
+		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+
+/*
+ * Divider clocks
+ */
+
+struct rockchip_div_data {
+	int shift;
+	int width;
+	int flags;
+	struct clk_div_table *table;
+};
+
+#define RK_DIV(n, s, w, f, t)				\
+static const __initconst struct rockchip_div_data n = {	\
+	.shift = s,					\
+	.width = w,					\
+	.flags = f,					\
+	.table = t,					\
+}
+
+RK_DIV(cpu_div_data, 0, 5, 0, NULL);
+RK_DIV(aclk_periph_div_data, 0, 5, 0, NULL);
+RK_DIV(aclk_cpu_div_data, 0, 3, 0, NULL);
+RK_DIV(hclk_div_data, 8, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+RK_DIV(pclk_div_data, 12, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+RK_DIV(mmc_div_data, 0, 6, CLK_DIVIDER_EVEN, NULL);
+RK_DIV(uart_div_data, 0, 7, 0, NULL);
+
+struct clk_div_table core_periph_table[] = {
+	{ 0, 2 },
+	{ 1, 4 },
+	{ 2, 8 },
+	{ 3, 16 },
+	{ 0, 0 },
+};
+RK_DIV(core_periph_div_data, 6, 2, 0, core_periph_table);
+
+static const __initconst struct of_device_id clk_divider_match[] = {
+	{ .compatible = "rockchip,rk3066a-cpu-divider",
+		.data = &cpu_div_data },
+	{ .compatible = "rockchip,rk3066a-core-periph-divider",
+		.data = &core_periph_div_data },
+	{ .compatible = "rockchip,rk2928-aclk-periph-divider",
+		.data = &aclk_periph_div_data },
+	{ .compatible = "rockchip,rk3066a-aclk-cpu-divider",
+		.data = &aclk_cpu_div_data },
+	{ .compatible = "rockchip,rk2928-hclk-divider",
+		.data = &hclk_div_data },
+	{ .compatible = "rockchip,rk2928-pclk-divider",
+		.data = &pclk_div_data },
+	{ .compatible = "rockchip,rk2928-mmc-divider",
+		.data = &mmc_div_data },
+	{ .compatible = "rockchip,rk2928-uart-divider",
+		.data = &uart_div_data },
+	{}
+};
+
+static void __init rockchip_divider_clk_setup(struct device_node *node,
+					      struct rockchip_div_data *data)
+{
+	struct clk *clk;
+	const char *clk_name = node->name;
+	const char *clk_parent;
+	void __iomem *reg;
+	int flags;
+
+	reg = of_iomap(node, 0);
+
+	clk_parent = of_clk_get_parent_name(node, 0);
+
+	flags = data->flags;
+	flags |= CLK_DIVIDER_HIWORD_MASK;
+
+	if (data->table)
+		clk = clk_register_divider_table(NULL, clk_name, clk_parent, 0,
+						reg, data->shift, data->width,
+						flags, data->table, &clk_lock);
+	else
+		clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
+						reg, data->shift, data->width,
+						flags, &clk_lock);
+	if (clk)
+		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+
+/*
+ * Gate clocks
+ */
+
+static void __init rockchip_gate_clk_setup(struct device_node *node,
+					    void *data)
+{
+	struct clk_onecell_data *clk_data;
+	const char *clk_parent;
+	const char *clk_name;
+	void __iomem *reg;
+	void __iomem *reg_idx;
+	int flags;
+	int qty;
+	int reg_bit;
+	int clkflags = CLK_SET_RATE_PARENT;
+	int i;
+
+	qty = of_property_count_strings(node, "clock-output-names");
+	if (qty < 0) {
+		pr_err("%s: error in clock-output-names %d\n", __func__, qty);
+		return;
+	}
+
+	if (qty == 0) {
+		pr_info("%s: nothing to do\n", __func__);
+		return;
+	}
+
+	reg = of_iomap(node, 0);
+
+	clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+	if (!clk_data)
+		return;
+
+	clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL);
+	if (!clk_data->clks) {
+		kfree(clk_data);
+		return;
+	}
+
+	flags = CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE;
+
+	for (i = 0; i < qty; i++) {
+		of_property_read_string_index(node, "clock-output-names",
+					      i, &clk_name);
+
+		/* ignore empty slots */
+		if (!strcmp("reserved", clk_name))
+			continue;
+
+		clk_parent = of_clk_get_parent_name(node, i);
+
+		/* keep all gates untouched for now */
+		clkflags |= CLK_IGNORE_UNUSED;
+
+		reg_idx = reg + (4 * (i / 16));
+		reg_bit = (i % 16);
+
+		clk_data->clks[i] = clk_register_gate(NULL, clk_name,
+						      clk_parent, clkflags,
+						      reg_idx, reg_bit,
+						      flags,
+						      &clk_lock);
+		WARN_ON(IS_ERR(clk_data->clks[i]));
+	}
+
+	clk_data->clk_num = qty;
+
+	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+}
+
+static const __initconst struct of_device_id clk_gate_match[] = {
+	{ .compatible = "rockchip,rk2928-gate-clk" },
+	{}
+};
+
+void __init of_rockchip_clk_table_clock_setup(
+					const struct of_device_id *clk_match,
+					void *function)
+{
+	struct device_node *np;
+	const struct div_data *data;
+	const struct of_device_id *match;
+	void (*setup_function)(struct device_node *, const void *) = function;
+
+	for_each_matching_node(np, clk_match) {
+		match = of_match_node(clk_match, np);
+		data = match->data;
+		setup_function(np, data);
+	}
+}
+
+void __init rockchip_init_clocks(struct device_node *node)
+{
+	of_rockchip_clk_table_clock_setup(clk_pll_match,
+					  rockchip_pll_setup);
+
+	of_rockchip_clk_table_clock_setup(clk_mux_match,
+					  rockchip_mux_clk_setup);
+
+	of_rockchip_clk_table_clock_setup(clk_gate_match,
+					  rockchip_gate_clk_setup);
+
+	of_rockchip_clk_table_clock_setup(clk_divider_match,
+					  rockchip_divider_clk_setup);
+}
+CLK_OF_DECLARE(rockchip_clocks, "rockchip,clocks", rockchip_init_clocks);
-- 
1.7.2.3


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

* [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support
@ 2013-06-11 11:31   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:31 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Mike Turquette, Seungwon Jeon, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Jaehoon Chung,
	Andy Shevchenko, Grant Likely, Russell King, Chris Ball,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

This adds basic support for clocks on Rockchip rk3066 SoCs.
The clock handling thru small dt nodes is heavily inspired by the
sunxi clk code.

The plls are currently read-only, as their setting needs more
investigation. This also results in slow cpu speeds, as the apll starts
at a default of 600mhz.

Signed-off-by: Heiko Stuebner <heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
---
 arch/arm/boot/dts/rk3066a-clocks.dtsi   |  467 +++++++++++++++++++++++++++++++
 drivers/clk/Makefile                    |    1 +
 drivers/clk/rockchip/Makefile           |    6 +
 drivers/clk/rockchip/clk-rockchip-pll.c |  131 +++++++++
 drivers/clk/rockchip/clk-rockchip-pll.h |   19 ++
 drivers/clk/rockchip/clk-rockchip.c     |  330 ++++++++++++++++++++++
 6 files changed, 954 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/boot/dts/rk3066a-clocks.dtsi
 create mode 100644 drivers/clk/rockchip/Makefile
 create mode 100644 drivers/clk/rockchip/clk-rockchip-pll.c
 create mode 100644 drivers/clk/rockchip/clk-rockchip-pll.h
 create mode 100644 drivers/clk/rockchip/clk-rockchip.c

diff --git a/arch/arm/boot/dts/rk3066a-clocks.dtsi b/arch/arm/boot/dts/rk3066a-clocks.dtsi
new file mode 100644
index 0000000..d797710
--- /dev/null
+++ b/arch/arm/boot/dts/rk3066a-clocks.dtsi
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	clocks {
+		compatible = "rockchip,clocks";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		/*
+		 * This is a dummy clock, to be used as placeholder on
+		 * other mux clocks when a specific parent clock is not
+		 * yet implemented. It should be dropped when the driver
+		 * is complete.
+		 */
+		dummy: dummy {
+			compatible = "fixed-clock";
+			clock-frequency = <0>;
+			#clock-cells = <0>;
+		};
+
+		xin24m: xin24m {
+			compatible = "fixed-clock";
+			clock-frequency = <24000000>;
+			#clock-cells = <0>;
+		};
+
+		apll: apll@20000000 {
+			compatible = "rockchip,rk3066a-apll";
+			reg = <0x20000000 0x10>,
+			      <0x20000040 0x04>;
+			clocks = <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		dpll: dpll@20000000 {
+			compatible = "rockchip,rk3066a-dpll";
+			reg = <0x20000010 0x10>,
+			      <0x20000040 0x04>;
+			clocks = <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		cpll: cpll@20000000 {
+			compatible = "rockchip,rk3066a-cpll";
+			reg = <0x20000020 0x10>,
+			      <0x20000040 0x04>;
+			clocks = <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		gpll: gpll@20000000 {
+			compatible = "rockchip,rk3066a-gpll";
+			reg = <0x20000030 0x10>,
+			      <0x20000040 0x04>;
+			clocks = <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		mux_aclk_periph: mux-aclk-periph@2000006c {
+			compatible = "rockchip,rk2928-gpll-cpll-bit15-mux";
+			reg = <0x2000006c 0x04>;
+			clocks = <&gpll>, <&cpll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart_pll: mux-uart_pll@20000074 {
+			compatible = "rockchip,rk2928-gpll-cpll-bit15-mux";
+			reg = <0x20000074 0x04>;
+			clocks = <&gpll>, <&cpll>;
+			#clock-cells = <0>;
+		};
+
+		div_uart0: div-uart0@20000078 {
+			compatible = "rockchip,rk2928-uart-divider";
+			reg = <0x20000078 0x04>;
+			clocks = <&mux_uart_pll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart0: mux-uart0@20000078 {
+			compatible = "rockchip,rk2928-uart-mux";
+			reg = <0x20000078 0x04>;
+			clocks = <&clk_gates1 8>, <&dummy>, <&xin24m>; /* dummy is uart0_frac_div */
+			#clock-cells = <0>;
+		};
+
+		div_uart1: div-uart1@2000007c {
+			compatible = "rockchip,rk2928-uart-divider";
+			reg = <0x2000007c 0x04>;
+			clocks = <&mux_uart_pll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart1: mux-uart1@2000007c {
+			compatible = "rockchip,rk2928-uart-mux";
+			reg = <0x2000007c 0x04>;
+			clocks = <&clk_gates1 10>, <&dummy>, <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		div_uart2: div-uart2@20000080 {
+			compatible = "rockchip,rk2928-uart-divider";
+			reg = <0x20000080 0x04>;
+			clocks = <&mux_uart_pll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart2: mux-uart2@20000080 {
+			compatible = "rockchip,rk2928-uart-mux";
+			reg = <0x20000080 0x04>;
+			clocks = <&clk_gates1 12>, <&dummy>, <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		div_uart3: div-uart3@20000084 {
+			compatible = "rockchip,rk2928-uart-divider";
+			reg = <0x20000084 0x04>;
+			clocks = <&mux_uart_pll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart3: mux-uart3@20000084 {
+			compatible = "rockchip,rk2928-uart-mux";
+			reg = <0x20000084 0x04>;
+			clocks = <&clk_gates1 14>, <&dummy>, <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		mux_cpu: mux-cpu@20000044 {
+			compatible = "rockchip,rk3066-cpu-mux";
+			reg = <0x20000044 0x4>;
+			clocks = <&apll>, <&dummy> /* cpu_gpll_path */;
+			#clock-cells = <0>;
+		};
+
+		div_cpu: div-cpu@20000044 {
+			compatible = "rockchip,rk3066a-cpu-divider";
+			reg = <0x20000044 0x4>;
+			clocks = <&mux_cpu>;
+			#clock-cells = <0>;
+		};
+
+		div_core_periph: div-core-periph@20000044 {
+			compatible = "rockchip,rk3066a-core-periph-divider";
+			reg = <0x20000044 0x4>;
+			clocks = <&div_cpu>;
+			#clock-cells = <0>;
+		};
+
+		div_aclk_cpu: div-aclk-cpu@20000048 {
+			compatible = "rockchip,rk3066a-aclk-cpu-divider";
+			reg = <0x20000048 0x4>;
+			clocks = <&div_cpu>;
+			#clock-cells = <0>;
+		};
+
+		div_aclk_periph: div-aclk-periph@2000006c {
+			compatible = "rockchip,rk2928-aclk-periph-divider";
+			reg = <0x2000006c 0x4>;
+			clocks = <&mux_aclk_periph>;
+			#clock-cells = <0>;
+		};
+
+		div_hclk_periph: div-hclk-periph@2000006c {
+			compatible = "rockchip,rk2928-hclk-divider";
+			reg = <0x2000006c 0x4>;
+			clocks = <&clk_gates2 1>;
+			#clock-cells = <0>;
+		};
+
+		div_pclk_periph: div-pclk-periph@2000006c {
+			compatible = "rockchip,rk2928-pclk-divider";
+			reg = <0x2000006c 0x4>;
+			clocks = <&clk_gates2 1>;
+			#clock-cells = <0>;
+		};
+
+		div_hclk_cpu: div-hclk-cpu@20000048 {
+			compatible = "rockchip,rk2928-hclk-divider";
+			reg = <0x20000048 0x4>;
+			clocks = <&clk_gates0 3>;
+			#clock-cells = <0>;
+		};
+
+		div_pclk_cpu: div-pclk-cpu@20000048 {
+			compatible = "rockchip,rk2928-pclk-divider";
+			reg = <0x20000048 0x4>;
+			clocks = <&clk_gates0 3>;
+			#clock-cells = <0>;
+		};
+
+		div_mmc0: div-mmc0@20000070 {
+			compatible = "rockchip,rk2928-mmc-divider";
+			reg = <0x20000070 0x4>;
+			clocks = <&clk_gates2 2>;
+			#clock-cells = <0>;
+		};
+
+		div_mmc1: div-mmc1@20000074 {
+			compatible = "rockchip,rk2928-mmc-divider";
+			reg = <0x20000074 0x4>;
+			clocks = <&clk_gates2 2>;
+			#clock-cells = <0>;
+		};
+
+		clk_gates0: gate-clk@200000d0 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000d0 0x4>;
+			clocks = <&dummy>, <&dummy>,
+				 <&dummy>, <&div_aclk_cpu>,
+				 <&div_hclk_cpu>, <&div_pclk_cpu>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>;
+
+			clock-output-names =
+				"gate_core_periph", "gate_cpu_gpll",
+				"gate_ddrphy", "gate_aclk_cpu",
+				"gate_hclk_cpu", "gate_pclk_cpu",
+				"gate_atclk_cpu", "gate_i2s0",
+				"gate_i2s0_frac", "gate_i2s1",
+				"gate_i2s1_frac", "gate_i2s2",
+				"gate_i2s2_frac", "gate_spdif",
+				"gate_spdif_frac", "gate_testclk";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates1: gate-clk@200000d4 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000d4 0x4>;
+			clocks = <&xin24m>, <&xin24m>,
+				 <&xin24m>, <&dummy>,
+				 <&dummy>, <&xin24m>,
+				 <&xin24m>, <&dummy>,
+				 <&div_uart0>, <&dummy>,
+				 <&div_uart1>, <&dummy>,
+				 <&div_uart2>, <&dummy>,
+				 <&div_uart3>, <&dummy>;
+
+			clock-output-names =
+				"gate_timer0", "gate_timer1",
+				"gate_timer2", "gate_jtag",
+				"gate_aclk_lcdc1_src", "gate_otgphy0",
+				"gate_otgphy1", "gate_ddr_gpll",
+				"gate_uart0", "gate_frac_uart0",
+				"gate_uart1", "gate_frac_uart1",
+				"gate_uart2", "gate_frac_uart2",
+				"gate_uart3", "gate_frac_uart3";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates2: gate-clk@200000d8 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000d8 0x4>;
+			clocks = <&clk_gates2 1>, <&div_aclk_periph>,
+				 <&div_hclk_periph>, <&div_pclk_periph>,
+				 <&dummy>, <&dummy>,
+				 <&clk_gates2 3>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&div_mmc0>,
+				 <&dummy>, <&div_mmc1>,
+				 <&dummy>, <&dummy>;
+
+			clock-output-names =
+				"gate_periph_src", "gate_aclk_periph",
+				"gate_hclk_periph", "gate_pclk_periph",
+				"gate_smc", "gate_mac",
+				"gate_hsadc", "gate_hsadc_frac",
+				"gate_saradc", "gate_spi0",
+				"gate_spi1", "gate_mmc0",
+				"gate_mac_lbtest", "gate_mmc1",
+				"gate_emmc", "gate_tsadc";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates3: gate-clk@200000dc {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000dc 0x4>;
+			clocks = <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>;
+
+			clock-output-names =
+				"gate_aclk_lcdc0_src", "gate_dclk_lcdc0",
+				"gate_dclk_lcdc1", "gate_pclkin_cif0",
+				"gate_pclkin_cif1", "reserved",
+				"reserved", "gate_cif0_out",
+				"gate_cif1_out", "gate_aclk_vepu",
+				"gate_hclk_vepu", "gate_aclk_vdpu",
+				"gate_hclk_vdpu", "gate_gpu_src",
+				"reserved", "gate_xin27m";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates4: gate-clk@200000e0 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000e0 0x4>;
+			clocks = <&clk_gates2 2>, <&clk_gates2 3>,
+				 <&clk_gates2 1>, <&clk_gates2 1>,
+				 <&clk_gates2 1>, <&clk_gates2 2>,
+				 <&clk_gates2 2>, <&clk_gates2 2>,
+				 <&clk_gates0 4>, <&clk_gates0 4>,
+				 <&clk_gates0 3>, <&clk_gates0 3>,
+				 <&clk_gates0 3>, <&clk_gates2 3>,
+				 <&clk_gates0 4>;
+
+			clock-output-names =
+				"gate_hclk_peri_axi_matrix", "gate_pclk_peri_axi_matrix",
+				"gate_aclk_cpu_peri", "gate_aclk_peri_axi_matrix",
+				"gate_aclk_pei_niu", "gate_hclk_usb_peri",
+				"gate_hclk_peri_ahb_arbi", "gate_hclk_emem_peri",
+				"gate_hclk_cpubus", "gate_hclk_ahb2apb",
+				"gate_aclk_strc_sys", "gate_aclk_l2mem_con",
+				"gate_aclk_intmem", "gate_pclk_tsadc",
+				"gate_hclk_hdmi";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates5: gate-clk@200000e4 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000e4 0x4>;
+			clocks = <&clk_gates0 3>, <&clk_gates2 1>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates0 4>, <&clk_gates0 5>,
+				 <&clk_gates2 1>, <&clk_gates2 2>,
+				 <&clk_gates2 2>, <&clk_gates2 2>,
+				 <&clk_gates2 2>, <&clk_gates4 5>,
+				 <&clk_gates4 5>, <&dummy>;
+
+			clock-output-names =
+				"gate_aclk_dmac1", "gate_aclk_dmac2",
+				"gate_pclk_efuse", "gate_pclk_tzpc",
+				"gate_pclk_grf", "gate_pclk_pmu",
+				"gate_hclk_rom", "gate_pclk_ddrupctl",
+				"gate_aclk_smc", "gate_hclk_nandc",
+				"gate_hclk_mmc0", "gate_hclk_mmc1",
+				"gate_hclk_emmc", "gate_hclk_otg0",
+				"gate_hclk_otg1", "gate_aclk_gpu";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates6: gate-clk@200000e8 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000e8 0x4>;
+			clocks = <&clk_gates3 0>, <&clk_gates0 4>,
+				 <&clk_gates0 4>, <&clk_gates1 4>,
+				 <&clk_gates0 4>, <&clk_gates3 0>,
+				 <&clk_gates0 4>, <&clk_gates1 4>,
+				 <&clk_gates3 0>, <&clk_gates0 4>,
+				 <&clk_gates0 4>, <&clk_gates1 4>,
+				 <&clk_gates0 4>, <&clk_gates3 0>,
+				 <&dummy>, <&dummy>;
+
+			clock-output-names =
+				"gate_aclk_lcdc0", "gate_hclk_lcdc0",
+				"gate_hclk_lcdc1", "gate_aclk_lcdc1",
+				"gate_hclk_cif0", "gate_aclk_cif0",
+				"gate_hclk_cif1", "gate_aclk_cif1",
+				"gate_aclk_ipp", "gate_hclk_ipp",
+				"gate_hclk_rga", "gate_aclk_rga",
+				"gate_hclk_vio_bus", "gate_aclk_vio0",
+				"gate_aclk_vcodec", "gate_shclk_vio_h2h";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates7: gate-clk@200000ec {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000ec 0x4>;
+			clocks = <&clk_gates2 2>, <&clk_gates0 4>,
+				 <&clk_gates0 4>, <&clk_gates0 4>,
+				 <&clk_gates0 4>, <&clk_gates2 2>,
+				 <&clk_gates2 2>, <&clk_gates0 5>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates0 5>, <&clk_gates2 3>,
+				 <&clk_gates2 3>, <&clk_gates2 3>,
+				 <&clk_gates2 3>, <&clk_gates2 3>;
+
+			clock-output-names =
+				"gate_hclk_emac", "gate_hclk_spdif",
+				"gate_hclk_i2s0_2ch", "gate_hclk_i2s1_2ch",
+				"gate_hclk_i2s_8ch", "gate_hclk_hsadc",
+				"gate_hclk_pidf", "gate_pclk_timer0",
+				"gate_pclk_timer1", "gate_pclk_timer2",
+				"gate_pclk_pwm01", "gate_pclk_pwm23",
+				"gate_pclk_spi0", "gate_pclk_spi1",
+				"gate_pclk_saradc", "gate_pclk_wdt";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates8: gate-clk@200000f0 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000f0 0x4>;
+			clocks = <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates2 3>, <&clk_gates2 3>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates2 3>, <&clk_gates2 3>,
+				 <&clk_gates2 3>, <&clk_gates0 5>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates2 3>, <&clk_gates2 3>,
+				 <&dummy>, <&clk_gates0 5>;
+
+			clock-output-names =
+				"gate_pclk_uart0", "gate_pclk_uart1",
+				"gate_pclk_uart2", "gate_pclk_uart3",
+				"gate_pclk_i2c0", "gate_pclk_i2c1",
+				"gate_pclk_i2c2", "gate_pclk_i2c3",
+				"gate_pclk_i2c4", "gate_pclk_gpio0",
+				"gate_pclk_gpio1", "gate_pclk_gpio2",
+				"gate_pclk_gpio3", "gate_pclk_gpio4",
+				"reserved", "gate_pclk_gpio6";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates9: gate-clk@200000f4 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000f4 0x4>;
+			clocks = <&dummy>, <&clk_gates0 5>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&clk_gates1 4>,
+				 <&clk_gates0 5>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>;
+
+			clock-output-names =
+				"gate_clk_core_dbg", "gate_pclk_dbg",
+				"gate_clk_trace", "gate_atclk",
+				"gate_clk_l2c", "gate_aclk_vio1",
+				"gate_pclk_publ", "gate_aclk_intmem0",
+				"gate_aclk_intmem1", "gate_aclk_intmem2",
+				"gate_aclk_intmem3";
+
+			#clock-cells = <1>;
+		};
+	};
+
+};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f51b52b..2e2e957 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -25,6 +25,7 @@ ifeq ($(CONFIG_COMMON_CLK), y)
 obj-$(CONFIG_ARCH_MMP)		+= mmp/
 endif
 obj-$(CONFIG_MACH_LOONGSON1)	+= clk-ls1x.o
+obj-$(CONFIG_ARCH_ROCKCHIP)	+= rockchip/
 obj-$(CONFIG_ARCH_SUNXI)	+= sunxi/
 obj-$(CONFIG_ARCH_U8500)	+= ux500/
 obj-$(CONFIG_ARCH_VT8500)	+= clk-vt8500.o
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
new file mode 100644
index 0000000..e0fbafb
--- /dev/null
+++ b/drivers/clk/rockchip/Makefile
@@ -0,0 +1,6 @@
+#
+# Rockchip Clock specific Makefile
+#
+
+obj-y	+= clk-rockchip.o
+obj-y	+= clk-rockchip-pll.o
diff --git a/drivers/clk/rockchip/clk-rockchip-pll.c b/drivers/clk/rockchip/clk-rockchip-pll.c
new file mode 100644
index 0000000..4456445
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rockchip-pll.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/div64.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-private.h>
+
+#define RK3X_PLL_MODE_MASK		0x3
+#define RK3X_PLL_MODE_SLOW		0x0
+#define RK3X_PLL_MODE_NORM		0x1
+#define RK3X_PLL_MODE_DEEP		0x2
+
+#define RK3X_PLLCON0_OD_MASK		0xf
+#define RK3X_PLLCON0_OD_SHIFT		0
+#define RK3X_PLLCON0_NR_MASK		0x3f
+#define RK3X_PLLCON0_NR_SHIFT		8
+
+#define RK3X_PLLCON1_NF_MASK		0x1fff
+#define RK3X_PLLCON1_NF_SHIFT		0
+
+#define RK3X_PLLCON3_REST		(1 << 5)
+#define RK3X_PLLCON3_BYPASS		(1 << 0)
+
+struct rockchip_clk_pll {
+	struct clk_hw		hw;
+	void __iomem		*reg_base;
+	void __iomem		*reg_mode;
+	unsigned int		shift_mode;
+	spinlock_t		*lock;
+};
+
+#define to_clk_pll(_hw) container_of(_hw, struct rockchip_clk_pll, hw)
+
+static unsigned long rk3x_generic_pll_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct rockchip_clk_pll *pll = to_clk_pll(hw);
+	u32 pll_con0 = readl_relaxed(pll->reg_base);
+	u32 pll_con1 = readl_relaxed(pll->reg_base + 0x4);
+	u32 pll_con3 = readl_relaxed(pll->reg_base + 0xc);
+	u32 mode_con = readl_relaxed(pll->reg_mode) >> pll->shift_mode;
+	u64 pll_nf;
+	u64 pll_nr;
+	u64 pll_no;
+	u64 rate64;
+
+	if (pll_con3 & RK3X_PLLCON3_BYPASS) {
+		pr_debug("%s: pll %s is bypassed\n", __func__,
+			__clk_get_name(hw->clk));
+		return parent_rate;
+	}
+
+	mode_con &= RK3X_PLL_MODE_MASK;
+	if (mode_con != RK3X_PLL_MODE_NORM) {
+		pr_debug("%s: pll %s not in normal mode: %d\n", __func__,
+			__clk_get_name(hw->clk), mode_con);
+		return parent_rate;
+	}
+
+	pll_nf = (pll_con1 >> RK3X_PLLCON1_NF_SHIFT);
+	pll_nf &= RK3X_PLLCON1_NF_MASK;
+	pll_nf++;
+	rate64 = (u64)parent_rate * pll_nf;
+
+	pll_nr = (pll_con0 >> RK3X_PLLCON0_NR_SHIFT);
+	pll_nr &= RK3X_PLLCON0_NR_MASK;
+	pll_nr++;
+	do_div(rate64, pll_nr);
+
+	pll_no = (pll_con0 >> RK3X_PLLCON0_OD_SHIFT);
+	pll_no &= RK3X_PLLCON0_OD_MASK;
+	pll_no++;
+	do_div(rate64, pll_no);
+
+	return (unsigned long)rate64;
+}
+
+static const struct clk_ops rk3x_generic_pll_clk_ops = {
+	.recalc_rate = rk3x_generic_pll_recalc_rate,
+};
+
+struct clk * __init rockchip_clk_register_rk3x_pll(const char *name,
+			const char *pname, void __iomem *reg_base,
+			void __iomem *reg_mode, unsigned int shift_mode,
+			spinlock_t *lock)
+{
+	struct rockchip_clk_pll *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll) {
+		pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+		return NULL;
+	}
+
+	init.name = name;
+	init.ops = &rk3x_generic_pll_clk_ops;
+	init.flags = CLK_GET_RATE_NOCACHE;
+	init.parent_names = &pname;
+	init.num_parents = 1;
+
+	pll->hw.init = &init;
+	pll->reg_base = reg_base;
+	pll->reg_mode = reg_mode;
+	pll->shift_mode = shift_mode;
+	pll->lock = lock;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: failed to register pll clock %s\n", __func__,
+				name);
+		kfree(pll);
+	}
+
+	return clk;
+}
diff --git a/drivers/clk/rockchip/clk-rockchip-pll.h b/drivers/clk/rockchip/clk-rockchip-pll.h
new file mode 100644
index 0000000..a63288a
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rockchip-pll.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+extern struct clk * __init rockchip_clk_register_rk3x_pll(const char *name,
+			const char *pname, const void __iomem *reg_base,
+			const void __iomem *reg_mode, unsigned int shift_mode,
+			spinlock_t *lock);
diff --git a/drivers/clk/rockchip/clk-rockchip.c b/drivers/clk/rockchip/clk-rockchip.c
new file mode 100644
index 0000000..660b00f
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rockchip.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "clk-rockchip-pll.h"
+
+static DEFINE_SPINLOCK(clk_lock);
+
+struct rockchip_pll_data {
+	int mode_shift;
+};
+
+struct rockchip_pll_data rk3066a_apll_data = {
+	.mode_shift = 0,
+};
+
+struct rockchip_pll_data rk3066a_dpll_data = {
+	.mode_shift = 4,
+};
+
+struct rockchip_pll_data rk3066a_cpll_data = {
+	.mode_shift = 8,
+};
+
+struct rockchip_pll_data rk3066a_gpll_data = {
+	.mode_shift = 12,
+};
+
+/* Matches for plls */
+static const __initconst struct of_device_id clk_pll_match[] = {
+	{ .compatible = "rockchip,rk3066a-apll", .data = &rk3066a_apll_data },
+	{ .compatible = "rockchip,rk3066a-dpll", .data = &rk3066a_dpll_data },
+	{ .compatible = "rockchip,rk3066a-cpll", .data = &rk3066a_cpll_data },
+	{ .compatible = "rockchip,rk3066a-gpll", .data = &rk3066a_gpll_data },
+	{}
+};
+
+static void __init rockchip_pll_setup(struct device_node *node,
+				      struct rockchip_pll_data *data)
+{
+	struct clk *clk;
+	const char *clk_name = node->name;
+	const char *clk_parent;
+	void __iomem *reg_base;
+	void __iomem *reg_mode;
+	u32 rate;
+
+	reg_base = of_iomap(node, 0);
+	reg_mode = of_iomap(node, 1);
+
+	clk_parent = of_clk_get_parent_name(node, 0);
+
+	pr_debug("%s: adding %s as child of %s\n",
+		__func__, clk_name, clk_parent);
+
+	clk = rockchip_clk_register_rk3x_pll(clk_name, clk_parent, reg_base,
+					     reg_mode, data->mode_shift,
+					     &clk_lock);
+	if (clk) {
+		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+		/* optionally set a target frequency for the pll */
+		if (!of_property_read_u32(node, "clock-frequency", &rate))
+			clk_set_rate(clk, rate);
+	}
+}
+
+/*
+ * Mux clocks
+ */
+
+struct rockchip_mux_data {
+	int shift;
+	int width;
+};
+
+#define RK_MUX(n, s, w)					\
+static const __initconst struct rockchip_mux_data n = {	\
+	.shift = s,					\
+	.width = w,					\
+}
+
+RK_MUX(gpll_cpll_15_mux_data, 15, 1);
+RK_MUX(uart_mux_data, 8, 2);
+RK_MUX(cpu_mux_data, 8, 1);
+
+static const __initconst struct of_device_id clk_mux_match[] = {
+	{ .compatible = "rockchip,rk2928-gpll-cpll-bit15-mux",
+		.data = &gpll_cpll_15_mux_data },
+	{ .compatible = "rockchip,rk2928-uart-mux",
+		.data = &uart_mux_data },
+	{ .compatible = "rockchip,rk3066-cpu-mux",
+		.data = &cpu_mux_data },
+	{}
+};
+
+static void __init rockchip_mux_clk_setup(struct device_node *node,
+					  struct rockchip_mux_data *data)
+{
+	struct clk *clk;
+	const char *clk_name = node->name;
+	void __iomem *reg;
+	int max_parents = (1 << data->width);
+	const char *parents[max_parents];
+	int flags;
+	int i = 0;
+
+	reg = of_iomap(node, 0);
+
+	while (i < max_parents &&
+	       (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
+		i++;
+
+	flags = CLK_MUX_HIWORD_MASK;
+
+	clk = clk_register_mux(NULL, clk_name, parents, i, 0,
+			       reg, data->shift, data->width,
+			       flags, &clk_lock);
+	if (clk)
+		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+
+/*
+ * Divider clocks
+ */
+
+struct rockchip_div_data {
+	int shift;
+	int width;
+	int flags;
+	struct clk_div_table *table;
+};
+
+#define RK_DIV(n, s, w, f, t)				\
+static const __initconst struct rockchip_div_data n = {	\
+	.shift = s,					\
+	.width = w,					\
+	.flags = f,					\
+	.table = t,					\
+}
+
+RK_DIV(cpu_div_data, 0, 5, 0, NULL);
+RK_DIV(aclk_periph_div_data, 0, 5, 0, NULL);
+RK_DIV(aclk_cpu_div_data, 0, 3, 0, NULL);
+RK_DIV(hclk_div_data, 8, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+RK_DIV(pclk_div_data, 12, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+RK_DIV(mmc_div_data, 0, 6, CLK_DIVIDER_EVEN, NULL);
+RK_DIV(uart_div_data, 0, 7, 0, NULL);
+
+struct clk_div_table core_periph_table[] = {
+	{ 0, 2 },
+	{ 1, 4 },
+	{ 2, 8 },
+	{ 3, 16 },
+	{ 0, 0 },
+};
+RK_DIV(core_periph_div_data, 6, 2, 0, core_periph_table);
+
+static const __initconst struct of_device_id clk_divider_match[] = {
+	{ .compatible = "rockchip,rk3066a-cpu-divider",
+		.data = &cpu_div_data },
+	{ .compatible = "rockchip,rk3066a-core-periph-divider",
+		.data = &core_periph_div_data },
+	{ .compatible = "rockchip,rk2928-aclk-periph-divider",
+		.data = &aclk_periph_div_data },
+	{ .compatible = "rockchip,rk3066a-aclk-cpu-divider",
+		.data = &aclk_cpu_div_data },
+	{ .compatible = "rockchip,rk2928-hclk-divider",
+		.data = &hclk_div_data },
+	{ .compatible = "rockchip,rk2928-pclk-divider",
+		.data = &pclk_div_data },
+	{ .compatible = "rockchip,rk2928-mmc-divider",
+		.data = &mmc_div_data },
+	{ .compatible = "rockchip,rk2928-uart-divider",
+		.data = &uart_div_data },
+	{}
+};
+
+static void __init rockchip_divider_clk_setup(struct device_node *node,
+					      struct rockchip_div_data *data)
+{
+	struct clk *clk;
+	const char *clk_name = node->name;
+	const char *clk_parent;
+	void __iomem *reg;
+	int flags;
+
+	reg = of_iomap(node, 0);
+
+	clk_parent = of_clk_get_parent_name(node, 0);
+
+	flags = data->flags;
+	flags |= CLK_DIVIDER_HIWORD_MASK;
+
+	if (data->table)
+		clk = clk_register_divider_table(NULL, clk_name, clk_parent, 0,
+						reg, data->shift, data->width,
+						flags, data->table, &clk_lock);
+	else
+		clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
+						reg, data->shift, data->width,
+						flags, &clk_lock);
+	if (clk)
+		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+
+/*
+ * Gate clocks
+ */
+
+static void __init rockchip_gate_clk_setup(struct device_node *node,
+					    void *data)
+{
+	struct clk_onecell_data *clk_data;
+	const char *clk_parent;
+	const char *clk_name;
+	void __iomem *reg;
+	void __iomem *reg_idx;
+	int flags;
+	int qty;
+	int reg_bit;
+	int clkflags = CLK_SET_RATE_PARENT;
+	int i;
+
+	qty = of_property_count_strings(node, "clock-output-names");
+	if (qty < 0) {
+		pr_err("%s: error in clock-output-names %d\n", __func__, qty);
+		return;
+	}
+
+	if (qty == 0) {
+		pr_info("%s: nothing to do\n", __func__);
+		return;
+	}
+
+	reg = of_iomap(node, 0);
+
+	clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+	if (!clk_data)
+		return;
+
+	clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL);
+	if (!clk_data->clks) {
+		kfree(clk_data);
+		return;
+	}
+
+	flags = CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE;
+
+	for (i = 0; i < qty; i++) {
+		of_property_read_string_index(node, "clock-output-names",
+					      i, &clk_name);
+
+		/* ignore empty slots */
+		if (!strcmp("reserved", clk_name))
+			continue;
+
+		clk_parent = of_clk_get_parent_name(node, i);
+
+		/* keep all gates untouched for now */
+		clkflags |= CLK_IGNORE_UNUSED;
+
+		reg_idx = reg + (4 * (i / 16));
+		reg_bit = (i % 16);
+
+		clk_data->clks[i] = clk_register_gate(NULL, clk_name,
+						      clk_parent, clkflags,
+						      reg_idx, reg_bit,
+						      flags,
+						      &clk_lock);
+		WARN_ON(IS_ERR(clk_data->clks[i]));
+	}
+
+	clk_data->clk_num = qty;
+
+	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+}
+
+static const __initconst struct of_device_id clk_gate_match[] = {
+	{ .compatible = "rockchip,rk2928-gate-clk" },
+	{}
+};
+
+void __init of_rockchip_clk_table_clock_setup(
+					const struct of_device_id *clk_match,
+					void *function)
+{
+	struct device_node *np;
+	const struct div_data *data;
+	const struct of_device_id *match;
+	void (*setup_function)(struct device_node *, const void *) = function;
+
+	for_each_matching_node(np, clk_match) {
+		match = of_match_node(clk_match, np);
+		data = match->data;
+		setup_function(np, data);
+	}
+}
+
+void __init rockchip_init_clocks(struct device_node *node)
+{
+	of_rockchip_clk_table_clock_setup(clk_pll_match,
+					  rockchip_pll_setup);
+
+	of_rockchip_clk_table_clock_setup(clk_mux_match,
+					  rockchip_mux_clk_setup);
+
+	of_rockchip_clk_table_clock_setup(clk_gate_match,
+					  rockchip_gate_clk_setup);
+
+	of_rockchip_clk_table_clock_setup(clk_divider_match,
+					  rockchip_divider_clk_setup);
+}
+CLK_OF_DECLARE(rockchip_clocks, "rockchip,clocks", rockchip_init_clocks);
-- 
1.7.2.3

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

* [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support
@ 2013-06-11 11:31   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

This adds basic support for clocks on Rockchip rk3066 SoCs.
The clock handling thru small dt nodes is heavily inspired by the
sunxi clk code.

The plls are currently read-only, as their setting needs more
investigation. This also results in slow cpu speeds, as the apll starts
at a default of 600mhz.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/boot/dts/rk3066a-clocks.dtsi   |  467 +++++++++++++++++++++++++++++++
 drivers/clk/Makefile                    |    1 +
 drivers/clk/rockchip/Makefile           |    6 +
 drivers/clk/rockchip/clk-rockchip-pll.c |  131 +++++++++
 drivers/clk/rockchip/clk-rockchip-pll.h |   19 ++
 drivers/clk/rockchip/clk-rockchip.c     |  330 ++++++++++++++++++++++
 6 files changed, 954 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/boot/dts/rk3066a-clocks.dtsi
 create mode 100644 drivers/clk/rockchip/Makefile
 create mode 100644 drivers/clk/rockchip/clk-rockchip-pll.c
 create mode 100644 drivers/clk/rockchip/clk-rockchip-pll.h
 create mode 100644 drivers/clk/rockchip/clk-rockchip.c

diff --git a/arch/arm/boot/dts/rk3066a-clocks.dtsi b/arch/arm/boot/dts/rk3066a-clocks.dtsi
new file mode 100644
index 0000000..d797710
--- /dev/null
+++ b/arch/arm/boot/dts/rk3066a-clocks.dtsi
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	clocks {
+		compatible = "rockchip,clocks";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		/*
+		 * This is a dummy clock, to be used as placeholder on
+		 * other mux clocks when a specific parent clock is not
+		 * yet implemented. It should be dropped when the driver
+		 * is complete.
+		 */
+		dummy: dummy {
+			compatible = "fixed-clock";
+			clock-frequency = <0>;
+			#clock-cells = <0>;
+		};
+
+		xin24m: xin24m {
+			compatible = "fixed-clock";
+			clock-frequency = <24000000>;
+			#clock-cells = <0>;
+		};
+
+		apll: apll at 20000000 {
+			compatible = "rockchip,rk3066a-apll";
+			reg = <0x20000000 0x10>,
+			      <0x20000040 0x04>;
+			clocks = <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		dpll: dpll at 20000000 {
+			compatible = "rockchip,rk3066a-dpll";
+			reg = <0x20000010 0x10>,
+			      <0x20000040 0x04>;
+			clocks = <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		cpll: cpll at 20000000 {
+			compatible = "rockchip,rk3066a-cpll";
+			reg = <0x20000020 0x10>,
+			      <0x20000040 0x04>;
+			clocks = <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		gpll: gpll at 20000000 {
+			compatible = "rockchip,rk3066a-gpll";
+			reg = <0x20000030 0x10>,
+			      <0x20000040 0x04>;
+			clocks = <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		mux_aclk_periph: mux-aclk-periph at 2000006c {
+			compatible = "rockchip,rk2928-gpll-cpll-bit15-mux";
+			reg = <0x2000006c 0x04>;
+			clocks = <&gpll>, <&cpll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart_pll: mux-uart_pll at 20000074 {
+			compatible = "rockchip,rk2928-gpll-cpll-bit15-mux";
+			reg = <0x20000074 0x04>;
+			clocks = <&gpll>, <&cpll>;
+			#clock-cells = <0>;
+		};
+
+		div_uart0: div-uart0 at 20000078 {
+			compatible = "rockchip,rk2928-uart-divider";
+			reg = <0x20000078 0x04>;
+			clocks = <&mux_uart_pll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart0: mux-uart0 at 20000078 {
+			compatible = "rockchip,rk2928-uart-mux";
+			reg = <0x20000078 0x04>;
+			clocks = <&clk_gates1 8>, <&dummy>, <&xin24m>; /* dummy is uart0_frac_div */
+			#clock-cells = <0>;
+		};
+
+		div_uart1: div-uart1 at 2000007c {
+			compatible = "rockchip,rk2928-uart-divider";
+			reg = <0x2000007c 0x04>;
+			clocks = <&mux_uart_pll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart1: mux-uart1 at 2000007c {
+			compatible = "rockchip,rk2928-uart-mux";
+			reg = <0x2000007c 0x04>;
+			clocks = <&clk_gates1 10>, <&dummy>, <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		div_uart2: div-uart2 at 20000080 {
+			compatible = "rockchip,rk2928-uart-divider";
+			reg = <0x20000080 0x04>;
+			clocks = <&mux_uart_pll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart2: mux-uart2 at 20000080 {
+			compatible = "rockchip,rk2928-uart-mux";
+			reg = <0x20000080 0x04>;
+			clocks = <&clk_gates1 12>, <&dummy>, <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		div_uart3: div-uart3 at 20000084 {
+			compatible = "rockchip,rk2928-uart-divider";
+			reg = <0x20000084 0x04>;
+			clocks = <&mux_uart_pll>;
+			#clock-cells = <0>;
+		};
+
+		mux_uart3: mux-uart3 at 20000084 {
+			compatible = "rockchip,rk2928-uart-mux";
+			reg = <0x20000084 0x04>;
+			clocks = <&clk_gates1 14>, <&dummy>, <&xin24m>;
+			#clock-cells = <0>;
+		};
+
+		mux_cpu: mux-cpu at 20000044 {
+			compatible = "rockchip,rk3066-cpu-mux";
+			reg = <0x20000044 0x4>;
+			clocks = <&apll>, <&dummy> /* cpu_gpll_path */;
+			#clock-cells = <0>;
+		};
+
+		div_cpu: div-cpu at 20000044 {
+			compatible = "rockchip,rk3066a-cpu-divider";
+			reg = <0x20000044 0x4>;
+			clocks = <&mux_cpu>;
+			#clock-cells = <0>;
+		};
+
+		div_core_periph: div-core-periph at 20000044 {
+			compatible = "rockchip,rk3066a-core-periph-divider";
+			reg = <0x20000044 0x4>;
+			clocks = <&div_cpu>;
+			#clock-cells = <0>;
+		};
+
+		div_aclk_cpu: div-aclk-cpu at 20000048 {
+			compatible = "rockchip,rk3066a-aclk-cpu-divider";
+			reg = <0x20000048 0x4>;
+			clocks = <&div_cpu>;
+			#clock-cells = <0>;
+		};
+
+		div_aclk_periph: div-aclk-periph at 2000006c {
+			compatible = "rockchip,rk2928-aclk-periph-divider";
+			reg = <0x2000006c 0x4>;
+			clocks = <&mux_aclk_periph>;
+			#clock-cells = <0>;
+		};
+
+		div_hclk_periph: div-hclk-periph at 2000006c {
+			compatible = "rockchip,rk2928-hclk-divider";
+			reg = <0x2000006c 0x4>;
+			clocks = <&clk_gates2 1>;
+			#clock-cells = <0>;
+		};
+
+		div_pclk_periph: div-pclk-periph at 2000006c {
+			compatible = "rockchip,rk2928-pclk-divider";
+			reg = <0x2000006c 0x4>;
+			clocks = <&clk_gates2 1>;
+			#clock-cells = <0>;
+		};
+
+		div_hclk_cpu: div-hclk-cpu at 20000048 {
+			compatible = "rockchip,rk2928-hclk-divider";
+			reg = <0x20000048 0x4>;
+			clocks = <&clk_gates0 3>;
+			#clock-cells = <0>;
+		};
+
+		div_pclk_cpu: div-pclk-cpu at 20000048 {
+			compatible = "rockchip,rk2928-pclk-divider";
+			reg = <0x20000048 0x4>;
+			clocks = <&clk_gates0 3>;
+			#clock-cells = <0>;
+		};
+
+		div_mmc0: div-mmc0 at 20000070 {
+			compatible = "rockchip,rk2928-mmc-divider";
+			reg = <0x20000070 0x4>;
+			clocks = <&clk_gates2 2>;
+			#clock-cells = <0>;
+		};
+
+		div_mmc1: div-mmc1 at 20000074 {
+			compatible = "rockchip,rk2928-mmc-divider";
+			reg = <0x20000074 0x4>;
+			clocks = <&clk_gates2 2>;
+			#clock-cells = <0>;
+		};
+
+		clk_gates0: gate-clk at 200000d0 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000d0 0x4>;
+			clocks = <&dummy>, <&dummy>,
+				 <&dummy>, <&div_aclk_cpu>,
+				 <&div_hclk_cpu>, <&div_pclk_cpu>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>;
+
+			clock-output-names =
+				"gate_core_periph", "gate_cpu_gpll",
+				"gate_ddrphy", "gate_aclk_cpu",
+				"gate_hclk_cpu", "gate_pclk_cpu",
+				"gate_atclk_cpu", "gate_i2s0",
+				"gate_i2s0_frac", "gate_i2s1",
+				"gate_i2s1_frac", "gate_i2s2",
+				"gate_i2s2_frac", "gate_spdif",
+				"gate_spdif_frac", "gate_testclk";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates1: gate-clk at 200000d4 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000d4 0x4>;
+			clocks = <&xin24m>, <&xin24m>,
+				 <&xin24m>, <&dummy>,
+				 <&dummy>, <&xin24m>,
+				 <&xin24m>, <&dummy>,
+				 <&div_uart0>, <&dummy>,
+				 <&div_uart1>, <&dummy>,
+				 <&div_uart2>, <&dummy>,
+				 <&div_uart3>, <&dummy>;
+
+			clock-output-names =
+				"gate_timer0", "gate_timer1",
+				"gate_timer2", "gate_jtag",
+				"gate_aclk_lcdc1_src", "gate_otgphy0",
+				"gate_otgphy1", "gate_ddr_gpll",
+				"gate_uart0", "gate_frac_uart0",
+				"gate_uart1", "gate_frac_uart1",
+				"gate_uart2", "gate_frac_uart2",
+				"gate_uart3", "gate_frac_uart3";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates2: gate-clk at 200000d8 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000d8 0x4>;
+			clocks = <&clk_gates2 1>, <&div_aclk_periph>,
+				 <&div_hclk_periph>, <&div_pclk_periph>,
+				 <&dummy>, <&dummy>,
+				 <&clk_gates2 3>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&div_mmc0>,
+				 <&dummy>, <&div_mmc1>,
+				 <&dummy>, <&dummy>;
+
+			clock-output-names =
+				"gate_periph_src", "gate_aclk_periph",
+				"gate_hclk_periph", "gate_pclk_periph",
+				"gate_smc", "gate_mac",
+				"gate_hsadc", "gate_hsadc_frac",
+				"gate_saradc", "gate_spi0",
+				"gate_spi1", "gate_mmc0",
+				"gate_mac_lbtest", "gate_mmc1",
+				"gate_emmc", "gate_tsadc";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates3: gate-clk at 200000dc {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000dc 0x4>;
+			clocks = <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&dummy>;
+
+			clock-output-names =
+				"gate_aclk_lcdc0_src", "gate_dclk_lcdc0",
+				"gate_dclk_lcdc1", "gate_pclkin_cif0",
+				"gate_pclkin_cif1", "reserved",
+				"reserved", "gate_cif0_out",
+				"gate_cif1_out", "gate_aclk_vepu",
+				"gate_hclk_vepu", "gate_aclk_vdpu",
+				"gate_hclk_vdpu", "gate_gpu_src",
+				"reserved", "gate_xin27m";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates4: gate-clk at 200000e0 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000e0 0x4>;
+			clocks = <&clk_gates2 2>, <&clk_gates2 3>,
+				 <&clk_gates2 1>, <&clk_gates2 1>,
+				 <&clk_gates2 1>, <&clk_gates2 2>,
+				 <&clk_gates2 2>, <&clk_gates2 2>,
+				 <&clk_gates0 4>, <&clk_gates0 4>,
+				 <&clk_gates0 3>, <&clk_gates0 3>,
+				 <&clk_gates0 3>, <&clk_gates2 3>,
+				 <&clk_gates0 4>;
+
+			clock-output-names =
+				"gate_hclk_peri_axi_matrix", "gate_pclk_peri_axi_matrix",
+				"gate_aclk_cpu_peri", "gate_aclk_peri_axi_matrix",
+				"gate_aclk_pei_niu", "gate_hclk_usb_peri",
+				"gate_hclk_peri_ahb_arbi", "gate_hclk_emem_peri",
+				"gate_hclk_cpubus", "gate_hclk_ahb2apb",
+				"gate_aclk_strc_sys", "gate_aclk_l2mem_con",
+				"gate_aclk_intmem", "gate_pclk_tsadc",
+				"gate_hclk_hdmi";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates5: gate-clk at 200000e4 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000e4 0x4>;
+			clocks = <&clk_gates0 3>, <&clk_gates2 1>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates0 4>, <&clk_gates0 5>,
+				 <&clk_gates2 1>, <&clk_gates2 2>,
+				 <&clk_gates2 2>, <&clk_gates2 2>,
+				 <&clk_gates2 2>, <&clk_gates4 5>,
+				 <&clk_gates4 5>, <&dummy>;
+
+			clock-output-names =
+				"gate_aclk_dmac1", "gate_aclk_dmac2",
+				"gate_pclk_efuse", "gate_pclk_tzpc",
+				"gate_pclk_grf", "gate_pclk_pmu",
+				"gate_hclk_rom", "gate_pclk_ddrupctl",
+				"gate_aclk_smc", "gate_hclk_nandc",
+				"gate_hclk_mmc0", "gate_hclk_mmc1",
+				"gate_hclk_emmc", "gate_hclk_otg0",
+				"gate_hclk_otg1", "gate_aclk_gpu";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates6: gate-clk at 200000e8 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000e8 0x4>;
+			clocks = <&clk_gates3 0>, <&clk_gates0 4>,
+				 <&clk_gates0 4>, <&clk_gates1 4>,
+				 <&clk_gates0 4>, <&clk_gates3 0>,
+				 <&clk_gates0 4>, <&clk_gates1 4>,
+				 <&clk_gates3 0>, <&clk_gates0 4>,
+				 <&clk_gates0 4>, <&clk_gates1 4>,
+				 <&clk_gates0 4>, <&clk_gates3 0>,
+				 <&dummy>, <&dummy>;
+
+			clock-output-names =
+				"gate_aclk_lcdc0", "gate_hclk_lcdc0",
+				"gate_hclk_lcdc1", "gate_aclk_lcdc1",
+				"gate_hclk_cif0", "gate_aclk_cif0",
+				"gate_hclk_cif1", "gate_aclk_cif1",
+				"gate_aclk_ipp", "gate_hclk_ipp",
+				"gate_hclk_rga", "gate_aclk_rga",
+				"gate_hclk_vio_bus", "gate_aclk_vio0",
+				"gate_aclk_vcodec", "gate_shclk_vio_h2h";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates7: gate-clk at 200000ec {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000ec 0x4>;
+			clocks = <&clk_gates2 2>, <&clk_gates0 4>,
+				 <&clk_gates0 4>, <&clk_gates0 4>,
+				 <&clk_gates0 4>, <&clk_gates2 2>,
+				 <&clk_gates2 2>, <&clk_gates0 5>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates0 5>, <&clk_gates2 3>,
+				 <&clk_gates2 3>, <&clk_gates2 3>,
+				 <&clk_gates2 3>, <&clk_gates2 3>;
+
+			clock-output-names =
+				"gate_hclk_emac", "gate_hclk_spdif",
+				"gate_hclk_i2s0_2ch", "gate_hclk_i2s1_2ch",
+				"gate_hclk_i2s_8ch", "gate_hclk_hsadc",
+				"gate_hclk_pidf", "gate_pclk_timer0",
+				"gate_pclk_timer1", "gate_pclk_timer2",
+				"gate_pclk_pwm01", "gate_pclk_pwm23",
+				"gate_pclk_spi0", "gate_pclk_spi1",
+				"gate_pclk_saradc", "gate_pclk_wdt";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates8: gate-clk at 200000f0 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000f0 0x4>;
+			clocks = <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates2 3>, <&clk_gates2 3>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates2 3>, <&clk_gates2 3>,
+				 <&clk_gates2 3>, <&clk_gates0 5>,
+				 <&clk_gates0 5>, <&clk_gates0 5>,
+				 <&clk_gates2 3>, <&clk_gates2 3>,
+				 <&dummy>, <&clk_gates0 5>;
+
+			clock-output-names =
+				"gate_pclk_uart0", "gate_pclk_uart1",
+				"gate_pclk_uart2", "gate_pclk_uart3",
+				"gate_pclk_i2c0", "gate_pclk_i2c1",
+				"gate_pclk_i2c2", "gate_pclk_i2c3",
+				"gate_pclk_i2c4", "gate_pclk_gpio0",
+				"gate_pclk_gpio1", "gate_pclk_gpio2",
+				"gate_pclk_gpio3", "gate_pclk_gpio4",
+				"reserved", "gate_pclk_gpio6";
+
+			#clock-cells = <1>;
+		};
+
+		clk_gates9: gate-clk at 200000f4 {
+			compatible = "rockchip,rk2928-gate-clk";
+			reg = <0x200000f4 0x4>;
+			clocks = <&dummy>, <&clk_gates0 5>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>, <&clk_gates1 4>,
+				 <&clk_gates0 5>, <&dummy>,
+				 <&dummy>, <&dummy>,
+				 <&dummy>;
+
+			clock-output-names =
+				"gate_clk_core_dbg", "gate_pclk_dbg",
+				"gate_clk_trace", "gate_atclk",
+				"gate_clk_l2c", "gate_aclk_vio1",
+				"gate_pclk_publ", "gate_aclk_intmem0",
+				"gate_aclk_intmem1", "gate_aclk_intmem2",
+				"gate_aclk_intmem3";
+
+			#clock-cells = <1>;
+		};
+	};
+
+};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f51b52b..2e2e957 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -25,6 +25,7 @@ ifeq ($(CONFIG_COMMON_CLK), y)
 obj-$(CONFIG_ARCH_MMP)		+= mmp/
 endif
 obj-$(CONFIG_MACH_LOONGSON1)	+= clk-ls1x.o
+obj-$(CONFIG_ARCH_ROCKCHIP)	+= rockchip/
 obj-$(CONFIG_ARCH_SUNXI)	+= sunxi/
 obj-$(CONFIG_ARCH_U8500)	+= ux500/
 obj-$(CONFIG_ARCH_VT8500)	+= clk-vt8500.o
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
new file mode 100644
index 0000000..e0fbafb
--- /dev/null
+++ b/drivers/clk/rockchip/Makefile
@@ -0,0 +1,6 @@
+#
+# Rockchip Clock specific Makefile
+#
+
+obj-y	+= clk-rockchip.o
+obj-y	+= clk-rockchip-pll.o
diff --git a/drivers/clk/rockchip/clk-rockchip-pll.c b/drivers/clk/rockchip/clk-rockchip-pll.c
new file mode 100644
index 0000000..4456445
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rockchip-pll.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/div64.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-private.h>
+
+#define RK3X_PLL_MODE_MASK		0x3
+#define RK3X_PLL_MODE_SLOW		0x0
+#define RK3X_PLL_MODE_NORM		0x1
+#define RK3X_PLL_MODE_DEEP		0x2
+
+#define RK3X_PLLCON0_OD_MASK		0xf
+#define RK3X_PLLCON0_OD_SHIFT		0
+#define RK3X_PLLCON0_NR_MASK		0x3f
+#define RK3X_PLLCON0_NR_SHIFT		8
+
+#define RK3X_PLLCON1_NF_MASK		0x1fff
+#define RK3X_PLLCON1_NF_SHIFT		0
+
+#define RK3X_PLLCON3_REST		(1 << 5)
+#define RK3X_PLLCON3_BYPASS		(1 << 0)
+
+struct rockchip_clk_pll {
+	struct clk_hw		hw;
+	void __iomem		*reg_base;
+	void __iomem		*reg_mode;
+	unsigned int		shift_mode;
+	spinlock_t		*lock;
+};
+
+#define to_clk_pll(_hw) container_of(_hw, struct rockchip_clk_pll, hw)
+
+static unsigned long rk3x_generic_pll_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct rockchip_clk_pll *pll = to_clk_pll(hw);
+	u32 pll_con0 = readl_relaxed(pll->reg_base);
+	u32 pll_con1 = readl_relaxed(pll->reg_base + 0x4);
+	u32 pll_con3 = readl_relaxed(pll->reg_base + 0xc);
+	u32 mode_con = readl_relaxed(pll->reg_mode) >> pll->shift_mode;
+	u64 pll_nf;
+	u64 pll_nr;
+	u64 pll_no;
+	u64 rate64;
+
+	if (pll_con3 & RK3X_PLLCON3_BYPASS) {
+		pr_debug("%s: pll %s is bypassed\n", __func__,
+			__clk_get_name(hw->clk));
+		return parent_rate;
+	}
+
+	mode_con &= RK3X_PLL_MODE_MASK;
+	if (mode_con != RK3X_PLL_MODE_NORM) {
+		pr_debug("%s: pll %s not in normal mode: %d\n", __func__,
+			__clk_get_name(hw->clk), mode_con);
+		return parent_rate;
+	}
+
+	pll_nf = (pll_con1 >> RK3X_PLLCON1_NF_SHIFT);
+	pll_nf &= RK3X_PLLCON1_NF_MASK;
+	pll_nf++;
+	rate64 = (u64)parent_rate * pll_nf;
+
+	pll_nr = (pll_con0 >> RK3X_PLLCON0_NR_SHIFT);
+	pll_nr &= RK3X_PLLCON0_NR_MASK;
+	pll_nr++;
+	do_div(rate64, pll_nr);
+
+	pll_no = (pll_con0 >> RK3X_PLLCON0_OD_SHIFT);
+	pll_no &= RK3X_PLLCON0_OD_MASK;
+	pll_no++;
+	do_div(rate64, pll_no);
+
+	return (unsigned long)rate64;
+}
+
+static const struct clk_ops rk3x_generic_pll_clk_ops = {
+	.recalc_rate = rk3x_generic_pll_recalc_rate,
+};
+
+struct clk * __init rockchip_clk_register_rk3x_pll(const char *name,
+			const char *pname, void __iomem *reg_base,
+			void __iomem *reg_mode, unsigned int shift_mode,
+			spinlock_t *lock)
+{
+	struct rockchip_clk_pll *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll) {
+		pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+		return NULL;
+	}
+
+	init.name = name;
+	init.ops = &rk3x_generic_pll_clk_ops;
+	init.flags = CLK_GET_RATE_NOCACHE;
+	init.parent_names = &pname;
+	init.num_parents = 1;
+
+	pll->hw.init = &init;
+	pll->reg_base = reg_base;
+	pll->reg_mode = reg_mode;
+	pll->shift_mode = shift_mode;
+	pll->lock = lock;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: failed to register pll clock %s\n", __func__,
+				name);
+		kfree(pll);
+	}
+
+	return clk;
+}
diff --git a/drivers/clk/rockchip/clk-rockchip-pll.h b/drivers/clk/rockchip/clk-rockchip-pll.h
new file mode 100644
index 0000000..a63288a
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rockchip-pll.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+extern struct clk * __init rockchip_clk_register_rk3x_pll(const char *name,
+			const char *pname, const void __iomem *reg_base,
+			const void __iomem *reg_mode, unsigned int shift_mode,
+			spinlock_t *lock);
diff --git a/drivers/clk/rockchip/clk-rockchip.c b/drivers/clk/rockchip/clk-rockchip.c
new file mode 100644
index 0000000..660b00f
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rockchip.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "clk-rockchip-pll.h"
+
+static DEFINE_SPINLOCK(clk_lock);
+
+struct rockchip_pll_data {
+	int mode_shift;
+};
+
+struct rockchip_pll_data rk3066a_apll_data = {
+	.mode_shift = 0,
+};
+
+struct rockchip_pll_data rk3066a_dpll_data = {
+	.mode_shift = 4,
+};
+
+struct rockchip_pll_data rk3066a_cpll_data = {
+	.mode_shift = 8,
+};
+
+struct rockchip_pll_data rk3066a_gpll_data = {
+	.mode_shift = 12,
+};
+
+/* Matches for plls */
+static const __initconst struct of_device_id clk_pll_match[] = {
+	{ .compatible = "rockchip,rk3066a-apll", .data = &rk3066a_apll_data },
+	{ .compatible = "rockchip,rk3066a-dpll", .data = &rk3066a_dpll_data },
+	{ .compatible = "rockchip,rk3066a-cpll", .data = &rk3066a_cpll_data },
+	{ .compatible = "rockchip,rk3066a-gpll", .data = &rk3066a_gpll_data },
+	{}
+};
+
+static void __init rockchip_pll_setup(struct device_node *node,
+				      struct rockchip_pll_data *data)
+{
+	struct clk *clk;
+	const char *clk_name = node->name;
+	const char *clk_parent;
+	void __iomem *reg_base;
+	void __iomem *reg_mode;
+	u32 rate;
+
+	reg_base = of_iomap(node, 0);
+	reg_mode = of_iomap(node, 1);
+
+	clk_parent = of_clk_get_parent_name(node, 0);
+
+	pr_debug("%s: adding %s as child of %s\n",
+		__func__, clk_name, clk_parent);
+
+	clk = rockchip_clk_register_rk3x_pll(clk_name, clk_parent, reg_base,
+					     reg_mode, data->mode_shift,
+					     &clk_lock);
+	if (clk) {
+		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+		/* optionally set a target frequency for the pll */
+		if (!of_property_read_u32(node, "clock-frequency", &rate))
+			clk_set_rate(clk, rate);
+	}
+}
+
+/*
+ * Mux clocks
+ */
+
+struct rockchip_mux_data {
+	int shift;
+	int width;
+};
+
+#define RK_MUX(n, s, w)					\
+static const __initconst struct rockchip_mux_data n = {	\
+	.shift = s,					\
+	.width = w,					\
+}
+
+RK_MUX(gpll_cpll_15_mux_data, 15, 1);
+RK_MUX(uart_mux_data, 8, 2);
+RK_MUX(cpu_mux_data, 8, 1);
+
+static const __initconst struct of_device_id clk_mux_match[] = {
+	{ .compatible = "rockchip,rk2928-gpll-cpll-bit15-mux",
+		.data = &gpll_cpll_15_mux_data },
+	{ .compatible = "rockchip,rk2928-uart-mux",
+		.data = &uart_mux_data },
+	{ .compatible = "rockchip,rk3066-cpu-mux",
+		.data = &cpu_mux_data },
+	{}
+};
+
+static void __init rockchip_mux_clk_setup(struct device_node *node,
+					  struct rockchip_mux_data *data)
+{
+	struct clk *clk;
+	const char *clk_name = node->name;
+	void __iomem *reg;
+	int max_parents = (1 << data->width);
+	const char *parents[max_parents];
+	int flags;
+	int i = 0;
+
+	reg = of_iomap(node, 0);
+
+	while (i < max_parents &&
+	       (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
+		i++;
+
+	flags = CLK_MUX_HIWORD_MASK;
+
+	clk = clk_register_mux(NULL, clk_name, parents, i, 0,
+			       reg, data->shift, data->width,
+			       flags, &clk_lock);
+	if (clk)
+		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+
+/*
+ * Divider clocks
+ */
+
+struct rockchip_div_data {
+	int shift;
+	int width;
+	int flags;
+	struct clk_div_table *table;
+};
+
+#define RK_DIV(n, s, w, f, t)				\
+static const __initconst struct rockchip_div_data n = {	\
+	.shift = s,					\
+	.width = w,					\
+	.flags = f,					\
+	.table = t,					\
+}
+
+RK_DIV(cpu_div_data, 0, 5, 0, NULL);
+RK_DIV(aclk_periph_div_data, 0, 5, 0, NULL);
+RK_DIV(aclk_cpu_div_data, 0, 3, 0, NULL);
+RK_DIV(hclk_div_data, 8, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+RK_DIV(pclk_div_data, 12, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
+RK_DIV(mmc_div_data, 0, 6, CLK_DIVIDER_EVEN, NULL);
+RK_DIV(uart_div_data, 0, 7, 0, NULL);
+
+struct clk_div_table core_periph_table[] = {
+	{ 0, 2 },
+	{ 1, 4 },
+	{ 2, 8 },
+	{ 3, 16 },
+	{ 0, 0 },
+};
+RK_DIV(core_periph_div_data, 6, 2, 0, core_periph_table);
+
+static const __initconst struct of_device_id clk_divider_match[] = {
+	{ .compatible = "rockchip,rk3066a-cpu-divider",
+		.data = &cpu_div_data },
+	{ .compatible = "rockchip,rk3066a-core-periph-divider",
+		.data = &core_periph_div_data },
+	{ .compatible = "rockchip,rk2928-aclk-periph-divider",
+		.data = &aclk_periph_div_data },
+	{ .compatible = "rockchip,rk3066a-aclk-cpu-divider",
+		.data = &aclk_cpu_div_data },
+	{ .compatible = "rockchip,rk2928-hclk-divider",
+		.data = &hclk_div_data },
+	{ .compatible = "rockchip,rk2928-pclk-divider",
+		.data = &pclk_div_data },
+	{ .compatible = "rockchip,rk2928-mmc-divider",
+		.data = &mmc_div_data },
+	{ .compatible = "rockchip,rk2928-uart-divider",
+		.data = &uart_div_data },
+	{}
+};
+
+static void __init rockchip_divider_clk_setup(struct device_node *node,
+					      struct rockchip_div_data *data)
+{
+	struct clk *clk;
+	const char *clk_name = node->name;
+	const char *clk_parent;
+	void __iomem *reg;
+	int flags;
+
+	reg = of_iomap(node, 0);
+
+	clk_parent = of_clk_get_parent_name(node, 0);
+
+	flags = data->flags;
+	flags |= CLK_DIVIDER_HIWORD_MASK;
+
+	if (data->table)
+		clk = clk_register_divider_table(NULL, clk_name, clk_parent, 0,
+						reg, data->shift, data->width,
+						flags, data->table, &clk_lock);
+	else
+		clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
+						reg, data->shift, data->width,
+						flags, &clk_lock);
+	if (clk)
+		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+
+/*
+ * Gate clocks
+ */
+
+static void __init rockchip_gate_clk_setup(struct device_node *node,
+					    void *data)
+{
+	struct clk_onecell_data *clk_data;
+	const char *clk_parent;
+	const char *clk_name;
+	void __iomem *reg;
+	void __iomem *reg_idx;
+	int flags;
+	int qty;
+	int reg_bit;
+	int clkflags = CLK_SET_RATE_PARENT;
+	int i;
+
+	qty = of_property_count_strings(node, "clock-output-names");
+	if (qty < 0) {
+		pr_err("%s: error in clock-output-names %d\n", __func__, qty);
+		return;
+	}
+
+	if (qty == 0) {
+		pr_info("%s: nothing to do\n", __func__);
+		return;
+	}
+
+	reg = of_iomap(node, 0);
+
+	clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+	if (!clk_data)
+		return;
+
+	clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL);
+	if (!clk_data->clks) {
+		kfree(clk_data);
+		return;
+	}
+
+	flags = CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE;
+
+	for (i = 0; i < qty; i++) {
+		of_property_read_string_index(node, "clock-output-names",
+					      i, &clk_name);
+
+		/* ignore empty slots */
+		if (!strcmp("reserved", clk_name))
+			continue;
+
+		clk_parent = of_clk_get_parent_name(node, i);
+
+		/* keep all gates untouched for now */
+		clkflags |= CLK_IGNORE_UNUSED;
+
+		reg_idx = reg + (4 * (i / 16));
+		reg_bit = (i % 16);
+
+		clk_data->clks[i] = clk_register_gate(NULL, clk_name,
+						      clk_parent, clkflags,
+						      reg_idx, reg_bit,
+						      flags,
+						      &clk_lock);
+		WARN_ON(IS_ERR(clk_data->clks[i]));
+	}
+
+	clk_data->clk_num = qty;
+
+	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+}
+
+static const __initconst struct of_device_id clk_gate_match[] = {
+	{ .compatible = "rockchip,rk2928-gate-clk" },
+	{}
+};
+
+void __init of_rockchip_clk_table_clock_setup(
+					const struct of_device_id *clk_match,
+					void *function)
+{
+	struct device_node *np;
+	const struct div_data *data;
+	const struct of_device_id *match;
+	void (*setup_function)(struct device_node *, const void *) = function;
+
+	for_each_matching_node(np, clk_match) {
+		match = of_match_node(clk_match, np);
+		data = match->data;
+		setup_function(np, data);
+	}
+}
+
+void __init rockchip_init_clocks(struct device_node *node)
+{
+	of_rockchip_clk_table_clock_setup(clk_pll_match,
+					  rockchip_pll_setup);
+
+	of_rockchip_clk_table_clock_setup(clk_mux_match,
+					  rockchip_mux_clk_setup);
+
+	of_rockchip_clk_table_clock_setup(clk_gate_match,
+					  rockchip_gate_clk_setup);
+
+	of_rockchip_clk_table_clock_setup(clk_divider_match,
+					  rockchip_divider_clk_setup);
+}
+CLK_OF_DECLARE(rockchip_clocks, "rockchip,clocks", rockchip_init_clocks);
-- 
1.7.2.3

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

* [PATCH v3 6/7] arm: add debug uarts for rockchip rk29xx and rk3xxx series
  2013-06-11 11:28 ` Heiko Stübner
  (?)
@ 2013-06-11 11:32   ` Heiko Stübner
  -1 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mike Turquette, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

Uarts on all recent Rockchip SoCs are Synopsis DesignWare 8250 types.
Only their addresses vary very much.

This patch adds the necessary definitions to use any of the uart ports
for early debug purposes.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/Kconfig.debug            |   34 +++++++++++++++++++++++++++++
 arch/arm/include/debug/rockchip.S |   42 +++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/debug/rockchip.S

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 29f7623..2060cd5 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -360,6 +360,13 @@ choice
 		  their output to the standard serial port on the RealView
 		  PB1176 platform.
 
+	config DEBUG_ROCKCHIP_UART
+		bool "Kernel low-level debugging messages via Rockchip UART"
+		depends on ARCH_ROCKCHIP
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on Rockchip based platforms.
+
 	config DEBUG_S3C_UART0
 		depends on PLAT_SAMSUNG
 		select DEBUG_EXYNOS_UART if ARCH_EXYNOS
@@ -597,6 +604,32 @@ endchoice
 
 choice
 	prompt "Low-level debug console UART"
+	depends on DEBUG_ROCKCHIP_UART
+
+	config DEBUG_RK29_UART0
+		bool "RK29 UART0"
+
+	config DEBUG_RK29_UART1
+		bool "RK29 UART1"
+
+	config DEBUG_RK29_UART2
+		bool "RK29 UART2"
+
+	config DEBUG_RK3X_UART0
+		bool "RK3X UART0"
+
+	config DEBUG_RK3X_UART1
+		bool "RK3X UART1"
+
+	config DEBUG_RK3X_UART2
+		bool "RK3X UART2"
+
+	config DEBUG_RK3X_UART3
+		bool "RK3X UART3"
+endchoice
+
+choice
+	prompt "Low-level debug console UART"
 	depends on DEBUG_LL && DEBUG_TEGRA_UART
 
 	config TEGRA_DEBUG_UART_AUTO_ODMDATA
@@ -648,6 +681,7 @@ config DEBUG_LL_INCLUDE
 	default "debug/picoxcell.S" if DEBUG_PICOXCELL_UART
 	default "debug/pxa.S" if DEBUG_PXA_UART1 || DEBUG_MMP_UART2 || \
 				 DEBUG_MMP_UART3
+	default "debug/rockchip.S" if DEBUG_ROCKCHIP_UART
 	default "debug/sirf.S" if DEBUG_SIRFPRIMA2_UART1 || DEBUG_SIRFMARCO_UART1
 	default "debug/socfpga.S" if DEBUG_SOCFPGA_UART
 	default "debug/sunxi.S" if DEBUG_SUNXI_UART0 || DEBUG_SUNXI_UART1
diff --git a/arch/arm/include/debug/rockchip.S b/arch/arm/include/debug/rockchip.S
new file mode 100644
index 0000000..cfd883e
--- /dev/null
+++ b/arch/arm/include/debug/rockchip.S
@@ -0,0 +1,42 @@
+/*
+ * Early serial output macro for Rockchip SoCs
+ *
+ * Copyright (C) 2012 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#if defined(CONFIG_DEBUG_RK29_UART0)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20060000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed60000
+#elif defined(CONFIG_DEBUG_RK29_UART1)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20064000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed64000
+#elif defined(CONFIG_DEBUG_RK29_UART2)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20068000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed68000
+#elif defined(CONFIG_DEBUG_RK3X_UART0)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x10124000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfeb24000
+#elif defined(CONFIG_DEBUG_RK3X_UART1)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x10126000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfeb26000
+#elif defined(CONFIG_DEBUG_RK3X_UART2)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20064000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed64000
+#elif defined(CONFIG_DEBUG_RK3X_UART3)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20068000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed68000
+#endif
+
+	.macro	addruart, rp, rv, tmp
+	ldr	\rp, =ROCKCHIP_UART_DEBUG_PHYS_BASE
+	ldr	\rv, =ROCKCHIP_UART_DEBUG_VIRT_BASE
+	.endm
+
+#define UART_SHIFT	2
+#include <asm/hardware/debug-8250.S>
-- 
1.7.2.3


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

* [PATCH v3 6/7] arm: add debug uarts for rockchip rk29xx and rk3xxx series
@ 2013-06-11 11:32   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mike Turquette, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

Uarts on all recent Rockchip SoCs are Synopsis DesignWare 8250 types.
Only their addresses vary very much.

This patch adds the necessary definitions to use any of the uart ports
for early debug purposes.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/Kconfig.debug            |   34 +++++++++++++++++++++++++++++
 arch/arm/include/debug/rockchip.S |   42 +++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/debug/rockchip.S

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 29f7623..2060cd5 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -360,6 +360,13 @@ choice
 		  their output to the standard serial port on the RealView
 		  PB1176 platform.
 
+	config DEBUG_ROCKCHIP_UART
+		bool "Kernel low-level debugging messages via Rockchip UART"
+		depends on ARCH_ROCKCHIP
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on Rockchip based platforms.
+
 	config DEBUG_S3C_UART0
 		depends on PLAT_SAMSUNG
 		select DEBUG_EXYNOS_UART if ARCH_EXYNOS
@@ -597,6 +604,32 @@ endchoice
 
 choice
 	prompt "Low-level debug console UART"
+	depends on DEBUG_ROCKCHIP_UART
+
+	config DEBUG_RK29_UART0
+		bool "RK29 UART0"
+
+	config DEBUG_RK29_UART1
+		bool "RK29 UART1"
+
+	config DEBUG_RK29_UART2
+		bool "RK29 UART2"
+
+	config DEBUG_RK3X_UART0
+		bool "RK3X UART0"
+
+	config DEBUG_RK3X_UART1
+		bool "RK3X UART1"
+
+	config DEBUG_RK3X_UART2
+		bool "RK3X UART2"
+
+	config DEBUG_RK3X_UART3
+		bool "RK3X UART3"
+endchoice
+
+choice
+	prompt "Low-level debug console UART"
 	depends on DEBUG_LL && DEBUG_TEGRA_UART
 
 	config TEGRA_DEBUG_UART_AUTO_ODMDATA
@@ -648,6 +681,7 @@ config DEBUG_LL_INCLUDE
 	default "debug/picoxcell.S" if DEBUG_PICOXCELL_UART
 	default "debug/pxa.S" if DEBUG_PXA_UART1 || DEBUG_MMP_UART2 || \
 				 DEBUG_MMP_UART3
+	default "debug/rockchip.S" if DEBUG_ROCKCHIP_UART
 	default "debug/sirf.S" if DEBUG_SIRFPRIMA2_UART1 || DEBUG_SIRFMARCO_UART1
 	default "debug/socfpga.S" if DEBUG_SOCFPGA_UART
 	default "debug/sunxi.S" if DEBUG_SUNXI_UART0 || DEBUG_SUNXI_UART1
diff --git a/arch/arm/include/debug/rockchip.S b/arch/arm/include/debug/rockchip.S
new file mode 100644
index 0000000..cfd883e
--- /dev/null
+++ b/arch/arm/include/debug/rockchip.S
@@ -0,0 +1,42 @@
+/*
+ * Early serial output macro for Rockchip SoCs
+ *
+ * Copyright (C) 2012 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#if defined(CONFIG_DEBUG_RK29_UART0)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20060000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed60000
+#elif defined(CONFIG_DEBUG_RK29_UART1)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20064000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed64000
+#elif defined(CONFIG_DEBUG_RK29_UART2)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20068000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed68000
+#elif defined(CONFIG_DEBUG_RK3X_UART0)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x10124000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfeb24000
+#elif defined(CONFIG_DEBUG_RK3X_UART1)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x10126000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfeb26000
+#elif defined(CONFIG_DEBUG_RK3X_UART2)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20064000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed64000
+#elif defined(CONFIG_DEBUG_RK3X_UART3)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20068000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed68000
+#endif
+
+	.macro	addruart, rp, rv, tmp
+	ldr	\rp, =ROCKCHIP_UART_DEBUG_PHYS_BASE
+	ldr	\rv, =ROCKCHIP_UART_DEBUG_VIRT_BASE
+	.endm
+
+#define UART_SHIFT	2
+#include <asm/hardware/debug-8250.S>
-- 
1.7.2.3

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

* [PATCH v3 6/7] arm: add debug uarts for rockchip rk29xx and rk3xxx series
@ 2013-06-11 11:32   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

Uarts on all recent Rockchip SoCs are Synopsis DesignWare 8250 types.
Only their addresses vary very much.

This patch adds the necessary definitions to use any of the uart ports
for early debug purposes.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/Kconfig.debug            |   34 +++++++++++++++++++++++++++++
 arch/arm/include/debug/rockchip.S |   42 +++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/debug/rockchip.S

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 29f7623..2060cd5 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -360,6 +360,13 @@ choice
 		  their output to the standard serial port on the RealView
 		  PB1176 platform.
 
+	config DEBUG_ROCKCHIP_UART
+		bool "Kernel low-level debugging messages via Rockchip UART"
+		depends on ARCH_ROCKCHIP
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on Rockchip based platforms.
+
 	config DEBUG_S3C_UART0
 		depends on PLAT_SAMSUNG
 		select DEBUG_EXYNOS_UART if ARCH_EXYNOS
@@ -597,6 +604,32 @@ endchoice
 
 choice
 	prompt "Low-level debug console UART"
+	depends on DEBUG_ROCKCHIP_UART
+
+	config DEBUG_RK29_UART0
+		bool "RK29 UART0"
+
+	config DEBUG_RK29_UART1
+		bool "RK29 UART1"
+
+	config DEBUG_RK29_UART2
+		bool "RK29 UART2"
+
+	config DEBUG_RK3X_UART0
+		bool "RK3X UART0"
+
+	config DEBUG_RK3X_UART1
+		bool "RK3X UART1"
+
+	config DEBUG_RK3X_UART2
+		bool "RK3X UART2"
+
+	config DEBUG_RK3X_UART3
+		bool "RK3X UART3"
+endchoice
+
+choice
+	prompt "Low-level debug console UART"
 	depends on DEBUG_LL && DEBUG_TEGRA_UART
 
 	config TEGRA_DEBUG_UART_AUTO_ODMDATA
@@ -648,6 +681,7 @@ config DEBUG_LL_INCLUDE
 	default "debug/picoxcell.S" if DEBUG_PICOXCELL_UART
 	default "debug/pxa.S" if DEBUG_PXA_UART1 || DEBUG_MMP_UART2 || \
 				 DEBUG_MMP_UART3
+	default "debug/rockchip.S" if DEBUG_ROCKCHIP_UART
 	default "debug/sirf.S" if DEBUG_SIRFPRIMA2_UART1 || DEBUG_SIRFMARCO_UART1
 	default "debug/socfpga.S" if DEBUG_SOCFPGA_UART
 	default "debug/sunxi.S" if DEBUG_SUNXI_UART0 || DEBUG_SUNXI_UART1
diff --git a/arch/arm/include/debug/rockchip.S b/arch/arm/include/debug/rockchip.S
new file mode 100644
index 0000000..cfd883e
--- /dev/null
+++ b/arch/arm/include/debug/rockchip.S
@@ -0,0 +1,42 @@
+/*
+ * Early serial output macro for Rockchip SoCs
+ *
+ * Copyright (C) 2012 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#if defined(CONFIG_DEBUG_RK29_UART0)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20060000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed60000
+#elif defined(CONFIG_DEBUG_RK29_UART1)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20064000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed64000
+#elif defined(CONFIG_DEBUG_RK29_UART2)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20068000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed68000
+#elif defined(CONFIG_DEBUG_RK3X_UART0)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x10124000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfeb24000
+#elif defined(CONFIG_DEBUG_RK3X_UART1)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x10126000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfeb26000
+#elif defined(CONFIG_DEBUG_RK3X_UART2)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20064000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed64000
+#elif defined(CONFIG_DEBUG_RK3X_UART3)
+#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20068000
+#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed68000
+#endif
+
+	.macro	addruart, rp, rv, tmp
+	ldr	\rp, =ROCKCHIP_UART_DEBUG_PHYS_BASE
+	ldr	\rv, =ROCKCHIP_UART_DEBUG_VIRT_BASE
+	.endm
+
+#define UART_SHIFT	2
+#include <asm/hardware/debug-8250.S>
-- 
1.7.2.3

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

* [PATCH v3 7/7] arm: add basic support for Rockchip RK3066a boards
  2013-06-11 11:28 ` Heiko Stübner
  (?)
@ 2013-06-11 11:32   ` Heiko Stübner
  -1 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mike Turquette, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

This adds a generic devicetree board file and a dtsi for boards
based on the RK3066a SoCs from Rockchip.

Apart from the generic parts (gic, clocks, pinctrl) the only components
currently supported are the timers, uarts and mmc ports (all DesignWare-
based).

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/Kconfig                  |    2 +
 arch/arm/Makefile                 |    1 +
 arch/arm/boot/dts/rk3066a.dtsi    |  390 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-rockchip/Kconfig    |   16 ++
 arch/arm/mach-rockchip/Makefile   |    1 +
 arch/arm/mach-rockchip/rockchip.c |   54 +++++
 6 files changed, 464 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/boot/dts/rk3066a.dtsi
 create mode 100644 arch/arm/mach-rockchip/Kconfig
 create mode 100644 arch/arm/mach-rockchip/Makefile
 create mode 100644 arch/arm/mach-rockchip/rockchip.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4315d18..6355589 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -983,6 +983,8 @@ source "arch/arm/mach-mmp/Kconfig"
 
 source "arch/arm/mach-realview/Kconfig"
 
+source "arch/arm/mach-rockchip/Kconfig"
+
 source "arch/arm/mach-sa1100/Kconfig"
 
 source "arch/arm/plat-samsung/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 3380c4f..0153f60 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -172,6 +172,7 @@ machine-$(CONFIG_ARCH_PICOXCELL)	+= picoxcell
 machine-$(CONFIG_ARCH_PRIMA2)		+= prima2
 machine-$(CONFIG_ARCH_PXA)		+= pxa
 machine-$(CONFIG_ARCH_REALVIEW)		+= realview
+machine-$(CONFIG_ARCH_ROCKCHIP)		+= rockchip
 machine-$(CONFIG_ARCH_RPC)		+= rpc
 machine-$(CONFIG_ARCH_S3C24XX)		+= s3c24xx
 machine-$(CONFIG_ARCH_S3C64XX)		+= s3c64xx
diff --git a/arch/arm/boot/dts/rk3066a.dtsi b/arch/arm/boot/dts/rk3066a.dtsi
new file mode 100644
index 0000000..afb73f2
--- /dev/null
+++ b/arch/arm/boot/dts/rk3066a.dtsi
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "skeleton.dtsi"
+#include "rk3066a-clocks.dtsi"
+
+/ {
+	compatible = "rockchip,rk3066a";
+	interrupt-parent = <&gic>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			next-level-cache = <&L2>;
+			reg = <0x0>;
+		};
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			next-level-cache = <&L2>;
+			reg = <0x1>;
+		};
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		ranges;
+
+		gic: interrupt-controller@1013d000 {
+			compatible = "arm,cortex-a9-gic";
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			reg = <0x1013d000 0x1000>,
+			      <0x1013c100 0x0100>;
+		};
+
+		L2: l2-cache-controller@10138000 {
+			compatible = "arm,pl310-cache";
+			reg = <0x10138000 0x1000>;
+			cache-unified;
+			cache-level = <2>;
+		};
+
+		local-timer@1013c600 {
+			compatible = "arm,cortex-a9-twd-timer";
+			reg = <0x1013c600 0x20>;
+			interrupts = <GIC_PPI 13 0x304>;
+			clocks = <&div_core_periph>;
+		};
+
+		timer@20038000 {
+			compatible = "snps,dw-apb-timer-osc";
+			reg = <0x20038000 0x100>;
+			interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk_gates1 0>, <&clk_gates7 7>;
+			clock-names = "timer", "pclk";
+		};
+
+		timer@2003a000 {
+			compatible = "snps,dw-apb-timer-osc";
+			reg = <0x2003a000 0x100>;
+			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk_gates1 1>, <&clk_gates7 8>;
+			clock-names = "timer", "pclk";
+		};
+
+		timer@2000e000 {
+			compatible = "snps,dw-apb-timer-osc";
+			reg = <0x2000e000 0x100>;
+			interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk_gates1 2>, <&clk_gates7 9>;
+			clock-names = "timer", "pclk";
+		};
+
+		pinctrl@20008000 {
+			compatible = "rockchip,rk3066a-pinctrl";
+			reg = <0x20008000 0x150>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			gpio0: gpio0@20034000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x20034000 0x100>;
+				interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 9>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio1: gpio1@2003c000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x2003c000 0x100>;
+				interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 10>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio2: gpio2@2003e000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x2003e000 0x100>;
+				interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 11>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio3: gpio3@20080000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x20080000 0x100>;
+				interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 12>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio4: gpio4@20084000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x20084000 0x100>;
+				interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 13>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio6: gpio6@2000a000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x2000a000 0x100>;
+				interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 15>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			pcfg_pull_default: pcfg_pull_default {
+				bias-pull-pin-default;
+			};
+
+			pcfg_pull_none: pcfg_pull_none {
+				bias-disable;
+			};
+
+			uart0 {
+				uart0_xfer: uart0-xfer {
+					rockchip,pins = <RK_GPIO1 0 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO1 1 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart0_cts: uart0-cts {
+					rockchip,pins = <RK_GPIO1 2 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart0_rts: uart0-rts {
+					rockchip,pins = <RK_GPIO1 3 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+
+			uart1 {
+				uart1_xfer: uart1-xfer {
+					rockchip,pins = <RK_GPIO1 4 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO1 5 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart1_cts: uart1-cts {
+					rockchip,pins = <RK_GPIO1 6 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart1_rts: uart1-rts {
+					rockchip,pins = <RK_GPIO1 7 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+
+			uart2 {
+				uart2_xfer: uart2-xfer {
+					rockchip,pins = <RK_GPIO1 8 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO1 9 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+				/* no rts / cts for uart2 */
+			};
+
+			uart3 {
+				uart3_xfer: uart3-xfer {
+					rockchip,pins = <RK_GPIO3 27 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 28 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart3_cts: uart3-cts {
+					rockchip,pins = <RK_GPIO3 29 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart3_rts: uart3-rts {
+					rockchip,pins = <RK_GPIO3 30 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+
+			sd0 {
+				sd0_clk: sd0-clk {
+					rockchip,pins = <RK_GPIO3 8 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_cmd: sd0-cmd {
+					rockchip,pins = <RK_GPIO3 9 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_cd: sd0-cd {
+					rockchip,pins = <RK_GPIO3 14 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_wp: sd0-wp {
+					rockchip,pins = <RK_GPIO3 15 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_bus1: sd0-bus-width1 {
+					rockchip,pins = <RK_GPIO3 10 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_bus4: sd0-bus-width4 {
+					rockchip,pins = <RK_GPIO3 10 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 11 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 12 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 13 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+
+			sd1 {
+				sd1_clk: sd1-clk {
+					rockchip,pins = <RK_GPIO3 21 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_cmd: sd1-cmd {
+					rockchip,pins = <RK_GPIO3 16 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_cd: sd1-cd {
+					rockchip,pins = <RK_GPIO3 22 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_wp: sd1-wp {
+					rockchip,pins = <RK_GPIO3 23 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_bus1: sd1-bus-width1 {
+					rockchip,pins = <RK_GPIO3 17 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_bus4: sd1-bus-width4 {
+					rockchip,pins = <RK_GPIO3 17 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 18 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 19 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 20 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+		};
+
+		uart0: serial@10124000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x10124000 0x400>;
+			interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <1>;
+			clocks = <&mux_uart0>;
+			status = "disabled";
+		};
+
+		uart1: serial@10126000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x10126000 0x400>;
+			interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <1>;
+			clocks = <&mux_uart1>;
+			status = "disabled";
+		};
+
+		uart2: serial@20064000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x20064000 0x400>;
+			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <1>;
+			clocks = <&mux_uart2>;
+			status = "disabled";
+		};
+
+		uart3: serial@20068000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x20068000 0x400>;
+			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <1>;
+			clocks = <&mux_uart3>;
+			status = "disabled";
+		};
+
+		dwmmc@10214000 {
+			compatible = "rockchip,cortex-a9-dw-mshc";
+			reg = <0x10214000 0x1000>;
+			interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			clocks = <&clk_gates5 10>, <&clk_gates2 11>;
+			clock-names = "biu", "ciu";
+
+			status = "disabled";
+		};
+
+		dwmmc@10218000 {
+			compatible = "rockchip,cortex-a9-dw-mshc";
+			reg = <0x10218000 0x1000>;
+			interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			clocks = <&clk_gates5 11>, <&clk_gates2 13>;
+			clock-names = "biu", "ciu";
+
+			status = "disabled";
+		};
+	};
+};
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
new file mode 100644
index 0000000..25ee12b
--- /dev/null
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -0,0 +1,16 @@
+config ARCH_ROCKCHIP
+	bool "Rockchip RK2928 and RK3xxx SOCs" if ARCH_MULTI_V7
+	select PINCTRL
+	select PINCTRL_ROCKCHIP
+	select ARCH_REQUIRE_GPIOLIB
+	select ARM_GIC
+	select CACHE_L2X0
+	select HAVE_ARM_TWD if LOCAL_TIMERS
+	select HAVE_SMP
+	select LOCAL_TIMERS if SMP
+	select COMMON_CLK
+	select GENERIC_CLOCKEVENTS
+	select DW_APB_TIMER_OF
+	help
+	  Support for Rockchip's Cortex-A9 Single-to-Quad-Core-SoCs
+	  containing the RK2928, RK30xx and RK31xx series.
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
new file mode 100644
index 0000000..1547d4f
--- /dev/null
+++ b/arch/arm/mach-rockchip/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip.o
diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c
new file mode 100644
index 0000000..0933e17
--- /dev/null
+++ b/arch/arm/mach-rockchip/rockchip.c
@@ -0,0 +1,54 @@
+/*
+ * Device Tree support for Rockchip SoCs
+ *
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <linux/irqchip.h>
+#include <linux/dw_apb_timer.h>
+#include <linux/clk-provider.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/cache-l2x0.h>
+
+static void __init rockchip_timer_init(void)
+{
+	of_clk_init(NULL);
+	clocksource_of_init();
+}
+
+static void __init rockchip_dt_init(void)
+{
+#ifdef CONFIG_CACHE_L2X0
+	l2x0_of_init(0, ~0UL);
+#endif
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char * const rockchip_board_dt_compat[] = {
+	"rockchip,rk2928",
+	"rockchip,rk3066a",
+	"rockchip,rk3066b",
+	"rockchip,rk3188",
+	NULL,
+};
+
+DT_MACHINE_START(ROCKCHIP_DT, "Rockchip Cortex-A9 (Device Tree)")
+	.init_machine	= rockchip_dt_init,
+	.init_time	= rockchip_timer_init,
+	.dt_compat	= rockchip_board_dt_compat,
+MACHINE_END
-- 
1.7.2.3


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

* [PATCH v3 7/7] arm: add basic support for Rockchip RK3066a boards
@ 2013-06-11 11:32   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mike Turquette, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

This adds a generic devicetree board file and a dtsi for boards
based on the RK3066a SoCs from Rockchip.

Apart from the generic parts (gic, clocks, pinctrl) the only components
currently supported are the timers, uarts and mmc ports (all DesignWare-
based).

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/Kconfig                  |    2 +
 arch/arm/Makefile                 |    1 +
 arch/arm/boot/dts/rk3066a.dtsi    |  390 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-rockchip/Kconfig    |   16 ++
 arch/arm/mach-rockchip/Makefile   |    1 +
 arch/arm/mach-rockchip/rockchip.c |   54 +++++
 6 files changed, 464 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/boot/dts/rk3066a.dtsi
 create mode 100644 arch/arm/mach-rockchip/Kconfig
 create mode 100644 arch/arm/mach-rockchip/Makefile
 create mode 100644 arch/arm/mach-rockchip/rockchip.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4315d18..6355589 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -983,6 +983,8 @@ source "arch/arm/mach-mmp/Kconfig"
 
 source "arch/arm/mach-realview/Kconfig"
 
+source "arch/arm/mach-rockchip/Kconfig"
+
 source "arch/arm/mach-sa1100/Kconfig"
 
 source "arch/arm/plat-samsung/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 3380c4f..0153f60 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -172,6 +172,7 @@ machine-$(CONFIG_ARCH_PICOXCELL)	+= picoxcell
 machine-$(CONFIG_ARCH_PRIMA2)		+= prima2
 machine-$(CONFIG_ARCH_PXA)		+= pxa
 machine-$(CONFIG_ARCH_REALVIEW)		+= realview
+machine-$(CONFIG_ARCH_ROCKCHIP)		+= rockchip
 machine-$(CONFIG_ARCH_RPC)		+= rpc
 machine-$(CONFIG_ARCH_S3C24XX)		+= s3c24xx
 machine-$(CONFIG_ARCH_S3C64XX)		+= s3c64xx
diff --git a/arch/arm/boot/dts/rk3066a.dtsi b/arch/arm/boot/dts/rk3066a.dtsi
new file mode 100644
index 0000000..afb73f2
--- /dev/null
+++ b/arch/arm/boot/dts/rk3066a.dtsi
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "skeleton.dtsi"
+#include "rk3066a-clocks.dtsi"
+
+/ {
+	compatible = "rockchip,rk3066a";
+	interrupt-parent = <&gic>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			next-level-cache = <&L2>;
+			reg = <0x0>;
+		};
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			next-level-cache = <&L2>;
+			reg = <0x1>;
+		};
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		ranges;
+
+		gic: interrupt-controller@1013d000 {
+			compatible = "arm,cortex-a9-gic";
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			reg = <0x1013d000 0x1000>,
+			      <0x1013c100 0x0100>;
+		};
+
+		L2: l2-cache-controller@10138000 {
+			compatible = "arm,pl310-cache";
+			reg = <0x10138000 0x1000>;
+			cache-unified;
+			cache-level = <2>;
+		};
+
+		local-timer@1013c600 {
+			compatible = "arm,cortex-a9-twd-timer";
+			reg = <0x1013c600 0x20>;
+			interrupts = <GIC_PPI 13 0x304>;
+			clocks = <&div_core_periph>;
+		};
+
+		timer@20038000 {
+			compatible = "snps,dw-apb-timer-osc";
+			reg = <0x20038000 0x100>;
+			interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk_gates1 0>, <&clk_gates7 7>;
+			clock-names = "timer", "pclk";
+		};
+
+		timer@2003a000 {
+			compatible = "snps,dw-apb-timer-osc";
+			reg = <0x2003a000 0x100>;
+			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk_gates1 1>, <&clk_gates7 8>;
+			clock-names = "timer", "pclk";
+		};
+
+		timer@2000e000 {
+			compatible = "snps,dw-apb-timer-osc";
+			reg = <0x2000e000 0x100>;
+			interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk_gates1 2>, <&clk_gates7 9>;
+			clock-names = "timer", "pclk";
+		};
+
+		pinctrl@20008000 {
+			compatible = "rockchip,rk3066a-pinctrl";
+			reg = <0x20008000 0x150>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			gpio0: gpio0@20034000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x20034000 0x100>;
+				interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 9>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio1: gpio1@2003c000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x2003c000 0x100>;
+				interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 10>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio2: gpio2@2003e000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x2003e000 0x100>;
+				interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 11>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio3: gpio3@20080000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x20080000 0x100>;
+				interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 12>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio4: gpio4@20084000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x20084000 0x100>;
+				interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 13>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio6: gpio6@2000a000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x2000a000 0x100>;
+				interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 15>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			pcfg_pull_default: pcfg_pull_default {
+				bias-pull-pin-default;
+			};
+
+			pcfg_pull_none: pcfg_pull_none {
+				bias-disable;
+			};
+
+			uart0 {
+				uart0_xfer: uart0-xfer {
+					rockchip,pins = <RK_GPIO1 0 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO1 1 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart0_cts: uart0-cts {
+					rockchip,pins = <RK_GPIO1 2 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart0_rts: uart0-rts {
+					rockchip,pins = <RK_GPIO1 3 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+
+			uart1 {
+				uart1_xfer: uart1-xfer {
+					rockchip,pins = <RK_GPIO1 4 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO1 5 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart1_cts: uart1-cts {
+					rockchip,pins = <RK_GPIO1 6 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart1_rts: uart1-rts {
+					rockchip,pins = <RK_GPIO1 7 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+
+			uart2 {
+				uart2_xfer: uart2-xfer {
+					rockchip,pins = <RK_GPIO1 8 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO1 9 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+				/* no rts / cts for uart2 */
+			};
+
+			uart3 {
+				uart3_xfer: uart3-xfer {
+					rockchip,pins = <RK_GPIO3 27 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 28 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart3_cts: uart3-cts {
+					rockchip,pins = <RK_GPIO3 29 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart3_rts: uart3-rts {
+					rockchip,pins = <RK_GPIO3 30 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+
+			sd0 {
+				sd0_clk: sd0-clk {
+					rockchip,pins = <RK_GPIO3 8 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_cmd: sd0-cmd {
+					rockchip,pins = <RK_GPIO3 9 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_cd: sd0-cd {
+					rockchip,pins = <RK_GPIO3 14 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_wp: sd0-wp {
+					rockchip,pins = <RK_GPIO3 15 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_bus1: sd0-bus-width1 {
+					rockchip,pins = <RK_GPIO3 10 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_bus4: sd0-bus-width4 {
+					rockchip,pins = <RK_GPIO3 10 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 11 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 12 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 13 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+
+			sd1 {
+				sd1_clk: sd1-clk {
+					rockchip,pins = <RK_GPIO3 21 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_cmd: sd1-cmd {
+					rockchip,pins = <RK_GPIO3 16 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_cd: sd1-cd {
+					rockchip,pins = <RK_GPIO3 22 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_wp: sd1-wp {
+					rockchip,pins = <RK_GPIO3 23 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_bus1: sd1-bus-width1 {
+					rockchip,pins = <RK_GPIO3 17 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_bus4: sd1-bus-width4 {
+					rockchip,pins = <RK_GPIO3 17 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 18 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 19 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 20 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+		};
+
+		uart0: serial@10124000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x10124000 0x400>;
+			interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <1>;
+			clocks = <&mux_uart0>;
+			status = "disabled";
+		};
+
+		uart1: serial@10126000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x10126000 0x400>;
+			interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <1>;
+			clocks = <&mux_uart1>;
+			status = "disabled";
+		};
+
+		uart2: serial@20064000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x20064000 0x400>;
+			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <1>;
+			clocks = <&mux_uart2>;
+			status = "disabled";
+		};
+
+		uart3: serial@20068000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x20068000 0x400>;
+			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <1>;
+			clocks = <&mux_uart3>;
+			status = "disabled";
+		};
+
+		dwmmc@10214000 {
+			compatible = "rockchip,cortex-a9-dw-mshc";
+			reg = <0x10214000 0x1000>;
+			interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			clocks = <&clk_gates5 10>, <&clk_gates2 11>;
+			clock-names = "biu", "ciu";
+
+			status = "disabled";
+		};
+
+		dwmmc@10218000 {
+			compatible = "rockchip,cortex-a9-dw-mshc";
+			reg = <0x10218000 0x1000>;
+			interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			clocks = <&clk_gates5 11>, <&clk_gates2 13>;
+			clock-names = "biu", "ciu";
+
+			status = "disabled";
+		};
+	};
+};
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
new file mode 100644
index 0000000..25ee12b
--- /dev/null
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -0,0 +1,16 @@
+config ARCH_ROCKCHIP
+	bool "Rockchip RK2928 and RK3xxx SOCs" if ARCH_MULTI_V7
+	select PINCTRL
+	select PINCTRL_ROCKCHIP
+	select ARCH_REQUIRE_GPIOLIB
+	select ARM_GIC
+	select CACHE_L2X0
+	select HAVE_ARM_TWD if LOCAL_TIMERS
+	select HAVE_SMP
+	select LOCAL_TIMERS if SMP
+	select COMMON_CLK
+	select GENERIC_CLOCKEVENTS
+	select DW_APB_TIMER_OF
+	help
+	  Support for Rockchip's Cortex-A9 Single-to-Quad-Core-SoCs
+	  containing the RK2928, RK30xx and RK31xx series.
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
new file mode 100644
index 0000000..1547d4f
--- /dev/null
+++ b/arch/arm/mach-rockchip/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip.o
diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c
new file mode 100644
index 0000000..0933e17
--- /dev/null
+++ b/arch/arm/mach-rockchip/rockchip.c
@@ -0,0 +1,54 @@
+/*
+ * Device Tree support for Rockchip SoCs
+ *
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <linux/irqchip.h>
+#include <linux/dw_apb_timer.h>
+#include <linux/clk-provider.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/cache-l2x0.h>
+
+static void __init rockchip_timer_init(void)
+{
+	of_clk_init(NULL);
+	clocksource_of_init();
+}
+
+static void __init rockchip_dt_init(void)
+{
+#ifdef CONFIG_CACHE_L2X0
+	l2x0_of_init(0, ~0UL);
+#endif
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char * const rockchip_board_dt_compat[] = {
+	"rockchip,rk2928",
+	"rockchip,rk3066a",
+	"rockchip,rk3066b",
+	"rockchip,rk3188",
+	NULL,
+};
+
+DT_MACHINE_START(ROCKCHIP_DT, "Rockchip Cortex-A9 (Device Tree)")
+	.init_machine	= rockchip_dt_init,
+	.init_time	= rockchip_timer_init,
+	.dt_compat	= rockchip_board_dt_compat,
+MACHINE_END
-- 
1.7.2.3

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

* [PATCH v3 7/7] arm: add basic support for Rockchip RK3066a boards
@ 2013-06-11 11:32   ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

This adds a generic devicetree board file and a dtsi for boards
based on the RK3066a SoCs from Rockchip.

Apart from the generic parts (gic, clocks, pinctrl) the only components
currently supported are the timers, uarts and mmc ports (all DesignWare-
based).

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/Kconfig                  |    2 +
 arch/arm/Makefile                 |    1 +
 arch/arm/boot/dts/rk3066a.dtsi    |  390 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-rockchip/Kconfig    |   16 ++
 arch/arm/mach-rockchip/Makefile   |    1 +
 arch/arm/mach-rockchip/rockchip.c |   54 +++++
 6 files changed, 464 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/boot/dts/rk3066a.dtsi
 create mode 100644 arch/arm/mach-rockchip/Kconfig
 create mode 100644 arch/arm/mach-rockchip/Makefile
 create mode 100644 arch/arm/mach-rockchip/rockchip.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4315d18..6355589 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -983,6 +983,8 @@ source "arch/arm/mach-mmp/Kconfig"
 
 source "arch/arm/mach-realview/Kconfig"
 
+source "arch/arm/mach-rockchip/Kconfig"
+
 source "arch/arm/mach-sa1100/Kconfig"
 
 source "arch/arm/plat-samsung/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 3380c4f..0153f60 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -172,6 +172,7 @@ machine-$(CONFIG_ARCH_PICOXCELL)	+= picoxcell
 machine-$(CONFIG_ARCH_PRIMA2)		+= prima2
 machine-$(CONFIG_ARCH_PXA)		+= pxa
 machine-$(CONFIG_ARCH_REALVIEW)		+= realview
+machine-$(CONFIG_ARCH_ROCKCHIP)		+= rockchip
 machine-$(CONFIG_ARCH_RPC)		+= rpc
 machine-$(CONFIG_ARCH_S3C24XX)		+= s3c24xx
 machine-$(CONFIG_ARCH_S3C64XX)		+= s3c64xx
diff --git a/arch/arm/boot/dts/rk3066a.dtsi b/arch/arm/boot/dts/rk3066a.dtsi
new file mode 100644
index 0000000..afb73f2
--- /dev/null
+++ b/arch/arm/boot/dts/rk3066a.dtsi
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include "skeleton.dtsi"
+#include "rk3066a-clocks.dtsi"
+
+/ {
+	compatible = "rockchip,rk3066a";
+	interrupt-parent = <&gic>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu at 0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			next-level-cache = <&L2>;
+			reg = <0x0>;
+		};
+		cpu at 1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			next-level-cache = <&L2>;
+			reg = <0x1>;
+		};
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		ranges;
+
+		gic: interrupt-controller at 1013d000 {
+			compatible = "arm,cortex-a9-gic";
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			reg = <0x1013d000 0x1000>,
+			      <0x1013c100 0x0100>;
+		};
+
+		L2: l2-cache-controller at 10138000 {
+			compatible = "arm,pl310-cache";
+			reg = <0x10138000 0x1000>;
+			cache-unified;
+			cache-level = <2>;
+		};
+
+		local-timer at 1013c600 {
+			compatible = "arm,cortex-a9-twd-timer";
+			reg = <0x1013c600 0x20>;
+			interrupts = <GIC_PPI 13 0x304>;
+			clocks = <&div_core_periph>;
+		};
+
+		timer at 20038000 {
+			compatible = "snps,dw-apb-timer-osc";
+			reg = <0x20038000 0x100>;
+			interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk_gates1 0>, <&clk_gates7 7>;
+			clock-names = "timer", "pclk";
+		};
+
+		timer at 2003a000 {
+			compatible = "snps,dw-apb-timer-osc";
+			reg = <0x2003a000 0x100>;
+			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk_gates1 1>, <&clk_gates7 8>;
+			clock-names = "timer", "pclk";
+		};
+
+		timer at 2000e000 {
+			compatible = "snps,dw-apb-timer-osc";
+			reg = <0x2000e000 0x100>;
+			interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk_gates1 2>, <&clk_gates7 9>;
+			clock-names = "timer", "pclk";
+		};
+
+		pinctrl at 20008000 {
+			compatible = "rockchip,rk3066a-pinctrl";
+			reg = <0x20008000 0x150>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			gpio0: gpio0 at 20034000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x20034000 0x100>;
+				interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 9>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio1: gpio1 at 2003c000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x2003c000 0x100>;
+				interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 10>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio2: gpio2 at 2003e000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x2003e000 0x100>;
+				interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 11>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio3: gpio3 at 20080000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x20080000 0x100>;
+				interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 12>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio4: gpio4 at 20084000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x20084000 0x100>;
+				interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 13>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			gpio6: gpio6 at 2000a000 {
+				compatible = "rockchip,gpio-bank";
+				reg = <0x2000a000 0x100>;
+				interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk_gates8 15>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
+
+			pcfg_pull_default: pcfg_pull_default {
+				bias-pull-pin-default;
+			};
+
+			pcfg_pull_none: pcfg_pull_none {
+				bias-disable;
+			};
+
+			uart0 {
+				uart0_xfer: uart0-xfer {
+					rockchip,pins = <RK_GPIO1 0 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO1 1 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart0_cts: uart0-cts {
+					rockchip,pins = <RK_GPIO1 2 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart0_rts: uart0-rts {
+					rockchip,pins = <RK_GPIO1 3 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+
+			uart1 {
+				uart1_xfer: uart1-xfer {
+					rockchip,pins = <RK_GPIO1 4 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO1 5 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart1_cts: uart1-cts {
+					rockchip,pins = <RK_GPIO1 6 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart1_rts: uart1-rts {
+					rockchip,pins = <RK_GPIO1 7 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+
+			uart2 {
+				uart2_xfer: uart2-xfer {
+					rockchip,pins = <RK_GPIO1 8 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO1 9 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+				/* no rts / cts for uart2 */
+			};
+
+			uart3 {
+				uart3_xfer: uart3-xfer {
+					rockchip,pins = <RK_GPIO3 27 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 28 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart3_cts: uart3-cts {
+					rockchip,pins = <RK_GPIO3 29 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				uart3_rts: uart3-rts {
+					rockchip,pins = <RK_GPIO3 30 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+
+			sd0 {
+				sd0_clk: sd0-clk {
+					rockchip,pins = <RK_GPIO3 8 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_cmd: sd0-cmd {
+					rockchip,pins = <RK_GPIO3 9 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_cd: sd0-cd {
+					rockchip,pins = <RK_GPIO3 14 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_wp: sd0-wp {
+					rockchip,pins = <RK_GPIO3 15 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_bus1: sd0-bus-width1 {
+					rockchip,pins = <RK_GPIO3 10 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd0_bus4: sd0-bus-width4 {
+					rockchip,pins = <RK_GPIO3 10 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 11 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 12 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 13 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+
+			sd1 {
+				sd1_clk: sd1-clk {
+					rockchip,pins = <RK_GPIO3 21 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_cmd: sd1-cmd {
+					rockchip,pins = <RK_GPIO3 16 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_cd: sd1-cd {
+					rockchip,pins = <RK_GPIO3 22 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_wp: sd1-wp {
+					rockchip,pins = <RK_GPIO3 23 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_bus1: sd1-bus-width1 {
+					rockchip,pins = <RK_GPIO3 17 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+
+				sd1_bus4: sd1-bus-width4 {
+					rockchip,pins = <RK_GPIO3 17 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 18 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 19 RK_FUNC_1 &pcfg_pull_default>,
+							<RK_GPIO3 20 RK_FUNC_1 &pcfg_pull_default>;
+					rockchip,config = <&pcfg_pull_default>;
+				};
+			};
+		};
+
+		uart0: serial at 10124000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x10124000 0x400>;
+			interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <1>;
+			clocks = <&mux_uart0>;
+			status = "disabled";
+		};
+
+		uart1: serial at 10126000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x10126000 0x400>;
+			interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <1>;
+			clocks = <&mux_uart1>;
+			status = "disabled";
+		};
+
+		uart2: serial at 20064000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x20064000 0x400>;
+			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <1>;
+			clocks = <&mux_uart2>;
+			status = "disabled";
+		};
+
+		uart3: serial at 20068000 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x20068000 0x400>;
+			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+			reg-shift = <2>;
+			reg-io-width = <1>;
+			clocks = <&mux_uart3>;
+			status = "disabled";
+		};
+
+		dwmmc at 10214000 {
+			compatible = "rockchip,cortex-a9-dw-mshc";
+			reg = <0x10214000 0x1000>;
+			interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			clocks = <&clk_gates5 10>, <&clk_gates2 11>;
+			clock-names = "biu", "ciu";
+
+			status = "disabled";
+		};
+
+		dwmmc at 10218000 {
+			compatible = "rockchip,cortex-a9-dw-mshc";
+			reg = <0x10218000 0x1000>;
+			interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			clocks = <&clk_gates5 11>, <&clk_gates2 13>;
+			clock-names = "biu", "ciu";
+
+			status = "disabled";
+		};
+	};
+};
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
new file mode 100644
index 0000000..25ee12b
--- /dev/null
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -0,0 +1,16 @@
+config ARCH_ROCKCHIP
+	bool "Rockchip RK2928 and RK3xxx SOCs" if ARCH_MULTI_V7
+	select PINCTRL
+	select PINCTRL_ROCKCHIP
+	select ARCH_REQUIRE_GPIOLIB
+	select ARM_GIC
+	select CACHE_L2X0
+	select HAVE_ARM_TWD if LOCAL_TIMERS
+	select HAVE_SMP
+	select LOCAL_TIMERS if SMP
+	select COMMON_CLK
+	select GENERIC_CLOCKEVENTS
+	select DW_APB_TIMER_OF
+	help
+	  Support for Rockchip's Cortex-A9 Single-to-Quad-Core-SoCs
+	  containing the RK2928, RK30xx and RK31xx series.
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
new file mode 100644
index 0000000..1547d4f
--- /dev/null
+++ b/arch/arm/mach-rockchip/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip.o
diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c
new file mode 100644
index 0000000..0933e17
--- /dev/null
+++ b/arch/arm/mach-rockchip/rockchip.c
@@ -0,0 +1,54 @@
+/*
+ * Device Tree support for Rockchip SoCs
+ *
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <linux/irqchip.h>
+#include <linux/dw_apb_timer.h>
+#include <linux/clk-provider.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/cache-l2x0.h>
+
+static void __init rockchip_timer_init(void)
+{
+	of_clk_init(NULL);
+	clocksource_of_init();
+}
+
+static void __init rockchip_dt_init(void)
+{
+#ifdef CONFIG_CACHE_L2X0
+	l2x0_of_init(0, ~0UL);
+#endif
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char * const rockchip_board_dt_compat[] = {
+	"rockchip,rk2928",
+	"rockchip,rk3066a",
+	"rockchip,rk3066b",
+	"rockchip,rk3188",
+	NULL,
+};
+
+DT_MACHINE_START(ROCKCHIP_DT, "Rockchip Cortex-A9 (Device Tree)")
+	.init_machine	= rockchip_dt_init,
+	.init_time	= rockchip_timer_init,
+	.dt_compat	= rockchip_board_dt_compat,
+MACHINE_END
-- 
1.7.2.3

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

* Re: [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
  2013-06-11 11:29   ` Heiko Stübner
  (?)
@ 2013-06-11 11:51     ` Andy Shevchenko
  -1 siblings, 0 replies; 56+ messages in thread
From: Andy Shevchenko @ 2013-06-11 11:51 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: linux-arm-kernel, linux-kernel, Mike Turquette, Seungwon Jeon,
	Jaehoon Chung, Chris Ball, linux-mmc, Grant Likely, Rob Herring,
	Linus Walleij, Devicetree Discuss, Russell King, Arnd Bergmann,
	Olof Johansson, Thomas Petazzoni

On Tue, Jun 11, 2013 at 2:29 PM, Heiko Stübner <heiko@sntech.de> wrote:
> SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> that use the regular mechanisms for storage but allow only even
> dividers and 1 to be used.
>
> Therefore add a flag that lets _is_valid_div limit the valid dividers
> to these values. _get_maxdiv is also adapted to return even values
> for the CLK_DIVIDER_ONE_BASED case.

Just one nitpick below (I'm okay with current implementation, but you
might find my proposal useful).

> --- a/drivers/clk/clk-divider.c
> +++ b/drivers/clk/clk-divider.c

> @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
>                 return is_power_of_2(div);
>         if (divider->table)
>                 return _is_valid_table_div(divider->table, div);
> +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) != 0)
> +               return false;
>         return true;
>  }

What if rewrite like

 if (divider->flags & CLK_DIVIDER_EVEN == 0)
 return true;

return div < 2 || div % 2 == 0;


--
With Best Regards,
Andy Shevchenko

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

* Re: [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
@ 2013-06-11 11:51     ` Andy Shevchenko
  0 siblings, 0 replies; 56+ messages in thread
From: Andy Shevchenko @ 2013-06-11 11:51 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: linux-arm-kernel, linux-kernel, Mike Turquette, Seungwon Jeon,
	Jaehoon Chung, Chris Ball, linux-mmc, Grant Likely, Rob Herring,
	Linus Walleij, Devicetree Discuss, Russell King, Arnd Bergmann,
	Olof Johansson, Thomas Petazzoni

On Tue, Jun 11, 2013 at 2:29 PM, Heiko Stübner <heiko@sntech.de> wrote:
> SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> that use the regular mechanisms for storage but allow only even
> dividers and 1 to be used.
>
> Therefore add a flag that lets _is_valid_div limit the valid dividers
> to these values. _get_maxdiv is also adapted to return even values
> for the CLK_DIVIDER_ONE_BASED case.

Just one nitpick below (I'm okay with current implementation, but you
might find my proposal useful).

> --- a/drivers/clk/clk-divider.c
> +++ b/drivers/clk/clk-divider.c

> @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
>                 return is_power_of_2(div);
>         if (divider->table)
>                 return _is_valid_table_div(divider->table, div);
> +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) != 0)
> +               return false;
>         return true;
>  }

What if rewrite like

 if (divider->flags & CLK_DIVIDER_EVEN == 0)
 return true;

return div < 2 || div % 2 == 0;


--
With Best Regards,
Andy Shevchenko

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

* [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
@ 2013-06-11 11:51     ` Andy Shevchenko
  0 siblings, 0 replies; 56+ messages in thread
From: Andy Shevchenko @ 2013-06-11 11:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 11, 2013 at 2:29 PM, Heiko St?bner <heiko@sntech.de> wrote:
> SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> that use the regular mechanisms for storage but allow only even
> dividers and 1 to be used.
>
> Therefore add a flag that lets _is_valid_div limit the valid dividers
> to these values. _get_maxdiv is also adapted to return even values
> for the CLK_DIVIDER_ONE_BASED case.

Just one nitpick below (I'm okay with current implementation, but you
might find my proposal useful).

> --- a/drivers/clk/clk-divider.c
> +++ b/drivers/clk/clk-divider.c

> @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
>                 return is_power_of_2(div);
>         if (divider->table)
>                 return _is_valid_table_div(divider->table, div);
> +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) != 0)
> +               return false;
>         return true;
>  }

What if rewrite like

 if (divider->flags & CLK_DIVIDER_EVEN == 0)
 return true;

return div < 2 || div % 2 == 0;


--
With Best Regards,
Andy Shevchenko

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

* Re: [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
  2013-06-11 11:51     ` Andy Shevchenko
  (?)
@ 2013-06-11 12:06       ` Heiko Stübner
  -1 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 12:06 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linux-arm-kernel, linux-kernel, Mike Turquette, Seungwon Jeon,
	Jaehoon Chung, Chris Ball, linux-mmc, Grant Likely, Rob Herring,
	Linus Walleij, Devicetree Discuss, Russell King, Arnd Bergmann,
	Olof Johansson, Thomas Petazzoni

Am Dienstag, 11. Juni 2013, 13:51:56 schrieb Andy Shevchenko:
> On Tue, Jun 11, 2013 at 2:29 PM, Heiko Stübner <heiko@sntech.de> wrote:
> > SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> > that use the regular mechanisms for storage but allow only even
> > dividers and 1 to be used.
> > 
> > Therefore add a flag that lets _is_valid_div limit the valid dividers
> > to these values. _get_maxdiv is also adapted to return even values
> > for the CLK_DIVIDER_ONE_BASED case.
> 
> Just one nitpick below (I'm okay with current implementation, but you
> might find my proposal useful).
> 
> > --- a/drivers/clk/clk-divider.c
> > +++ b/drivers/clk/clk-divider.c
> > 
> > @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider
> > *divider, unsigned int div)
> > 
> >                 return is_power_of_2(div);
> >         
> >         if (divider->table)
> >         
> >                 return _is_valid_table_div(divider->table, div);
> > 
> > +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) !=
> > 0) +               return false;
> > 
> >         return true;
> >  
> >  }
> 
> What if rewrite like
> 
>  if (divider->flags & CLK_DIVIDER_EVEN == 0)
>  return true;
> 
> return div < 2 || div % 2 == 0;

hmm, the current structure is of the form of testing for each feature and 
doing a applicable action if the flag is set. So it also is extensible for 
future flags and checking for the absence of an attribute while the rest of 
the conditionals check for the presence also might make the code harder to 
read.

So for me the current variant somehow looks more intuitive.

But I'll just let the majority decide ;-)


Heiko

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

* Re: [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
@ 2013-06-11 12:06       ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 12:06 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linux-arm-kernel, linux-kernel, Mike Turquette, Seungwon Jeon,
	Jaehoon Chung, Chris Ball, linux-mmc, Grant Likely, Rob Herring,
	Linus Walleij, Devicetree Discuss, Russell King, Arnd Bergmann,
	Olof Johansson, Thomas Petazzoni

Am Dienstag, 11. Juni 2013, 13:51:56 schrieb Andy Shevchenko:
> On Tue, Jun 11, 2013 at 2:29 PM, Heiko Stübner <heiko@sntech.de> wrote:
> > SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> > that use the regular mechanisms for storage but allow only even
> > dividers and 1 to be used.
> > 
> > Therefore add a flag that lets _is_valid_div limit the valid dividers
> > to these values. _get_maxdiv is also adapted to return even values
> > for the CLK_DIVIDER_ONE_BASED case.
> 
> Just one nitpick below (I'm okay with current implementation, but you
> might find my proposal useful).
> 
> > --- a/drivers/clk/clk-divider.c
> > +++ b/drivers/clk/clk-divider.c
> > 
> > @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider
> > *divider, unsigned int div)
> > 
> >                 return is_power_of_2(div);
> >         
> >         if (divider->table)
> >         
> >                 return _is_valid_table_div(divider->table, div);
> > 
> > +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) !=
> > 0) +               return false;
> > 
> >         return true;
> >  
> >  }
> 
> What if rewrite like
> 
>  if (divider->flags & CLK_DIVIDER_EVEN == 0)
>  return true;
> 
> return div < 2 || div % 2 == 0;

hmm, the current structure is of the form of testing for each feature and 
doing a applicable action if the flag is set. So it also is extensible for 
future flags and checking for the absence of an attribute while the rest of 
the conditionals check for the presence also might make the code harder to 
read.

So for me the current variant somehow looks more intuitive.

But I'll just let the majority decide ;-)


Heiko

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

* [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
@ 2013-06-11 12:06       ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 12:06 UTC (permalink / raw)
  To: linux-arm-kernel

Am Dienstag, 11. Juni 2013, 13:51:56 schrieb Andy Shevchenko:
> On Tue, Jun 11, 2013 at 2:29 PM, Heiko St?bner <heiko@sntech.de> wrote:
> > SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> > that use the regular mechanisms for storage but allow only even
> > dividers and 1 to be used.
> > 
> > Therefore add a flag that lets _is_valid_div limit the valid dividers
> > to these values. _get_maxdiv is also adapted to return even values
> > for the CLK_DIVIDER_ONE_BASED case.
> 
> Just one nitpick below (I'm okay with current implementation, but you
> might find my proposal useful).
> 
> > --- a/drivers/clk/clk-divider.c
> > +++ b/drivers/clk/clk-divider.c
> > 
> > @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider
> > *divider, unsigned int div)
> > 
> >                 return is_power_of_2(div);
> >         
> >         if (divider->table)
> >         
> >                 return _is_valid_table_div(divider->table, div);
> > 
> > +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) !=
> > 0) +               return false;
> > 
> >         return true;
> >  
> >  }
> 
> What if rewrite like
> 
>  if (divider->flags & CLK_DIVIDER_EVEN == 0)
>  return true;
> 
> return div < 2 || div % 2 == 0;

hmm, the current structure is of the form of testing for each feature and 
doing a applicable action if the flag is set. So it also is extensible for 
future flags and checking for the absence of an attribute while the rest of 
the conditionals check for the presence also might make the code harder to 
read.

So for me the current variant somehow looks more intuitive.

But I'll just let the majority decide ;-)


Heiko

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

* Re: [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
  2013-06-11 12:06       ` Heiko Stübner
  (?)
@ 2013-06-11 12:37         ` Andy Shevchenko
  -1 siblings, 0 replies; 56+ messages in thread
From: Andy Shevchenko @ 2013-06-11 12:37 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: linux-arm-kernel, linux-kernel, Mike Turquette, Seungwon Jeon,
	Jaehoon Chung, Chris Ball, linux-mmc, Grant Likely, Rob Herring,
	Linus Walleij, Devicetree Discuss, Russell King, Arnd Bergmann,
	Olof Johansson, Thomas Petazzoni

On Tue, Jun 11, 2013 at 3:06 PM, Heiko Stübner <heiko@sntech.de> wrote:
> Am Dienstag, 11. Juni 2013, 13:51:56 schrieb Andy Shevchenko:
>> On Tue, Jun 11, 2013 at 2:29 PM, Heiko Stübner <heiko@sntech.de> wrote:

[]

>> > @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider
>> > *divider, unsigned int div)
>> >
>> >                 return is_power_of_2(div);
>> >
>> >         if (divider->table)
>> >
>> >                 return _is_valid_table_div(divider->table, div);
>> >
>> > +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) !=
>> > 0) +               return false;
>> >
>> >         return true;
>> >
>> >  }
>>
>> What if rewrite like
>>
>>  if (divider->flags & CLK_DIVIDER_EVEN == 0)
>>  return true;
>>
>> return div < 2 || div % 2 == 0;
>
> hmm, the current structure is of the form of testing for each feature and
> doing a applicable action if the flag is set. So it also is extensible for
> future flags and checking for the absence of an attribute while the rest of
> the conditionals check for the presence also might make the code harder to
> read.
>
> So for me the current variant somehow looks more intuitive.

This variant I think fits:

if (!(divider->flags & CLK_DIVIDER_EVEN))
  return div < 2 || div % 2 == 0;

You check for feature and do accordingly.

--
With Best Regards,
Andy Shevchenko

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

* Re: [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
@ 2013-06-11 12:37         ` Andy Shevchenko
  0 siblings, 0 replies; 56+ messages in thread
From: Andy Shevchenko @ 2013-06-11 12:37 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: linux-arm-kernel, linux-kernel, Mike Turquette, Seungwon Jeon,
	Jaehoon Chung, Chris Ball, linux-mmc, Grant Likely, Rob Herring,
	Linus Walleij, Devicetree Discuss, Russell King, Arnd Bergmann,
	Olof Johansson, Thomas Petazzoni

On Tue, Jun 11, 2013 at 3:06 PM, Heiko Stübner <heiko@sntech.de> wrote:
> Am Dienstag, 11. Juni 2013, 13:51:56 schrieb Andy Shevchenko:
>> On Tue, Jun 11, 2013 at 2:29 PM, Heiko Stübner <heiko@sntech.de> wrote:

[]

>> > @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider
>> > *divider, unsigned int div)
>> >
>> >                 return is_power_of_2(div);
>> >
>> >         if (divider->table)
>> >
>> >                 return _is_valid_table_div(divider->table, div);
>> >
>> > +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) !=
>> > 0) +               return false;
>> >
>> >         return true;
>> >
>> >  }
>>
>> What if rewrite like
>>
>>  if (divider->flags & CLK_DIVIDER_EVEN == 0)
>>  return true;
>>
>> return div < 2 || div % 2 == 0;
>
> hmm, the current structure is of the form of testing for each feature and
> doing a applicable action if the flag is set. So it also is extensible for
> future flags and checking for the absence of an attribute while the rest of
> the conditionals check for the presence also might make the code harder to
> read.
>
> So for me the current variant somehow looks more intuitive.

This variant I think fits:

if (!(divider->flags & CLK_DIVIDER_EVEN))
  return div < 2 || div % 2 == 0;

You check for feature and do accordingly.

--
With Best Regards,
Andy Shevchenko

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

* [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
@ 2013-06-11 12:37         ` Andy Shevchenko
  0 siblings, 0 replies; 56+ messages in thread
From: Andy Shevchenko @ 2013-06-11 12:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 11, 2013 at 3:06 PM, Heiko St?bner <heiko@sntech.de> wrote:
> Am Dienstag, 11. Juni 2013, 13:51:56 schrieb Andy Shevchenko:
>> On Tue, Jun 11, 2013 at 2:29 PM, Heiko St?bner <heiko@sntech.de> wrote:

[]

>> > @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider
>> > *divider, unsigned int div)
>> >
>> >                 return is_power_of_2(div);
>> >
>> >         if (divider->table)
>> >
>> >                 return _is_valid_table_div(divider->table, div);
>> >
>> > +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) !=
>> > 0) +               return false;
>> >
>> >         return true;
>> >
>> >  }
>>
>> What if rewrite like
>>
>>  if (divider->flags & CLK_DIVIDER_EVEN == 0)
>>  return true;
>>
>> return div < 2 || div % 2 == 0;
>
> hmm, the current structure is of the form of testing for each feature and
> doing a applicable action if the flag is set. So it also is extensible for
> future flags and checking for the absence of an attribute while the rest of
> the conditionals check for the presence also might make the code harder to
> read.
>
> So for me the current variant somehow looks more intuitive.

This variant I think fits:

if (!(divider->flags & CLK_DIVIDER_EVEN))
  return div < 2 || div % 2 == 0;

You check for feature and do accordingly.

--
With Best Regards,
Andy Shevchenko

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

* Re: [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
  2013-06-11 12:37         ` Andy Shevchenko
  (?)
@ 2013-06-11 12:39           ` Andy Shevchenko
  -1 siblings, 0 replies; 56+ messages in thread
From: Andy Shevchenko @ 2013-06-11 12:39 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: linux-arm-kernel, linux-kernel, Mike Turquette, Seungwon Jeon,
	Jaehoon Chung, Chris Ball, linux-mmc, Grant Likely, Rob Herring,
	Linus Walleij, Devicetree Discuss, Russell King, Arnd Bergmann,
	Olof Johansson, Thomas Petazzoni

On Tue, Jun 11, 2013 at 3:37 PM, Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Tue, Jun 11, 2013 at 3:06 PM, Heiko Stübner <heiko@sntech.de> wrote:
>> Am Dienstag, 11. Juni 2013, 13:51:56 schrieb Andy Shevchenko:
>>> On Tue, Jun 11, 2013 at 2:29 PM, Heiko Stübner <heiko@sntech.de> wrote:

> This variant I think fits:
>
> if (!(divider->flags & CLK_DIVIDER_EVEN))

Oops, without "!()" of course.

>   return div < 2 || div % 2 == 0;
>
> You check for feature and do accordingly.


--
With Best Regards,
Andy Shevchenko

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

* Re: [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
@ 2013-06-11 12:39           ` Andy Shevchenko
  0 siblings, 0 replies; 56+ messages in thread
From: Andy Shevchenko @ 2013-06-11 12:39 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: linux-arm-kernel, linux-kernel, Mike Turquette, Seungwon Jeon,
	Jaehoon Chung, Chris Ball, linux-mmc, Grant Likely, Rob Herring,
	Linus Walleij, Devicetree Discuss, Russell King, Arnd Bergmann,
	Olof Johansson, Thomas Petazzoni

On Tue, Jun 11, 2013 at 3:37 PM, Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Tue, Jun 11, 2013 at 3:06 PM, Heiko Stübner <heiko@sntech.de> wrote:
>> Am Dienstag, 11. Juni 2013, 13:51:56 schrieb Andy Shevchenko:
>>> On Tue, Jun 11, 2013 at 2:29 PM, Heiko Stübner <heiko@sntech.de> wrote:

> This variant I think fits:
>
> if (!(divider->flags & CLK_DIVIDER_EVEN))

Oops, without "!()" of course.

>   return div < 2 || div % 2 == 0;
>
> You check for feature and do accordingly.


--
With Best Regards,
Andy Shevchenko

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

* [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
@ 2013-06-11 12:39           ` Andy Shevchenko
  0 siblings, 0 replies; 56+ messages in thread
From: Andy Shevchenko @ 2013-06-11 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 11, 2013 at 3:37 PM, Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Tue, Jun 11, 2013 at 3:06 PM, Heiko St?bner <heiko@sntech.de> wrote:
>> Am Dienstag, 11. Juni 2013, 13:51:56 schrieb Andy Shevchenko:
>>> On Tue, Jun 11, 2013 at 2:29 PM, Heiko St?bner <heiko@sntech.de> wrote:

> This variant I think fits:
>
> if (!(divider->flags & CLK_DIVIDER_EVEN))

Oops, without "!()" of course.

>   return div < 2 || div % 2 == 0;
>
> You check for feature and do accordingly.


--
With Best Regards,
Andy Shevchenko

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

* Re: [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
  2013-06-11 11:29   ` Heiko Stübner
@ 2013-06-11 18:57     ` Mike Turquette
  -1 siblings, 0 replies; 56+ messages in thread
From: Mike Turquette @ 2013-06-11 18:57 UTC (permalink / raw)
  To: Heiko Stübner, linux-arm-kernel
  Cc: linux-kernel, Seungwon Jeon, Jaehoon Chung, Chris Ball,
	linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

Quoting Heiko Stübner (2013-06-11 04:29:32)
> SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> that use the regular mechanisms for storage but allow only even
> dividers and 1 to be used.
> 
> Therefore add a flag that lets _is_valid_div limit the valid dividers
> to these values. _get_maxdiv is also adapted to return even values
> for the CLK_DIVIDER_ONE_BASED case.
> 
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> ---
>  drivers/clk/clk-divider.c    |   14 ++++++++++++--
>  include/linux/clk-provider.h |    2 ++
>  2 files changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
> index ce5cfe9..bdee7cf 100644
> --- a/drivers/clk/clk-divider.c
> +++ b/drivers/clk/clk-divider.c
> @@ -45,8 +45,16 @@ static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
>  
>  static unsigned int _get_maxdiv(struct clk_divider *divider)
>  {
> -       if (divider->flags & CLK_DIVIDER_ONE_BASED)
> -               return div_mask(divider);
> +       if (divider->flags & CLK_DIVIDER_ONE_BASED) {
> +               unsigned int div = div_mask(divider);
> +
> +               /* decrease to even number */
> +               if (divider->flags & CLK_DIVIDER_EVEN)
> +                       div--;
> +
> +               return div;
> +       }
> +
>         if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
>                 return 1 << div_mask(divider);
>         if (divider->table)
> @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
>                 return is_power_of_2(div);
>         if (divider->table)
>                 return _is_valid_table_div(divider->table, div);
> +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) != 0)

Is it correct to check for 'div != 1' here?  Wouldn't that check only be
valid in the presence of CLK_DIVIDER_ONE_BASED?

Maybe something like this would be more correct:

	if (divider->flags & CLK_DIVIDER_EVEN && (div % 2) != 0) {
		if (divider->flags & CLK_DIVIDER_ONE_BASED && div == 1)
			return true;
		return false;
	}

Regards,
Mike

> +               return false;
>         return true;
>  }
>  
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index 1ec14a7..bd52e52 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -266,6 +266,7 @@ struct clk_div_table {
>   *   of this register, and mask of divider bits are in higher 16-bit of this
>   *   register.  While setting the divider bits, higher 16-bit should also be
>   *   updated to indicate changing divider bits.
> + * CLK_DIVIDER_EVEN - only allow even divider values
>   */
>  struct clk_divider {
>         struct clk_hw   hw;
> @@ -281,6 +282,7 @@ struct clk_divider {
>  #define CLK_DIVIDER_POWER_OF_TWO       BIT(1)
>  #define CLK_DIVIDER_ALLOW_ZERO         BIT(2)
>  #define CLK_DIVIDER_HIWORD_MASK                BIT(3)
> +#define CLK_DIVIDER_EVEN               BIT(4)
>  
>  extern const struct clk_ops clk_divider_ops;
>  struct clk *clk_register_divider(struct device *dev, const char *name,
> -- 
> 1.7.2.3

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

* [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
@ 2013-06-11 18:57     ` Mike Turquette
  0 siblings, 0 replies; 56+ messages in thread
From: Mike Turquette @ 2013-06-11 18:57 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Heiko St?bner (2013-06-11 04:29:32)
> SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> that use the regular mechanisms for storage but allow only even
> dividers and 1 to be used.
> 
> Therefore add a flag that lets _is_valid_div limit the valid dividers
> to these values. _get_maxdiv is also adapted to return even values
> for the CLK_DIVIDER_ONE_BASED case.
> 
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> ---
>  drivers/clk/clk-divider.c    |   14 ++++++++++++--
>  include/linux/clk-provider.h |    2 ++
>  2 files changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
> index ce5cfe9..bdee7cf 100644
> --- a/drivers/clk/clk-divider.c
> +++ b/drivers/clk/clk-divider.c
> @@ -45,8 +45,16 @@ static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
>  
>  static unsigned int _get_maxdiv(struct clk_divider *divider)
>  {
> -       if (divider->flags & CLK_DIVIDER_ONE_BASED)
> -               return div_mask(divider);
> +       if (divider->flags & CLK_DIVIDER_ONE_BASED) {
> +               unsigned int div = div_mask(divider);
> +
> +               /* decrease to even number */
> +               if (divider->flags & CLK_DIVIDER_EVEN)
> +                       div--;
> +
> +               return div;
> +       }
> +
>         if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
>                 return 1 << div_mask(divider);
>         if (divider->table)
> @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
>                 return is_power_of_2(div);
>         if (divider->table)
>                 return _is_valid_table_div(divider->table, div);
> +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) != 0)

Is it correct to check for 'div != 1' here?  Wouldn't that check only be
valid in the presence of CLK_DIVIDER_ONE_BASED?

Maybe something like this would be more correct:

	if (divider->flags & CLK_DIVIDER_EVEN && (div % 2) != 0) {
		if (divider->flags & CLK_DIVIDER_ONE_BASED && div == 1)
			return true;
		return false;
	}

Regards,
Mike

> +               return false;
>         return true;
>  }
>  
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index 1ec14a7..bd52e52 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -266,6 +266,7 @@ struct clk_div_table {
>   *   of this register, and mask of divider bits are in higher 16-bit of this
>   *   register.  While setting the divider bits, higher 16-bit should also be
>   *   updated to indicate changing divider bits.
> + * CLK_DIVIDER_EVEN - only allow even divider values
>   */
>  struct clk_divider {
>         struct clk_hw   hw;
> @@ -281,6 +282,7 @@ struct clk_divider {
>  #define CLK_DIVIDER_POWER_OF_TWO       BIT(1)
>  #define CLK_DIVIDER_ALLOW_ZERO         BIT(2)
>  #define CLK_DIVIDER_HIWORD_MASK                BIT(3)
> +#define CLK_DIVIDER_EVEN               BIT(4)
>  
>  extern const struct clk_ops clk_divider_ops;
>  struct clk *clk_register_divider(struct device *dev, const char *name,
> -- 
> 1.7.2.3

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

* Re: [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
  2013-06-11 18:57     ` Mike Turquette
  (?)
@ 2013-06-11 19:23       ` Heiko Stübner
  -1 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 19:23 UTC (permalink / raw)
  To: Mike Turquette
  Cc: linux-arm-kernel, linux-kernel, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

Am Dienstag, 11. Juni 2013, 20:57:50 schrieb Mike Turquette:
> Quoting Heiko Stübner (2013-06-11 04:29:32)
> 
> > SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> > that use the regular mechanisms for storage but allow only even
> > dividers and 1 to be used.
> > 
> > Therefore add a flag that lets _is_valid_div limit the valid dividers
> > to these values. _get_maxdiv is also adapted to return even values
> > for the CLK_DIVIDER_ONE_BASED case.
> > 
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> > ---
> > 
> >  drivers/clk/clk-divider.c    |   14 ++++++++++++--
> >  include/linux/clk-provider.h |    2 ++
> >  2 files changed, 14 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
> > index ce5cfe9..bdee7cf 100644
> > --- a/drivers/clk/clk-divider.c
> > +++ b/drivers/clk/clk-divider.c
> > @@ -45,8 +45,16 @@ static unsigned int _get_table_maxdiv(const struct
> > clk_div_table *table)
> > 
> >  static unsigned int _get_maxdiv(struct clk_divider *divider)
> >  {
> > 
> > -       if (divider->flags & CLK_DIVIDER_ONE_BASED)
> > -               return div_mask(divider);
> > +       if (divider->flags & CLK_DIVIDER_ONE_BASED) {
> > +               unsigned int div = div_mask(divider);
> > +
> > +               /* decrease to even number */
> > +               if (divider->flags & CLK_DIVIDER_EVEN)
> > +                       div--;
> > +
> > +               return div;
> > +       }
> > +
> > 
> >         if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
> >         
> >                 return 1 << div_mask(divider);
> >         
> >         if (divider->table)
> > 
> > @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider
> > *divider, unsigned int div)
> > 
> >                 return is_power_of_2(div);
> >         
> >         if (divider->table)
> >         
> >                 return _is_valid_table_div(divider->table, div);
> > 
> > +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) !=
> > 0)
> 
> Is it correct to check for 'div != 1' here?  Wouldn't that check only be
> valid in the presence of CLK_DIVIDER_ONE_BASED?
> 
> Maybe something like this would be more correct:
> 
> 	if (divider->flags & CLK_DIVIDER_EVEN && (div % 2) != 0) {
> 		if (divider->flags & CLK_DIVIDER_ONE_BASED && div == 1)
> 			return true;
> 		return false;
> 	}

hmm, not necessarily. As I understand the doc DIVIDER_ONE_BASED describes how 
the divider is stored in the register, i.e. if the register value is div-1 or 
div.

When div is 1, it of course means don't divide [rate/1], and CLK_DIVIDER_EVEN 
needs to just make sure that bigger dividers that really divide the rate are 
even values (so limiting the possible dividers to 1 2 4 ...), independent on 
how the divider value is stored in the register.



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

* Re: [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
@ 2013-06-11 19:23       ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 19:23 UTC (permalink / raw)
  To: Mike Turquette
  Cc: linux-arm-kernel, linux-kernel, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

Am Dienstag, 11. Juni 2013, 20:57:50 schrieb Mike Turquette:
> Quoting Heiko Stübner (2013-06-11 04:29:32)
> 
> > SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> > that use the regular mechanisms for storage but allow only even
> > dividers and 1 to be used.
> > 
> > Therefore add a flag that lets _is_valid_div limit the valid dividers
> > to these values. _get_maxdiv is also adapted to return even values
> > for the CLK_DIVIDER_ONE_BASED case.
> > 
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> > ---
> > 
> >  drivers/clk/clk-divider.c    |   14 ++++++++++++--
> >  include/linux/clk-provider.h |    2 ++
> >  2 files changed, 14 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
> > index ce5cfe9..bdee7cf 100644
> > --- a/drivers/clk/clk-divider.c
> > +++ b/drivers/clk/clk-divider.c
> > @@ -45,8 +45,16 @@ static unsigned int _get_table_maxdiv(const struct
> > clk_div_table *table)
> > 
> >  static unsigned int _get_maxdiv(struct clk_divider *divider)
> >  {
> > 
> > -       if (divider->flags & CLK_DIVIDER_ONE_BASED)
> > -               return div_mask(divider);
> > +       if (divider->flags & CLK_DIVIDER_ONE_BASED) {
> > +               unsigned int div = div_mask(divider);
> > +
> > +               /* decrease to even number */
> > +               if (divider->flags & CLK_DIVIDER_EVEN)
> > +                       div--;
> > +
> > +               return div;
> > +       }
> > +
> > 
> >         if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
> >         
> >                 return 1 << div_mask(divider);
> >         
> >         if (divider->table)
> > 
> > @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider
> > *divider, unsigned int div)
> > 
> >                 return is_power_of_2(div);
> >         
> >         if (divider->table)
> >         
> >                 return _is_valid_table_div(divider->table, div);
> > 
> > +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) !=
> > 0)
> 
> Is it correct to check for 'div != 1' here?  Wouldn't that check only be
> valid in the presence of CLK_DIVIDER_ONE_BASED?
> 
> Maybe something like this would be more correct:
> 
> 	if (divider->flags & CLK_DIVIDER_EVEN && (div % 2) != 0) {
> 		if (divider->flags & CLK_DIVIDER_ONE_BASED && div == 1)
> 			return true;
> 		return false;
> 	}

hmm, not necessarily. As I understand the doc DIVIDER_ONE_BASED describes how 
the divider is stored in the register, i.e. if the register value is div-1 or 
div.

When div is 1, it of course means don't divide [rate/1], and CLK_DIVIDER_EVEN 
needs to just make sure that bigger dividers that really divide the rate are 
even values (so limiting the possible dividers to 1 2 4 ...), independent on 
how the divider value is stored in the register.



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

* [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers
@ 2013-06-11 19:23       ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-11 19:23 UTC (permalink / raw)
  To: linux-arm-kernel

Am Dienstag, 11. Juni 2013, 20:57:50 schrieb Mike Turquette:
> Quoting Heiko St?bner (2013-06-11 04:29:32)
> 
> > SoCs like the Rockchip Cortex-A9 ones contain divider some clocks
> > that use the regular mechanisms for storage but allow only even
> > dividers and 1 to be used.
> > 
> > Therefore add a flag that lets _is_valid_div limit the valid dividers
> > to these values. _get_maxdiv is also adapted to return even values
> > for the CLK_DIVIDER_ONE_BASED case.
> > 
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> > ---
> > 
> >  drivers/clk/clk-divider.c    |   14 ++++++++++++--
> >  include/linux/clk-provider.h |    2 ++
> >  2 files changed, 14 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
> > index ce5cfe9..bdee7cf 100644
> > --- a/drivers/clk/clk-divider.c
> > +++ b/drivers/clk/clk-divider.c
> > @@ -45,8 +45,16 @@ static unsigned int _get_table_maxdiv(const struct
> > clk_div_table *table)
> > 
> >  static unsigned int _get_maxdiv(struct clk_divider *divider)
> >  {
> > 
> > -       if (divider->flags & CLK_DIVIDER_ONE_BASED)
> > -               return div_mask(divider);
> > +       if (divider->flags & CLK_DIVIDER_ONE_BASED) {
> > +               unsigned int div = div_mask(divider);
> > +
> > +               /* decrease to even number */
> > +               if (divider->flags & CLK_DIVIDER_EVEN)
> > +                       div--;
> > +
> > +               return div;
> > +       }
> > +
> > 
> >         if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
> >         
> >                 return 1 << div_mask(divider);
> >         
> >         if (divider->table)
> > 
> > @@ -141,6 +149,8 @@ static bool _is_valid_div(struct clk_divider
> > *divider, unsigned int div)
> > 
> >                 return is_power_of_2(div);
> >         
> >         if (divider->table)
> >         
> >                 return _is_valid_table_div(divider->table, div);
> > 
> > +       if (divider->flags & CLK_DIVIDER_EVEN && div != 1 && (div % 2) !=
> > 0)
> 
> Is it correct to check for 'div != 1' here?  Wouldn't that check only be
> valid in the presence of CLK_DIVIDER_ONE_BASED?
> 
> Maybe something like this would be more correct:
> 
> 	if (divider->flags & CLK_DIVIDER_EVEN && (div % 2) != 0) {
> 		if (divider->flags & CLK_DIVIDER_ONE_BASED && div == 1)
> 			return true;
> 		return false;
> 	}

hmm, not necessarily. As I understand the doc DIVIDER_ONE_BASED describes how 
the divider is stored in the register, i.e. if the register value is div-1 or 
div.

When div is 1, it of course means don't divide [rate/1], and CLK_DIVIDER_EVEN 
needs to just make sure that bigger dividers that really divide the rate are 
even values (so limiting the possible dividers to 1 2 4 ...), independent on 
how the divider value is stored in the register.

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

* Re: [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support
  2013-06-11 11:31   ` Heiko Stübner
@ 2013-06-11 20:06     ` Mike Turquette
  -1 siblings, 0 replies; 56+ messages in thread
From: Mike Turquette @ 2013-06-11 20:06 UTC (permalink / raw)
  To: Heiko Stübner, linux-arm-kernel
  Cc: linux-kernel, Seungwon Jeon, Jaehoon Chung, Chris Ball,
	linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

Quoting Heiko Stübner (2013-06-11 04:31:31)
> This adds basic support for clocks on Rockchip rk3066 SoCs.
> The clock handling thru small dt nodes is heavily inspired by the
> sunxi clk code.
> 
> The plls are currently read-only, as their setting needs more
> investigation. This also results in slow cpu speeds, as the apll starts
> at a default of 600mhz.
> 
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> ---
>  arch/arm/boot/dts/rk3066a-clocks.dtsi   |  467 +++++++++++++++++++++++++++++++

It's best to separate the DT data changes from the clock driver.  The
new dtsi can be a separate patch.

Also the rockchip clock bindings need to be documented in
Documentation/devicetree/bindings/clock.

<snip>

> diff --git a/drivers/clk/rockchip/clk-rockchip-pll.c b/drivers/clk/rockchip/clk-rockchip-pll.c
> new file mode 100644
> index 0000000..4456445
> --- /dev/null
> +++ b/drivers/clk/rockchip/clk-rockchip-pll.c
> @@ -0,0 +1,131 @@
> +/*
> + * Copyright (c) 2013 MundoReader S.L.
> + * Author: Heiko Stuebner <heiko@sntech.de>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <asm/div64.h>
> +#include <linux/slab.h>
> +#include <linux/io.h>
> +#include <linux/clk.h>
> +#include <linux/clk-private.h>

NACK.  Please use clk-provider.h.  Do you really need something from
clk-private.h?

> +
> +#define RK3X_PLL_MODE_MASK             0x3
> +#define RK3X_PLL_MODE_SLOW             0x0
> +#define RK3X_PLL_MODE_NORM             0x1
> +#define RK3X_PLL_MODE_DEEP             0x2
> +
> +#define RK3X_PLLCON0_OD_MASK           0xf
> +#define RK3X_PLLCON0_OD_SHIFT          0
> +#define RK3X_PLLCON0_NR_MASK           0x3f
> +#define RK3X_PLLCON0_NR_SHIFT          8
> +
> +#define RK3X_PLLCON1_NF_MASK           0x1fff
> +#define RK3X_PLLCON1_NF_SHIFT          0
> +
> +#define RK3X_PLLCON3_REST              (1 << 5)
> +#define RK3X_PLLCON3_BYPASS            (1 << 0)
> +
> +struct rockchip_clk_pll {
> +       struct clk_hw           hw;
> +       void __iomem            *reg_base;
> +       void __iomem            *reg_mode;
> +       unsigned int            shift_mode;
> +       spinlock_t              *lock;
> +};
> +
> +#define to_clk_pll(_hw) container_of(_hw, struct rockchip_clk_pll, hw)
> +
> +static unsigned long rk3x_generic_pll_recalc_rate(struct clk_hw *hw,
> +                               unsigned long parent_rate)
> +{
> +       struct rockchip_clk_pll *pll = to_clk_pll(hw);
> +       u32 pll_con0 = readl_relaxed(pll->reg_base);
> +       u32 pll_con1 = readl_relaxed(pll->reg_base + 0x4);
> +       u32 pll_con3 = readl_relaxed(pll->reg_base + 0xc);
> +       u32 mode_con = readl_relaxed(pll->reg_mode) >> pll->shift_mode;
> +       u64 pll_nf;
> +       u64 pll_nr;
> +       u64 pll_no;
> +       u64 rate64;
> +
> +       if (pll_con3 & RK3X_PLLCON3_BYPASS) {
> +               pr_debug("%s: pll %s is bypassed\n", __func__,
> +                       __clk_get_name(hw->clk));
> +               return parent_rate;
> +       }
> +
> +       mode_con &= RK3X_PLL_MODE_MASK;
> +       if (mode_con != RK3X_PLL_MODE_NORM) {
> +               pr_debug("%s: pll %s not in normal mode: %d\n", __func__,
> +                       __clk_get_name(hw->clk), mode_con);
> +               return parent_rate;
> +       }
> +
> +       pll_nf = (pll_con1 >> RK3X_PLLCON1_NF_SHIFT);
> +       pll_nf &= RK3X_PLLCON1_NF_MASK;
> +       pll_nf++;
> +       rate64 = (u64)parent_rate * pll_nf;
> +
> +       pll_nr = (pll_con0 >> RK3X_PLLCON0_NR_SHIFT);
> +       pll_nr &= RK3X_PLLCON0_NR_MASK;
> +       pll_nr++;
> +       do_div(rate64, pll_nr);
> +
> +       pll_no = (pll_con0 >> RK3X_PLLCON0_OD_SHIFT);
> +       pll_no &= RK3X_PLLCON0_OD_MASK;
> +       pll_no++;
> +       do_div(rate64, pll_no);
> +
> +       return (unsigned long)rate64;
> +}
> +
> +static const struct clk_ops rk3x_generic_pll_clk_ops = {
> +       .recalc_rate = rk3x_generic_pll_recalc_rate,
> +};
> +
> +struct clk * __init rockchip_clk_register_rk3x_pll(const char *name,
> +                       const char *pname, void __iomem *reg_base,
> +                       void __iomem *reg_mode, unsigned int shift_mode,
> +                       spinlock_t *lock)
> +{
> +       struct rockchip_clk_pll *pll;
> +       struct clk *clk;
> +       struct clk_init_data init;
> +
> +       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
> +       if (!pll) {
> +               pr_err("%s: could not allocate pll clk %s\n", __func__, name);
> +               return NULL;
> +       }
> +
> +       init.name = name;
> +       init.ops = &rk3x_generic_pll_clk_ops;
> +       init.flags = CLK_GET_RATE_NOCACHE;
> +       init.parent_names = &pname;
> +       init.num_parents = 1;
> +
> +       pll->hw.init = &init;
> +       pll->reg_base = reg_base;
> +       pll->reg_mode = reg_mode;
> +       pll->shift_mode = shift_mode;
> +       pll->lock = lock;
> +
> +       clk = clk_register(NULL, &pll->hw);
> +       if (IS_ERR(clk)) {
> +               pr_err("%s: failed to register pll clock %s\n", __func__,
> +                               name);
> +               kfree(pll);
> +       }
> +
> +       return clk;
> +}
> diff --git a/drivers/clk/rockchip/clk-rockchip-pll.h b/drivers/clk/rockchip/clk-rockchip-pll.h
> new file mode 100644
> index 0000000..a63288a
> --- /dev/null
> +++ b/drivers/clk/rockchip/clk-rockchip-pll.h
> @@ -0,0 +1,19 @@
> +/*
> + * Copyright (c) 2013 MundoReader S.L.
> + * Author: Heiko Stuebner <heiko@sntech.de>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +extern struct clk * __init rockchip_clk_register_rk3x_pll(const char *name,
> +                       const char *pname, const void __iomem *reg_base,
> +                       const void __iomem *reg_mode, unsigned int shift_mode,
> +                       spinlock_t *lock);
> diff --git a/drivers/clk/rockchip/clk-rockchip.c b/drivers/clk/rockchip/clk-rockchip.c
> new file mode 100644
> index 0000000..660b00f
> --- /dev/null
> +++ b/drivers/clk/rockchip/clk-rockchip.c
> @@ -0,0 +1,330 @@
> +/*
> + * Copyright (c) 2013 MundoReader S.L.
> + * Author: Heiko Stuebner <heiko@sntech.de>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +
> +#include "clk-rockchip-pll.h"
> +
> +static DEFINE_SPINLOCK(clk_lock);
> +
> +struct rockchip_pll_data {
> +       int mode_shift;
> +};
> +
> +struct rockchip_pll_data rk3066a_apll_data = {
> +       .mode_shift = 0,
> +};
> +
> +struct rockchip_pll_data rk3066a_dpll_data = {
> +       .mode_shift = 4,
> +};
> +
> +struct rockchip_pll_data rk3066a_cpll_data = {
> +       .mode_shift = 8,
> +};
> +
> +struct rockchip_pll_data rk3066a_gpll_data = {
> +       .mode_shift = 12,
> +};
> +
> +/* Matches for plls */
> +static const __initconst struct of_device_id clk_pll_match[] = {
> +       { .compatible = "rockchip,rk3066a-apll", .data = &rk3066a_apll_data },
> +       { .compatible = "rockchip,rk3066a-dpll", .data = &rk3066a_dpll_data },
> +       { .compatible = "rockchip,rk3066a-cpll", .data = &rk3066a_cpll_data },
> +       { .compatible = "rockchip,rk3066a-gpll", .data = &rk3066a_gpll_data },
> +       {}
> +};
> +
> +static void __init rockchip_pll_setup(struct device_node *node,
> +                                     struct rockchip_pll_data *data)
> +{
> +       struct clk *clk;
> +       const char *clk_name = node->name;
> +       const char *clk_parent;
> +       void __iomem *reg_base;
> +       void __iomem *reg_mode;
> +       u32 rate;
> +
> +       reg_base = of_iomap(node, 0);
> +       reg_mode = of_iomap(node, 1);
> +
> +       clk_parent = of_clk_get_parent_name(node, 0);
> +
> +       pr_debug("%s: adding %s as child of %s\n",
> +               __func__, clk_name, clk_parent);
> +
> +       clk = rockchip_clk_register_rk3x_pll(clk_name, clk_parent, reg_base,
> +                                            reg_mode, data->mode_shift,
> +                                            &clk_lock);
> +       if (clk) {
> +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +
> +               /* optionally set a target frequency for the pll */
> +               if (!of_property_read_u32(node, "clock-frequency", &rate))
> +                       clk_set_rate(clk, rate);
> +       }
> +}
> +
> +/*
> + * Mux clocks
> + */
> +
> +struct rockchip_mux_data {
> +       int shift;
> +       int width;
> +};
> +
> +#define RK_MUX(n, s, w)                                        \
> +static const __initconst struct rockchip_mux_data n = {        \
> +       .shift = s,                                     \
> +       .width = w,                                     \
> +}
> +
> +RK_MUX(gpll_cpll_15_mux_data, 15, 1);
> +RK_MUX(uart_mux_data, 8, 2);
> +RK_MUX(cpu_mux_data, 8, 1);
> +
> +static const __initconst struct of_device_id clk_mux_match[] = {
> +       { .compatible = "rockchip,rk2928-gpll-cpll-bit15-mux",
> +               .data = &gpll_cpll_15_mux_data },
> +       { .compatible = "rockchip,rk2928-uart-mux",
> +               .data = &uart_mux_data },
> +       { .compatible = "rockchip,rk3066-cpu-mux",
> +               .data = &cpu_mux_data },
> +       {}
> +};
> +
> +static void __init rockchip_mux_clk_setup(struct device_node *node,
> +                                         struct rockchip_mux_data *data)
> +{
> +       struct clk *clk;
> +       const char *clk_name = node->name;
> +       void __iomem *reg;
> +       int max_parents = (1 << data->width);
> +       const char *parents[max_parents];
> +       int flags;
> +       int i = 0;
> +
> +       reg = of_iomap(node, 0);
> +
> +       while (i < max_parents &&
> +              (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
> +               i++;
> +
> +       flags = CLK_MUX_HIWORD_MASK;
> +
> +       clk = clk_register_mux(NULL, clk_name, parents, i, 0,
> +                              reg, data->shift, data->width,
> +                              flags, &clk_lock);
> +       if (clk)
> +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +}
> +
> +/*
> + * Divider clocks
> + */
> +
> +struct rockchip_div_data {
> +       int shift;
> +       int width;
> +       int flags;
> +       struct clk_div_table *table;
> +};
> +
> +#define RK_DIV(n, s, w, f, t)                          \
> +static const __initconst struct rockchip_div_data n = {        \
> +       .shift = s,                                     \
> +       .width = w,                                     \
> +       .flags = f,                                     \
> +       .table = t,                                     \
> +}
> +
> +RK_DIV(cpu_div_data, 0, 5, 0, NULL);
> +RK_DIV(aclk_periph_div_data, 0, 5, 0, NULL);
> +RK_DIV(aclk_cpu_div_data, 0, 3, 0, NULL);
> +RK_DIV(hclk_div_data, 8, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> +RK_DIV(pclk_div_data, 12, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> +RK_DIV(mmc_div_data, 0, 6, CLK_DIVIDER_EVEN, NULL);
> +RK_DIV(uart_div_data, 0, 7, 0, NULL);
> +
> +struct clk_div_table core_periph_table[] = {
> +       { 0, 2 },
> +       { 1, 4 },
> +       { 2, 8 },
> +       { 3, 16 },
> +       { 0, 0 },
> +};
> +RK_DIV(core_periph_div_data, 6, 2, 0, core_periph_table);
> +
> +static const __initconst struct of_device_id clk_divider_match[] = {
> +       { .compatible = "rockchip,rk3066a-cpu-divider",
> +               .data = &cpu_div_data },
> +       { .compatible = "rockchip,rk3066a-core-periph-divider",
> +               .data = &core_periph_div_data },
> +       { .compatible = "rockchip,rk2928-aclk-periph-divider",
> +               .data = &aclk_periph_div_data },
> +       { .compatible = "rockchip,rk3066a-aclk-cpu-divider",
> +               .data = &aclk_cpu_div_data },
> +       { .compatible = "rockchip,rk2928-hclk-divider",
> +               .data = &hclk_div_data },
> +       { .compatible = "rockchip,rk2928-pclk-divider",
> +               .data = &pclk_div_data },
> +       { .compatible = "rockchip,rk2928-mmc-divider",
> +               .data = &mmc_div_data },
> +       { .compatible = "rockchip,rk2928-uart-divider",
> +               .data = &uart_div_data },
> +       {}
> +};
> +
> +static void __init rockchip_divider_clk_setup(struct device_node *node,
> +                                             struct rockchip_div_data *data)
> +{
> +       struct clk *clk;
> +       const char *clk_name = node->name;
> +       const char *clk_parent;
> +       void __iomem *reg;
> +       int flags;
> +
> +       reg = of_iomap(node, 0);
> +
> +       clk_parent = of_clk_get_parent_name(node, 0);
> +
> +       flags = data->flags;
> +       flags |= CLK_DIVIDER_HIWORD_MASK;
> +
> +       if (data->table)
> +               clk = clk_register_divider_table(NULL, clk_name, clk_parent, 0,
> +                                               reg, data->shift, data->width,
> +                                               flags, data->table, &clk_lock);
> +       else
> +               clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
> +                                               reg, data->shift, data->width,
> +                                               flags, &clk_lock);
> +       if (clk)
> +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +}
> +
> +/*
> + * Gate clocks
> + */
> +
> +static void __init rockchip_gate_clk_setup(struct device_node *node,
> +                                           void *data)
> +{
> +       struct clk_onecell_data *clk_data;
> +       const char *clk_parent;
> +       const char *clk_name;
> +       void __iomem *reg;
> +       void __iomem *reg_idx;
> +       int flags;
> +       int qty;
> +       int reg_bit;
> +       int clkflags = CLK_SET_RATE_PARENT;
> +       int i;
> +
> +       qty = of_property_count_strings(node, "clock-output-names");
> +       if (qty < 0) {
> +               pr_err("%s: error in clock-output-names %d\n", __func__, qty);
> +               return;
> +       }
> +
> +       if (qty == 0) {
> +               pr_info("%s: nothing to do\n", __func__);
> +               return;
> +       }
> +
> +       reg = of_iomap(node, 0);
> +
> +       clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
> +       if (!clk_data)
> +               return;
> +
> +       clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL);
> +       if (!clk_data->clks) {
> +               kfree(clk_data);
> +               return;
> +       }
> +
> +       flags = CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE;
> +
> +       for (i = 0; i < qty; i++) {
> +               of_property_read_string_index(node, "clock-output-names",
> +                                             i, &clk_name);
> +
> +               /* ignore empty slots */
> +               if (!strcmp("reserved", clk_name))
> +                       continue;
> +
> +               clk_parent = of_clk_get_parent_name(node, i);
> +
> +               /* keep all gates untouched for now */
> +               clkflags |= CLK_IGNORE_UNUSED;
> +
> +               reg_idx = reg + (4 * (i / 16));
> +               reg_bit = (i % 16);
> +
> +               clk_data->clks[i] = clk_register_gate(NULL, clk_name,
> +                                                     clk_parent, clkflags,
> +                                                     reg_idx, reg_bit,
> +                                                     flags,
> +                                                     &clk_lock);
> +               WARN_ON(IS_ERR(clk_data->clks[i]));
> +       }
> +
> +       clk_data->clk_num = qty;
> +
> +       of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> +}
> +
> +static const __initconst struct of_device_id clk_gate_match[] = {
> +       { .compatible = "rockchip,rk2928-gate-clk" },
> +       {}
> +};
> +
> +void __init of_rockchip_clk_table_clock_setup(
> +                                       const struct of_device_id *clk_match,
> +                                       void *function)
> +{
> +       struct device_node *np;
> +       const struct div_data *data;
> +       const struct of_device_id *match;
> +       void (*setup_function)(struct device_node *, const void *) = function;
> +
> +       for_each_matching_node(np, clk_match) {
> +               match = of_match_node(clk_match, np);
> +               data = match->data;
> +               setup_function(np, data);
> +       }
> +}

Can you use of_clk_init instead of the above function?

Regards,
Mike

> +
> +void __init rockchip_init_clocks(struct device_node *node)
> +{
> +       of_rockchip_clk_table_clock_setup(clk_pll_match,
> +                                         rockchip_pll_setup);
> +
> +       of_rockchip_clk_table_clock_setup(clk_mux_match,
> +                                         rockchip_mux_clk_setup);
> +
> +       of_rockchip_clk_table_clock_setup(clk_gate_match,
> +                                         rockchip_gate_clk_setup);
> +
> +       of_rockchip_clk_table_clock_setup(clk_divider_match,
> +                                         rockchip_divider_clk_setup);
> +}
> +CLK_OF_DECLARE(rockchip_clocks, "rockchip,clocks", rockchip_init_clocks);
> -- 
> 1.7.2.3

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

* [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support
@ 2013-06-11 20:06     ` Mike Turquette
  0 siblings, 0 replies; 56+ messages in thread
From: Mike Turquette @ 2013-06-11 20:06 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Heiko St?bner (2013-06-11 04:31:31)
> This adds basic support for clocks on Rockchip rk3066 SoCs.
> The clock handling thru small dt nodes is heavily inspired by the
> sunxi clk code.
> 
> The plls are currently read-only, as their setting needs more
> investigation. This also results in slow cpu speeds, as the apll starts
> at a default of 600mhz.
> 
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> ---
>  arch/arm/boot/dts/rk3066a-clocks.dtsi   |  467 +++++++++++++++++++++++++++++++

It's best to separate the DT data changes from the clock driver.  The
new dtsi can be a separate patch.

Also the rockchip clock bindings need to be documented in
Documentation/devicetree/bindings/clock.

<snip>

> diff --git a/drivers/clk/rockchip/clk-rockchip-pll.c b/drivers/clk/rockchip/clk-rockchip-pll.c
> new file mode 100644
> index 0000000..4456445
> --- /dev/null
> +++ b/drivers/clk/rockchip/clk-rockchip-pll.c
> @@ -0,0 +1,131 @@
> +/*
> + * Copyright (c) 2013 MundoReader S.L.
> + * Author: Heiko Stuebner <heiko@sntech.de>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <asm/div64.h>
> +#include <linux/slab.h>
> +#include <linux/io.h>
> +#include <linux/clk.h>
> +#include <linux/clk-private.h>

NACK.  Please use clk-provider.h.  Do you really need something from
clk-private.h?

> +
> +#define RK3X_PLL_MODE_MASK             0x3
> +#define RK3X_PLL_MODE_SLOW             0x0
> +#define RK3X_PLL_MODE_NORM             0x1
> +#define RK3X_PLL_MODE_DEEP             0x2
> +
> +#define RK3X_PLLCON0_OD_MASK           0xf
> +#define RK3X_PLLCON0_OD_SHIFT          0
> +#define RK3X_PLLCON0_NR_MASK           0x3f
> +#define RK3X_PLLCON0_NR_SHIFT          8
> +
> +#define RK3X_PLLCON1_NF_MASK           0x1fff
> +#define RK3X_PLLCON1_NF_SHIFT          0
> +
> +#define RK3X_PLLCON3_REST              (1 << 5)
> +#define RK3X_PLLCON3_BYPASS            (1 << 0)
> +
> +struct rockchip_clk_pll {
> +       struct clk_hw           hw;
> +       void __iomem            *reg_base;
> +       void __iomem            *reg_mode;
> +       unsigned int            shift_mode;
> +       spinlock_t              *lock;
> +};
> +
> +#define to_clk_pll(_hw) container_of(_hw, struct rockchip_clk_pll, hw)
> +
> +static unsigned long rk3x_generic_pll_recalc_rate(struct clk_hw *hw,
> +                               unsigned long parent_rate)
> +{
> +       struct rockchip_clk_pll *pll = to_clk_pll(hw);
> +       u32 pll_con0 = readl_relaxed(pll->reg_base);
> +       u32 pll_con1 = readl_relaxed(pll->reg_base + 0x4);
> +       u32 pll_con3 = readl_relaxed(pll->reg_base + 0xc);
> +       u32 mode_con = readl_relaxed(pll->reg_mode) >> pll->shift_mode;
> +       u64 pll_nf;
> +       u64 pll_nr;
> +       u64 pll_no;
> +       u64 rate64;
> +
> +       if (pll_con3 & RK3X_PLLCON3_BYPASS) {
> +               pr_debug("%s: pll %s is bypassed\n", __func__,
> +                       __clk_get_name(hw->clk));
> +               return parent_rate;
> +       }
> +
> +       mode_con &= RK3X_PLL_MODE_MASK;
> +       if (mode_con != RK3X_PLL_MODE_NORM) {
> +               pr_debug("%s: pll %s not in normal mode: %d\n", __func__,
> +                       __clk_get_name(hw->clk), mode_con);
> +               return parent_rate;
> +       }
> +
> +       pll_nf = (pll_con1 >> RK3X_PLLCON1_NF_SHIFT);
> +       pll_nf &= RK3X_PLLCON1_NF_MASK;
> +       pll_nf++;
> +       rate64 = (u64)parent_rate * pll_nf;
> +
> +       pll_nr = (pll_con0 >> RK3X_PLLCON0_NR_SHIFT);
> +       pll_nr &= RK3X_PLLCON0_NR_MASK;
> +       pll_nr++;
> +       do_div(rate64, pll_nr);
> +
> +       pll_no = (pll_con0 >> RK3X_PLLCON0_OD_SHIFT);
> +       pll_no &= RK3X_PLLCON0_OD_MASK;
> +       pll_no++;
> +       do_div(rate64, pll_no);
> +
> +       return (unsigned long)rate64;
> +}
> +
> +static const struct clk_ops rk3x_generic_pll_clk_ops = {
> +       .recalc_rate = rk3x_generic_pll_recalc_rate,
> +};
> +
> +struct clk * __init rockchip_clk_register_rk3x_pll(const char *name,
> +                       const char *pname, void __iomem *reg_base,
> +                       void __iomem *reg_mode, unsigned int shift_mode,
> +                       spinlock_t *lock)
> +{
> +       struct rockchip_clk_pll *pll;
> +       struct clk *clk;
> +       struct clk_init_data init;
> +
> +       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
> +       if (!pll) {
> +               pr_err("%s: could not allocate pll clk %s\n", __func__, name);
> +               return NULL;
> +       }
> +
> +       init.name = name;
> +       init.ops = &rk3x_generic_pll_clk_ops;
> +       init.flags = CLK_GET_RATE_NOCACHE;
> +       init.parent_names = &pname;
> +       init.num_parents = 1;
> +
> +       pll->hw.init = &init;
> +       pll->reg_base = reg_base;
> +       pll->reg_mode = reg_mode;
> +       pll->shift_mode = shift_mode;
> +       pll->lock = lock;
> +
> +       clk = clk_register(NULL, &pll->hw);
> +       if (IS_ERR(clk)) {
> +               pr_err("%s: failed to register pll clock %s\n", __func__,
> +                               name);
> +               kfree(pll);
> +       }
> +
> +       return clk;
> +}
> diff --git a/drivers/clk/rockchip/clk-rockchip-pll.h b/drivers/clk/rockchip/clk-rockchip-pll.h
> new file mode 100644
> index 0000000..a63288a
> --- /dev/null
> +++ b/drivers/clk/rockchip/clk-rockchip-pll.h
> @@ -0,0 +1,19 @@
> +/*
> + * Copyright (c) 2013 MundoReader S.L.
> + * Author: Heiko Stuebner <heiko@sntech.de>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +extern struct clk * __init rockchip_clk_register_rk3x_pll(const char *name,
> +                       const char *pname, const void __iomem *reg_base,
> +                       const void __iomem *reg_mode, unsigned int shift_mode,
> +                       spinlock_t *lock);
> diff --git a/drivers/clk/rockchip/clk-rockchip.c b/drivers/clk/rockchip/clk-rockchip.c
> new file mode 100644
> index 0000000..660b00f
> --- /dev/null
> +++ b/drivers/clk/rockchip/clk-rockchip.c
> @@ -0,0 +1,330 @@
> +/*
> + * Copyright (c) 2013 MundoReader S.L.
> + * Author: Heiko Stuebner <heiko@sntech.de>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +
> +#include "clk-rockchip-pll.h"
> +
> +static DEFINE_SPINLOCK(clk_lock);
> +
> +struct rockchip_pll_data {
> +       int mode_shift;
> +};
> +
> +struct rockchip_pll_data rk3066a_apll_data = {
> +       .mode_shift = 0,
> +};
> +
> +struct rockchip_pll_data rk3066a_dpll_data = {
> +       .mode_shift = 4,
> +};
> +
> +struct rockchip_pll_data rk3066a_cpll_data = {
> +       .mode_shift = 8,
> +};
> +
> +struct rockchip_pll_data rk3066a_gpll_data = {
> +       .mode_shift = 12,
> +};
> +
> +/* Matches for plls */
> +static const __initconst struct of_device_id clk_pll_match[] = {
> +       { .compatible = "rockchip,rk3066a-apll", .data = &rk3066a_apll_data },
> +       { .compatible = "rockchip,rk3066a-dpll", .data = &rk3066a_dpll_data },
> +       { .compatible = "rockchip,rk3066a-cpll", .data = &rk3066a_cpll_data },
> +       { .compatible = "rockchip,rk3066a-gpll", .data = &rk3066a_gpll_data },
> +       {}
> +};
> +
> +static void __init rockchip_pll_setup(struct device_node *node,
> +                                     struct rockchip_pll_data *data)
> +{
> +       struct clk *clk;
> +       const char *clk_name = node->name;
> +       const char *clk_parent;
> +       void __iomem *reg_base;
> +       void __iomem *reg_mode;
> +       u32 rate;
> +
> +       reg_base = of_iomap(node, 0);
> +       reg_mode = of_iomap(node, 1);
> +
> +       clk_parent = of_clk_get_parent_name(node, 0);
> +
> +       pr_debug("%s: adding %s as child of %s\n",
> +               __func__, clk_name, clk_parent);
> +
> +       clk = rockchip_clk_register_rk3x_pll(clk_name, clk_parent, reg_base,
> +                                            reg_mode, data->mode_shift,
> +                                            &clk_lock);
> +       if (clk) {
> +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +
> +               /* optionally set a target frequency for the pll */
> +               if (!of_property_read_u32(node, "clock-frequency", &rate))
> +                       clk_set_rate(clk, rate);
> +       }
> +}
> +
> +/*
> + * Mux clocks
> + */
> +
> +struct rockchip_mux_data {
> +       int shift;
> +       int width;
> +};
> +
> +#define RK_MUX(n, s, w)                                        \
> +static const __initconst struct rockchip_mux_data n = {        \
> +       .shift = s,                                     \
> +       .width = w,                                     \
> +}
> +
> +RK_MUX(gpll_cpll_15_mux_data, 15, 1);
> +RK_MUX(uart_mux_data, 8, 2);
> +RK_MUX(cpu_mux_data, 8, 1);
> +
> +static const __initconst struct of_device_id clk_mux_match[] = {
> +       { .compatible = "rockchip,rk2928-gpll-cpll-bit15-mux",
> +               .data = &gpll_cpll_15_mux_data },
> +       { .compatible = "rockchip,rk2928-uart-mux",
> +               .data = &uart_mux_data },
> +       { .compatible = "rockchip,rk3066-cpu-mux",
> +               .data = &cpu_mux_data },
> +       {}
> +};
> +
> +static void __init rockchip_mux_clk_setup(struct device_node *node,
> +                                         struct rockchip_mux_data *data)
> +{
> +       struct clk *clk;
> +       const char *clk_name = node->name;
> +       void __iomem *reg;
> +       int max_parents = (1 << data->width);
> +       const char *parents[max_parents];
> +       int flags;
> +       int i = 0;
> +
> +       reg = of_iomap(node, 0);
> +
> +       while (i < max_parents &&
> +              (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
> +               i++;
> +
> +       flags = CLK_MUX_HIWORD_MASK;
> +
> +       clk = clk_register_mux(NULL, clk_name, parents, i, 0,
> +                              reg, data->shift, data->width,
> +                              flags, &clk_lock);
> +       if (clk)
> +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +}
> +
> +/*
> + * Divider clocks
> + */
> +
> +struct rockchip_div_data {
> +       int shift;
> +       int width;
> +       int flags;
> +       struct clk_div_table *table;
> +};
> +
> +#define RK_DIV(n, s, w, f, t)                          \
> +static const __initconst struct rockchip_div_data n = {        \
> +       .shift = s,                                     \
> +       .width = w,                                     \
> +       .flags = f,                                     \
> +       .table = t,                                     \
> +}
> +
> +RK_DIV(cpu_div_data, 0, 5, 0, NULL);
> +RK_DIV(aclk_periph_div_data, 0, 5, 0, NULL);
> +RK_DIV(aclk_cpu_div_data, 0, 3, 0, NULL);
> +RK_DIV(hclk_div_data, 8, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> +RK_DIV(pclk_div_data, 12, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> +RK_DIV(mmc_div_data, 0, 6, CLK_DIVIDER_EVEN, NULL);
> +RK_DIV(uart_div_data, 0, 7, 0, NULL);
> +
> +struct clk_div_table core_periph_table[] = {
> +       { 0, 2 },
> +       { 1, 4 },
> +       { 2, 8 },
> +       { 3, 16 },
> +       { 0, 0 },
> +};
> +RK_DIV(core_periph_div_data, 6, 2, 0, core_periph_table);
> +
> +static const __initconst struct of_device_id clk_divider_match[] = {
> +       { .compatible = "rockchip,rk3066a-cpu-divider",
> +               .data = &cpu_div_data },
> +       { .compatible = "rockchip,rk3066a-core-periph-divider",
> +               .data = &core_periph_div_data },
> +       { .compatible = "rockchip,rk2928-aclk-periph-divider",
> +               .data = &aclk_periph_div_data },
> +       { .compatible = "rockchip,rk3066a-aclk-cpu-divider",
> +               .data = &aclk_cpu_div_data },
> +       { .compatible = "rockchip,rk2928-hclk-divider",
> +               .data = &hclk_div_data },
> +       { .compatible = "rockchip,rk2928-pclk-divider",
> +               .data = &pclk_div_data },
> +       { .compatible = "rockchip,rk2928-mmc-divider",
> +               .data = &mmc_div_data },
> +       { .compatible = "rockchip,rk2928-uart-divider",
> +               .data = &uart_div_data },
> +       {}
> +};
> +
> +static void __init rockchip_divider_clk_setup(struct device_node *node,
> +                                             struct rockchip_div_data *data)
> +{
> +       struct clk *clk;
> +       const char *clk_name = node->name;
> +       const char *clk_parent;
> +       void __iomem *reg;
> +       int flags;
> +
> +       reg = of_iomap(node, 0);
> +
> +       clk_parent = of_clk_get_parent_name(node, 0);
> +
> +       flags = data->flags;
> +       flags |= CLK_DIVIDER_HIWORD_MASK;
> +
> +       if (data->table)
> +               clk = clk_register_divider_table(NULL, clk_name, clk_parent, 0,
> +                                               reg, data->shift, data->width,
> +                                               flags, data->table, &clk_lock);
> +       else
> +               clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
> +                                               reg, data->shift, data->width,
> +                                               flags, &clk_lock);
> +       if (clk)
> +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +}
> +
> +/*
> + * Gate clocks
> + */
> +
> +static void __init rockchip_gate_clk_setup(struct device_node *node,
> +                                           void *data)
> +{
> +       struct clk_onecell_data *clk_data;
> +       const char *clk_parent;
> +       const char *clk_name;
> +       void __iomem *reg;
> +       void __iomem *reg_idx;
> +       int flags;
> +       int qty;
> +       int reg_bit;
> +       int clkflags = CLK_SET_RATE_PARENT;
> +       int i;
> +
> +       qty = of_property_count_strings(node, "clock-output-names");
> +       if (qty < 0) {
> +               pr_err("%s: error in clock-output-names %d\n", __func__, qty);
> +               return;
> +       }
> +
> +       if (qty == 0) {
> +               pr_info("%s: nothing to do\n", __func__);
> +               return;
> +       }
> +
> +       reg = of_iomap(node, 0);
> +
> +       clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
> +       if (!clk_data)
> +               return;
> +
> +       clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL);
> +       if (!clk_data->clks) {
> +               kfree(clk_data);
> +               return;
> +       }
> +
> +       flags = CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE;
> +
> +       for (i = 0; i < qty; i++) {
> +               of_property_read_string_index(node, "clock-output-names",
> +                                             i, &clk_name);
> +
> +               /* ignore empty slots */
> +               if (!strcmp("reserved", clk_name))
> +                       continue;
> +
> +               clk_parent = of_clk_get_parent_name(node, i);
> +
> +               /* keep all gates untouched for now */
> +               clkflags |= CLK_IGNORE_UNUSED;
> +
> +               reg_idx = reg + (4 * (i / 16));
> +               reg_bit = (i % 16);
> +
> +               clk_data->clks[i] = clk_register_gate(NULL, clk_name,
> +                                                     clk_parent, clkflags,
> +                                                     reg_idx, reg_bit,
> +                                                     flags,
> +                                                     &clk_lock);
> +               WARN_ON(IS_ERR(clk_data->clks[i]));
> +       }
> +
> +       clk_data->clk_num = qty;
> +
> +       of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> +}
> +
> +static const __initconst struct of_device_id clk_gate_match[] = {
> +       { .compatible = "rockchip,rk2928-gate-clk" },
> +       {}
> +};
> +
> +void __init of_rockchip_clk_table_clock_setup(
> +                                       const struct of_device_id *clk_match,
> +                                       void *function)
> +{
> +       struct device_node *np;
> +       const struct div_data *data;
> +       const struct of_device_id *match;
> +       void (*setup_function)(struct device_node *, const void *) = function;
> +
> +       for_each_matching_node(np, clk_match) {
> +               match = of_match_node(clk_match, np);
> +               data = match->data;
> +               setup_function(np, data);
> +       }
> +}

Can you use of_clk_init instead of the above function?

Regards,
Mike

> +
> +void __init rockchip_init_clocks(struct device_node *node)
> +{
> +       of_rockchip_clk_table_clock_setup(clk_pll_match,
> +                                         rockchip_pll_setup);
> +
> +       of_rockchip_clk_table_clock_setup(clk_mux_match,
> +                                         rockchip_mux_clk_setup);
> +
> +       of_rockchip_clk_table_clock_setup(clk_gate_match,
> +                                         rockchip_gate_clk_setup);
> +
> +       of_rockchip_clk_table_clock_setup(clk_divider_match,
> +                                         rockchip_divider_clk_setup);
> +}
> +CLK_OF_DECLARE(rockchip_clocks, "rockchip,clocks", rockchip_init_clocks);
> -- 
> 1.7.2.3

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

* RE: [PATCH v3 3/7] mmc: dw_mmc-pltfm: move probe and remove below dt match table
  2013-06-11 11:30   ` Heiko Stübner
@ 2013-06-12  1:16     ` Seungwon Jeon
  -1 siblings, 0 replies; 56+ messages in thread
From: Seungwon Jeon @ 2013-06-12  1:16 UTC (permalink / raw)
  To: 'Heiko Stübner', linux-arm-kernel
  Cc: linux-kernel, 'Mike Turquette', 'Jaehoon Chung',
	'Chris Ball', linux-mmc, 'Grant Likely',
	'Rob Herring', 'Linus Walleij',
	devicetree-discuss, 'Russell King',
	'Arnd Bergmann', 'Olof Johansson',
	'Thomas Petazzoni', 'Andy Shevchenko'

On 06/11/13 2013 8:30 PM Heiko Stübner wrote:
> In a subsquent patch probe will need to do some handling of data from
> the dt match table. So to prevent the need for forward declarations,
> move probe and remove below the match table.
> 
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>

Acked-by: Seungwon Jeon <tgih.jun@samsung.com>



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

* [PATCH v3 3/7] mmc: dw_mmc-pltfm: move probe and remove below dt match table
@ 2013-06-12  1:16     ` Seungwon Jeon
  0 siblings, 0 replies; 56+ messages in thread
From: Seungwon Jeon @ 2013-06-12  1:16 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/11/13 2013 8:30 PM Heiko St?bner wrote:
> In a subsquent patch probe will need to do some handling of data from
> the dt match table. So to prevent the need for forward declarations,
> move probe and remove below the match table.
> 
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>

Acked-by: Seungwon Jeon <tgih.jun@samsung.com>

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

* RE: [PATCH v3 4/7] mmc: dw_mmc-pltfm: add Rockchip variant
  2013-06-11 11:30   ` Heiko Stübner
@ 2013-06-12  1:22     ` Seungwon Jeon
  -1 siblings, 0 replies; 56+ messages in thread
From: Seungwon Jeon @ 2013-06-12  1:22 UTC (permalink / raw)
  To: 'Heiko Stübner', linux-arm-kernel
  Cc: linux-kernel, 'Mike Turquette', 'Jaehoon Chung',
	'Chris Ball', linux-mmc, 'Grant Likely',
	'Rob Herring', 'Linus Walleij',
	devicetree-discuss, 'Russell King',
	'Arnd Bergmann', 'Olof Johansson',
	'Thomas Petazzoni', 'Andy Shevchenko'

Looks good to me.
But this patch has a dependency on '[PATCH 2/2] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA'
After that, it can be applied.(SDMMC_CMD_USE_HOLD_REG should be moved in dw_mmc.h)

Acked-by: Seungwon Jeon <tgih.jun@samsung.com>

Thanks,
Seungwon Jeon

On 06/11/13 2013 8:31 PM Heiko Stübner wrote:
> Cortex-A9 SoCs from Rockchip use a slightly modified variant of dw_mmc
> controllers that seems to require the SDMMC_CMD_USE_HOLD_REG bit to
> always be set.
> 
> There also seem to be no other modifications (additional register etc)
> present, so to keep the footprint low, add this small variant to the
> pltfm driver.
> 
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> ---
>  drivers/mmc/host/dw_mmc-pltfm.c |   21 ++++++++++++++++++++-
>  1 files changed, 20 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
> index 9b05381..cbbbcf3 100644
> --- a/drivers/mmc/host/dw_mmc-pltfm.c
> +++ b/drivers/mmc/host/dw_mmc-pltfm.c
> @@ -24,6 +24,15 @@
> 
>  #include "dw_mmc.h"
> 
> +static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
> +{
> +	*cmdr |= SDMMC_CMD_USE_HOLD_REG;
> +}
> +
> +static const struct dw_mci_drv_data rockchip_drv_data = {
> +	.prepare_command	= dw_mci_rockchip_prepare_command,
> +};
> +
>  int dw_mci_pltfm_register(struct platform_device *pdev,
>  				const struct dw_mci_drv_data *drv_data)
>  {
> @@ -100,13 +109,23 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
> 
>  static const struct of_device_id dw_mci_pltfm_match[] = {
>  	{ .compatible = "snps,dw-mshc", },
> +	{ .compatible = "rockchip,cortex-a9-dw-mshc",
> +		.data = &rockchip_drv_data },
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
> 
>  static int dw_mci_pltfm_probe(struct platform_device *pdev)
>  {
> -	return dw_mci_pltfm_register(pdev, NULL);
> +	const struct dw_mci_drv_data *drv_data = NULL;
> +	const struct of_device_id *match;
> +
> +	if (pdev->dev.of_node) {
> +		match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
> +		drv_data = match->data;
> +	}
> +
> +	return dw_mci_pltfm_register(pdev, drv_data);
>  }
> 
>  int dw_mci_pltfm_remove(struct platform_device *pdev)
> --
> 1.7.2.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* [PATCH v3 4/7] mmc: dw_mmc-pltfm: add Rockchip variant
@ 2013-06-12  1:22     ` Seungwon Jeon
  0 siblings, 0 replies; 56+ messages in thread
From: Seungwon Jeon @ 2013-06-12  1:22 UTC (permalink / raw)
  To: linux-arm-kernel

Looks good to me.
But this patch has a dependency on '[PATCH 2/2] mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA'
After that, it can be applied.(SDMMC_CMD_USE_HOLD_REG should be moved in dw_mmc.h)

Acked-by: Seungwon Jeon <tgih.jun@samsung.com>

Thanks,
Seungwon Jeon

On 06/11/13 2013 8:31 PM Heiko St?bner wrote:
> Cortex-A9 SoCs from Rockchip use a slightly modified variant of dw_mmc
> controllers that seems to require the SDMMC_CMD_USE_HOLD_REG bit to
> always be set.
> 
> There also seem to be no other modifications (additional register etc)
> present, so to keep the footprint low, add this small variant to the
> pltfm driver.
> 
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> ---
>  drivers/mmc/host/dw_mmc-pltfm.c |   21 ++++++++++++++++++++-
>  1 files changed, 20 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
> index 9b05381..cbbbcf3 100644
> --- a/drivers/mmc/host/dw_mmc-pltfm.c
> +++ b/drivers/mmc/host/dw_mmc-pltfm.c
> @@ -24,6 +24,15 @@
> 
>  #include "dw_mmc.h"
> 
> +static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
> +{
> +	*cmdr |= SDMMC_CMD_USE_HOLD_REG;
> +}
> +
> +static const struct dw_mci_drv_data rockchip_drv_data = {
> +	.prepare_command	= dw_mci_rockchip_prepare_command,
> +};
> +
>  int dw_mci_pltfm_register(struct platform_device *pdev,
>  				const struct dw_mci_drv_data *drv_data)
>  {
> @@ -100,13 +109,23 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
> 
>  static const struct of_device_id dw_mci_pltfm_match[] = {
>  	{ .compatible = "snps,dw-mshc", },
> +	{ .compatible = "rockchip,cortex-a9-dw-mshc",
> +		.data = &rockchip_drv_data },
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
> 
>  static int dw_mci_pltfm_probe(struct platform_device *pdev)
>  {
> -	return dw_mci_pltfm_register(pdev, NULL);
> +	const struct dw_mci_drv_data *drv_data = NULL;
> +	const struct of_device_id *match;
> +
> +	if (pdev->dev.of_node) {
> +		match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
> +		drv_data = match->data;
> +	}
> +
> +	return dw_mci_pltfm_register(pdev, drv_data);
>  }
> 
>  int dw_mci_pltfm_remove(struct platform_device *pdev)
> --
> 1.7.2.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support
  2013-06-11 20:06     ` Mike Turquette
  (?)
@ 2013-06-12 22:45       ` Heiko Stübner
  -1 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-12 22:45 UTC (permalink / raw)
  To: Mike Turquette
  Cc: linux-arm-kernel, linux-kernel, Seungwon Jeon, Jaehoon Chung,
	Chris Ball, linux-mmc, Grant Likely, Rob Herring, Linus Walleij,
	devicetree-discuss, Russell King, Arnd Bergmann, Olof Johansson,
	Thomas Petazzoni, Andy Shevchenko

Am Dienstag, 11. Juni 2013, 22:06:10 schrieb Mike Turquette:
> Quoting Heiko Stübner (2013-06-11 04:31:31)
> 
> > This adds basic support for clocks on Rockchip rk3066 SoCs.
> > The clock handling thru small dt nodes is heavily inspired by the
> > sunxi clk code.
> > 
> > The plls are currently read-only, as their setting needs more
> > investigation. This also results in slow cpu speeds, as the apll starts
> > at a default of 600mhz.
> > 
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> > ---
> > 
> >  arch/arm/boot/dts/rk3066a-clocks.dtsi   |  467
> >  +++++++++++++++++++++++++++++++
> 
> It's best to separate the DT data changes from the clock driver.  The
> new dtsi can be a separate patch.
> 
> Also the rockchip clock bindings need to be documented in
> Documentation/devicetree/bindings/clock.
> 
> <snip>
> 
> > diff --git a/drivers/clk/rockchip/clk-rockchip-pll.c
> > b/drivers/clk/rockchip/clk-rockchip-pll.c new file mode 100644
> > index 0000000..4456445
> > --- /dev/null
> > +++ b/drivers/clk/rockchip/clk-rockchip-pll.c
> > @@ -0,0 +1,131 @@
> > +/*
> > + * Copyright (c) 2013 MundoReader S.L.
> > + * Author: Heiko Stuebner <heiko@sntech.de>
> > + *
> > + * 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.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#include <asm/div64.h>
> > +#include <linux/slab.h>
> > +#include <linux/io.h>
> > +#include <linux/clk.h>
> > +#include <linux/clk-private.h>
> 
> NACK.  Please use clk-provider.h.  Do you really need something from
> clk-private.h?

ok, clk-private is unnecessary, I'll remove it

[...]
> > diff --git a/drivers/clk/rockchip/clk-rockchip.c
> > b/drivers/clk/rockchip/clk-rockchip.c new file mode 100644
> > index 0000000..660b00f
> > --- /dev/null
> > +++ b/drivers/clk/rockchip/clk-rockchip.c
> > @@ -0,0 +1,330 @@
> > +/*
> > + * Copyright (c) 2013 MundoReader S.L.
> > + * Author: Heiko Stuebner <heiko@sntech.de>
> > + *
> > + * 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.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#include <linux/clk-provider.h>
> > +#include <linux/clkdev.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +
> > +#include "clk-rockchip-pll.h"
> > +
> > +static DEFINE_SPINLOCK(clk_lock);
> > +
> > +struct rockchip_pll_data {
> > +       int mode_shift;
> > +};
> > +
> > +struct rockchip_pll_data rk3066a_apll_data = {
> > +       .mode_shift = 0,
> > +};
> > +
> > +struct rockchip_pll_data rk3066a_dpll_data = {
> > +       .mode_shift = 4,
> > +};
> > +
> > +struct rockchip_pll_data rk3066a_cpll_data = {
> > +       .mode_shift = 8,
> > +};
> > +
> > +struct rockchip_pll_data rk3066a_gpll_data = {
> > +       .mode_shift = 12,
> > +};
> > +
> > +/* Matches for plls */
> > +static const __initconst struct of_device_id clk_pll_match[] = {
> > +       { .compatible = "rockchip,rk3066a-apll", .data =
> > &rk3066a_apll_data }, +       { .compatible = "rockchip,rk3066a-dpll",
> > .data = &rk3066a_dpll_data }, +       { .compatible =
> > "rockchip,rk3066a-cpll", .data = &rk3066a_cpll_data }, +       {
> > .compatible = "rockchip,rk3066a-gpll", .data = &rk3066a_gpll_data }, +  
> >     {}
> > +};
> > +
> > +static void __init rockchip_pll_setup(struct device_node *node,
> > +                                     struct rockchip_pll_data *data)
> > +{
> > +       struct clk *clk;
> > +       const char *clk_name = node->name;
> > +       const char *clk_parent;
> > +       void __iomem *reg_base;
> > +       void __iomem *reg_mode;
> > +       u32 rate;
> > +
> > +       reg_base = of_iomap(node, 0);
> > +       reg_mode = of_iomap(node, 1);
> > +
> > +       clk_parent = of_clk_get_parent_name(node, 0);
> > +
> > +       pr_debug("%s: adding %s as child of %s\n",
> > +               __func__, clk_name, clk_parent);
> > +
> > +       clk = rockchip_clk_register_rk3x_pll(clk_name, clk_parent,
> > reg_base, +                                            reg_mode,
> > data->mode_shift, +                                           
> > &clk_lock);
> > +       if (clk) {
> > +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> > +
> > +               /* optionally set a target frequency for the pll */
> > +               if (!of_property_read_u32(node, "clock-frequency",
> > &rate)) +                       clk_set_rate(clk, rate);
> > +       }
> > +}
> > +
> > +/*
> > + * Mux clocks
> > + */
> > +
> > +struct rockchip_mux_data {
> > +       int shift;
> > +       int width;
> > +};
> > +
> > +#define RK_MUX(n, s, w)                                        \
> > +static const __initconst struct rockchip_mux_data n = {        \
> > +       .shift = s,                                     \
> > +       .width = w,                                     \
> > +}
> > +
> > +RK_MUX(gpll_cpll_15_mux_data, 15, 1);
> > +RK_MUX(uart_mux_data, 8, 2);
> > +RK_MUX(cpu_mux_data, 8, 1);
> > +
> > +static const __initconst struct of_device_id clk_mux_match[] = {
> > +       { .compatible = "rockchip,rk2928-gpll-cpll-bit15-mux",
> > +               .data = &gpll_cpll_15_mux_data },
> > +       { .compatible = "rockchip,rk2928-uart-mux",
> > +               .data = &uart_mux_data },
> > +       { .compatible = "rockchip,rk3066-cpu-mux",
> > +               .data = &cpu_mux_data },
> > +       {}
> > +};
> > +
> > +static void __init rockchip_mux_clk_setup(struct device_node *node,
> > +                                         struct rockchip_mux_data *data)
> > +{
> > +       struct clk *clk;
> > +       const char *clk_name = node->name;
> > +       void __iomem *reg;
> > +       int max_parents = (1 << data->width);
> > +       const char *parents[max_parents];
> > +       int flags;
> > +       int i = 0;
> > +
> > +       reg = of_iomap(node, 0);
> > +
> > +       while (i < max_parents &&
> > +              (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
> > +               i++;
> > +
> > +       flags = CLK_MUX_HIWORD_MASK;
> > +
> > +       clk = clk_register_mux(NULL, clk_name, parents, i, 0,
> > +                              reg, data->shift, data->width,
> > +                              flags, &clk_lock);
> > +       if (clk)
> > +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> > +}
> > +
> > +/*
> > + * Divider clocks
> > + */
> > +
> > +struct rockchip_div_data {
> > +       int shift;
> > +       int width;
> > +       int flags;
> > +       struct clk_div_table *table;
> > +};
> > +
> > +#define RK_DIV(n, s, w, f, t)                          \
> > +static const __initconst struct rockchip_div_data n = {        \
> > +       .shift = s,                                     \
> > +       .width = w,                                     \
> > +       .flags = f,                                     \
> > +       .table = t,                                     \
> > +}
> > +
> > +RK_DIV(cpu_div_data, 0, 5, 0, NULL);
> > +RK_DIV(aclk_periph_div_data, 0, 5, 0, NULL);
> > +RK_DIV(aclk_cpu_div_data, 0, 3, 0, NULL);
> > +RK_DIV(hclk_div_data, 8, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> > +RK_DIV(pclk_div_data, 12, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> > +RK_DIV(mmc_div_data, 0, 6, CLK_DIVIDER_EVEN, NULL);
> > +RK_DIV(uart_div_data, 0, 7, 0, NULL);
> > +
> > +struct clk_div_table core_periph_table[] = {
> > +       { 0, 2 },
> > +       { 1, 4 },
> > +       { 2, 8 },
> > +       { 3, 16 },
> > +       { 0, 0 },
> > +};
> > +RK_DIV(core_periph_div_data, 6, 2, 0, core_periph_table);
> > +
> > +static const __initconst struct of_device_id clk_divider_match[] = {
> > +       { .compatible = "rockchip,rk3066a-cpu-divider",
> > +               .data = &cpu_div_data },
> > +       { .compatible = "rockchip,rk3066a-core-periph-divider",
> > +               .data = &core_periph_div_data },
> > +       { .compatible = "rockchip,rk2928-aclk-periph-divider",
> > +               .data = &aclk_periph_div_data },
> > +       { .compatible = "rockchip,rk3066a-aclk-cpu-divider",
> > +               .data = &aclk_cpu_div_data },
> > +       { .compatible = "rockchip,rk2928-hclk-divider",
> > +               .data = &hclk_div_data },
> > +       { .compatible = "rockchip,rk2928-pclk-divider",
> > +               .data = &pclk_div_data },
> > +       { .compatible = "rockchip,rk2928-mmc-divider",
> > +               .data = &mmc_div_data },
> > +       { .compatible = "rockchip,rk2928-uart-divider",
> > +               .data = &uart_div_data },
> > +       {}
> > +};
> > +
> > +static void __init rockchip_divider_clk_setup(struct device_node *node,
> > +                                             struct rockchip_div_data
> > *data) +{
> > +       struct clk *clk;
> > +       const char *clk_name = node->name;
> > +       const char *clk_parent;
> > +       void __iomem *reg;
> > +       int flags;
> > +
> > +       reg = of_iomap(node, 0);
> > +
> > +       clk_parent = of_clk_get_parent_name(node, 0);
> > +
> > +       flags = data->flags;
> > +       flags |= CLK_DIVIDER_HIWORD_MASK;
> > +
> > +       if (data->table)
> > +               clk = clk_register_divider_table(NULL, clk_name,
> > clk_parent, 0, +                                               reg,
> > data->shift, data->width, +                                             
> >  flags, data->table, &clk_lock); +       else
> > +               clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
> > +                                               reg, data->shift,
> > data->width, +                                               flags,
> > &clk_lock); +       if (clk)
> > +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> > +}
> > +
> > +/*
> > + * Gate clocks
> > + */
> > +
> > +static void __init rockchip_gate_clk_setup(struct device_node *node,
> > +                                           void *data)
> > +{
> > +       struct clk_onecell_data *clk_data;
> > +       const char *clk_parent;
> > +       const char *clk_name;
> > +       void __iomem *reg;
> > +       void __iomem *reg_idx;
> > +       int flags;
> > +       int qty;
> > +       int reg_bit;
> > +       int clkflags = CLK_SET_RATE_PARENT;
> > +       int i;
> > +
> > +       qty = of_property_count_strings(node, "clock-output-names");
> > +       if (qty < 0) {
> > +               pr_err("%s: error in clock-output-names %d\n", __func__,
> > qty); +               return;
> > +       }
> > +
> > +       if (qty == 0) {
> > +               pr_info("%s: nothing to do\n", __func__);
> > +               return;
> > +       }
> > +
> > +       reg = of_iomap(node, 0);
> > +
> > +       clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
> > +       if (!clk_data)
> > +               return;
> > +
> > +       clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL);
> > +       if (!clk_data->clks) {
> > +               kfree(clk_data);
> > +               return;
> > +       }
> > +
> > +       flags = CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE;
> > +
> > +       for (i = 0; i < qty; i++) {
> > +               of_property_read_string_index(node, "clock-output-names",
> > +                                             i, &clk_name);
> > +
> > +               /* ignore empty slots */
> > +               if (!strcmp("reserved", clk_name))
> > +                       continue;
> > +
> > +               clk_parent = of_clk_get_parent_name(node, i);
> > +
> > +               /* keep all gates untouched for now */
> > +               clkflags |= CLK_IGNORE_UNUSED;
> > +
> > +               reg_idx = reg + (4 * (i / 16));
> > +               reg_bit = (i % 16);
> > +
> > +               clk_data->clks[i] = clk_register_gate(NULL, clk_name,
> > +                                                     clk_parent,
> > clkflags, +                                                     reg_idx,
> > reg_bit, +                                                     flags,
> > +                                                     &clk_lock);
> > +               WARN_ON(IS_ERR(clk_data->clks[i]));
> > +       }
> > +
> > +       clk_data->clk_num = qty;
> > +
> > +       of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> > +}
> > +
> > +static const __initconst struct of_device_id clk_gate_match[] = {
> > +       { .compatible = "rockchip,rk2928-gate-clk" },
> > +       {}
> > +};
> > +
> > +void __init of_rockchip_clk_table_clock_setup(
> > +                                       const struct of_device_id
> > *clk_match, +                                       void *function)
> > +{
> > +       struct device_node *np;
> > +       const struct div_data *data;
> > +       const struct of_device_id *match;
> > +       void (*setup_function)(struct device_node *, const void *) =
> > function; +
> > +       for_each_matching_node(np, clk_match) {
> > +               match = of_match_node(clk_match, np);
> > +               data = match->data;
> > +               setup_function(np, data);
> > +       }
> > +}
> 
> Can you use of_clk_init instead of the above function?

As can be seen below I did use CLK_OF_DECLARE :-) . The reason for this 
cheating was to not introduce numerous individual clocks when I want to remove 
all of them again, once your divider and mux dt patches are ready, because the 
clocks above and in the dt fit the use-case of those really well.

So, I'm not 100% sure how to proceed here, using CLK_OF_DECLARE for each 
individual divier and mux would need the clock to be matched again to get the 
clock data [or provide an init function for each clock], which somehow seems 
overkill for stuff that will be hopefully gone for 3.12(?) when the mux and 
divider clocks might have their own dt support.


Part of me simply wants to wait for this - but rockchip stuff might be to late 
for 3.11 anyway, as we're near rc6.


> > +
> > +void __init rockchip_init_clocks(struct device_node *node)
> > +{
> > +       of_rockchip_clk_table_clock_setup(clk_pll_match,
> > +                                         rockchip_pll_setup);
> > +
> > +       of_rockchip_clk_table_clock_setup(clk_mux_match,
> > +                                         rockchip_mux_clk_setup);
> > +
> > +       of_rockchip_clk_table_clock_setup(clk_gate_match,
> > +                                         rockchip_gate_clk_setup);
> > +
> > +       of_rockchip_clk_table_clock_setup(clk_divider_match,
> > +                                         rockchip_divider_clk_setup);
> > +}
> > +CLK_OF_DECLARE(rockchip_clocks, "rockchip,clocks",
> > rockchip_init_clocks);


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

* Re: [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support
@ 2013-06-12 22:45       ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-12 22:45 UTC (permalink / raw)
  To: Mike Turquette
  Cc: Russell King, Seungwon Jeon, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Jaehoon Chung,
	Andy Shevchenko, Grant Likely, Chris Ball,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Am Dienstag, 11. Juni 2013, 22:06:10 schrieb Mike Turquette:
> Quoting Heiko Stübner (2013-06-11 04:31:31)
> 
> > This adds basic support for clocks on Rockchip rk3066 SoCs.
> > The clock handling thru small dt nodes is heavily inspired by the
> > sunxi clk code.
> > 
> > The plls are currently read-only, as their setting needs more
> > investigation. This also results in slow cpu speeds, as the apll starts
> > at a default of 600mhz.
> > 
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> > ---
> > 
> >  arch/arm/boot/dts/rk3066a-clocks.dtsi   |  467
> >  +++++++++++++++++++++++++++++++
> 
> It's best to separate the DT data changes from the clock driver.  The
> new dtsi can be a separate patch.
> 
> Also the rockchip clock bindings need to be documented in
> Documentation/devicetree/bindings/clock.
> 
> <snip>
> 
> > diff --git a/drivers/clk/rockchip/clk-rockchip-pll.c
> > b/drivers/clk/rockchip/clk-rockchip-pll.c new file mode 100644
> > index 0000000..4456445
> > --- /dev/null
> > +++ b/drivers/clk/rockchip/clk-rockchip-pll.c
> > @@ -0,0 +1,131 @@
> > +/*
> > + * Copyright (c) 2013 MundoReader S.L.
> > + * Author: Heiko Stuebner <heiko@sntech.de>
> > + *
> > + * 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.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#include <asm/div64.h>
> > +#include <linux/slab.h>
> > +#include <linux/io.h>
> > +#include <linux/clk.h>
> > +#include <linux/clk-private.h>
> 
> NACK.  Please use clk-provider.h.  Do you really need something from
> clk-private.h?

ok, clk-private is unnecessary, I'll remove it

[...]
> > diff --git a/drivers/clk/rockchip/clk-rockchip.c
> > b/drivers/clk/rockchip/clk-rockchip.c new file mode 100644
> > index 0000000..660b00f
> > --- /dev/null
> > +++ b/drivers/clk/rockchip/clk-rockchip.c
> > @@ -0,0 +1,330 @@
> > +/*
> > + * Copyright (c) 2013 MundoReader S.L.
> > + * Author: Heiko Stuebner <heiko@sntech.de>
> > + *
> > + * 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.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#include <linux/clk-provider.h>
> > +#include <linux/clkdev.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +
> > +#include "clk-rockchip-pll.h"
> > +
> > +static DEFINE_SPINLOCK(clk_lock);
> > +
> > +struct rockchip_pll_data {
> > +       int mode_shift;
> > +};
> > +
> > +struct rockchip_pll_data rk3066a_apll_data = {
> > +       .mode_shift = 0,
> > +};
> > +
> > +struct rockchip_pll_data rk3066a_dpll_data = {
> > +       .mode_shift = 4,
> > +};
> > +
> > +struct rockchip_pll_data rk3066a_cpll_data = {
> > +       .mode_shift = 8,
> > +};
> > +
> > +struct rockchip_pll_data rk3066a_gpll_data = {
> > +       .mode_shift = 12,
> > +};
> > +
> > +/* Matches for plls */
> > +static const __initconst struct of_device_id clk_pll_match[] = {
> > +       { .compatible = "rockchip,rk3066a-apll", .data =
> > &rk3066a_apll_data }, +       { .compatible = "rockchip,rk3066a-dpll",
> > .data = &rk3066a_dpll_data }, +       { .compatible =
> > "rockchip,rk3066a-cpll", .data = &rk3066a_cpll_data }, +       {
> > .compatible = "rockchip,rk3066a-gpll", .data = &rk3066a_gpll_data }, +  
> >     {}
> > +};
> > +
> > +static void __init rockchip_pll_setup(struct device_node *node,
> > +                                     struct rockchip_pll_data *data)
> > +{
> > +       struct clk *clk;
> > +       const char *clk_name = node->name;
> > +       const char *clk_parent;
> > +       void __iomem *reg_base;
> > +       void __iomem *reg_mode;
> > +       u32 rate;
> > +
> > +       reg_base = of_iomap(node, 0);
> > +       reg_mode = of_iomap(node, 1);
> > +
> > +       clk_parent = of_clk_get_parent_name(node, 0);
> > +
> > +       pr_debug("%s: adding %s as child of %s\n",
> > +               __func__, clk_name, clk_parent);
> > +
> > +       clk = rockchip_clk_register_rk3x_pll(clk_name, clk_parent,
> > reg_base, +                                            reg_mode,
> > data->mode_shift, +                                           
> > &clk_lock);
> > +       if (clk) {
> > +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> > +
> > +               /* optionally set a target frequency for the pll */
> > +               if (!of_property_read_u32(node, "clock-frequency",
> > &rate)) +                       clk_set_rate(clk, rate);
> > +       }
> > +}
> > +
> > +/*
> > + * Mux clocks
> > + */
> > +
> > +struct rockchip_mux_data {
> > +       int shift;
> > +       int width;
> > +};
> > +
> > +#define RK_MUX(n, s, w)                                        \
> > +static const __initconst struct rockchip_mux_data n = {        \
> > +       .shift = s,                                     \
> > +       .width = w,                                     \
> > +}
> > +
> > +RK_MUX(gpll_cpll_15_mux_data, 15, 1);
> > +RK_MUX(uart_mux_data, 8, 2);
> > +RK_MUX(cpu_mux_data, 8, 1);
> > +
> > +static const __initconst struct of_device_id clk_mux_match[] = {
> > +       { .compatible = "rockchip,rk2928-gpll-cpll-bit15-mux",
> > +               .data = &gpll_cpll_15_mux_data },
> > +       { .compatible = "rockchip,rk2928-uart-mux",
> > +               .data = &uart_mux_data },
> > +       { .compatible = "rockchip,rk3066-cpu-mux",
> > +               .data = &cpu_mux_data },
> > +       {}
> > +};
> > +
> > +static void __init rockchip_mux_clk_setup(struct device_node *node,
> > +                                         struct rockchip_mux_data *data)
> > +{
> > +       struct clk *clk;
> > +       const char *clk_name = node->name;
> > +       void __iomem *reg;
> > +       int max_parents = (1 << data->width);
> > +       const char *parents[max_parents];
> > +       int flags;
> > +       int i = 0;
> > +
> > +       reg = of_iomap(node, 0);
> > +
> > +       while (i < max_parents &&
> > +              (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
> > +               i++;
> > +
> > +       flags = CLK_MUX_HIWORD_MASK;
> > +
> > +       clk = clk_register_mux(NULL, clk_name, parents, i, 0,
> > +                              reg, data->shift, data->width,
> > +                              flags, &clk_lock);
> > +       if (clk)
> > +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> > +}
> > +
> > +/*
> > + * Divider clocks
> > + */
> > +
> > +struct rockchip_div_data {
> > +       int shift;
> > +       int width;
> > +       int flags;
> > +       struct clk_div_table *table;
> > +};
> > +
> > +#define RK_DIV(n, s, w, f, t)                          \
> > +static const __initconst struct rockchip_div_data n = {        \
> > +       .shift = s,                                     \
> > +       .width = w,                                     \
> > +       .flags = f,                                     \
> > +       .table = t,                                     \
> > +}
> > +
> > +RK_DIV(cpu_div_data, 0, 5, 0, NULL);
> > +RK_DIV(aclk_periph_div_data, 0, 5, 0, NULL);
> > +RK_DIV(aclk_cpu_div_data, 0, 3, 0, NULL);
> > +RK_DIV(hclk_div_data, 8, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> > +RK_DIV(pclk_div_data, 12, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> > +RK_DIV(mmc_div_data, 0, 6, CLK_DIVIDER_EVEN, NULL);
> > +RK_DIV(uart_div_data, 0, 7, 0, NULL);
> > +
> > +struct clk_div_table core_periph_table[] = {
> > +       { 0, 2 },
> > +       { 1, 4 },
> > +       { 2, 8 },
> > +       { 3, 16 },
> > +       { 0, 0 },
> > +};
> > +RK_DIV(core_periph_div_data, 6, 2, 0, core_periph_table);
> > +
> > +static const __initconst struct of_device_id clk_divider_match[] = {
> > +       { .compatible = "rockchip,rk3066a-cpu-divider",
> > +               .data = &cpu_div_data },
> > +       { .compatible = "rockchip,rk3066a-core-periph-divider",
> > +               .data = &core_periph_div_data },
> > +       { .compatible = "rockchip,rk2928-aclk-periph-divider",
> > +               .data = &aclk_periph_div_data },
> > +       { .compatible = "rockchip,rk3066a-aclk-cpu-divider",
> > +               .data = &aclk_cpu_div_data },
> > +       { .compatible = "rockchip,rk2928-hclk-divider",
> > +               .data = &hclk_div_data },
> > +       { .compatible = "rockchip,rk2928-pclk-divider",
> > +               .data = &pclk_div_data },
> > +       { .compatible = "rockchip,rk2928-mmc-divider",
> > +               .data = &mmc_div_data },
> > +       { .compatible = "rockchip,rk2928-uart-divider",
> > +               .data = &uart_div_data },
> > +       {}
> > +};
> > +
> > +static void __init rockchip_divider_clk_setup(struct device_node *node,
> > +                                             struct rockchip_div_data
> > *data) +{
> > +       struct clk *clk;
> > +       const char *clk_name = node->name;
> > +       const char *clk_parent;
> > +       void __iomem *reg;
> > +       int flags;
> > +
> > +       reg = of_iomap(node, 0);
> > +
> > +       clk_parent = of_clk_get_parent_name(node, 0);
> > +
> > +       flags = data->flags;
> > +       flags |= CLK_DIVIDER_HIWORD_MASK;
> > +
> > +       if (data->table)
> > +               clk = clk_register_divider_table(NULL, clk_name,
> > clk_parent, 0, +                                               reg,
> > data->shift, data->width, +                                             
> >  flags, data->table, &clk_lock); +       else
> > +               clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
> > +                                               reg, data->shift,
> > data->width, +                                               flags,
> > &clk_lock); +       if (clk)
> > +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> > +}
> > +
> > +/*
> > + * Gate clocks
> > + */
> > +
> > +static void __init rockchip_gate_clk_setup(struct device_node *node,
> > +                                           void *data)
> > +{
> > +       struct clk_onecell_data *clk_data;
> > +       const char *clk_parent;
> > +       const char *clk_name;
> > +       void __iomem *reg;
> > +       void __iomem *reg_idx;
> > +       int flags;
> > +       int qty;
> > +       int reg_bit;
> > +       int clkflags = CLK_SET_RATE_PARENT;
> > +       int i;
> > +
> > +       qty = of_property_count_strings(node, "clock-output-names");
> > +       if (qty < 0) {
> > +               pr_err("%s: error in clock-output-names %d\n", __func__,
> > qty); +               return;
> > +       }
> > +
> > +       if (qty == 0) {
> > +               pr_info("%s: nothing to do\n", __func__);
> > +               return;
> > +       }
> > +
> > +       reg = of_iomap(node, 0);
> > +
> > +       clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
> > +       if (!clk_data)
> > +               return;
> > +
> > +       clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL);
> > +       if (!clk_data->clks) {
> > +               kfree(clk_data);
> > +               return;
> > +       }
> > +
> > +       flags = CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE;
> > +
> > +       for (i = 0; i < qty; i++) {
> > +               of_property_read_string_index(node, "clock-output-names",
> > +                                             i, &clk_name);
> > +
> > +               /* ignore empty slots */
> > +               if (!strcmp("reserved", clk_name))
> > +                       continue;
> > +
> > +               clk_parent = of_clk_get_parent_name(node, i);
> > +
> > +               /* keep all gates untouched for now */
> > +               clkflags |= CLK_IGNORE_UNUSED;
> > +
> > +               reg_idx = reg + (4 * (i / 16));
> > +               reg_bit = (i % 16);
> > +
> > +               clk_data->clks[i] = clk_register_gate(NULL, clk_name,
> > +                                                     clk_parent,
> > clkflags, +                                                     reg_idx,
> > reg_bit, +                                                     flags,
> > +                                                     &clk_lock);
> > +               WARN_ON(IS_ERR(clk_data->clks[i]));
> > +       }
> > +
> > +       clk_data->clk_num = qty;
> > +
> > +       of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> > +}
> > +
> > +static const __initconst struct of_device_id clk_gate_match[] = {
> > +       { .compatible = "rockchip,rk2928-gate-clk" },
> > +       {}
> > +};
> > +
> > +void __init of_rockchip_clk_table_clock_setup(
> > +                                       const struct of_device_id
> > *clk_match, +                                       void *function)
> > +{
> > +       struct device_node *np;
> > +       const struct div_data *data;
> > +       const struct of_device_id *match;
> > +       void (*setup_function)(struct device_node *, const void *) =
> > function; +
> > +       for_each_matching_node(np, clk_match) {
> > +               match = of_match_node(clk_match, np);
> > +               data = match->data;
> > +               setup_function(np, data);
> > +       }
> > +}
> 
> Can you use of_clk_init instead of the above function?

As can be seen below I did use CLK_OF_DECLARE :-) . The reason for this 
cheating was to not introduce numerous individual clocks when I want to remove 
all of them again, once your divider and mux dt patches are ready, because the 
clocks above and in the dt fit the use-case of those really well.

So, I'm not 100% sure how to proceed here, using CLK_OF_DECLARE for each 
individual divier and mux would need the clock to be matched again to get the 
clock data [or provide an init function for each clock], which somehow seems 
overkill for stuff that will be hopefully gone for 3.12(?) when the mux and 
divider clocks might have their own dt support.


Part of me simply wants to wait for this - but rockchip stuff might be to late 
for 3.11 anyway, as we're near rc6.


> > +
> > +void __init rockchip_init_clocks(struct device_node *node)
> > +{
> > +       of_rockchip_clk_table_clock_setup(clk_pll_match,
> > +                                         rockchip_pll_setup);
> > +
> > +       of_rockchip_clk_table_clock_setup(clk_mux_match,
> > +                                         rockchip_mux_clk_setup);
> > +
> > +       of_rockchip_clk_table_clock_setup(clk_gate_match,
> > +                                         rockchip_gate_clk_setup);
> > +
> > +       of_rockchip_clk_table_clock_setup(clk_divider_match,
> > +                                         rockchip_divider_clk_setup);
> > +}
> > +CLK_OF_DECLARE(rockchip_clocks, "rockchip,clocks",
> > rockchip_init_clocks);

_______________________________________________
devicetree-discuss mailing list
devicetree-discuss@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/devicetree-discuss

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

* [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support
@ 2013-06-12 22:45       ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-12 22:45 UTC (permalink / raw)
  To: linux-arm-kernel

Am Dienstag, 11. Juni 2013, 22:06:10 schrieb Mike Turquette:
> Quoting Heiko St?bner (2013-06-11 04:31:31)
> 
> > This adds basic support for clocks on Rockchip rk3066 SoCs.
> > The clock handling thru small dt nodes is heavily inspired by the
> > sunxi clk code.
> > 
> > The plls are currently read-only, as their setting needs more
> > investigation. This also results in slow cpu speeds, as the apll starts
> > at a default of 600mhz.
> > 
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> > ---
> > 
> >  arch/arm/boot/dts/rk3066a-clocks.dtsi   |  467
> >  +++++++++++++++++++++++++++++++
> 
> It's best to separate the DT data changes from the clock driver.  The
> new dtsi can be a separate patch.
> 
> Also the rockchip clock bindings need to be documented in
> Documentation/devicetree/bindings/clock.
> 
> <snip>
> 
> > diff --git a/drivers/clk/rockchip/clk-rockchip-pll.c
> > b/drivers/clk/rockchip/clk-rockchip-pll.c new file mode 100644
> > index 0000000..4456445
> > --- /dev/null
> > +++ b/drivers/clk/rockchip/clk-rockchip-pll.c
> > @@ -0,0 +1,131 @@
> > +/*
> > + * Copyright (c) 2013 MundoReader S.L.
> > + * Author: Heiko Stuebner <heiko@sntech.de>
> > + *
> > + * 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.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#include <asm/div64.h>
> > +#include <linux/slab.h>
> > +#include <linux/io.h>
> > +#include <linux/clk.h>
> > +#include <linux/clk-private.h>
> 
> NACK.  Please use clk-provider.h.  Do you really need something from
> clk-private.h?

ok, clk-private is unnecessary, I'll remove it

[...]
> > diff --git a/drivers/clk/rockchip/clk-rockchip.c
> > b/drivers/clk/rockchip/clk-rockchip.c new file mode 100644
> > index 0000000..660b00f
> > --- /dev/null
> > +++ b/drivers/clk/rockchip/clk-rockchip.c
> > @@ -0,0 +1,330 @@
> > +/*
> > + * Copyright (c) 2013 MundoReader S.L.
> > + * Author: Heiko Stuebner <heiko@sntech.de>
> > + *
> > + * 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.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#include <linux/clk-provider.h>
> > +#include <linux/clkdev.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +
> > +#include "clk-rockchip-pll.h"
> > +
> > +static DEFINE_SPINLOCK(clk_lock);
> > +
> > +struct rockchip_pll_data {
> > +       int mode_shift;
> > +};
> > +
> > +struct rockchip_pll_data rk3066a_apll_data = {
> > +       .mode_shift = 0,
> > +};
> > +
> > +struct rockchip_pll_data rk3066a_dpll_data = {
> > +       .mode_shift = 4,
> > +};
> > +
> > +struct rockchip_pll_data rk3066a_cpll_data = {
> > +       .mode_shift = 8,
> > +};
> > +
> > +struct rockchip_pll_data rk3066a_gpll_data = {
> > +       .mode_shift = 12,
> > +};
> > +
> > +/* Matches for plls */
> > +static const __initconst struct of_device_id clk_pll_match[] = {
> > +       { .compatible = "rockchip,rk3066a-apll", .data =
> > &rk3066a_apll_data }, +       { .compatible = "rockchip,rk3066a-dpll",
> > .data = &rk3066a_dpll_data }, +       { .compatible =
> > "rockchip,rk3066a-cpll", .data = &rk3066a_cpll_data }, +       {
> > .compatible = "rockchip,rk3066a-gpll", .data = &rk3066a_gpll_data }, +  
> >     {}
> > +};
> > +
> > +static void __init rockchip_pll_setup(struct device_node *node,
> > +                                     struct rockchip_pll_data *data)
> > +{
> > +       struct clk *clk;
> > +       const char *clk_name = node->name;
> > +       const char *clk_parent;
> > +       void __iomem *reg_base;
> > +       void __iomem *reg_mode;
> > +       u32 rate;
> > +
> > +       reg_base = of_iomap(node, 0);
> > +       reg_mode = of_iomap(node, 1);
> > +
> > +       clk_parent = of_clk_get_parent_name(node, 0);
> > +
> > +       pr_debug("%s: adding %s as child of %s\n",
> > +               __func__, clk_name, clk_parent);
> > +
> > +       clk = rockchip_clk_register_rk3x_pll(clk_name, clk_parent,
> > reg_base, +                                            reg_mode,
> > data->mode_shift, +                                           
> > &clk_lock);
> > +       if (clk) {
> > +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> > +
> > +               /* optionally set a target frequency for the pll */
> > +               if (!of_property_read_u32(node, "clock-frequency",
> > &rate)) +                       clk_set_rate(clk, rate);
> > +       }
> > +}
> > +
> > +/*
> > + * Mux clocks
> > + */
> > +
> > +struct rockchip_mux_data {
> > +       int shift;
> > +       int width;
> > +};
> > +
> > +#define RK_MUX(n, s, w)                                        \
> > +static const __initconst struct rockchip_mux_data n = {        \
> > +       .shift = s,                                     \
> > +       .width = w,                                     \
> > +}
> > +
> > +RK_MUX(gpll_cpll_15_mux_data, 15, 1);
> > +RK_MUX(uart_mux_data, 8, 2);
> > +RK_MUX(cpu_mux_data, 8, 1);
> > +
> > +static const __initconst struct of_device_id clk_mux_match[] = {
> > +       { .compatible = "rockchip,rk2928-gpll-cpll-bit15-mux",
> > +               .data = &gpll_cpll_15_mux_data },
> > +       { .compatible = "rockchip,rk2928-uart-mux",
> > +               .data = &uart_mux_data },
> > +       { .compatible = "rockchip,rk3066-cpu-mux",
> > +               .data = &cpu_mux_data },
> > +       {}
> > +};
> > +
> > +static void __init rockchip_mux_clk_setup(struct device_node *node,
> > +                                         struct rockchip_mux_data *data)
> > +{
> > +       struct clk *clk;
> > +       const char *clk_name = node->name;
> > +       void __iomem *reg;
> > +       int max_parents = (1 << data->width);
> > +       const char *parents[max_parents];
> > +       int flags;
> > +       int i = 0;
> > +
> > +       reg = of_iomap(node, 0);
> > +
> > +       while (i < max_parents &&
> > +              (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
> > +               i++;
> > +
> > +       flags = CLK_MUX_HIWORD_MASK;
> > +
> > +       clk = clk_register_mux(NULL, clk_name, parents, i, 0,
> > +                              reg, data->shift, data->width,
> > +                              flags, &clk_lock);
> > +       if (clk)
> > +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> > +}
> > +
> > +/*
> > + * Divider clocks
> > + */
> > +
> > +struct rockchip_div_data {
> > +       int shift;
> > +       int width;
> > +       int flags;
> > +       struct clk_div_table *table;
> > +};
> > +
> > +#define RK_DIV(n, s, w, f, t)                          \
> > +static const __initconst struct rockchip_div_data n = {        \
> > +       .shift = s,                                     \
> > +       .width = w,                                     \
> > +       .flags = f,                                     \
> > +       .table = t,                                     \
> > +}
> > +
> > +RK_DIV(cpu_div_data, 0, 5, 0, NULL);
> > +RK_DIV(aclk_periph_div_data, 0, 5, 0, NULL);
> > +RK_DIV(aclk_cpu_div_data, 0, 3, 0, NULL);
> > +RK_DIV(hclk_div_data, 8, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> > +RK_DIV(pclk_div_data, 12, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
> > +RK_DIV(mmc_div_data, 0, 6, CLK_DIVIDER_EVEN, NULL);
> > +RK_DIV(uart_div_data, 0, 7, 0, NULL);
> > +
> > +struct clk_div_table core_periph_table[] = {
> > +       { 0, 2 },
> > +       { 1, 4 },
> > +       { 2, 8 },
> > +       { 3, 16 },
> > +       { 0, 0 },
> > +};
> > +RK_DIV(core_periph_div_data, 6, 2, 0, core_periph_table);
> > +
> > +static const __initconst struct of_device_id clk_divider_match[] = {
> > +       { .compatible = "rockchip,rk3066a-cpu-divider",
> > +               .data = &cpu_div_data },
> > +       { .compatible = "rockchip,rk3066a-core-periph-divider",
> > +               .data = &core_periph_div_data },
> > +       { .compatible = "rockchip,rk2928-aclk-periph-divider",
> > +               .data = &aclk_periph_div_data },
> > +       { .compatible = "rockchip,rk3066a-aclk-cpu-divider",
> > +               .data = &aclk_cpu_div_data },
> > +       { .compatible = "rockchip,rk2928-hclk-divider",
> > +               .data = &hclk_div_data },
> > +       { .compatible = "rockchip,rk2928-pclk-divider",
> > +               .data = &pclk_div_data },
> > +       { .compatible = "rockchip,rk2928-mmc-divider",
> > +               .data = &mmc_div_data },
> > +       { .compatible = "rockchip,rk2928-uart-divider",
> > +               .data = &uart_div_data },
> > +       {}
> > +};
> > +
> > +static void __init rockchip_divider_clk_setup(struct device_node *node,
> > +                                             struct rockchip_div_data
> > *data) +{
> > +       struct clk *clk;
> > +       const char *clk_name = node->name;
> > +       const char *clk_parent;
> > +       void __iomem *reg;
> > +       int flags;
> > +
> > +       reg = of_iomap(node, 0);
> > +
> > +       clk_parent = of_clk_get_parent_name(node, 0);
> > +
> > +       flags = data->flags;
> > +       flags |= CLK_DIVIDER_HIWORD_MASK;
> > +
> > +       if (data->table)
> > +               clk = clk_register_divider_table(NULL, clk_name,
> > clk_parent, 0, +                                               reg,
> > data->shift, data->width, +                                             
> >  flags, data->table, &clk_lock); +       else
> > +               clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
> > +                                               reg, data->shift,
> > data->width, +                                               flags,
> > &clk_lock); +       if (clk)
> > +               of_clk_add_provider(node, of_clk_src_simple_get, clk);
> > +}
> > +
> > +/*
> > + * Gate clocks
> > + */
> > +
> > +static void __init rockchip_gate_clk_setup(struct device_node *node,
> > +                                           void *data)
> > +{
> > +       struct clk_onecell_data *clk_data;
> > +       const char *clk_parent;
> > +       const char *clk_name;
> > +       void __iomem *reg;
> > +       void __iomem *reg_idx;
> > +       int flags;
> > +       int qty;
> > +       int reg_bit;
> > +       int clkflags = CLK_SET_RATE_PARENT;
> > +       int i;
> > +
> > +       qty = of_property_count_strings(node, "clock-output-names");
> > +       if (qty < 0) {
> > +               pr_err("%s: error in clock-output-names %d\n", __func__,
> > qty); +               return;
> > +       }
> > +
> > +       if (qty == 0) {
> > +               pr_info("%s: nothing to do\n", __func__);
> > +               return;
> > +       }
> > +
> > +       reg = of_iomap(node, 0);
> > +
> > +       clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
> > +       if (!clk_data)
> > +               return;
> > +
> > +       clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL);
> > +       if (!clk_data->clks) {
> > +               kfree(clk_data);
> > +               return;
> > +       }
> > +
> > +       flags = CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE;
> > +
> > +       for (i = 0; i < qty; i++) {
> > +               of_property_read_string_index(node, "clock-output-names",
> > +                                             i, &clk_name);
> > +
> > +               /* ignore empty slots */
> > +               if (!strcmp("reserved", clk_name))
> > +                       continue;
> > +
> > +               clk_parent = of_clk_get_parent_name(node, i);
> > +
> > +               /* keep all gates untouched for now */
> > +               clkflags |= CLK_IGNORE_UNUSED;
> > +
> > +               reg_idx = reg + (4 * (i / 16));
> > +               reg_bit = (i % 16);
> > +
> > +               clk_data->clks[i] = clk_register_gate(NULL, clk_name,
> > +                                                     clk_parent,
> > clkflags, +                                                     reg_idx,
> > reg_bit, +                                                     flags,
> > +                                                     &clk_lock);
> > +               WARN_ON(IS_ERR(clk_data->clks[i]));
> > +       }
> > +
> > +       clk_data->clk_num = qty;
> > +
> > +       of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
> > +}
> > +
> > +static const __initconst struct of_device_id clk_gate_match[] = {
> > +       { .compatible = "rockchip,rk2928-gate-clk" },
> > +       {}
> > +};
> > +
> > +void __init of_rockchip_clk_table_clock_setup(
> > +                                       const struct of_device_id
> > *clk_match, +                                       void *function)
> > +{
> > +       struct device_node *np;
> > +       const struct div_data *data;
> > +       const struct of_device_id *match;
> > +       void (*setup_function)(struct device_node *, const void *) =
> > function; +
> > +       for_each_matching_node(np, clk_match) {
> > +               match = of_match_node(clk_match, np);
> > +               data = match->data;
> > +               setup_function(np, data);
> > +       }
> > +}
> 
> Can you use of_clk_init instead of the above function?

As can be seen below I did use CLK_OF_DECLARE :-) . The reason for this 
cheating was to not introduce numerous individual clocks when I want to remove 
all of them again, once your divider and mux dt patches are ready, because the 
clocks above and in the dt fit the use-case of those really well.

So, I'm not 100% sure how to proceed here, using CLK_OF_DECLARE for each 
individual divier and mux would need the clock to be matched again to get the 
clock data [or provide an init function for each clock], which somehow seems 
overkill for stuff that will be hopefully gone for 3.12(?) when the mux and 
divider clocks might have their own dt support.


Part of me simply wants to wait for this - but rockchip stuff might be to late 
for 3.11 anyway, as we're near rc6.


> > +
> > +void __init rockchip_init_clocks(struct device_node *node)
> > +{
> > +       of_rockchip_clk_table_clock_setup(clk_pll_match,
> > +                                         rockchip_pll_setup);
> > +
> > +       of_rockchip_clk_table_clock_setup(clk_mux_match,
> > +                                         rockchip_mux_clk_setup);
> > +
> > +       of_rockchip_clk_table_clock_setup(clk_gate_match,
> > +                                         rockchip_gate_clk_setup);
> > +
> > +       of_rockchip_clk_table_clock_setup(clk_divider_match,
> > +                                         rockchip_divider_clk_setup);
> > +}
> > +CLK_OF_DECLARE(rockchip_clocks, "rockchip,clocks",
> > rockchip_init_clocks);

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

* Re: [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support
  2013-06-12 22:45       ` Heiko Stübner
  (?)
@ 2013-06-12 23:02         ` Olof Johansson
  -1 siblings, 0 replies; 56+ messages in thread
From: Olof Johansson @ 2013-06-12 23:02 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: Mike Turquette, linux-arm-kernel, linux-kernel, Seungwon Jeon,
	Jaehoon Chung, Chris Ball, linux-mmc, Grant Likely, Rob Herring,
	Linus Walleij, devicetree-discuss, Russell King, Arnd Bergmann,
	Thomas Petazzoni, Andy Shevchenko

On Thu, Jun 13, 2013 at 12:45:41AM +0200, Heiko Stübner wrote:
> Part of me simply wants to wait for this - but rockchip stuff might be to late 
> for 3.11 anyway, as we're near rc6.

For a new platform like this, it's useful to get some of the drivers to land
even if the main platform code isn't. Where things tend to get messy is when we
have to add a lot of code late in the cycle that has a lot of external
dependencies, since everybody then has to scramble about getting things sorted
out.

It's not too late for 3.11 yet, and in particular it'd be nice to see things
like clock and pinctrl stuff go in even if some other stuff misses the train.


-Olof

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

* Re: [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support
@ 2013-06-12 23:02         ` Olof Johansson
  0 siblings, 0 replies; 56+ messages in thread
From: Olof Johansson @ 2013-06-12 23:02 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: Mike Turquette, linux-arm-kernel, linux-kernel, Seungwon Jeon,
	Jaehoon Chung, Chris Ball, linux-mmc, Grant Likely, Rob Herring,
	Linus Walleij, devicetree-discuss, Russell King, Arnd Bergmann,
	Thomas Petazzoni, Andy Shevchenko

On Thu, Jun 13, 2013 at 12:45:41AM +0200, Heiko Stübner wrote:
> Part of me simply wants to wait for this - but rockchip stuff might be to late 
> for 3.11 anyway, as we're near rc6.

For a new platform like this, it's useful to get some of the drivers to land
even if the main platform code isn't. Where things tend to get messy is when we
have to add a lot of code late in the cycle that has a lot of external
dependencies, since everybody then has to scramble about getting things sorted
out.

It's not too late for 3.11 yet, and in particular it'd be nice to see things
like clock and pinctrl stuff go in even if some other stuff misses the train.


-Olof

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

* [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support
@ 2013-06-12 23:02         ` Olof Johansson
  0 siblings, 0 replies; 56+ messages in thread
From: Olof Johansson @ 2013-06-12 23:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 13, 2013 at 12:45:41AM +0200, Heiko St?bner wrote:
> Part of me simply wants to wait for this - but rockchip stuff might be to late 
> for 3.11 anyway, as we're near rc6.

For a new platform like this, it's useful to get some of the drivers to land
even if the main platform code isn't. Where things tend to get messy is when we
have to add a lot of code late in the cycle that has a lot of external
dependencies, since everybody then has to scramble about getting things sorted
out.

It's not too late for 3.11 yet, and in particular it'd be nice to see things
like clock and pinctrl stuff go in even if some other stuff misses the train.


-Olof

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

* Re: [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support
  2013-06-12 23:02         ` Olof Johansson
  (?)
@ 2013-06-12 23:40           ` Heiko Stübner
  -1 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-12 23:40 UTC (permalink / raw)
  To: Olof Johansson
  Cc: Mike Turquette, linux-arm-kernel, linux-kernel, Seungwon Jeon,
	Jaehoon Chung, Chris Ball, linux-mmc, Grant Likely, Rob Herring,
	Linus Walleij, devicetree-discuss, Russell King, Arnd Bergmann,
	Thomas Petazzoni, Andy Shevchenko

Am Donnerstag, 13. Juni 2013, 01:02:34 schrieb Olof Johansson:
> On Thu, Jun 13, 2013 at 12:45:41AM +0200, Heiko Stübner wrote:
> > Part of me simply wants to wait for this - but rockchip stuff might be to
> > late for 3.11 anyway, as we're near rc6.
> 
> For a new platform like this, it's useful to get some of the drivers to
> land even if the main platform code isn't. Where things tend to get messy
> is when we have to add a lot of code late in the cycle that has a lot of
> external dependencies, since everybody then has to scramble about getting
> things sorted out.
> 
> It's not too late for 3.11 yet, and in particular it'd be nice to see
> things like clock and pinctrl stuff go in even if some other stuff misses
> the train.

pinctrl is already in Linus Walleijs tree :-)

Tomorrow I'll try to send the mmc stuff to the mmc lists, as my dw-mmc 
dependency from Dinh Nguyen also seems to go this way.

The clocks are the really hard part, simply because Mike's upcoming dt support 
for the divider and mux clocks will let me get rid of the small clocks that 
simply hold. And of course I also need the HIWORD_MASK flag for the clocks from 
the hisilicon series.

Is there some sane intermediate step for the clocks? One possibility that 
comes to mind, would be to only declare the gates and provide fixed rate 
parents to the timer and mmc and add the divs and muxes when Mikes dt patches 
are ready.

I.e. I would keep the gate clocks grouped like now to not have to declare 160 
individual gates later :-)


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

* Re: [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support
@ 2013-06-12 23:40           ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-12 23:40 UTC (permalink / raw)
  To: Olof Johansson
  Cc: Mike Turquette, linux-arm-kernel, linux-kernel, Seungwon Jeon,
	Jaehoon Chung, Chris Ball, linux-mmc, Grant Likely, Rob Herring,
	Linus Walleij, devicetree-discuss, Russell King, Arnd Bergmann,
	Thomas Petazzoni, Andy Shevchenko

Am Donnerstag, 13. Juni 2013, 01:02:34 schrieb Olof Johansson:
> On Thu, Jun 13, 2013 at 12:45:41AM +0200, Heiko Stübner wrote:
> > Part of me simply wants to wait for this - but rockchip stuff might be to
> > late for 3.11 anyway, as we're near rc6.
> 
> For a new platform like this, it's useful to get some of the drivers to
> land even if the main platform code isn't. Where things tend to get messy
> is when we have to add a lot of code late in the cycle that has a lot of
> external dependencies, since everybody then has to scramble about getting
> things sorted out.
> 
> It's not too late for 3.11 yet, and in particular it'd be nice to see
> things like clock and pinctrl stuff go in even if some other stuff misses
> the train.

pinctrl is already in Linus Walleijs tree :-)

Tomorrow I'll try to send the mmc stuff to the mmc lists, as my dw-mmc 
dependency from Dinh Nguyen also seems to go this way.

The clocks are the really hard part, simply because Mike's upcoming dt support 
for the divider and mux clocks will let me get rid of the small clocks that 
simply hold. And of course I also need the HIWORD_MASK flag for the clocks from 
the hisilicon series.

Is there some sane intermediate step for the clocks? One possibility that 
comes to mind, would be to only declare the gates and provide fixed rate 
parents to the timer and mmc and add the divs and muxes when Mikes dt patches 
are ready.

I.e. I would keep the gate clocks grouped like now to not have to declare 160 
individual gates later :-)


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

* [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support
@ 2013-06-12 23:40           ` Heiko Stübner
  0 siblings, 0 replies; 56+ messages in thread
From: Heiko Stübner @ 2013-06-12 23:40 UTC (permalink / raw)
  To: linux-arm-kernel

Am Donnerstag, 13. Juni 2013, 01:02:34 schrieb Olof Johansson:
> On Thu, Jun 13, 2013 at 12:45:41AM +0200, Heiko St?bner wrote:
> > Part of me simply wants to wait for this - but rockchip stuff might be to
> > late for 3.11 anyway, as we're near rc6.
> 
> For a new platform like this, it's useful to get some of the drivers to
> land even if the main platform code isn't. Where things tend to get messy
> is when we have to add a lot of code late in the cycle that has a lot of
> external dependencies, since everybody then has to scramble about getting
> things sorted out.
> 
> It's not too late for 3.11 yet, and in particular it'd be nice to see
> things like clock and pinctrl stuff go in even if some other stuff misses
> the train.

pinctrl is already in Linus Walleijs tree :-)

Tomorrow I'll try to send the mmc stuff to the mmc lists, as my dw-mmc 
dependency from Dinh Nguyen also seems to go this way.

The clocks are the really hard part, simply because Mike's upcoming dt support 
for the divider and mux clocks will let me get rid of the small clocks that 
simply hold. And of course I also need the HIWORD_MASK flag for the clocks from 
the hisilicon series.

Is there some sane intermediate step for the clocks? One possibility that 
comes to mind, would be to only declare the gates and provide fixed rate 
parents to the timer and mmc and add the divs and muxes when Mikes dt patches 
are ready.

I.e. I would keep the gate clocks grouped like now to not have to declare 160 
individual gates later :-)

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

end of thread, other threads:[~2013-06-12 23:40 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-11 11:28 [PATCH v3 0/7] arm: add basic support for Rockchip Cortex-A9 SoCs Heiko Stübner
2013-06-11 11:28 ` Heiko Stübner
2013-06-11 11:28 ` Heiko Stübner
2013-06-11 11:29 ` [PATCH v3 1/7] clk: divider: add flag to limit possible dividers to even numbers Heiko Stübner
2013-06-11 11:29   ` Heiko Stübner
2013-06-11 11:29   ` Heiko Stübner
2013-06-11 11:51   ` Andy Shevchenko
2013-06-11 11:51     ` Andy Shevchenko
2013-06-11 11:51     ` Andy Shevchenko
2013-06-11 12:06     ` Heiko Stübner
2013-06-11 12:06       ` Heiko Stübner
2013-06-11 12:06       ` Heiko Stübner
2013-06-11 12:37       ` Andy Shevchenko
2013-06-11 12:37         ` Andy Shevchenko
2013-06-11 12:37         ` Andy Shevchenko
2013-06-11 12:39         ` Andy Shevchenko
2013-06-11 12:39           ` Andy Shevchenko
2013-06-11 12:39           ` Andy Shevchenko
2013-06-11 18:57   ` Mike Turquette
2013-06-11 18:57     ` Mike Turquette
2013-06-11 19:23     ` Heiko Stübner
2013-06-11 19:23       ` Heiko Stübner
2013-06-11 19:23       ` Heiko Stübner
2013-06-11 11:29 ` [PATCH v3 2/7] mmc: dw_mmc-pltfm: remove static from dw_mci_pltfm_remove Heiko Stübner
2013-06-11 11:29   ` Heiko Stübner
2013-06-11 11:29   ` Heiko Stübner
2013-06-11 11:30 ` [PATCH v3 3/7] mmc: dw_mmc-pltfm: move probe and remove below dt match table Heiko Stübner
2013-06-11 11:30   ` Heiko Stübner
2013-06-11 11:30   ` Heiko Stübner
2013-06-12  1:16   ` Seungwon Jeon
2013-06-12  1:16     ` Seungwon Jeon
2013-06-11 11:30 ` [PATCH v3 4/7] mmc: dw_mmc-pltfm: add Rockchip variant Heiko Stübner
2013-06-11 11:30   ` Heiko Stübner
2013-06-11 11:30   ` Heiko Stübner
2013-06-12  1:22   ` Seungwon Jeon
2013-06-12  1:22     ` Seungwon Jeon
2013-06-11 11:31 ` [PATCH v3 5/7] clk: add basic Rockchip rk3066a clock support Heiko Stübner
2013-06-11 11:31   ` Heiko Stübner
2013-06-11 11:31   ` Heiko Stübner
2013-06-11 20:06   ` Mike Turquette
2013-06-11 20:06     ` Mike Turquette
2013-06-12 22:45     ` Heiko Stübner
2013-06-12 22:45       ` Heiko Stübner
2013-06-12 22:45       ` Heiko Stübner
2013-06-12 23:02       ` Olof Johansson
2013-06-12 23:02         ` Olof Johansson
2013-06-12 23:02         ` Olof Johansson
2013-06-12 23:40         ` Heiko Stübner
2013-06-12 23:40           ` Heiko Stübner
2013-06-12 23:40           ` Heiko Stübner
2013-06-11 11:32 ` [PATCH v3 6/7] arm: add debug uarts for rockchip rk29xx and rk3xxx series Heiko Stübner
2013-06-11 11:32   ` Heiko Stübner
2013-06-11 11:32   ` Heiko Stübner
2013-06-11 11:32 ` [PATCH v3 7/7] arm: add basic support for Rockchip RK3066a boards Heiko Stübner
2013-06-11 11:32   ` Heiko Stübner
2013-06-11 11:32   ` Heiko Stübner

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.