rk: rm drivers/clk/rk

Change-Id: I8c541c0edb446a285ca5097b597216635e755460
Signed-off-by: Huang, Tao <huangtao@rock-chips.com>
This commit is contained in:
Huang, Tao
2016-12-22 14:23:30 +08:00
parent 436d4c489e
commit fa25ca7318
10 changed files with 0 additions and 7015 deletions

View File

@@ -1,5 +0,0 @@
obj-y += clk.o
obj-y += clk-ops.o
obj-y += clk-pll.o
obj-y += clk-pd.o
obj-y += pd-rk3368.o

View File

@@ -1,921 +0,0 @@
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk-private.h>
#include <linux/delay.h>
#include <linux/rockchip/common.h>
#include <linux/rockchip/cpu.h>
#include "clk-ops.h"
/* mux_ops */
struct clk_ops_table rk_clk_mux_ops_table[] = {
{.index = CLKOPS_TABLE_END},
};
/* rate_ops */
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
#define div_mask(d) ((1 << ((d)->width)) - 1)
static u32 clk_gcd(u32 numerator, u32 denominator)
{
u32 a, b;
if (!numerator || !denominator)
return 0;
if (numerator > denominator) {
a = numerator;
b = denominator;
} else {
a = denominator;
b = numerator;
}
while (b != 0) {
int r = b;
b = a % b;
a = r;
}
return a;
}
static int clk_fracdiv_get_config(unsigned long rate_out, unsigned long rate,
u32 *numerator, u32 *denominator)
{
u32 gcd_val;
gcd_val = clk_gcd(rate, rate_out);
clk_debug("%s: frac_get_seting rate=%lu, parent=%lu, gcd=%d\n",
__func__, rate_out, rate, gcd_val);
if (!gcd_val) {
clk_err("gcd=0, frac div is not be supported\n");
return -EINVAL;
}
*numerator = rate_out / gcd_val;
*denominator = rate / gcd_val;
clk_debug("%s: frac_get_seting numerator=%d, denominator=%d, times=%d\n",
__func__, *numerator, *denominator,
*denominator / *numerator);
if (*numerator > 0xffff || *denominator > 0xffff ||
(*denominator / (*numerator)) < 20) {
clk_err("can't get a available nume and deno\n");
return -EINVAL;
}
return 0;
}
static int clk_fracdiv_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
u32 numerator, denominator;
struct clk_divider *div = to_clk_divider(hw);
if(clk_fracdiv_get_config(rate, parent_rate,
&numerator, &denominator) == 0) {
writel(numerator << 16 | denominator, div->reg);
clk_debug("%s set rate=%lu,is ok\n", hw->clk->name, rate);
} else {
clk_err("clk_frac_div name=%s can't get rate=%lu\n",
hw->clk->name, rate);
return -EINVAL;
}
return 0;
}
static unsigned long clk_fracdiv_recalc(struct clk_hw *hw,
unsigned long parent_rate)
{
unsigned long rate;
u64 rate64;
struct clk_divider *div = to_clk_divider(hw);
u32 numerator, denominator, reg_val;
reg_val = readl(div->reg);
if (reg_val == 0)
return parent_rate;
numerator = reg_val >> 16;
denominator = reg_val & 0xFFFF;
rate64 = (u64)parent_rate * numerator;
do_div(rate64, denominator);
rate = rate64;
clk_debug("%s: %s new clock rate is %lu, prate %lu (frac %u/%u)\n",
__func__, hw->clk->name, rate, parent_rate,
numerator, denominator);
return rate;
}
static long clk_fracdiv_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk *clk = hw->clk;
struct clk *parent = clk->parent;
long rate_out;
//FIXME: now just simply return rate
/*
*frac_div request a big input rate, and its parent is always a div,
*so we set parent->parent->rate as best_parent_rate.
*/
rate_out = rate;
*prate = parent->parent->rate;
return rate_out;
}
static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
return clk_divider_ops.recalc_rate(hw, parent_rate);
}
static long clk_divider_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long *prate)
{
return clk_divider_ops.round_rate(hw, rate, prate);
}
static int clk_divider_set_rate(struct clk_hw *hw,
unsigned long rate, unsigned long parent_rate)
{
return clk_divider_ops.set_rate(hw, rate, parent_rate);
}
static long clk_mux_with_div_determine_rate(struct clk_hw *div_hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_p)
{
struct clk *clk = div_hw->clk, *parent = NULL, *best_parent = NULL;
int i, num_parents;
unsigned long parent_rate = 0, best_prate = 0, best = 0, now = 0;
parent = __clk_get_parent(clk);
if(!parent){
best = __clk_get_rate(clk);
goto out;
}
/* if NO_REPARENT flag set, pass through to current parent */
if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
best_prate = __clk_get_rate(parent);
best = clk_divider_ops.round_rate(div_hw, rate, &best_prate);
goto out;
}
/* find the parent that can provide the fastest rate <= rate */
num_parents = clk->num_parents;
for (i = 0; i < num_parents; i++) {
parent = clk_get_parent_by_index(clk, i);
if (!parent)
continue;
parent_rate = __clk_get_rate(parent);
now = clk_divider_ops.round_rate(div_hw, rate, &parent_rate);
if (now <= rate && now > best) {
best_parent = parent;
best_prate = parent_rate;
best = now;
}
}
out:
if(best_prate)
*best_parent_rate = best_prate;
if (best_parent)
*best_parent_p = best_parent;
clk_debug("clk name = %s, determine rate = %lu, best = %lu\n"
"\tbest_parent name = %s, best_prate = %lu\n",
clk->name, rate, best,
__clk_get_name(*best_parent_p), *best_parent_rate);
return best;
}
const struct clk_ops clkops_rate_auto_parent = {
.recalc_rate = clk_divider_recalc_rate,
.round_rate = clk_divider_round_rate,
.set_rate = clk_divider_set_rate,
.determine_rate = clk_mux_with_div_determine_rate,
};
static long clk_div_round_rate_even(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
int i = 0;
struct clk_divider *divider =to_clk_divider(hw);
int max_div = 1 << divider->width;
for (i = 1; i <= max_div; i++) {
if (i > 1 && (i % 2 != 0))
continue;
if (rate >= (*prate / i))
return *prate / i;
}
return (*prate / max_div);
}
const struct clk_ops clkops_rate_evendiv = {
.recalc_rate = clk_divider_recalc_rate,
.round_rate = clk_div_round_rate_even,
.set_rate = clk_divider_set_rate,
};
static long clk_mux_with_evendiv_determine_rate(struct clk_hw *div_hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_p)
{
struct clk *clk = div_hw->clk, *parent = NULL, *best_parent = NULL;
int i, num_parents;
unsigned long parent_rate = 0, best_prate = 0, best = 0, now = 0;
parent = __clk_get_parent(clk);
if(!parent){
best = __clk_get_rate(clk);
goto out;
}
/* if NO_REPARENT flag set, pass through to current parent */
if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
best_prate = __clk_get_rate(parent);
best = clk_div_round_rate_even(div_hw, rate, &best_prate);
goto out;
}
/* find the parent that can provide the fastest rate <= rate */
num_parents = clk->num_parents;
for (i = 0; i < num_parents; i++) {
parent = clk_get_parent_by_index(clk, i);
if (!parent)
continue;
parent_rate = __clk_get_rate(parent);
now = clk_div_round_rate_even(div_hw, rate, &parent_rate);
if (now <= rate && now > best) {
best_parent = parent;
best_prate = parent_rate;
best = now;
}
}
out:
if(best_prate)
*best_parent_rate = best_prate;
if (best_parent)
*best_parent_p = best_parent;
clk_debug("clk name = %s, determine rate = %lu, best = %lu\n"
"\tbest_parent name = %s, best_prate = %lu\n",
clk->name, rate, best,
__clk_get_name(*best_parent_p), *best_parent_rate);
return best;
}
static long clk_mux_with_evendiv_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
return clk_div_round_rate_even(hw, rate, prate);
}
const struct clk_ops clkops_rate_mux_with_evendiv = {
.recalc_rate = clk_divider_recalc_rate,
.set_rate = clk_divider_set_rate,
.round_rate = clk_mux_with_evendiv_round_rate,
.determine_rate = clk_mux_with_evendiv_determine_rate,
};
static int clk_i2s_fracdiv_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
u32 numerator, denominator;
struct clk_divider *div = to_clk_divider(hw);
int i = 10;
if(clk_fracdiv_get_config(rate, parent_rate,
&numerator, &denominator) == 0) {
while (i--) {
writel((numerator - 1) << 16 | denominator, div->reg);
mdelay(1);
writel(numerator << 16 | denominator, div->reg);
mdelay(1);
}
clk_debug("%s set rate=%lu,is ok\n", hw->clk->name, rate);
} else {
clk_err("clk_frac_div name=%s can't get rate=%lu\n",
hw->clk->name, rate);
return -EINVAL;
}
return 0;
}
const struct clk_ops clkops_rate_frac = {
.recalc_rate = clk_fracdiv_recalc,
.round_rate = clk_fracdiv_round_rate,
.set_rate = clk_fracdiv_set_rate,
};
const struct clk_ops clkops_rate_i2s_frac = {
.recalc_rate = clk_fracdiv_recalc,
.round_rate = clk_fracdiv_round_rate,
.set_rate = clk_i2s_fracdiv_set_rate,
};
static unsigned long clk_core_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
/* As parent rate could be changed in clk_core.set_rate
* ops, the passing_in parent_rate may not be the newest
* and we should use the parent->rate instead. As a side
* effect, we should NOT directly set clk_core's parent
* (apll) rate, otherwise we will get a wrong recalc rate
* with clk_core_recalc_rate.
*/
struct clk *parent = __clk_get_parent(hw->clk);
return clk_divider_recalc_rate(hw, __clk_get_rate(parent));
}
static long clk_core_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_p)
{
struct clk *parent = __clk_get_parent(hw->clk);
if (IS_ERR_OR_NULL(parent)) {
clk_err("fail to get parent!\n");
return 0;
}
return clk_round_rate(parent, rate);
}
static long clk_core_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
return clk_core_determine_rate(hw, rate, prate, NULL);
}
static int clk_core_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk *parent = __clk_get_parent(hw->clk);
struct clk *grand_p = __clk_get_parent(parent);
int ret;
if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) {
clk_err("fail to get parent or grand_parent!\n");
return -EINVAL;
}
ret = parent->ops->set_rate(parent->hw, rate, __clk_get_rate(grand_p));
parent->rate = parent->ops->recalc_rate(parent->hw,
__clk_get_rate(grand_p));
return ret;
}
const struct clk_ops clkops_rate_core = {
.recalc_rate = clk_core_recalc_rate,
.round_rate = clk_core_round_rate,
.set_rate = clk_core_set_rate,
.determine_rate = clk_core_determine_rate,
};
/* Clk_ops for the child clk of clk_core, for example core_periph in rk3188 */
const struct clk_ops clkops_rate_core_peri = {
.recalc_rate = clk_divider_recalc_rate,
.round_rate = clk_divider_round_rate,
.set_rate = NULL,
};
static unsigned long clk_ddr_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
/* Same as clk_core, we should NOT set clk_ddr's parent
* (dpll) rate directly as a side effect.
*/
return clk_core_recalc_rate(hw, parent_rate);
}
static long clk_ddr_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_p)
{
long best = 0;
if (!ddr_round_rate) {
/* Do nothing before ddr init */
best = rate;//__clk_get_rate(hw->clk);
} else {
/* Func provided by ddr driver */
best = ddr_round_rate(rate/MHZ) * MHZ;
}
clk_debug("%s: from %lu to %lu\n", __func__, rate, best);
return best;
}
static long clk_ddr_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
return clk_ddr_determine_rate(hw, rate, prate, NULL);
}
static int clk_ddr_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk *parent = __clk_get_parent(hw->clk);
struct clk *grand_p = __clk_get_parent(parent);
/* Do nothing before ddr init */
if (!ddr_change_freq)
return 0;
if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) {
clk_err("fail to get parent or grand_parent!\n");
return -EINVAL;
}
clk_debug("%s: will set rate = %lu\n", __func__, rate);
/* Func provided by ddr driver */
ddr_change_freq(rate/MHZ);
parent->rate = parent->ops->recalc_rate(parent->hw,
__clk_get_rate(grand_p));
return 0;
}
const struct clk_ops clkops_rate_ddr = {
.recalc_rate = clk_ddr_recalc_rate,
.round_rate = clk_ddr_round_rate,
.set_rate = clk_ddr_set_rate,
.determine_rate = clk_ddr_determine_rate,
};
static unsigned long clk_ddr_div2_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
/* Same as clk_core, we should NOT set clk_ddr's parent
* (dpll) rate directly as a side effect.
*/
struct clk *parent = __clk_get_parent(hw->clk);
return clk_divider_recalc_rate(hw, __clk_get_rate(parent))/2;
}
const struct clk_ops clkops_rate_ddr_div2 = {
.recalc_rate = clk_ddr_div2_recalc_rate,
.round_rate = clk_ddr_round_rate,
.set_rate = clk_ddr_set_rate,
.determine_rate = clk_ddr_determine_rate,
};
static unsigned long clk_ddr_div4_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
/* Same as clk_core, we should NOT set clk_ddr's parent
* (dpll) rate directly as a side effect.
*/
struct clk *parent = __clk_get_parent(hw->clk);
return clk_divider_recalc_rate(hw, __clk_get_rate(parent))/4;
}
const struct clk_ops clkops_rate_ddr_div4 = {
.recalc_rate = clk_ddr_div4_recalc_rate,
.round_rate = clk_ddr_round_rate,
.set_rate = clk_ddr_set_rate,
.determine_rate = clk_ddr_determine_rate,
};
static unsigned long clk_3288_i2s_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
return parent_rate;
}
static long clk_3288_i2s_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
return rate;
}
static int clk_3288_i2s_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk *parent = __clk_get_parent(hw->clk);
struct clk *grand_p = __clk_get_parent(parent);
if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) {
return 0;
}
if (parent->ops->set_rate) {
parent->ops->set_rate(parent->hw, rate/2, __clk_get_rate(grand_p));
parent->ops->set_rate(parent->hw, rate, __clk_get_rate(grand_p));
}
return 0;
}
const struct clk_ops clkops_rate_3288_i2s = {
.recalc_rate = clk_3288_i2s_recalc_rate,
.round_rate = clk_3288_i2s_round_rate,
.set_rate = clk_3288_i2s_set_rate,
};
static bool usb480m_state = false;
static long clk_3288_usb480m_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_p)
{
if(rate == 0)
return 0;
else
return 480*MHZ;
}
static long clk_3288_usb480m_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
return clk_3288_usb480m_determine_rate(hw, rate, prate, NULL);
}
static int clk_3288_usb480m_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
if(rate == 0)
usb480m_state = false;
else
usb480m_state = true;
return 0;
}
static unsigned long clk_3288_usb480m_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
if(usb480m_state)
return 480*MHZ;
else
return 0;
}
const struct clk_ops clkops_rate_3288_usb480m = {
.determine_rate = clk_3288_usb480m_determine_rate,
.set_rate = clk_3288_usb480m_set_rate,
.round_rate = clk_3288_usb480m_round_rate,
.recalc_rate = clk_3288_usb480m_recalc_rate,
};
#define RK3288_LIMIT_PLL_VIO0 (600*MHZ)
static long clk_3288_dclk_lcdc0_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_p)
{
struct clk *gpll = clk_get(NULL, "clk_gpll");
struct clk *cpll = clk_get(NULL, "clk_cpll");
unsigned long best, div, prate, gpll_rate;
gpll_rate = __clk_get_rate(gpll);
if ((rate <= (297*MHZ)) && (gpll_rate%rate == 0)) {
*best_parent_p = gpll;
best = rate;
*best_parent_rate = gpll_rate;
} else {
*best_parent_p = cpll;
div = RK3288_LIMIT_PLL_VIO0/rate;
prate = div * rate;
*best_parent_rate = clk_round_rate(cpll, prate);
best = (*best_parent_rate)/div;
}
return best;
}
static long clk_3288_dclk_lcdc0_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
return clk_3288_dclk_lcdc0_determine_rate(hw, rate, prate, NULL);
}
static int clk_3288_dclk_lcdc0_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk* aclk_vio0 = clk_get(NULL, "aclk_vio0");
struct clk* hclk_vio = clk_get(NULL, "hclk_vio");
struct clk *aclk_vio1;
struct clk* parent;
struct clk *gpll = clk_get(NULL, "clk_gpll");
struct clk *cpll = clk_get(NULL, "clk_cpll");
clk_divider_ops.set_rate(hw, rate, parent_rate);
/* set aclk_vio */
if (parent_rate == __clk_get_rate(gpll)) {
parent = clk_get(NULL, "clk_gpll");
clk_set_parent(aclk_vio0, gpll);
clk_set_rate(aclk_vio0, 300*MHZ);
} else {
parent = clk_get(NULL, "clk_cpll");
clk_set_parent(aclk_vio0, cpll);
clk_set_rate(aclk_vio0, __clk_get_rate(cpll));
}
clk_set_rate(hclk_vio, 100*MHZ);
/* make aclk_isp and hclk_isp share a same pll in rk3288_eco */
if (rockchip_get_cpu_version() > 0) {
aclk_vio1 = clk_get(NULL, "aclk_vio1");
clk_set_parent(aclk_vio1, parent);
clk_set_rate(aclk_vio1, __clk_get_rate(parent));
}
return 0;
}
const struct clk_ops clkops_rate_3288_dclk_lcdc0 = {
.determine_rate = clk_3288_dclk_lcdc0_determine_rate,
.set_rate = clk_3288_dclk_lcdc0_set_rate,
.round_rate = clk_3288_dclk_lcdc0_round_rate,
.recalc_rate = clk_divider_recalc_rate,
};
#define RK3288_LIMIT_PLL_VIO1 (350*MHZ)
static long clk_3288_dclk_lcdc1_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_p)
{
struct clk *gpll = clk_get(NULL, "clk_gpll");
struct clk *cpll = clk_get(NULL, "clk_cpll");
unsigned long best, div, prate, gpll_rate;
gpll_rate = __clk_get_rate(gpll);
if ((rate <= (297*MHZ)) && ((gpll_rate)%rate == 0)) {
*best_parent_p = gpll;
best = rate;
*best_parent_rate = gpll_rate;
} else {
*best_parent_p = cpll;
div = RK3288_LIMIT_PLL_VIO1/rate;
prate = div * rate;
*best_parent_rate = clk_round_rate(cpll, prate);
best = (*best_parent_rate)/div;
}
return best;
}
static long clk_3288_dclk_lcdc1_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
return clk_3288_dclk_lcdc1_determine_rate(hw, rate, prate, NULL);
}
static int clk_3288_dclk_lcdc1_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk* aclk_vio1 = clk_get(NULL, "aclk_vio1");
struct clk* parent;
struct clk *gpll = clk_get(NULL, "clk_gpll");
struct clk *cpll = clk_get(NULL, "clk_cpll");
clk_divider_ops.set_rate(hw, rate, parent_rate);
/* set aclk_vio */
if (parent_rate == __clk_get_rate(gpll)) {
parent = clk_get(NULL, "clk_gpll");
clk_set_parent(aclk_vio1, gpll);
clk_set_rate(aclk_vio1, 300*MHZ);
} else {
parent = clk_get(NULL, "clk_cpll");
clk_set_parent(aclk_vio1, cpll);
clk_set_rate(aclk_vio1, __clk_get_rate(cpll));
}
if (rockchip_get_cpu_version() == 0) {
clk_set_parent(aclk_vio1, parent);
clk_set_rate(aclk_vio1, __clk_get_rate(parent));
}
return 0;
}
const struct clk_ops clkops_rate_3288_dclk_lcdc1 = {
.determine_rate = clk_3288_dclk_lcdc1_determine_rate,
.set_rate = clk_3288_dclk_lcdc1_set_rate,
.round_rate = clk_3288_dclk_lcdc1_round_rate,
.recalc_rate = clk_divider_recalc_rate,
};
#define CONFIG_RK3368_MUX_NO_USE_NPLL
static long clk_3368_mux_div_determine_rate(struct clk_hw *div_hw,
unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_p)
{
struct clk *clk = div_hw->clk, *parent = NULL, *best_parent = NULL;
int i, num_parents;
unsigned long parent_rate = 0, best_prate = 0, best = 0, now = 0;
parent = __clk_get_parent(clk);
if (!parent) {
best = __clk_get_rate(clk);
goto out;
}
/* if NO_REPARENT flag set, pass through to current parent */
if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
best_prate = __clk_get_rate(parent);
best = clk_divider_ops.round_rate(div_hw, rate, &best_prate);
goto out;
}
/* find the parent that can provide the fastest rate <= rate */
num_parents = clk->num_parents;
for (i = 0; i < num_parents; i++) {
parent = clk_get_parent_by_index(clk, i);
if (!parent)
continue;
#ifdef CONFIG_RK3368_MUX_NO_USE_NPLL
if (!strcmp(__clk_get_name(parent), "clk_npll"))
continue;
#endif
parent_rate = __clk_get_rate(parent);
now = clk_divider_ops.round_rate(div_hw, rate, &parent_rate);
if (now <= rate && now > best) {
best_parent = parent;
best_prate = parent_rate;
best = now;
}
}
out:
if (best_prate)
*best_parent_rate = best_prate;
if (best_parent)
*best_parent_p = best_parent;
clk_debug("clk name = %s, determine rate = %lu, best = %lu\n"
"\tbest_parent name = %s, best_prate = %lu\n",
clk->name, rate, best,
__clk_get_name(*best_parent_p), *best_parent_rate);
return best;
}
const struct clk_ops clkops_rate_3368_auto_parent = {
.recalc_rate = clk_divider_recalc_rate,
.round_rate = clk_divider_round_rate,
.set_rate = clk_divider_set_rate,
.determine_rate = clk_3368_mux_div_determine_rate,
};
#define RK3368_LIMIT_NPLL (1250*MHZ)
static long clk_3368_dclk_lcdc_determine_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_p)
{
struct clk *npll = clk_get(NULL, "clk_npll");
unsigned long div, prate, best, *p_prate;
static unsigned long rk3368_pll_rates[] = {1188*MHZ, 0};
if (best_parent_p)
*best_parent_p = npll;
/* first get parent_rate from table */
p_prate = rk3368_pll_rates;
while (*p_prate) {
if (!(*p_prate % (rate*2)) || (*p_prate == rate)) {
clk_debug("%s: get rate from table\n", __func__);
*best_parent_rate = *p_prate;
best = rate;
return best;
}
p_prate++;
}
/* if not suitable parent_rate found in table, then auto calc rate */
div = RK3368_LIMIT_NPLL/rate;
/* div should be even */
if (div % 2)
div = div - 1;
prate = div * rate;
*best_parent_rate = clk_round_rate(npll, prate);
best = (*best_parent_rate)/div;
return best;
}
static long clk_3368_dclk_lcdc_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
return clk_3368_dclk_lcdc_determine_rate(hw, rate, prate, NULL);
}
const struct clk_ops clkops_rate_3368_dclk_lcdc = {
.determine_rate = clk_3368_dclk_lcdc_determine_rate,
.set_rate = clk_divider_set_rate,
.round_rate = clk_3368_dclk_lcdc_round_rate,
.recalc_rate = clk_divider_recalc_rate,
};
static unsigned long clk_rk3368_ddr_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
if (!ddr_recalc_rate)
return (clk_core_recalc_rate(hw, parent_rate)/2);
else
return ddr_recalc_rate();
}
const struct clk_ops clkops_rate_rk3368_ddr = {
.recalc_rate = clk_rk3368_ddr_recalc_rate,
.round_rate = clk_ddr_round_rate,
.set_rate = clk_ddr_set_rate,
.determine_rate = clk_ddr_determine_rate,
};
struct clk_ops_table rk_clkops_rate_table[] = {
{.index = CLKOPS_RATE_MUX_DIV, .clk_ops = &clkops_rate_auto_parent},
{.index = CLKOPS_RATE_EVENDIV, .clk_ops = &clkops_rate_evendiv},
{.index = CLKOPS_RATE_MUX_EVENDIV, .clk_ops = &clkops_rate_mux_with_evendiv},
{.index = CLKOPS_RATE_I2S_FRAC, .clk_ops = &clkops_rate_i2s_frac},
{.index = CLKOPS_RATE_FRAC, .clk_ops = &clkops_rate_frac},
{.index = CLKOPS_RATE_CORE, .clk_ops = &clkops_rate_core},
{.index = CLKOPS_RATE_CORE_CHILD, .clk_ops = &clkops_rate_core_peri},
{.index = CLKOPS_RATE_DDR, .clk_ops = &clkops_rate_ddr},
{.index = CLKOPS_RATE_RK3288_I2S, .clk_ops = &clkops_rate_3288_i2s},
{.index = CLKOPS_RATE_RK3288_USB480M, .clk_ops = &clkops_rate_3288_usb480m},
{.index = CLKOPS_RATE_RK3288_DCLK_LCDC0,.clk_ops = &clkops_rate_3288_dclk_lcdc0},
{.index = CLKOPS_RATE_RK3288_DCLK_LCDC1,.clk_ops = &clkops_rate_3288_dclk_lcdc1},
{.index = CLKOPS_RATE_DDR_DIV2, .clk_ops = &clkops_rate_ddr_div2},
{.index = CLKOPS_RATE_DDR_DIV4, .clk_ops = &clkops_rate_ddr_div4},
{.index = CLKOPS_RATE_RK3368_MUX_DIV_NPLL, .clk_ops = &clkops_rate_3368_auto_parent},
{.index = CLKOPS_RATE_RK3368_DCLK_LCDC, .clk_ops = &clkops_rate_3368_dclk_lcdc},
{.index = CLKOPS_RATE_RK3368_DDR, .clk_ops = &clkops_rate_rk3368_ddr},
{.index = CLKOPS_RATE_I2S, .clk_ops = NULL},
{.index = CLKOPS_RATE_CIFOUT, .clk_ops = NULL},
{.index = CLKOPS_RATE_UART, .clk_ops = NULL},
{.index = CLKOPS_RATE_HSADC, .clk_ops = NULL},
{.index = CLKOPS_RATE_MAC_REF, .clk_ops = NULL},
{.index = CLKOPS_TABLE_END, .clk_ops = NULL},
};
const struct clk_ops *rk_get_clkops(unsigned int idx)
{
int i = 0;
unsigned int now_idx;
while(1){
now_idx = rk_clkops_rate_table[i].index;
if ((now_idx == idx) || (now_idx == CLKOPS_TABLE_END))
return rk_clkops_rate_table[i].clk_ops;
i++;
}
}
EXPORT_SYMBOL_GPL(rk_get_clkops);

View File

@@ -1,33 +0,0 @@
#ifndef __RK_CLK_OPS_H
#define __RK_CLK_OPS_H
#include <dt-bindings/clock/rockchip,rk3188.h>
#include <linux/rockchip/iomap.h>
#include <linux/rockchip/grf.h>
#define MHZ (1000UL * 1000UL)
#define KHZ (1000UL)
struct clk_ops_table {
unsigned int index;
const struct clk_ops *clk_ops;
};
const struct clk_ops *rk_get_clkops(unsigned int idx);
//#define RKCLK_DEBUG
//#define RKCLK_TEST
#if defined(RKCLK_DEBUG)
#define clk_debug(fmt, args...) printk(KERN_INFO "rkclk: "fmt, ##args)
#else
#define clk_debug(fmt, args...) do {} while(0)
#endif
#define clk_err(fmt, args...) printk(KERN_ERR "rkclk: "fmt, ##args)
u32 cru_readl(u32 offset);
void cru_writel(u32 val, u32 offset);
u32 grf_readl(u32 offset);
#endif /* __RK_CLKOPS_H */

View File

@@ -1,228 +0,0 @@
#include <linux/slab.h>
#include "clk-ops.h"
#include "clk-pd.h"
static LIST_HEAD(clk_pd_notifier_list);
static int __clk_pd_notify(struct clk *clk, unsigned long msg)
{
struct clk_pd_notifier *cn;
int ret = NOTIFY_DONE;
list_for_each_entry(cn, &clk_pd_notifier_list, node) {
if (cn->clk == clk) {
ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
NULL);
break;
}
}
return ret;
}
int rk_clk_pd_notifier_register(struct clk *clk, struct notifier_block *nb)
{
struct clk_pd_notifier *cn;
int ret = -ENOMEM;
if (!clk || !nb)
return -EINVAL;
//clk_prepare_lock();
/* search the list of notifiers for this clk */
list_for_each_entry(cn, &clk_pd_notifier_list, node)
if (cn->clk == clk)
break;
/* if clk wasn't in the notifier list, allocate new clk_notifier */
if (cn->clk != clk) {
cn = kzalloc(sizeof(struct clk_pd_notifier), GFP_KERNEL);
if (!cn)
goto out;
cn->clk = clk;
srcu_init_notifier_head(&cn->notifier_head);
list_add(&cn->node, &clk_pd_notifier_list);
}
ret = srcu_notifier_chain_register(&cn->notifier_head, nb);
//clk->notifier_count++;
out:
//clk_prepare_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(rk_clk_pd_notifier_register);
int rk_clk_pd_notifier_unregister(struct clk *clk, struct notifier_block *nb)
{
struct clk_pd_notifier *cn = NULL;
int ret = -EINVAL;
if (!clk || !nb)
return -EINVAL;
//clk_prepare_lock();
list_for_each_entry(cn, &clk_pd_notifier_list, node)
if (cn->clk == clk)
break;
if (cn->clk == clk) {
ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
//clk->notifier_count--;
/* XXX the notifier code should handle this better */
if (!cn->notifier_head.head) {
srcu_cleanup_notifier_head(&cn->notifier_head);
list_del(&cn->node);
kfree(cn);
}
} else {
ret = -ENOENT;
}
//clk_prepare_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(rk_clk_pd_notifier_unregister);
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 = 0;
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)
{
int ret = 0;
__clk_pd_notify(hw->clk, RK_CLK_PD_PRE_ENABLE);
ret = clk_pd_endisable(hw, true);
__clk_pd_notify(hw->clk, RK_CLK_PD_POST_ENABLE);
return ret;
}
static void clk_pd_disable(struct clk_hw *hw)
{
__clk_pd_notify(hw->clk, RK_CLK_PD_PRE_DISABLE);
clk_pd_endisable(hw, false);
__clk_pd_notify(hw->clk, RK_CLK_PD_POST_DISABLE);
}
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);
}
static int clk_pd_prepare(struct clk_hw *hw)
{
__clk_pd_notify(hw->clk, RK_CLK_PD_PREPARE);
return 0;
}
static void clk_pd_unprepare(struct clk_hw *hw)
{
__clk_pd_notify(hw->clk, RK_CLK_PD_UNPREPARE);
}
const struct clk_ops clk_pd_ops = {
.prepare = clk_pd_prepare,
.unprepare = clk_pd_unprepare,
.enable = clk_pd_enable,
.disable = clk_pd_disable,
.is_enabled = clk_pd_is_enabled,
};
static int clk_pd_virt_enable(struct clk_hw *hw)
{
__clk_pd_notify(hw->clk, RK_CLK_PD_PRE_ENABLE);
__clk_pd_notify(hw->clk, RK_CLK_PD_POST_ENABLE);
return 0;
}
static void clk_pd_virt_disable(struct clk_hw *hw)
{
__clk_pd_notify(hw->clk, RK_CLK_PD_PRE_DISABLE);
__clk_pd_notify(hw->clk, RK_CLK_PD_POST_DISABLE);
}
const struct clk_ops clk_pd_virt_ops = {
.prepare = clk_pd_prepare,
.unprepare = clk_pd_unprepare,
.enable = clk_pd_virt_enable,
.disable = clk_pd_virt_disable,
};
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);
if(pd_id == CLK_PD_VIRT)
init.ops = &clk_pd_virt_ops;
else
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

@@ -1,40 +0,0 @@
#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);
#define RK_CLK_PD_PRE_ENABLE BIT(0)
#define RK_CLK_PD_POST_ENABLE BIT(1)
#define RK_CLK_PD_PRE_DISABLE BIT(2)
#define RK_CLK_PD_POST_DISABLE BIT(3)
#define RK_CLK_PD_PREPARE BIT(4)
#define RK_CLK_PD_UNPREPARE BIT(5)
struct clk_pd_notifier {
struct clk *clk;
struct srcu_notifier_head notifier_head;
struct list_head node;
};
int rk_clk_pd_notifier_register(struct clk *clk, struct notifier_block *nb);
int rk_clk_pd_notifier_unregister(struct clk *clk, struct notifier_block *nb);
#endif /* __RK_CLK_PD_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,498 +0,0 @@
#ifndef __RK_CLK_PLL_H
#define __RK_CLK_PLL_H
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/rockchip/cru.h>
#define CLK_LOOPS_JIFFY_REF (11996091ULL)
#define CLK_LOOPS_RATE_REF (1200UL) //Mhz
#define CLK_LOOPS_RECALC(rate) \
div_u64(CLK_LOOPS_JIFFY_REF*(rate),CLK_LOOPS_RATE_REF*MHZ)
#define CLK_DIV_PLUS_ONE_SET(i, shift, width) \
((((i)-1) << (shift)) | (((2<<(width)) - 1) << ((shift)+16)))
/*******************RK3188 PLL******************************/
#define RK3188_PLL_CON(i) ((i) * 4)
/*******************PLL WORK MODE*************************/
#define _RK3188_PLL_MODE_MSK 0x3
#define _RK3188_PLL_MODE_SLOW 0x0
#define _RK3188_PLL_MODE_NORM 0x1
#define _RK3188_PLL_MODE_DEEP 0x2
#define _RK3188_PLL_MODE_GET(offset, shift) \
((cru_readl(offset) >> (shift)) & _RK3188_PLL_MODE_MSK)
#define _RK3188_PLL_MODE_IS_SLOW(offset, shift) \
(_RK3188_PLL_MODE_GET(offset, shift) == _RK3188_PLL_MODE_SLOW)
#define _RK3188_PLL_MODE_IS_NORM(offset, shift) \
(_RK3188_PLL_MODE_GET(offset, shift) == _RK3188_PLL_MODE_NORM)
#define _RK3188_PLL_MODE_IS_DEEP(offset, shift) \
(_RK3188_PLL_MODE_GET(offset, shift) == _RK3188_PLL_MODE_DEEP)
#define _RK3188_PLL_MODE_SET(val, shift) \
((val) << (shift)) | CRU_W_MSK(shift, _RK3188_PLL_MODE_MSK)
#define _RK3188_PLL_MODE_SLOW_SET(shift) \
_RK3188_PLL_MODE_SET(_RK3188_PLL_MODE_SLOW, shift)
#define _RK3188_PLL_MODE_NORM_SET(shift) \
_RK3188_PLL_MODE_SET(_RK3188_PLL_MODE_NORM, shift)
#define _RK3188_PLL_MODE_DEEP_SET(shift) \
_RK3188_PLL_MODE_SET(_RK3188_PLL_MODE_DEEP, shift)
/*******************PLL OPERATION MODE*********************/
#define _RK3188_PLL_BYPASS_SHIFT 0
#define _RK3188_PLL_POWERDOWN_SHIFT 1
#define _RK3188PLUS_PLL_BYPASS_SHIFT 0
#define _RK3188PLUS_PLL_POWERDOWN_SHIFT 1
#define _RK3188PLUS_PLL_RESET_SHIFT 5
#define _RK3188_PLL_OP_SET(val, shift) \
((val) << (shift)) | CRU_W_MSK(shift, 1)
#define _RK3188_PLL_BYPASS_SET(val) \
_RK3188_PLL_OP_SET(val, _RK3188_PLL_BYPASS_SHIFT)
#define _RK3188_PLL_POWERDOWN_SET(val) \
_RK3188_PLL_OP_SET(val, _RK3188_PLL_POWERDOWN_SHIFT)
#define _RK3188PLUS_PLL_BYPASS_SET(val) \
_RK3188_PLL_OP_SET(val, _RK3188PLUS_PLL_BYPASS_SHIFT)
#define _RK3188PLUS_PLL_POWERDOWN_SET(val) \
_RK3188_PLL_OP_SET(val, _RK3188PLUS_PLL_POWERDOWN_SHIFT)
#define _RK3188PLUS_PLL_RESET_SET(val) \
_RK3188_PLL_OP_SET(val, _RK3188PLUS_PLL_RESET_SHIFT)
/*******************PLL CON0 BITS***************************/
#define RK3188_PLL_CLKFACTOR_SET(val, shift, msk) \
((((val) - 1) & (msk)) << (shift))
#define RK3188_PLL_CLKFACTOR_GET(reg, shift, msk) \
((((reg) >> (shift)) & (msk)) + 1)
#define RK3188_PLL_OD_MSK (0x3f)
#define RK3188_PLL_OD_SHIFT (0x0)
#define RK3188_PLL_CLKOD(val) RK3188_PLL_CLKFACTOR_SET(val, RK3188_PLL_OD_SHIFT, RK3188_PLL_OD_MSK)
#define RK3188_PLL_NO(reg) RK3188_PLL_CLKFACTOR_GET(reg, RK3188_PLL_OD_SHIFT, RK3188_PLL_OD_MSK)
#define RK3188_PLL_CLKOD_SET(val) (RK3188_PLL_CLKOD(val) | CRU_W_MSK(RK3188_PLL_OD_SHIFT, RK3188_PLL_OD_MSK))
#define RK3188_PLL_NR_MSK (0x3f)
#define RK3188_PLL_NR_SHIFT (8)
#define RK3188_PLL_CLKR(val) RK3188_PLL_CLKFACTOR_SET(val, RK3188_PLL_NR_SHIFT, RK3188_PLL_NR_MSK)
#define RK3188_PLL_NR(reg) RK3188_PLL_CLKFACTOR_GET(reg, RK3188_PLL_NR_SHIFT, RK3188_PLL_NR_MSK)
#define RK3188_PLL_CLKR_SET(val) (RK3188_PLL_CLKR(val) | CRU_W_MSK(RK3188_PLL_NR_SHIFT, RK3188_PLL_NR_MSK))
#define RK3188PLUS_PLL_OD_MSK (0xf)
#define RK3188PLUS_PLL_OD_SHIFT (0x0)
#define RK3188PLUS_PLL_CLKOD(val) RK3188_PLL_CLKFACTOR_SET(val, RK3188PLUS_PLL_OD_SHIFT, RK3188PLUS_PLL_OD_MSK)
#define RK3188PLUS_PLL_NO(reg) RK3188_PLL_CLKFACTOR_GET(reg, RK3188PLUS_PLL_OD_SHIFT, RK3188PLUS_PLL_OD_MSK)
#define RK3188PLUS_PLL_CLKOD_SET(val) (RK3188PLUS_PLL_CLKOD(val) | CRU_W_MSK(RK3188PLUS_PLL_OD_SHIFT, RK3188PLUS_PLL_OD_MSK))
#define RK3188PLUS_PLL_NR_MSK (0x3f)
#define RK3188PLUS_PLL_NR_SHIFT (8)
#define RK3188PLUS_PLL_CLKR(val) RK3188_PLL_CLKFACTOR_SET(val, RK3188PLUS_PLL_NR_SHIFT, RK3188PLUS_PLL_NR_MSK)
#define RK3188PLUS_PLL_NR(reg) RK3188_PLL_CLKFACTOR_GET(reg, RK3188PLUS_PLL_NR_SHIFT, RK3188PLUS_PLL_NR_MSK)
#define RK3188PLUS_PLL_CLKR_SET(val) (RK3188PLUS_PLL_CLKR(val) | CRU_W_MSK(RK3188PLUS_PLL_NR_SHIFT, RK3188PLUS_PLL_NR_MSK))
/*******************PLL CON1 BITS***************************/
#define RK3188_PLL_NF_MSK (0xffff)
#define RK3188_PLL_NF_SHIFT (0)
#define RK3188_PLL_CLKF(val) RK3188_PLL_CLKFACTOR_SET(val, RK3188_PLL_NF_SHIFT, RK3188_PLL_NF_MSK)
#define RK3188_PLL_NF(reg) RK3188_PLL_CLKFACTOR_GET(reg, RK3188_PLL_NF_SHIFT, RK3188_PLL_NF_MSK)
#define RK3188_PLL_CLKF_SET(val) (RK3188_PLL_CLKF(val) | CRU_W_MSK(RK3188_PLL_NF_SHIFT, RK3188_PLL_NF_MSK))
#define RK3188PLUS_PLL_NF_MSK (0x1fff)
#define RK3188PLUS_PLL_NF_SHIFT (0)
#define RK3188PLUS_PLL_CLKF(val) RK3188_PLL_CLKFACTOR_SET(val, RK3188PLUS_PLL_NF_SHIFT, RK3188PLUS_PLL_NF_MSK)
#define RK3188PLUS_PLL_NF(reg) RK3188_PLL_CLKFACTOR_GET(reg, RK3188PLUS_PLL_NF_SHIFT, RK3188PLUS_PLL_NF_MSK)
#define RK3188PLUS_PLL_CLKF_SET(val) (RK3188PLUS_PLL_CLKF(val) | CRU_W_MSK(RK3188PLUS_PLL_NF_SHIFT, RK3188PLUS_PLL_NF_MSK))
/*******************PLL CON2 BITS***************************/
#define RK3188_PLL_BWADJ_MSK (0xfff)
#define RK3188_PLL_BWADJ_SHIFT (0)
#define RK3188_PLL_CLK_BWADJ_SET(val) ((val) | CRU_W_MSK(RK3188_PLL_BWADJ_SHIFT, RK3188_PLL_BWADJ_MSK))
#define RK3188PLUS_PLL_BWADJ_MSK (0xfff)
#define RK3188PLUS_PLL_BWADJ_SHIFT (0)
#define RK3188PLUS_PLL_CLK_BWADJ_SET(val) ((val) | CRU_W_MSK(RK3188PLUS_PLL_BWADJ_SHIFT, RK3188PLUS_PLL_BWADJ_MSK))
/*******************PLL CON3 BITS***************************/
#define RK3188_PLL_RESET_MSK (1 << 5)
#define RK3188_PLL_RESET_W_MSK (RK3188_PLL_RESET_MSK << 16)
#define RK3188_PLL_RESET (1 << 5)
#define RK3188_PLL_RESET_RESUME (0 << 5)
#define RK3188_PLL_BYPASS_MSK (1 << 0)
#define RK3188_PLL_BYPASS (1 << 0)
#define RK3188_PLL_NO_BYPASS (0 << 0)
#define RK3188_PLL_PWR_DN_MSK (1 << 1)
#define RK3188_PLL_PWR_DN_W_MSK (RK3188_PLL_PWR_DN_MSK << 16)
#define RK3188_PLL_PWR_DN (1 << 1)
#define RK3188_PLL_PWR_ON (0 << 1)
#define RK3188_PLL_STANDBY_MSK (1 << 2)
#define RK3188_PLL_STANDBY (1 << 2)
#define RK3188_PLL_NO_STANDBY (0 << 2)
/*******************CLKSEL0 BITS***************************/
//core_preiph div
#define RK3188_CORE_PERIPH_W_MSK (3 << 22)
#define RK3188_CORE_PERIPH_MSK (3 << 6)
#define RK3188_CORE_PERIPH_2 (0 << 6)
#define RK3188_CORE_PERIPH_4 (1 << 6)
#define RK3188_CORE_PERIPH_8 (2 << 6)
#define RK3188_CORE_PERIPH_16 (3 << 6)
//clk_core
#define RK3188_CORE_SEL_PLL_MSK (1 << 8)
#define RK3188_CORE_SEL_PLL_W_MSK (1 << 24)
#define RK3188_CORE_SEL_APLL (0 << 8)
#define RK3188_CORE_SEL_GPLL (1 << 8)
#define RK3188_CORE_CLK_DIV_W_MSK (0x1F << 25)
#define RK3188_CORE_CLK_DIV_MSK (0x1F << 9)
#define RK3188_CORE_CLK_DIV(i) ((((i) - 1) & 0x1F) << 9)
#define RK3188_CORE_CLK_MAX_DIV 32
/*******************CLKSEL1 BITS***************************/
//aclk_core div
#define RK3188_CORE_ACLK_W_MSK (7 << 19)
#define RK3188_CORE_ACLK_MSK (7 << 3)
#define RK3188_CORE_ACLK_11 (0 << 3)
#define RK3188_CORE_ACLK_21 (1 << 3)
#define RK3188_CORE_ACLK_31 (2 << 3)
#define RK3188_CORE_ACLK_41 (3 << 3)
#define RK3188_CORE_ACLK_81 (4 << 3)
#define RK3188_GET_CORE_ACLK_VAL(reg) ((reg)>=4 ? 8:((reg)+1))
/*******************PLL SET*********************************/
#define _RK3188_PLL_SET_CLKS(_mhz, nr, nf, no) \
{ \
.rate = (_mhz) * KHZ, \
.pllcon0 = RK3188_PLL_CLKR_SET(nr)|RK3188_PLL_CLKOD_SET(no), \
.pllcon1 = RK3188_PLL_CLKF_SET(nf),\
.pllcon2 = RK3188_PLL_CLK_BWADJ_SET(nf >> 1),\
.rst_dly = ((nr*500)/24+1),\
}
#define _RK3188PLUS_PLL_SET_CLKS(_mhz, nr, nf, no) \
{ \
.rate = (_mhz) * KHZ, \
.pllcon0 = RK3188PLUS_PLL_CLKR_SET(nr)|RK3188PLUS_PLL_CLKOD_SET(no), \
.pllcon1 = RK3188PLUS_PLL_CLKF_SET(nf),\
.pllcon2 = RK3188PLUS_PLL_CLK_BWADJ_SET(nf >> 1),\
.rst_dly = ((nr*500)/24+1),\
}
#define _RK3188PLUS_PLL_SET_CLKS_NB(_mhz, nr, nf, no, nb) \
{ \
.rate = (_mhz) * KHZ, \
.pllcon0 = RK3188PLUS_PLL_CLKR_SET(nr)|RK3188PLUS_PLL_CLKOD_SET(no), \
.pllcon1 = RK3188PLUS_PLL_CLKF_SET(nf),\
.pllcon2 = RK3188PLUS_PLL_CLK_BWADJ_SET(nb-1),\
.rst_dly = ((nr*500)/24+1),\
}
#define _RK3188_APLL_SET_CLKS(_mhz, nr, nf, no, _periph_div, _aclk_div) \
{ \
.rate = _mhz * MHZ, \
.pllcon0 = RK3188_PLL_CLKR_SET(nr) | RK3188_PLL_CLKOD_SET(no), \
.pllcon1 = RK3188_PLL_CLKF_SET(nf),\
.pllcon2 = RK3188_PLL_CLK_BWADJ_SET(nf >> 1),\
.rst_dly = ((nr*500)/24+1),\
.clksel0 = RK3188_CORE_PERIPH_W_MSK | RK3188_CORE_PERIPH_##_periph_div,\
.clksel1 = RK3188_CORE_ACLK_W_MSK | RK3188_CORE_ACLK_##_aclk_div,\
.lpj = (CLK_LOOPS_JIFFY_REF*_mhz) / CLK_LOOPS_RATE_REF,\
}
/*******************RK3288 PLL***********************************/
/*******************CLKSEL0 BITS***************************/
#define RK3288_CORE_SEL_PLL_W_MSK (1 << 31)
#define RK3288_CORE_SEL_APLL (0 << 15)
#define RK3288_CORE_SEL_GPLL (1 << 15)
#define RK3288_CORE_CLK_SHIFT 8
#define RK3288_CORE_CLK_WIDTH 5
#define RK3288_CORE_CLK_DIV(i) \
CLK_DIV_PLUS_ONE_SET(i, RK3288_CORE_CLK_SHIFT, RK3288_CORE_CLK_WIDTH)
#define RK3288_CORE_CLK_MAX_DIV (2<<RK3288_CORE_CLK_WIDTH)
#define RK3288_ACLK_M0_SHIFT 0
#define RK3288_ACLK_M0_WIDTH 4
#define RK3288_ACLK_M0_DIV(i) \
CLK_DIV_PLUS_ONE_SET(i, RK3288_ACLK_M0_SHIFT, RK3288_ACLK_M0_WIDTH)
#define RK3288_ACLK_MP_SHIFT 4
#define RK3288_ACLK_MP_WIDTH 4
#define RK3288_ACLK_MP_DIV(i) \
CLK_DIV_PLUS_ONE_SET(i, RK3288_ACLK_MP_SHIFT, RK3288_ACLK_MP_WIDTH)
/*******************CLKSEL37 BITS***************************/
#define RK3288_CLK_L2RAM_SHIFT 0
#define RK3288_CLK_L2RAM_WIDTH 3
#define RK3288_CLK_L2RAM_DIV(i) \
CLK_DIV_PLUS_ONE_SET(i, RK3288_CLK_L2RAM_SHIFT, RK3288_CLK_L2RAM_WIDTH)
#define RK3288_ATCLK_SHIFT 4
#define RK3288_ATCLK_WIDTH 5
#define RK3288_ATCLK_DIV(i) \
CLK_DIV_PLUS_ONE_SET(i, RK3288_ATCLK_SHIFT, RK3288_ATCLK_WIDTH)
#define RK3288_PCLK_DBG_SHIFT 9
#define RK3288_PCLK_DBG_WIDTH 5
#define RK3288_PCLK_DBG_DIV(i) \
CLK_DIV_PLUS_ONE_SET(i, RK3288_PCLK_DBG_SHIFT, RK3288_PCLK_DBG_WIDTH)
#define _RK3288_APLL_SET_CLKS(_mhz, nr, nf, no, l2_div, m0_div, mp_div, atclk_div, pclk_dbg_div) \
{ \
.rate = _mhz * MHZ, \
.pllcon0 = RK3188PLUS_PLL_CLKR_SET(nr) | RK3188PLUS_PLL_CLKOD_SET(no), \
.pllcon1 = RK3188PLUS_PLL_CLKF_SET(nf),\
.pllcon2 = RK3188PLUS_PLL_CLK_BWADJ_SET(nf >> 1),\
.rst_dly = ((nr*500)/24+1),\
.clksel0 = RK3288_ACLK_M0_DIV(m0_div) | RK3288_ACLK_MP_DIV(mp_div),\
.clksel1 = RK3288_CLK_L2RAM_DIV(l2_div) | RK3288_ATCLK_DIV(atclk_div) | RK3288_PCLK_DBG_DIV(pclk_dbg_div),\
.lpj = (CLK_LOOPS_JIFFY_REF*_mhz) / CLK_LOOPS_RATE_REF,\
}
/***************************RK3036 PLL**************************************/
#define LPJ_24M (CLK_LOOPS_JIFFY_REF * 24) / CLK_LOOPS_RATE_REF
/*PLL_CON 0,1,2*/
#define RK3036_PLL_PWR_ON (0)
#define RK3036_PLL_PWR_DN (1)
#define RK3036_PLL_BYPASS (1 << 15)
#define RK3036_PLL_NO_BYPASS (0 << 15)
/*con0*/
#define RK3036_PLL_BYPASS_SHIFT (15)
#define RK3036_PLL_POSTDIV1_MASK (0x7)
#define RK3036_PLL_POSTDIV1_SHIFT (12)
#define RK3036_PLL_FBDIV_MASK (0xfff)
#define RK3036_PLL_FBDIV_SHIFT (0)
/*con1*/
#define RK3036_PLL_RSTMODE_SHIFT (15)
#define RK3036_PLL_RST_SHIFT (14)
#define RK3036_PLL_PWR_DN_SHIFT (13)
#define RK3036_PLL_DSMPD_SHIFT (12)
#define RK3036_PLL_LOCK_SHIFT (10)
#define RK3036_PLL_POSTDIV2_MASK (0x7)
#define RK3036_PLL_POSTDIV2_SHIFT (6)
#define RK3036_PLL_REFDIV_MASK (0x3f)
#define RK3036_PLL_REFDIV_SHIFT (0)
/*con2*/
#define RK3036_PLL_FOUT4PHASE_PWR_DN_SHIFT (27)
#define RK3036_PLL_FOUTVCO_PWR_DN_SHIFT (26)
#define RK3036_PLL_FOUTPOSTDIV_PWR_DN_SHIFT (25)
#define RK3036_PLL_DAC_PWR_DN_SHIFT (24)
#define RK3036_PLL_FRAC_MASK (0xffffff)
#define RK3036_PLL_FRAC_SHIFT (0)
#define CRU_GET_REG_BIT_VAL(reg, bits_shift) (((reg) >> (bits_shift)) & (0x1))
#define CRU_GET_REG_BITS_VAL(reg, bits_shift, msk) (((reg) >> (bits_shift)) & (msk))
#define CRU_SET_BIT(val, bits_shift) (((val) & (0x1)) << (bits_shift))
#define CRU_W_MSK(bits_shift, msk) ((msk) << ((bits_shift) + 16))
#define CRU_W_MSK_SETBITS(val, bits_shift, msk) (CRU_W_MSK(bits_shift, msk) \
| CRU_SET_BITS(val, bits_shift, msk))
#define CRU_W_MSK_SETBIT(val, bits_shift) (CRU_W_MSK(bits_shift, 0x1) \
| CRU_SET_BIT(val, bits_shift))
#define RK3036_PLL_SET_REFDIV(val) CRU_W_MSK_SETBITS(val, RK3036_PLL_REFDIV_SHIFT, RK3036_PLL_REFDIV_MASK)
#define RK3036_PLL_SET_FBDIV(val) CRU_W_MSK_SETBITS(val, RK3036_PLL_FBDIV_SHIFT, RK3036_PLL_FBDIV_MASK)
#define RK3036_PLL_SET_POSTDIV1(val) CRU_W_MSK_SETBITS(val, RK3036_PLL_POSTDIV1_SHIFT, RK3036_PLL_POSTDIV1_MASK)
#define RK3036_PLL_SET_POSTDIV2(val) CRU_W_MSK_SETBITS(val, RK3036_PLL_POSTDIV2_SHIFT, RK3036_PLL_POSTDIV2_MASK)
#define RK3036_PLL_SET_FRAC(val) CRU_SET_BITS(val, RK3036_PLL_FRAC_SHIFT, RK3036_PLL_FRAC_MASK)
#define RK3036_PLL_GET_REFDIV(reg) CRU_GET_REG_BITS_VAL(reg, RK3036_PLL_REFDIV_SHIFT, RK3036_PLL_REFDIV_MASK)
#define RK3036_PLL_GET_FBDIV(reg) CRU_GET_REG_BITS_VAL(reg, RK3036_PLL_FBDIV_SHIFT, RK3036_PLL_FBDIV_MASK)
#define RK3036_PLL_GET_POSTDIV1(reg) CRU_GET_REG_BITS_VAL(reg, RK3036_PLL_POSTDIV1_SHIFT, RK3036_PLL_POSTDIV1_MASK)
#define RK3036_PLL_GET_POSTDIV2(reg) CRU_GET_REG_BITS_VAL(reg, RK3036_PLL_POSTDIV2_SHIFT, RK3036_PLL_POSTDIV2_MASK)
#define RK3036_PLL_GET_FRAC(reg) CRU_GET_REG_BITS_VAL(reg, RK3036_PLL_FRAC_SHIFT, RK3036_PLL_FRAC_MASK)
/*#define APLL_SET_BYPASS(val) CRU_SET_BIT(val, PLL_BYPASS_SHIFT)*/
#define RK3036_PLL_SET_DSMPD(val) CRU_W_MSK_SETBIT(val, RK3036_PLL_DSMPD_SHIFT)
#define RK3036_PLL_GET_DSMPD(reg) CRU_GET_REG_BIT_VAL(reg, RK3036_PLL_DSMPD_SHIFT)
/*******************CLKSEL0 BITS***************************/
#define RK3036_CLK_SET_DIV_CON_SUB1(val, bits_shift, msk) CRU_W_MSK_SETBITS((val - 1), bits_shift, msk)
#define RK3036_CPU_CLK_PLL_SEL_SHIFT (14)
#define RK3036_CPU_CLK_PLL_SEL_MASK (0x3)
#define RK3036_CORE_CLK_PLL_SEL_SHIFT (7)
#define RK3036_SEL_APLL (0)
#define RK3036_SEL_GPLL (1)
#define RK3036_CPU_SEL_PLL(plls) CRU_W_MSK_SETBITS(plls, RK3036_CPU_CLK_PLL_SEL_SHIFT, RK3036_CPU_CLK_PLL_SEL_MASK)
#define RK3036_CORE_SEL_PLL(plls) CRU_W_MSK_SETBIT(plls, RK3036_CORE_CLK_PLL_SEL_SHIFT)
#define RK3036_ACLK_CPU_DIV_MASK (0x1f)
#define RK3036_ACLK_CPU_DIV_SHIFT (8)
#define RK3036_A9_CORE_DIV_MASK (0x1f)
#define RK3036_A9_CORE_DIV_SHIFT (0)
#define RATIO_11 (1)
#define RATIO_21 (2)
#define RATIO_41 (4)
#define RATIO_81 (8)
#define RK3036_ACLK_CPU_DIV(val) RK3036_CLK_SET_DIV_CON_SUB1(val, RK3036_ACLK_CPU_DIV_SHIFT, RK3036_ACLK_CPU_DIV_MASK)
#define RK3036_CLK_CORE_DIV(val) RK3036_CLK_SET_DIV_CON_SUB1(val, RK3036_A9_CORE_DIV_SHIFT, RK3036_A9_CORE_DIV_MASK)
/*******************CLKSEL1 BITS***************************/
#define RK3036_PCLK_CPU_DIV_MASK (0x7)
#define RK3036_PCLK_CPU_DIV_SHIFT (12)
#define RK3036_HCLK_CPU_DIV_MASK (0x3)
#define RK3036_HCLK_CPU_DIV_SHIFT (8)
#define RK3036_ACLK_CORE_DIV_MASK (0x7)
#define RK3036_ACLK_CORE_DIV_SHIFT (4)
#define RK3036_CORE_PERIPH_DIV_MASK (0xf)
#define RK3036_CORE_PERIPH_DIV_SHIFT (0)
#define RK3036_PCLK_CPU_DIV(val) RK3036_CLK_SET_DIV_CON_SUB1(val, RK3036_PCLK_CPU_DIV_SHIFT, RK3036_PCLK_CPU_DIV_MASK)
#define RK3036_HCLK_CPU_DIV(val) RK3036_CLK_SET_DIV_CON_SUB1(val, RK3036_HCLK_CPU_DIV_SHIFT, RK3036_HCLK_CPU_DIV_MASK)
#define RK3036_ACLK_CORE_DIV(val) RK3036_CLK_SET_DIV_CON_SUB1(val, RK3036_ACLK_CORE_DIV_SHIFT, RK3036_ACLK_CORE_DIV_MASK)
#define RK3036_CLK_CORE_PERI_DIV(val) RK3036_CLK_SET_DIV_CON_SUB1(val, RK3036_CORE_PERIPH_DIV_SHIFT, RK3036_CORE_PERIPH_DIV_MASK)
/*******************clksel10***************************/
#define RK3036_PERI_PLL_SEL_SHIFT 14
#define RK3036_PERI_PLL_SEL_MASK (0x3)
#define RK3036_PERI_PCLK_DIV_MASK (0x3)
#define RK3036_PERI_PCLK_DIV_SHIFT (12)
#define RK3036_PERI_HCLK_DIV_MASK (0x3)
#define RK3036_PERI_HCLK_DIV_SHIFT (8)
#define RK3036_PERI_ACLK_DIV_MASK (0x1f)
#define RK3036_PERI_ACLK_DIV_SHIFT (0)
#define RK3036_SEL_3PLL_APLL (0)
#define RK3036_SEL_3PLL_DPLL (1)
#define RK3036_SEL_3PLL_GPLL (2)
#define RK3036_PERI_CLK_SEL_PLL(plls) CRU_W_MSK_SETBITS(plls, RK3036_PERI_PLL_SEL_SHIFT, RK3036_PERI_PLL_SEL_MASK)
#define RK3036_PERI_SET_ACLK_DIV(val) RK3036_CLK_SET_DIV_CON_SUB1(val, RK3036_PERI_ACLK_DIV_SHIFT, RK3036_PERI_ACLK_DIV_MASK)
/*******************gate BITS***************************/
#define RK3036_CLK_GATE_CLKID_CONS(i) RK3036_CRU_CLKGATES_CON((i) / 16)
#define RK3036_CLK_GATE(i) (1 << ((i)%16))
#define RK3036_CLK_UN_GATE(i) (0)
#define RK3036_CLK_GATE_W_MSK(i) (1 << (((i) % 16) + 16))
#define RK3036_CLK_GATE_CLKID(i) (16 * (i))
#define _RK3036_APLL_SET_CLKS(_mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac, \
_periph_div) \
{ \
.rate = (_mhz) * MHZ, \
.pllcon0 = RK3036_PLL_SET_POSTDIV1(_postdiv1) | RK3036_PLL_SET_FBDIV(_fbdiv), \
.pllcon1 = RK3036_PLL_SET_DSMPD(_dsmpd) | RK3036_PLL_SET_POSTDIV2(_postdiv2) | RK3036_PLL_SET_REFDIV(_refdiv), \
.pllcon2 = RK3036_PLL_SET_FRAC(_frac), \
.clksel1 = RK3036_CLK_CORE_PERI_DIV(RATIO_##_periph_div), \
.lpj = (CLK_LOOPS_JIFFY_REF * _mhz) / CLK_LOOPS_RATE_REF, \
.rst_dly = 0,\
}
#define _RK3036_PLL_SET_CLKS(_mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac) \
{ \
.rate = (_mhz) * KHZ, \
.pllcon0 = RK3036_PLL_SET_POSTDIV1(_postdiv1) | RK3036_PLL_SET_FBDIV(_fbdiv), \
.pllcon1 = RK3036_PLL_SET_DSMPD(_dsmpd) | RK3036_PLL_SET_POSTDIV2(_postdiv2) | RK3036_PLL_SET_REFDIV(_refdiv), \
.pllcon2 = RK3036_PLL_SET_FRAC(_frac), \
}
/***************************RK3368 PLL**************************************/
/*******************CLKSEL0/2 BITS***************************/
#define RK3368_CORE_SEL_PLL_W_MSK (1 << 23)
#define RK3368_CORE_SEL_APLL (0 << 7)
#define RK3368_CORE_SEL_GPLL (1 << 7)
#define RK3368_CORE_CLK_SHIFT 0
#define RK3368_CORE_CLK_WIDTH 5
#define RK3368_CORE_CLK_DIV(i) \
CLK_DIV_PLUS_ONE_SET(i, RK3368_CORE_CLK_SHIFT, RK3368_CORE_CLK_WIDTH)
#define RK3368_CORE_CLK_MAX_DIV (2<<RK3368_CORE_CLK_WIDTH)
#define RK3368_ACLKM_CORE_SHIFT 8
#define RK3368_ACLKM_CORE_WIDTH 5
#define RK3368_ACLKM_CORE_DIV(i) \
CLK_DIV_PLUS_ONE_SET(i, RK3368_ACLKM_CORE_SHIFT, RK3368_ACLKM_CORE_WIDTH)
/*******************CLKSEL1/3 BITS***************************/
#define RK3368_ATCLK_CORE_SHIFT 0
#define RK3368_ATCLK_CORE_WIDTH 5
#define RK3368_ATCLK_CORE_DIV(i) \
CLK_DIV_PLUS_ONE_SET(i, RK3368_ATCLK_CORE_SHIFT, RK3368_ATCLK_CORE_WIDTH)
#define RK3368_PCLK_DBG_SHIFT 8
#define RK3368_PCLK_DBG_WIDTH 5
#define RK3368_PCLK_DBG_DIV(i) \
CLK_DIV_PLUS_ONE_SET(i, RK3368_PCLK_DBG_SHIFT, RK3368_PCLK_DBG_WIDTH)
#define _RK3368_APLL_SET_CLKS(_mhz, nr, nf, no, aclkm_div, atclk_div, pclk_dbg_div) \
{ \
.rate = _mhz * MHZ, \
.pllcon0 = RK3188PLUS_PLL_CLKR_SET(nr) | RK3188PLUS_PLL_CLKOD_SET(no), \
.pllcon1 = RK3188PLUS_PLL_CLKF_SET(nf),\
.pllcon2 = RK3188PLUS_PLL_CLK_BWADJ_SET(nf >> 1),\
.rst_dly = ((nr*500)/24+1),\
.clksel0 = RK3368_ACLKM_CORE_DIV(aclkm_div),\
.clksel1 = RK3368_ATCLK_CORE_DIV(atclk_div) | RK3368_PCLK_DBG_DIV(pclk_dbg_div) \
}
struct pll_clk_set {
unsigned long rate;
u32 pllcon0;
u32 pllcon1;
u32 pllcon2;
unsigned long rst_dly;//us
};
struct apll_clk_set {
unsigned long rate;
u32 pllcon0;
u32 pllcon1;
u32 pllcon2;
u32 rst_dly;//us
u32 clksel0;
u32 clksel1;
unsigned long lpj;
};
#define to_clk_pll(_hw) container_of(_hw, struct clk_pll, hw)
struct clk_pll {
struct clk_hw hw;
u32 reg;
u32 width;
u32 mode_offset;
u8 mode_shift;
u32 status_offset;
u8 status_shift;
u32 flags;
const void *table;
spinlock_t *lock;
};
const struct clk_ops *rk_get_pll_ops(u32 pll_flags);
struct clk *rk_clk_register_pll(struct device *dev, const char *name,
const char *parent_name, unsigned long flags, u32 reg,
u32 width, u32 mode_offset, u8 mode_shift,
u32 status_offset, u8 status_shift, u32 pll_flags,
spinlock_t *lock);
#endif /* __RK_CLK_PLL_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,302 +0,0 @@
/*
* Power domain support for Rockchip RK3368
*
* Copyright (C) 2014-2015 ROCKCHIP, Inc.
*
* 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/of.h>
#include <linux/of_address.h>
#include <linux/rockchip/pmu.h>
#include <linux/rockchip/cru.h>
#include <linux/rockchip/cpu_axi.h>
#include "clk-ops.h"
static void __iomem *rk_pmu_base;
static u32 pmu_readl(u32 offset)
{
return readl_relaxed(rk_pmu_base + (offset));
}
static void pmu_writel(u32 val, u32 offset)
{
writel_relaxed(val, rk_pmu_base + (offset));
dsb(sy);
}
static const u8 pmu_pd_map[] = {
[PD_PERI] = 13,
[PD_VIDEO] = 14,
[PD_VIO] = 15,
[PD_GPU_0] = 16,
[PD_GPU_1] = 17,
};
static const u8 pmu_st_map[] = {
[PD_PERI] = 12,
[PD_VIDEO] = 13,
[PD_VIO] = 14,
[PD_GPU_0] = 15,
[PD_GPU_1] = 16,
};
static bool rk3368_pmu_power_domain_is_on(enum pmu_power_domain pd)
{
/* 1'b0: power on, 1'b1: power off */
return !(pmu_readl(RK3368_PMU_PWRDN_ST) & BIT(pmu_st_map[pd]));
}
static DEFINE_SPINLOCK(pmu_idle_lock);
static const u8 pmu_idle_map[] = {
[IDLE_REQ_GPU] = 2,
[IDLE_REQ_BUS] = 4,
[IDLE_REQ_PERI] = 6,
[IDLE_REQ_VIDEO] = 7,
[IDLE_REQ_VIO] = 8,
};
static int rk3368_pmu_set_idle_request(enum pmu_idle_req req, bool idle)
{
u32 bit = pmu_idle_map[req];
u32 idle_mask = BIT(bit) | BIT(bit + 16);
u32 idle_target = (idle << bit) | (idle << (bit + 16));
u32 mask = BIT(bit);
u32 val;
unsigned long flags;
spin_lock_irqsave(&pmu_idle_lock, flags);
val = pmu_readl(RK3368_PMU_IDLE_REQ);
if (idle)
val |= mask;
else
val &= ~mask;
pmu_writel(val, RK3368_PMU_IDLE_REQ);
dsb(sy);
while ((pmu_readl(RK3368_PMU_IDLE_ST) & idle_mask) != idle_target)
;
spin_unlock_irqrestore(&pmu_idle_lock, flags);
return 0;
}
static DEFINE_SPINLOCK(pmu_pd_lock);
static noinline void rk3368_do_pmu_set_power_domain
(enum pmu_power_domain domain, bool on)
{
u8 pd = pmu_pd_map[domain];
u32 val = pmu_readl(RK3368_PMU_PWRDN_CON);
if (on)
val &= ~BIT(pd);
else
val |= BIT(pd);
pmu_writel(val, RK3368_PMU_PWRDN_CON);
dsb(sy);
while ((pmu_readl(RK3368_PMU_PWRDN_ST) & BIT(pmu_st_map[domain])) == on)
;
}
/* PD_VIO */
static void __iomem *iep_qos_base;
static u32 iep_qos[CPU_AXI_QOS_NUM_REGS];
static void __iomem *isp_r0_qos_base;
static u32 isp_r0_qos[CPU_AXI_QOS_NUM_REGS];
static void __iomem *isp_r1_qos_base;
static u32 isp_r1_qos[CPU_AXI_QOS_NUM_REGS];
static void __iomem *isp_w0_qos_base;
static u32 isp_w0_qos[CPU_AXI_QOS_NUM_REGS];
static void __iomem *isp_w1_qos_base;
static u32 isp_w1_qos[CPU_AXI_QOS_NUM_REGS];
static void __iomem *vip_qos_base;
static u32 vip_qos[CPU_AXI_QOS_NUM_REGS];
static void __iomem *vop_qos_base;
static u32 vop_qos[CPU_AXI_QOS_NUM_REGS];
static void __iomem *rga_r_qos_base;
static u32 rga_r_qos[CPU_AXI_QOS_NUM_REGS];
static void __iomem *rga_w_qos_base;
static u32 rga_w_qos[CPU_AXI_QOS_NUM_REGS];
/* PD_VIDEO */
static void __iomem *hevc_r_qos_base;
static u32 hevc_r_qos[CPU_AXI_QOS_NUM_REGS];
static void __iomem *vpu_r_qos_base;
static u32 vpu_r_qos[CPU_AXI_QOS_NUM_REGS];
static void __iomem *vpu_w_qos_base;
static u32 vpu_w_qos[CPU_AXI_QOS_NUM_REGS];
/* PD_GPU_0 */
static void __iomem *gpu_qos_base;
static u32 gpu_qos[CPU_AXI_QOS_NUM_REGS];
/* PD_PERI */
static void __iomem *peri_qos_base;
static u32 peri_qos[CPU_AXI_QOS_NUM_REGS];
#define PD_SAVE_QOS(name) CPU_AXI_SAVE_QOS(name##_qos, name##_qos_base)
#define PD_RESTORE_QOS(name) CPU_AXI_RESTORE_QOS(name##_qos, name##_qos_base)
static int rk3368_pmu_set_power_domain(enum pmu_power_domain pd, bool on)
{
unsigned long flags;
spin_lock_irqsave(&pmu_pd_lock, flags);
if (rk3368_pmu_power_domain_is_on(pd) == on)
goto out;
if (!on) {
/* if power down, idle request to NIU first */
if (pd == PD_VIO) {
PD_SAVE_QOS(iep);
PD_SAVE_QOS(isp_r0);
PD_SAVE_QOS(isp_r1);
PD_SAVE_QOS(isp_w0);
PD_SAVE_QOS(isp_w1);
PD_SAVE_QOS(vip);
PD_SAVE_QOS(vop);
PD_SAVE_QOS(rga_r);
PD_SAVE_QOS(rga_w);
rk3368_pmu_set_idle_request(IDLE_REQ_VIO, true);
} else if (pd == PD_VIDEO) {
PD_SAVE_QOS(hevc_r);
PD_SAVE_QOS(vpu_r);
PD_SAVE_QOS(vpu_w);
rk3368_pmu_set_idle_request(IDLE_REQ_VIDEO, true);
} else if (pd == PD_GPU_0) {
PD_SAVE_QOS(gpu);
rk3368_pmu_set_idle_request(IDLE_REQ_GPU, true);
} else if (pd == PD_PERI) {
PD_SAVE_QOS(peri);
rk3368_pmu_set_idle_request(IDLE_REQ_PERI, true);
}
}
rk3368_do_pmu_set_power_domain(pd, on);
if (on) {
/* if power up, idle request release to NIU */
if (pd == PD_VIO) {
rk3368_pmu_set_idle_request(IDLE_REQ_VIO, false);
PD_RESTORE_QOS(iep);
PD_RESTORE_QOS(isp_r0);
PD_RESTORE_QOS(isp_r1);
PD_RESTORE_QOS(isp_w0);
PD_RESTORE_QOS(isp_w1);
PD_RESTORE_QOS(vip);
PD_RESTORE_QOS(vop);
PD_RESTORE_QOS(rga_r);
PD_RESTORE_QOS(rga_w);
} else if (pd == PD_VIDEO) {
rk3368_pmu_set_idle_request(IDLE_REQ_VIDEO, false);
PD_RESTORE_QOS(hevc_r);
PD_RESTORE_QOS(vpu_r);
PD_RESTORE_QOS(vpu_w);
} else if (pd == PD_GPU_0) {
rk3368_pmu_set_idle_request(IDLE_REQ_GPU, false);
PD_RESTORE_QOS(gpu);
} else if (pd == PD_PERI) {
rk3368_pmu_set_idle_request(IDLE_REQ_PERI, false);
PD_RESTORE_QOS(peri);
}
}
out:
spin_unlock_irqrestore(&pmu_pd_lock, flags);
return 0;
}
static int rk3368_sys_set_power_domain(enum pmu_power_domain pd, bool on)
{
u32 clks_ungating[RK3368_CRU_CLKGATES_CON_CNT];
u32 clks_save[RK3368_CRU_CLKGATES_CON_CNT];
u32 i, ret;
for (i = 0; i < RK3368_CRU_CLKGATES_CON_CNT; i++) {
clks_save[i] = cru_readl(RK3368_CRU_CLKGATES_CON(i));
clks_ungating[i] = 0;
}
for (i = 0; i < RK3368_CRU_CLKGATES_CON_CNT; i++)
cru_writel(0xffff0000, RK3368_CRU_CLKGATES_CON(i));
ret = rk3368_pmu_set_power_domain(pd, on);
for (i = 0; i < RK3368_CRU_CLKGATES_CON_CNT; i++)
cru_writel(clks_save[i] | 0xffff0000,
RK3368_CRU_CLKGATES_CON(i));
return ret;
}
static int __init rk3368_init_rockchip_pmu_ops(void)
{
struct device_node *node, *gp, *cp;
node = of_find_compatible_node(NULL, NULL, "rockchip,rk3368-pmu");
if (!node) {
pr_err("%s: could not find pmu dt node\n", __func__);
return -ENODEV;
}
rk_pmu_base = of_iomap(node, 0);
if (!rk_pmu_base) {
pr_err("%s: could not map pmu registers\n", __func__);
return -ENXIO;
}
node = of_find_compatible_node(NULL, NULL, "rockchip,cpu_axi_bus");
if (!node)
return -ENODEV;
#define MAP(name) \
do { \
cp = of_get_child_by_name(gp, #name); \
if (cp) \
name##_qos_base = of_iomap(cp, 0); \
if (!name##_qos_base) \
pr_err("%s: could not map qos %s register\n", \
__func__, #name); \
} while (0)
gp = of_get_child_by_name(node, "qos");
if (gp) {
MAP(peri);
MAP(iep);
MAP(isp_r0);
MAP(isp_r1);
MAP(isp_w0);
MAP(isp_w1);
MAP(vip);
MAP(vop);
MAP(rga_r);
MAP(rga_w);
MAP(hevc_r);
MAP(vpu_r);
MAP(vpu_w);
MAP(gpu);
}
#undef MAP
rockchip_pmu_ops.set_power_domain = rk3368_sys_set_power_domain;
rockchip_pmu_ops.power_domain_is_on = rk3368_pmu_power_domain_is_on;
return 0;
}
arch_initcall(rk3368_init_rockchip_pmu_ops);

View File

@@ -1,128 +0,0 @@
#ifndef __CPU_AXI_H
#define __CPU_AXI_H
#define CPU_AXI_QOS_PRIORITY 0x08
#define CPU_AXI_QOS_MODE 0x0c
#define CPU_AXI_QOS_BANDWIDTH 0x10
#define CPU_AXI_QOS_SATURATION 0x14
#define CPU_AXI_QOS_EXTCONTROL 0x18
#define CPU_AXI_QOS_MODE_NONE 0
#define CPU_AXI_QOS_MODE_FIXED 1
#define CPU_AXI_QOS_MODE_LIMITER 2
#define CPU_AXI_QOS_MODE_REGULATOR 3
#define CPU_AXI_QOS_PRIORITY_LEVEL(h, l) \
((((h) & 3) << 8) | (((h) & 3) << 2) | ((l) & 3))
#define CPU_AXI_SET_QOS_PRIORITY(h, l, base) \
writel_relaxed(CPU_AXI_QOS_PRIORITY_LEVEL(h, l), base + CPU_AXI_QOS_PRIORITY)
#define CPU_AXI_SET_QOS_MODE(mode, base) \
writel_relaxed((mode) & 3, base + CPU_AXI_QOS_MODE)
#define CPU_AXI_SET_QOS_BANDWIDTH(bandwidth, base) \
writel_relaxed((bandwidth) & 0x7ff, base + CPU_AXI_QOS_BANDWIDTH)
#define CPU_AXI_SET_QOS_SATURATION(saturation, base) \
writel_relaxed((saturation) & 0x3ff, base + CPU_AXI_QOS_SATURATION)
#define CPU_AXI_SET_QOS_EXTCONTROL(extcontrol, base) \
writel_relaxed((extcontrol) & 7, base + CPU_AXI_QOS_EXTCONTROL)
#define CPU_AXI_QOS_NUM_REGS 5
#define CPU_AXI_SAVE_QOS(array, base) do { \
array[0] = readl_relaxed(base + CPU_AXI_QOS_PRIORITY); \
array[1] = readl_relaxed(base + CPU_AXI_QOS_MODE); \
array[2] = readl_relaxed(base + CPU_AXI_QOS_BANDWIDTH); \
array[3] = readl_relaxed(base + CPU_AXI_QOS_SATURATION); \
array[4] = readl_relaxed(base + CPU_AXI_QOS_EXTCONTROL); \
} while (0)
#define CPU_AXI_RESTORE_QOS(array, base) do { \
writel_relaxed(array[0], base + CPU_AXI_QOS_PRIORITY); \
writel_relaxed(array[1], base + CPU_AXI_QOS_MODE); \
writel_relaxed(array[2], base + CPU_AXI_QOS_BANDWIDTH); \
writel_relaxed(array[3], base + CPU_AXI_QOS_SATURATION); \
writel_relaxed(array[4], base + CPU_AXI_QOS_EXTCONTROL); \
} while (0)
#define RK3188_CPU_AXI_DMAC_QOS_VIRT (RK_CPU_AXI_BUS_VIRT + 0x1000)
#define RK3188_CPU_AXI_CPU0_QOS_VIRT (RK_CPU_AXI_BUS_VIRT + 0x2000)
#define RK3188_CPU_AXI_CPU1R_QOS_VIRT (RK_CPU_AXI_BUS_VIRT + 0x2080)
#define RK3188_CPU_AXI_CPU1W_QOS_VIRT (RK_CPU_AXI_BUS_VIRT + 0x2100)
#define RK3188_CPU_AXI_PERI_QOS_VIRT (RK_CPU_AXI_BUS_VIRT + 0x4000)
#define RK3188_CPU_AXI_GPU_QOS_VIRT (RK_CPU_AXI_BUS_VIRT + 0x5000)
#define RK3188_CPU_AXI_VPU_QOS_VIRT (RK_CPU_AXI_BUS_VIRT + 0x6000)
#define RK3188_CPU_AXI_LCDC0_QOS_VIRT (RK_CPU_AXI_BUS_VIRT + 0x7000)
#define RK3188_CPU_AXI_CIF0_QOS_VIRT (RK_CPU_AXI_BUS_VIRT + 0x7080)
#define RK3188_CPU_AXI_IPP_QOS_VIRT (RK_CPU_AXI_BUS_VIRT + 0x7100)
#define RK3188_CPU_AXI_LCDC1_QOS_VIRT (RK_CPU_AXI_BUS_VIRT + 0x7180)
#define RK3188_CPU_AXI_CIF1_QOS_VIRT (RK_CPU_AXI_BUS_VIRT + 0x7200)
#define RK3188_CPU_AXI_RGA_QOS_VIRT (RK_CPU_AXI_BUS_VIRT + 0x7280)
/* service core */
#define RK3288_SERVICE_CORE_VIRT RK_CPU_AXI_BUS_VIRT
#define RK3288_CPU_AXI_CPUM_R_QOS_VIRT (RK3288_SERVICE_CORE_VIRT + 0x80)
#define RK3288_CPU_AXI_CPUM_W_QOS_VIRT (RK3288_SERVICE_CORE_VIRT + 0x100)
#define RK3288_CPU_AXI_CPUP_QOS_VIRT (RK3288_SERVICE_CORE_VIRT + 0x0)
/* service dmac */
#define RK3288_SERVICE_DMAC_VIRT (RK3288_SERVICE_CORE_VIRT + RK3288_SERVICE_CORE_SIZE)
#define RK3288_CPU_AXI_BUS_DMAC_QOS_VIRT (RK3288_SERVICE_DMAC_VIRT + 0x0)
#define RK3288_CPU_AXI_CCP_QOS_VIRT (RK3288_SERVICE_DMAC_VIRT + 0x180)
#define RK3288_CPU_AXI_CRYPTO_QOS_VIRT (RK3288_SERVICE_DMAC_VIRT + 0x100)
#define RK3288_CPU_AXI_CCS_QOS_VIRT (RK3288_SERVICE_DMAC_VIRT + 0x200)
#define RK3288_CPU_AXI_HOST_QOS_VIRT (RK3288_SERVICE_DMAC_VIRT + 0x80)
/* service gpu */
#define RK3288_SERVICE_GPU_VIRT (RK3288_SERVICE_DMAC_VIRT + RK3288_SERVICE_DMAC_SIZE)
#define RK3288_CPU_AXI_GPU_R_QOS_VIRT (RK3288_SERVICE_GPU_VIRT + 0x0)
#define RK3288_CPU_AXI_GPU_W_QOS_VIRT (RK3288_SERVICE_GPU_VIRT + 0x80)
/* service peri */
#define RK3288_SERVICE_PERI_VIRT (RK3288_SERVICE_GPU_VIRT + RK3288_SERVICE_GPU_SIZE)
#define RK3288_CPU_AXI_PERI_QOS_VIRT (RK3288_SERVICE_PERI_VIRT + 0x0)
/* service bus */
#define RK3288_SERVICE_BUS_VIRT (RK3288_SERVICE_PERI_VIRT + RK3288_SERVICE_PERI_SIZE)
/* service vio */
#define RK3288_SERVICE_VIO_VIRT (RK3288_SERVICE_BUS_VIRT + RK3288_SERVICE_BUS_SIZE)
#define RK3288_CPU_AXI_VIO0_IEP_QOS_VIRT (RK3288_SERVICE_VIO_VIRT + 0x500)
#define RK3288_CPU_AXI_VIO0_VIP_QOS_VIRT (RK3288_SERVICE_VIO_VIRT + 0x480)
#define RK3288_CPU_AXI_VIO0_VOP_QOS_VIRT (RK3288_SERVICE_VIO_VIRT + 0x400)
#define RK3288_CPU_AXI_VIO1_ISP_R_QOS_VIRT (RK3288_SERVICE_VIO_VIRT + 0x900)
#define RK3288_CPU_AXI_VIO1_ISP_W0_QOS_VIRT (RK3288_SERVICE_VIO_VIRT + 0x100)
#define RK3288_CPU_AXI_VIO1_ISP_W1_QOS_VIRT (RK3288_SERVICE_VIO_VIRT + 0x180)
#define RK3288_CPU_AXI_VIO1_VOP_QOS_VIRT (RK3288_SERVICE_VIO_VIRT + 0x0)
#define RK3288_CPU_AXI_VIO2_RGA_R_QOS_VIRT (RK3288_SERVICE_VIO_VIRT + 0x800)
#define RK3288_CPU_AXI_VIO2_RGA_W_QOS_VIRT (RK3288_SERVICE_VIO_VIRT + 0x880)
/* service video */
#define RK3288_SERVICE_VIDEO_VIRT (RK3288_SERVICE_VIO_VIRT + RK3288_SERVICE_VIO_SIZE)
#define RK3288_CPU_AXI_VIDEO_QOS_VIRT (RK3288_SERVICE_VIDEO_VIRT + 0x0)
/* service hevc */
#define RK3288_SERVICE_HEVC_VIRT (RK3288_SERVICE_VIDEO_VIRT + RK3288_SERVICE_VIDEO_SIZE)
#define RK3288_CPU_AXI_HEVC_R_QOS_VIRT (RK3288_SERVICE_HEVC_VIRT + 0x0)
#define RK3288_CPU_AXI_HEVC_W_QOS_VIRT (RK3288_SERVICE_HEVC_VIRT + 0x100)
#define RK312X_CPU_AXI_QOS_NUM_REGS 4
#define RK312X_CPU_AXI_SAVE_QOS(array, base) do { \
array[0] = readl_relaxed(base + CPU_AXI_QOS_PRIORITY); \
array[1] = readl_relaxed(base + CPU_AXI_QOS_MODE); \
array[2] = readl_relaxed(base + CPU_AXI_QOS_BANDWIDTH); \
array[3] = readl_relaxed(base + CPU_AXI_QOS_SATURATION); \
} while (0)
#define RK312X_CPU_AXI_RESTORE_QOS(array, base) do { \
writel_relaxed(array[0], base + CPU_AXI_QOS_PRIORITY); \
writel_relaxed(array[1], base + CPU_AXI_QOS_MODE); \
writel_relaxed(array[2], base + CPU_AXI_QOS_BANDWIDTH); \
writel_relaxed(array[3], base + CPU_AXI_QOS_SATURATION); \
} while (0)
#define RK312X_SERVICE_VIO_VIRT (RK_CPU_AXI_BUS_VIRT + 0x7000)
#define RK312X_CPU_AXI_VIO_RGA_QOS_VIRT (RK312X_SERVICE_VIO_VIRT)
#define RK312X_CPU_AXI_VIO_EBC_QOS_VIRT (RK312X_SERVICE_VIO_VIRT + 0x80)
#define RK312X_CPU_AXI_VIO_IEP_QOS_VIRT (RK312X_SERVICE_VIO_VIRT + 0x100)
#define RK312X_CPU_AXI_VIO_LCDC0_QOS_VIRT (RK312X_SERVICE_VIO_VIRT + 0x180)
#define RK312X_CPU_AXI_VIO_VIP0_QOS_VIRT (RK312X_SERVICE_VIO_VIRT + 0x200)
#define RK312X_SERVICE_GPU_VIRT (RK_CPU_AXI_BUS_VIRT + 0x5000)
#define RK312X_CPU_AXI_GPU_QOS_VIRT (RK312X_SERVICE_GPU_VIRT)
#define RK312X_SERVICE_VIDEO_VIRT (RK_CPU_AXI_BUS_VIRT + 0x6000)
#define RK312X_CPU_AXI_VIDEO_QOS_VIRT (RK312X_SERVICE_VIDEO_VIRT)
#endif