From 54775cd3b89cdc71b64e8399d62c3278f33c307c Mon Sep 17 00:00:00 2001 From: dkl Date: Mon, 14 Apr 2014 16:25:02 +0800 Subject: [PATCH] pd: rockchip: add clk_pd type and rk3288 clk_pd support --- arch/arm/boot/dts/rk3288-clocks.dtsi | 34 ++++ arch/arm/boot/dts/rk3288.dtsi | 8 +- arch/arm/mach-rockchip/common.c | 2 +- arch/arm/mach-rockchip/hotplug.c | 2 +- arch/arm/mach-rockchip/platsmp.c | 2 +- arch/arm/mach-rockchip/rk3188.c | 2 +- arch/arm/mach-rockchip/rk3288.c | 6 +- drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-pd.c | 82 +++++++++ drivers/clk/rockchip/clk-pd.h | 22 +++ drivers/clk/rockchip/clk.c | 163 ++++++++++++++++++ include/dt-bindings/clock/rockchip.h | 17 ++ .../linux/rockchip}/pmu.h | 0 13 files changed, 334 insertions(+), 7 deletions(-) create mode 100644 drivers/clk/rockchip/clk-pd.c create mode 100644 drivers/clk/rockchip/clk-pd.h rename {arch/arm/mach-rockchip => include/linux/rockchip}/pmu.h (100%) diff --git a/arch/arm/boot/dts/rk3288-clocks.dtsi b/arch/arm/boot/dts/rk3288-clocks.dtsi index cc0554064665..8f3ba98f019d 100755 --- a/arch/arm/boot/dts/rk3288-clocks.dtsi +++ b/arch/arm/boot/dts/rk3288-clocks.dtsi @@ -207,6 +207,40 @@ }; }; + pd_cons { + compatible = "rockchip,rk-pd-cons"; + + pd_gpu: pd_gpu { + compatible = "rockchip,rk-pd-clock"; + clock-output-names = "pd_gpu"; + rockchip,pd-id = ; + #clock-cells = <0>; + }; + + pd_video: pd_video { + compatible = "rockchip,rk-pd-clock"; + clock-output-names = "pd_video"; + rockchip,pd-id = ; + #clock-cells = <0>; + }; + + pd_vio: pd_vio { + compatible = "rockchip,rk-pd-clock"; + clock-output-names = "pd_vio"; + rockchip,pd-id = ; + #clock-cells = <0>; + }; + + pd_hevc: pd_hevc { + compatible = "rockchip,rk-pd-clock"; + clock-output-names = "pd_hevc"; + rockchip,pd-id = ; + #clock-cells = <0>; + }; + + }; + + clock_regs { compatible = "rockchip,rk-clock-regs"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index 07b9de0d6922..93137ab9a72c 100755 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -583,7 +583,13 @@ <&clk_gates5 12>,/*hdmi_hdcp_clk*/ /*UART*/ - <&clk_gates11 9>;/*pclk_uart2*/ + <&clk_gates11 9>,/*pclk_uart2*/ + + /*PD*/ + <&pd_gpu>, + <&pd_video>, + <&pd_vio>, + <&pd_hevc>; }; i2c0: i2c@ff650000 { diff --git a/arch/arm/mach-rockchip/common.c b/arch/arm/mach-rockchip/common.c index 97d37532b5db..44abfc4fa7c6 100755 --- a/arch/arm/mach-rockchip/common.c +++ b/arch/arm/mach-rockchip/common.c @@ -23,9 +23,9 @@ #include #include #include +#include #include "cpu_axi.h" #include "loader.h" -#include "pmu.h" #include "sram.h" static int __init rockchip_cpu_axi_init(void) diff --git a/arch/arm/mach-rockchip/hotplug.c b/arch/arm/mach-rockchip/hotplug.c index 82612ff32fab..bb2f7dcc6044 100644 --- a/arch/arm/mach-rockchip/hotplug.c +++ b/arch/arm/mach-rockchip/hotplug.c @@ -13,13 +13,13 @@ #include #include #include +#include #include #include #include #include -#include "pmu.h" static cpumask_t dead_cpus; diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c index 9444a1c5e541..db66d50bcadc 100644 --- a/arch/arm/mach-rockchip/platsmp.c +++ b/arch/arm/mach-rockchip/platsmp.c @@ -21,13 +21,13 @@ #include #include #include +#include #include #include #include #include -#include "pmu.h" #define SCU_CTRL 0x00 #define SCU_STANDBY_EN (1 << 5) diff --git a/arch/arm/mach-rockchip/rk3188.c b/arch/arm/mach-rockchip/rk3188.c index 18b1dd296fb3..b6288b3f4b9a 100644 --- a/arch/arm/mach-rockchip/rk3188.c +++ b/arch/arm/mach-rockchip/rk3188.c @@ -27,11 +27,11 @@ #include #include #include +#include #include #include #include "cpu_axi.h" #include "loader.h" -#include "pmu.h" #include "sram.h" #define RK3188_DEVICE(name) \ diff --git a/arch/arm/mach-rockchip/rk3288.c b/arch/arm/mach-rockchip/rk3288.c index 407f5112a8d5..23dc1fd555ca 100644 --- a/arch/arm/mach-rockchip/rk3288.c +++ b/arch/arm/mach-rockchip/rk3288.c @@ -29,13 +29,13 @@ #include #include #include +#include #include #include #include #include #include "cpu_axi.h" #include "loader.h" -#include "pmu.h" #include "sram.h" #define RK3288_DEVICE(name) \ @@ -341,9 +341,11 @@ out: return 0; } +int rk3288_sys_set_power_domain(enum pmu_power_domain pd, bool on); + static void __init rk3288_dt_init_timer(void) { - rockchip_pmu_ops.set_power_domain = rk3288_pmu_set_power_domain; + rockchip_pmu_ops.set_power_domain = rk3288_sys_set_power_domain; rockchip_pmu_ops.power_domain_is_on = rk3288_pmu_power_domain_is_on; rockchip_pmu_ops.set_idle_request = rk3288_pmu_set_idle_request; of_clk_init(NULL); diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 090212d78008..5ee45b65db56 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -1,3 +1,4 @@ obj-y += clk.o obj-y += clk-ops.o obj-y += clk-pll.o +obj-y += clk-pd.o diff --git a/drivers/clk/rockchip/clk-pd.c b/drivers/clk/rockchip/clk-pd.c new file mode 100644 index 000000000000..6c76fcb8b171 --- /dev/null +++ b/drivers/clk/rockchip/clk-pd.c @@ -0,0 +1,82 @@ +#include + +#include "clk-ops.h" +#include "clk-pd.h" + + +static int clk_pd_endisable(struct clk_hw *hw, bool enable) +{ + struct clk_pd *pd = to_clk_pd(hw); + unsigned long flags = 0; + int ret; + + if (pd->lock) + spin_lock_irqsave(pd->lock, flags); + + ret = rockchip_pmu_ops.set_power_domain(pd->id, enable); + + if (pd->lock) + spin_unlock_irqrestore(pd->lock, flags); + + return ret; +} + +static int clk_pd_enable(struct clk_hw *hw) +{ + return clk_pd_endisable(hw, true); +} + +static void clk_pd_disable(struct clk_hw *hw) +{ + clk_pd_endisable(hw, false); +} + +static int clk_pd_is_enabled(struct clk_hw *hw) +{ + struct clk_pd *pd = to_clk_pd(hw); + + return rockchip_pmu_ops.power_domain_is_on(pd->id); +} + +const struct clk_ops clk_pd_ops = { + .enable = clk_pd_enable, + .disable = clk_pd_disable, + .is_enabled = clk_pd_is_enabled, +}; + +struct clk *rk_clk_register_pd(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + u32 pd_id, spinlock_t *lock) +{ + struct clk_pd *pd; + struct clk *clk; + struct clk_init_data init; + + + /* allocate the pd */ + pd = kzalloc(sizeof(struct clk_pd), GFP_KERNEL); + if (!pd) { + clk_err("%s: could not allocate pd clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = (parent_name ? &parent_name: NULL); + init.num_parents = (parent_name ? 1 : 0); + init.ops = &clk_pd_ops; + + /* struct clk_pd assignments */ + pd->id= pd_id; + pd->lock = lock; + pd->hw.init = &init; + + /* register the clock */ + clk = clk_register(dev, &pd->hw); + + if (IS_ERR(clk)) + kfree(pd); + + return clk; +} + diff --git a/drivers/clk/rockchip/clk-pd.h b/drivers/clk/rockchip/clk-pd.h new file mode 100644 index 000000000000..7f94516384c9 --- /dev/null +++ b/drivers/clk/rockchip/clk-pd.h @@ -0,0 +1,22 @@ +#ifndef __RK_CLK_PD_H +#define __RK_CLK_PD_H + +#include +#include + + + +#define to_clk_pd(_hw) container_of(_hw, struct clk_pd, hw) + +struct clk_pd { + struct clk_hw hw; + u32 id; + spinlock_t *lock; +}; + +struct clk *rk_clk_register_pd(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + u32 pd_id, spinlock_t *lock); + + +#endif /* __RK_CLK_PD_H */ diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index c05687927cfd..72c8b04a5223 100755 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -23,6 +23,7 @@ #include "clk-ops.h" #include "clk-pll.h" +#include "clk-pd.h" struct rkclk_muxinfo { @@ -82,6 +83,14 @@ struct rkclk_fixed_factor_info { const char *parent_name; }; +struct rkclk_pd_info { + const char *clk_name; + struct device_node *np; + struct clk_pd *pd; + const char *parent_name; +}; + + struct rkclk { const char *clk_name; //struct device_node *np; @@ -94,6 +103,7 @@ struct rkclk { struct rkclk_gateinfo *gate_info; struct rkclk_fixed_rate_info *fixed_rate_info; struct rkclk_fixed_factor_info *fixed_factor_info; + struct rkclk_pd_info *pd_info; struct list_head node; }; @@ -107,6 +117,7 @@ LIST_HEAD(rk_clks); #define RKCLK_GATE_TYPE (1 << 4) #define RKCLK_FIXED_RATE_TYPE (1 << 5) #define RKCLK_FIXED_FACTOR_TYPE (1 << 6) +#define RKCLK_PD_TYPE (1 << 7) static int rkclk_init_muxinfo(struct device_node *np, void __iomem *addr) @@ -1043,6 +1054,85 @@ out: return ret; } +static int __init rkclk_init_pd(struct device_node *np) +{ + struct device_node *node = NULL; + struct rkclk_pd_info *pd_info = NULL; + struct clk_pd *pd = NULL; + int ret = 0; + u8 found = 0; + struct rkclk *rkclk = NULL; + + + for_each_available_child_of_node(np, node) { + pd_info = kzalloc(sizeof(struct rkclk_pd_info), GFP_KERNEL); + if (!pd_info) { + ret = -ENOMEM; + goto out; + } + + pd_info->pd = kzalloc(sizeof(struct clk_pd), GFP_KERNEL); + if (!pd_info->pd) { + ret = -ENOMEM; + goto out; + } + pd = pd_info->pd; + + pd_info->np = node; + + ret = of_property_read_string_index(node, "clock-output-names", + 0, &pd_info->clk_name); + if (ret) + goto out; + + pd_info->parent_name = of_clk_get_parent_name(node, 0); + + ret = of_property_read_u32(node, "rockchip,pd-id", &pd->id); + if (ret != 0) { + clk_err("%s: can not get pd-id\n", __func__); + goto out; + } + + found = 0; + list_for_each_entry(rkclk, &rk_clks, node) { + if (strcmp(pd_info->clk_name, rkclk->clk_name) == 0) { + clk_err("%s %d:\n", __func__, __LINE__); + clk_err("This clk (%s) has been used, error!\n", + rkclk->clk_name); + goto out; + } + } + + if (!found) { + rkclk = kzalloc(sizeof(struct rkclk), GFP_KERNEL); + if (!rkclk) { + ret = -ENOMEM; + goto out; + } + rkclk->clk_name = pd_info->clk_name; + rkclk->pd_info = pd_info; + rkclk->clk_type = RKCLK_PD_TYPE; + rkclk->flags = CLK_IS_ROOT; + clk_debug("%s: creat %s\n", __func__, rkclk->clk_name); + list_add_tail(&rkclk->node, &rk_clks); + } + } + +out: + if (ret) { + clk_err("%s error, ret = %d\n", __func__, ret); + if (pd_info) { + if (pd_info->pd) + kfree(pd_info->pd); + kfree(pd_info); + } + if (rkclk) + kfree(rkclk); + } + + return ret; +} + static int rkclk_register(struct rkclk *rkclk) { struct clk *clk = NULL; @@ -1053,6 +1143,7 @@ static int rkclk_register(struct rkclk *rkclk) struct clk_divider *frac = NULL; struct clk_fixed_rate *fixed_rate = NULL; struct clk_fixed_factor *fixed_factor = NULL; + struct clk_pd *pd = NULL; struct clk_hw *mux_hw = NULL; const struct clk_ops *mux_ops = NULL; @@ -1089,6 +1180,9 @@ static int rkclk_register(struct rkclk *rkclk) fixed_rate = rkclk->fixed_rate_info->fixed_rate; if (rkclk->fixed_factor_info && rkclk->fixed_factor_info->fixed_factor) fixed_factor = rkclk->fixed_factor_info->fixed_factor; + if (rkclk->pd_info && rkclk->pd_info->pd) + pd = rkclk->pd_info->pd; + switch (rkclk->clk_type) { case RKCLK_MUX_TYPE: @@ -1150,6 +1244,12 @@ static int rkclk_register(struct rkclk *rkclk) rkclk->flags, fixed_factor->mult, fixed_factor->div); goto add_lookup; + case RKCLK_PD_TYPE: + clk_debug("use rk_clk_register_pd\n"); + clk = rk_clk_register_pd(NULL, rkclk->clk_name, + rkclk->pd_info->parent_name, rkclk->flags, + pd->id, &clk_lock); + goto add_lookup; default: goto rgs_comp; } @@ -1377,6 +1477,10 @@ static void rkclk_add_provider(struct device_node *np) clk_err("%s: unknown\n", __func__); } } + } else if (strcmp(compatible, "rockchip,rk-pd-cons") == 0) { + for_each_available_child_of_node(node, node_prd) { + _rkclk_add_provider(node_prd); + } } else { clk_err("%s: unknown\n", __func__); } @@ -1446,6 +1550,7 @@ void rkclk_dump_info(struct rkclk *rkclk) struct clk_divider *frac = NULL; struct clk_fixed_rate *fixed_rate = NULL; struct clk_fixed_factor *fixed_factor = NULL; + struct clk_pd *pd = NULL; int i; @@ -1467,6 +1572,9 @@ void rkclk_dump_info(struct rkclk *rkclk) fixed_rate = rkclk->fixed_rate_info->fixed_rate; if (rkclk->fixed_factor_info && rkclk->fixed_factor_info->fixed_factor) fixed_factor = rkclk->fixed_factor_info->fixed_factor; + if (rkclk->pd_info && rkclk->pd_info->pd) + pd = rkclk->pd_info->pd; + if (rkclk->mux_info) { clk_debug("\t\tmux_info: name=%s, clkops_idx=%u\n", @@ -1554,6 +1662,15 @@ void rkclk_dump_info(struct rkclk *rkclk) fixed_factor->mult, fixed_factor->div); } } + + if (rkclk->pd_info) { + clk_debug("\t\tpd_info: name=%s, parent=%s\n", + rkclk->pd_info->clk_name, + rkclk->pd_info->parent_name); + if (pd) { + clk_debug("\t\tpd: id=%u\n", pd->id); + } + } } #else void rkclk_dump_info(struct rkclk *rkclk) {} @@ -1561,6 +1678,44 @@ void rkclk_dump_info(struct rkclk *rkclk) {} #ifdef RKCLK_TEST +char* pd_table[] = { + "pd_gpu", + "pd_video", + "pd_vio", + "pd_hevc", +}; + +void rk_clk_pd_test(void) +{ + struct clk *clk; + bool state; + int j, ret; + + + for (j = 0; j < ARRAY_SIZE(pd_table); j++) { + + clk = clk_get(NULL, pd_table[j]); + + ret = clk_prepare_enable(clk); + printk("%s: clk_prepare_enable %s, ret=%d\n", __func__, + __clk_get_name(clk), ret); + + state = __clk_is_enabled(clk); + printk("%s: clk_pd %s is %s\n", __func__, __clk_get_name(clk), + state ? "enable" : "disable"); + + clk_disable_unprepare(clk); + printk("%s: clk_disable_unprepare %s\n", __func__, + __clk_get_name(clk)); + + state = __clk_is_enabled(clk); + printk("%s: clk_pd %s is %s\n", __func__, __clk_get_name(clk), + state ? "enable" : "disable"); + + printk("\n"); + } +} + struct test_table { const char *name; u32 rate; @@ -1598,6 +1753,7 @@ struct test_table t_table[] = { {.name = "clk_core", .rate = 500000000}, }; + void rk_clk_test(void) { const char *clk_name; @@ -1652,6 +1808,7 @@ void rk_clk_test(void) rk_dump_cru(); } + rk_clk_pd_test(); } #else void rk_clk_test(void) {} @@ -1697,6 +1854,11 @@ static void __init rk_clk_tree_init(struct device_node *np) clk_err("%s: init reg cons err\n", __func__); return ; } + } else if (strcmp(compatible, "rockchip,rk-pd-cons") == 0) { + if (rkclk_init_pd(node) != 0) { + clk_err("%s: init pd err\n", __func__); + return ; + } } else { clk_err("%s: unknown\n", __func__); } @@ -1720,6 +1882,7 @@ static void __init rk_clk_tree_init(struct device_node *np) rkclk_init_clks(node_init); rk_clk_test(); + } CLK_OF_DECLARE(rk_clocks, "rockchip,rk-clocks", rk_clk_tree_init); diff --git a/include/dt-bindings/clock/rockchip.h b/include/dt-bindings/clock/rockchip.h index d05d846d8406..7e4a970e4912 100644 --- a/include/dt-bindings/clock/rockchip.h +++ b/include/dt-bindings/clock/rockchip.h @@ -53,4 +53,21 @@ #define CLKOPS_RATE_RK3288_I2S 14 #define CLKOPS_TABLE_END (~0) +/* pd id */ +#define CLK_PD_BCPU 0 +#define CLK_PD_BDSP 1 +#define CLK_PD_BUS 2 +#define CLK_PD_CPU_0 3 +#define CLK_PD_CPU_1 4 +#define CLK_PD_CPU_2 5 +#define CLK_PD_CPU_3 6 +#define CLK_PD_CS 7 +#define CLK_PD_GPU 8 +#define CLK_PD_HEVC 9 +#define CLK_PD_PERI 10 +#define CLK_PD_SCU 11 +#define CLK_PD_VIDEO 12 +#define CLK_PD_VIO 13 + + #endif /* _DT_BINDINGS_CLOCK_ROCKCHIP_H */ diff --git a/arch/arm/mach-rockchip/pmu.h b/include/linux/rockchip/pmu.h similarity index 100% rename from arch/arm/mach-rockchip/pmu.h rename to include/linux/rockchip/pmu.h -- 2.34.1