mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 14:42:37 +02:00
rk: rm drivers/clk/rk
Change-Id: I8c541c0edb446a285ca5097b597216635e755460 Signed-off-by: Huang, Tao <huangtao@rock-chips.com>
This commit is contained in:
parent
436d4c489e
commit
fa25ca7318
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
2279
drivers/clk/rk/clk.c
2279
drivers/clk/rk/clk.c
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue
Block a user