pd: rockchip: add clk_pd type and rk3288 clk_pd support

This commit is contained in:
dkl
2014-04-14 16:25:02 +08:00
parent b1055a5003
commit 54775cd3b8
13 changed files with 334 additions and 7 deletions

View File

@@ -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 = <CLK_PD_GPU>;
#clock-cells = <0>;
};
pd_video: pd_video {
compatible = "rockchip,rk-pd-clock";
clock-output-names = "pd_video";
rockchip,pd-id = <CLK_PD_VIDEO>;
#clock-cells = <0>;
};
pd_vio: pd_vio {
compatible = "rockchip,rk-pd-clock";
clock-output-names = "pd_vio";
rockchip,pd-id = <CLK_PD_VIO>;
#clock-cells = <0>;
};
pd_hevc: pd_hevc {
compatible = "rockchip,rk-pd-clock";
clock-output-names = "pd_hevc";
rockchip,pd-id = <CLK_PD_HEVC>;
#clock-cells = <0>;
};
};
clock_regs {
compatible = "rockchip,rk-clock-regs";
#address-cells = <1>;

View File

@@ -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 {

View File

@@ -23,9 +23,9 @@
#include <asm/cputype.h>
#include <asm/hardware/cache-l2x0.h>
#include <linux/rockchip/common.h>
#include <linux/rockchip/pmu.h>
#include "cpu_axi.h"
#include "loader.h"
#include "pmu.h"
#include "sram.h"
static int __init rockchip_cpu_axi_init(void)

View File

@@ -13,13 +13,13 @@
#include <linux/smp.h>
#include <linux/delay.h>
#include <linux/rockchip/common.h>
#include <linux/rockchip/pmu.h>
#include <asm/cacheflush.h>
#include <asm/cp15.h>
#include <asm/smp_plat.h>
#include <asm/system.h>
#include "pmu.h"
static cpumask_t dead_cpus;

View File

@@ -21,13 +21,13 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/rockchip/common.h>
#include <linux/rockchip/pmu.h>
#include <asm/cacheflush.h>
#include <asm/smp_scu.h>
#include <asm/smp_plat.h>
#include <asm/mach/map.h>
#include "pmu.h"
#define SCU_CTRL 0x00
#define SCU_STANDBY_EN (1 << 5)

View File

@@ -27,11 +27,11 @@
#include <linux/rockchip/cru.h>
#include <linux/rockchip/grf.h>
#include <linux/rockchip/iomap.h>
#include <linux/rockchip/pmu.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include "cpu_axi.h"
#include "loader.h"
#include "pmu.h"
#include "sram.h"
#define RK3188_DEVICE(name) \

View File

@@ -29,13 +29,13 @@
#include <linux/rockchip/dvfs.h>
#include <linux/rockchip/grf.h>
#include <linux/rockchip/iomap.h>
#include <linux/rockchip/pmu.h>
#include <asm/cpuidle.h>
#include <asm/cputype.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#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);

View File

@@ -1,3 +1,4 @@
obj-y += clk.o
obj-y += clk-ops.o
obj-y += clk-pll.o
obj-y += clk-pd.o

View File

@@ -0,0 +1,82 @@
#include <linux/slab.h>
#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;
}

View File

@@ -0,0 +1,22 @@
#ifndef __RK_CLK_PD_H
#define __RK_CLK_PD_H
#include <linux/clk-provider.h>
#include <linux/rockchip/pmu.h>
#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 */

View File

@@ -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);

View File

@@ -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 */