Commit f49540d1 authored by Stephen Warren's avatar Stephen Warren

Merge branch 'for-3.7/common-clk' into for-3.7/cleanup2

parents 1f10478c b4350f40
......@@ -686,6 +686,7 @@ config ARCH_TEGRA
select NEED_MACH_IO_H if PCI
select ARCH_HAS_CPUFREQ
select USE_OF
select COMMON_CLK
help
This enables support for NVIDIA Tegra based systems (Tegra APX,
Tegra 6xx and Tegra 2 series).
......
......@@ -12,9 +12,11 @@ obj-y += powergate.o
obj-y += apbio.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_CPU_IDLE) += sleep.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_SMP) += reset.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
......
......@@ -70,6 +70,7 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
/* name parent rate enabled */
{ "uarta", "pll_p", 216000000, true },
{ "uartd", "pll_p", 216000000, true },
{ "usbd", "clk_m", 12000000, false },
{ "usb2", "clk_m", 12000000, false },
......
/*
*
* Copyright (C) 2010 Google, Inc.
* Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@google.com>
......@@ -19,8 +20,6 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
......@@ -36,321 +35,67 @@
/*
* Locking:
*
* Each struct clk has a spinlock.
*
* To avoid AB-BA locking problems, locks must always be traversed from child
* clock to parent clock. For example, when enabling a clock, the clock's lock
* is taken, and then clk_enable is called on the parent, which take's the
* parent clock's lock. There is one exceptions to this ordering: When dumping
* the clock tree through debugfs. In this case, clk_lock_all is called,
* which attemps to iterate through the entire list of clocks and take every
* clock lock. If any call to spin_trylock fails, all locked clocks are
* unlocked, and the process is retried. When all the locks are held,
* the only clock operation that can be called is clk_get_rate_all_locked.
*
* Within a single clock, no clock operation can call another clock operation
* on itself, except for clk_get_rate_locked and clk_set_rate_locked. Any
* clock operation can call any other clock operation on any of it's possible
* parents.
*
* An additional mutex, clock_list_lock, is used to protect the list of all
* clocks.
*
* The clock operations must lock internally to protect against
* read-modify-write on registers that are shared by multiple clocks
*/
static DEFINE_MUTEX(clock_list_lock);
static LIST_HEAD(clocks);
struct clk *tegra_get_clock_by_name(const char *name)
void tegra_clk_add(struct clk *clk)
{
struct clk *c;
struct clk *ret = NULL;
mutex_lock(&clock_list_lock);
list_for_each_entry(c, &clocks, node) {
if (strcmp(c->name, name) == 0) {
ret = c;
break;
}
}
mutex_unlock(&clock_list_lock);
return ret;
}
/* Must be called with c->spinlock held */
static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)
{
u64 rate;
rate = clk_get_rate(p);
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
return rate;
}
/* Must be called with c->spinlock held */
unsigned long clk_get_rate_locked(struct clk *c)
{
unsigned long rate;
if (c->parent)
rate = clk_predict_rate_from_parent(c, c->parent);
else
rate = c->rate;
return rate;
}
unsigned long clk_get_rate(struct clk *c)
{
unsigned long flags;
unsigned long rate;
spin_lock_irqsave(&c->spinlock, flags);
rate = clk_get_rate_locked(c);
spin_unlock_irqrestore(&c->spinlock, flags);
return rate;
}
EXPORT_SYMBOL(clk_get_rate);
int clk_reparent(struct clk *c, struct clk *parent)
{
c->parent = parent;
return 0;
}
void clk_init(struct clk *c)
{
spin_lock_init(&c->spinlock);
if (c->ops && c->ops->init)
c->ops->init(c);
if (!c->ops || !c->ops->enable) {
c->refcnt++;
c->set = true;
if (c->parent)
c->state = c->parent->state;
else
c->state = ON;
}
struct clk_tegra *c = to_clk_tegra(__clk_get_hw(clk));
mutex_lock(&clock_list_lock);
list_add(&c->node, &clocks);
mutex_unlock(&clock_list_lock);
}
int clk_enable(struct clk *c)
{
int ret = 0;
unsigned long flags;
spin_lock_irqsave(&c->spinlock, flags);
if (c->refcnt == 0) {
if (c->parent) {
ret = clk_enable(c->parent);
if (ret)
goto out;
}
if (c->ops && c->ops->enable) {
ret = c->ops->enable(c);
if (ret) {
if (c->parent)
clk_disable(c->parent);
goto out;
}
c->state = ON;
c->set = true;
}
}
c->refcnt++;
out:
spin_unlock_irqrestore(&c->spinlock, flags);
return ret;
}
EXPORT_SYMBOL(clk_enable);
void clk_disable(struct clk *c)
{
unsigned long flags;
spin_lock_irqsave(&c->spinlock, flags);
if (c->refcnt == 0) {
WARN(1, "Attempting to disable clock %s with refcnt 0", c->name);
spin_unlock_irqrestore(&c->spinlock, flags);
return;
}
if (c->refcnt == 1) {
if (c->ops && c->ops->disable)
c->ops->disable(c);
if (c->parent)
clk_disable(c->parent);
c->state = OFF;
}
c->refcnt--;
spin_unlock_irqrestore(&c->spinlock, flags);
}
EXPORT_SYMBOL(clk_disable);
int clk_set_parent(struct clk *c, struct clk *parent)
{
int ret;
unsigned long flags;
unsigned long new_rate;
unsigned long old_rate;
spin_lock_irqsave(&c->spinlock, flags);
if (!c->ops || !c->ops->set_parent) {
ret = -ENOSYS;
goto out;
}
new_rate = clk_predict_rate_from_parent(c, parent);
old_rate = clk_get_rate_locked(c);
ret = c->ops->set_parent(c, parent);
if (ret)
goto out;
out:
spin_unlock_irqrestore(&c->spinlock, flags);
return ret;
}
EXPORT_SYMBOL(clk_set_parent);
struct clk *clk_get_parent(struct clk *c)
{
return c->parent;
}
EXPORT_SYMBOL(clk_get_parent);
int clk_set_rate_locked(struct clk *c, unsigned long rate)
{
long new_rate;
if (!c->ops || !c->ops->set_rate)
return -ENOSYS;
if (rate > c->max_rate)
rate = c->max_rate;
if (c->ops && c->ops->round_rate) {
new_rate = c->ops->round_rate(c, rate);
if (new_rate < 0)
return new_rate;
rate = new_rate;
}
return c->ops->set_rate(c, rate);
}
int clk_set_rate(struct clk *c, unsigned long rate)
{
int ret;
unsigned long flags;
spin_lock_irqsave(&c->spinlock, flags);
ret = clk_set_rate_locked(c, rate);
spin_unlock_irqrestore(&c->spinlock, flags);
return ret;
}
EXPORT_SYMBOL(clk_set_rate);
/* Must be called with clocks lock and all indvidual clock locks held */
unsigned long clk_get_rate_all_locked(struct clk *c)
struct clk *tegra_get_clock_by_name(const char *name)
{
u64 rate;
int mul = 1;
int div = 1;
struct clk *p = c;
while (p) {
c = p;
if (c->mul != 0 && c->div != 0) {
mul *= c->mul;
div *= c->div;
struct clk_tegra *c;
struct clk *ret = NULL;
mutex_lock(&clock_list_lock);
list_for_each_entry(c, &clocks, node) {
if (strcmp(__clk_get_name(c->hw.clk), name) == 0) {
ret = c->hw.clk;
break;
}
p = c->parent;
}
rate = c->rate;
rate *= mul;
do_div(rate, div);
return rate;
}
long clk_round_rate(struct clk *c, unsigned long rate)
{
unsigned long flags;
long ret;
spin_lock_irqsave(&c->spinlock, flags);
if (!c->ops || !c->ops->round_rate) {
ret = -ENOSYS;
goto out;
}
if (rate > c->max_rate)
rate = c->max_rate;
ret = c->ops->round_rate(c, rate);
out:
spin_unlock_irqrestore(&c->spinlock, flags);
mutex_unlock(&clock_list_lock);
return ret;
}
EXPORT_SYMBOL(clk_round_rate);
static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
{
struct clk *c;
struct clk *p;
struct clk *parent;
int ret = 0;
c = tegra_get_clock_by_name(table->name);
if (!c) {
pr_warning("Unable to initialize clock %s\n",
pr_warn("Unable to initialize clock %s\n",
table->name);
return -ENODEV;
}
parent = clk_get_parent(c);
if (table->parent) {
p = tegra_get_clock_by_name(table->parent);
if (!p) {
pr_warning("Unable to find parent %s of clock %s\n",
pr_warn("Unable to find parent %s of clock %s\n",
table->parent, table->name);
return -ENODEV;
}
if (c->parent != p) {
if (parent != p) {
ret = clk_set_parent(c, p);
if (ret) {
pr_warning("Unable to set parent %s of clock %s: %d\n",
pr_warn("Unable to set parent %s of clock %s: %d\n",
table->parent, table->name, ret);
return -EINVAL;
}
......@@ -360,16 +105,16 @@ static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
if (table->rate && table->rate != clk_get_rate(c)) {
ret = clk_set_rate(c, table->rate);
if (ret) {
pr_warning("Unable to set clock %s to rate %lu: %d\n",
pr_warn("Unable to set clock %s to rate %lu: %d\n",
table->name, table->rate, ret);
return -EINVAL;
}
}
if (table->enabled) {
ret = clk_enable(c);
ret = clk_prepare_enable(c);
if (ret) {
pr_warning("Unable to enable clock %s: %d\n",
pr_warn("Unable to enable clock %s: %d\n",
table->name, ret);
return -EINVAL;
}
......@@ -383,19 +128,20 @@ void tegra_clk_init_from_table(struct tegra_clk_init_table *table)
for (; table->name; table++)
tegra_clk_init_one_from_table(table);
}
EXPORT_SYMBOL(tegra_clk_init_from_table);
void tegra_periph_reset_deassert(struct clk *c)
{
BUG_ON(!c->ops->reset);
c->ops->reset(c, false);
struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
BUG_ON(!clk->reset);
clk->reset(__clk_get_hw(c), false);
}
EXPORT_SYMBOL(tegra_periph_reset_deassert);
void tegra_periph_reset_assert(struct clk *c)
{
BUG_ON(!c->ops->reset);
c->ops->reset(c, true);
struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
BUG_ON(!clk->reset);
clk->reset(__clk_get_hw(c), true);
}
EXPORT_SYMBOL(tegra_periph_reset_assert);
......@@ -405,268 +151,14 @@ EXPORT_SYMBOL(tegra_periph_reset_assert);
int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
{
int ret = 0;
unsigned long flags;
struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
spin_lock_irqsave(&c->spinlock, flags);
if (!c->ops || !c->ops->clk_cfg_ex) {
if (!clk->clk_cfg_ex) {
ret = -ENOSYS;
goto out;
}
ret = c->ops->clk_cfg_ex(c, p, setting);
ret = clk->clk_cfg_ex(__clk_get_hw(c), p, setting);
out:
spin_unlock_irqrestore(&c->spinlock, flags);
return ret;
}
#ifdef CONFIG_DEBUG_FS
static int __clk_lock_all_spinlocks(void)
{
struct clk *c;
list_for_each_entry(c, &clocks, node)
if (!spin_trylock(&c->spinlock))
goto unlock_spinlocks;
return 0;
unlock_spinlocks:
list_for_each_entry_continue_reverse(c, &clocks, node)
spin_unlock(&c->spinlock);
return -EAGAIN;
}
static void __clk_unlock_all_spinlocks(void)
{
struct clk *c;
list_for_each_entry_reverse(c, &clocks, node)
spin_unlock(&c->spinlock);
}
/*
* This function retries until it can take all locks, and may take
* an arbitrarily long time to complete.
* Must be called with irqs enabled, returns with irqs disabled
* Must be called with clock_list_lock held
*/
static void clk_lock_all(void)
{
int ret;
retry:
local_irq_disable();
ret = __clk_lock_all_spinlocks();
if (ret)
goto failed_spinlocks;
/* All locks taken successfully, return */
return;
failed_spinlocks:
local_irq_enable();
yield();
goto retry;
}
/*
* Unlocks all clocks after a clk_lock_all
* Must be called with irqs disabled, returns with irqs enabled
* Must be called with clock_list_lock held
*/
static void clk_unlock_all(void)
{
__clk_unlock_all_spinlocks();
local_irq_enable();
}
static struct dentry *clk_debugfs_root;
static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
{
struct clk *child;
const char *state = "uninit";
char div[8] = {0};
if (c->state == ON)
state = "on";
else if (c->state == OFF)
state = "off";
if (c->mul != 0 && c->div != 0) {
if (c->mul > c->div) {
int mul = c->mul / c->div;
int mul2 = (c->mul * 10 / c->div) % 10;
int mul3 = (c->mul * 10) % c->div;
if (mul2 == 0 && mul3 == 0)
snprintf(div, sizeof(div), "x%d", mul);
else if (mul3 == 0)
snprintf(div, sizeof(div), "x%d.%d", mul, mul2);
else
snprintf(div, sizeof(div), "x%d.%d..", mul, mul2);
} else {
snprintf(div, sizeof(div), "%d%s", c->div / c->mul,
(c->div % c->mul) ? ".5" : "");
}
}
seq_printf(s, "%*s%c%c%-*s %-6s %-3d %-8s %-10lu\n",
level * 3 + 1, "",
c->rate > c->max_rate ? '!' : ' ',
!c->set ? '*' : ' ',
30 - level * 3, c->name,
state, c->refcnt, div, clk_get_rate_all_locked(c));
list_for_each_entry(child, &clocks, node) {
if (child->parent != c)
continue;
clock_tree_show_one(s, child, level + 1);
}
}
static int clock_tree_show(struct seq_file *s, void *data)
{
struct clk *c;
seq_printf(s, " clock state ref div rate\n");
seq_printf(s, "--------------------------------------------------------------\n");
mutex_lock(&clock_list_lock);
clk_lock_all();
list_for_each_entry(c, &clocks, node)
if (c->parent == NULL)
clock_tree_show_one(s, c, 0);
clk_unlock_all();
mutex_unlock(&clock_list_lock);
return 0;
}
static int clock_tree_open(struct inode *inode, struct file *file)
{
return single_open(file, clock_tree_show, inode->i_private);
}
static const struct file_operations clock_tree_fops = {
.open = clock_tree_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int possible_parents_show(struct seq_file *s, void *data)
{
struct clk *c = s->private;
int i;
for (i = 0; c->inputs[i].input; i++) {
char *first = (i == 0) ? "" : " ";
seq_printf(s, "%s%s", first, c->inputs[i].input->name);
}
seq_printf(s, "\n");
return 0;
}
static int possible_parents_open(struct inode *inode, struct file *file)
{
return single_open(file, possible_parents_show, inode->i_private);
}
static const struct file_operations possible_parents_fops = {
.open = possible_parents_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int clk_debugfs_register_one(struct clk *c)
{
struct dentry *d;
d = debugfs_create_dir(c->name, clk_debugfs_root);
if (!d)
return -ENOMEM;
c->dent = d;
d = debugfs_create_u8("refcnt", S_IRUGO, c->dent, (u8 *)&c->refcnt);
if (!d)
goto err_out;
d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
if (!d)
goto err_out;
d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
if (!d)
goto err_out;
if (c->inputs) {
d = debugfs_create_file("possible_parents", S_IRUGO, c->dent,
c, &possible_parents_fops);
if (!d)
goto err_out;
}
return 0;
err_out:
debugfs_remove_recursive(c->dent);
return -ENOMEM;
}
static int clk_debugfs_register(struct clk *c)
{
int err;
struct clk *pa = c->parent;
if (pa && !pa->dent) {
err = clk_debugfs_register(pa);
if (err)
return err;
}
if (!c->dent) {
err = clk_debugfs_register_one(c);
if (err)
return err;
}
return 0;
}
int __init tegra_clk_debugfs_init(void)
{
struct clk *c;
struct dentry *d;
int err = -ENOMEM;
d = debugfs_create_dir("clock", NULL);
if (!d)
return -ENOMEM;
clk_debugfs_root = d;
d = debugfs_create_file("clock_tree", S_IRUGO, clk_debugfs_root, NULL,
&clock_tree_fops);
if (!d)
goto err_out;
list_for_each_entry(c, &clocks, node) {
err = clk_debugfs_register(c);
if (err)
goto err_out;
}
return 0;
err_out:
debugfs_remove_recursive(clk_debugfs_root);
return err;
}
#endif
......@@ -2,6 +2,7 @@
* arch/arm/mach-tegra/include/mach/clock.h
*
* Copyright (C) 2010 Google, Inc.
* Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@google.com>
......@@ -20,9 +21,9 @@
#ifndef __MACH_TEGRA_CLOCK_H
#define __MACH_TEGRA_CLOCK_H
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <mach/clk.h>
......@@ -52,7 +53,8 @@
#define ENABLE_ON_INIT (1 << 28)
#define PERIPH_ON_APB (1 << 29)
struct clk;
struct clk_tegra;
#define to_clk_tegra(_hw) container_of(_hw, struct clk_tegra, hw)
struct clk_mux_sel {
struct clk *input;
......@@ -68,47 +70,29 @@ struct clk_pll_freq_table {
u8 cpcon;
};
struct clk_ops {
void (*init)(struct clk *);
int (*enable)(struct clk *);
void (*disable)(struct clk *);
int (*set_parent)(struct clk *, struct clk *);
int (*set_rate)(struct clk *, unsigned long);
long (*round_rate)(struct clk *, unsigned long);
void (*reset)(struct clk *, bool);
int (*clk_cfg_ex)(struct clk *,
enum tegra_clk_ex_param, u32);
};
enum clk_state {
UNINITIALIZED = 0,
ON,
OFF,
};
struct clk {
struct clk_tegra {
/* node for master clocks list */
struct list_head node; /* node for list of all clocks */
struct list_head node; /* node for list of all clocks */
struct clk_lookup lookup;
struct clk_hw hw;
#ifdef CONFIG_DEBUG_FS
struct dentry *dent;
#endif
bool set;
struct clk_ops *ops;
unsigned long rate;
unsigned long fixed_rate;
unsigned long max_rate;
unsigned long min_rate;
u32 flags;
const char *name;
u32 refcnt;
enum clk_state state;
struct clk *parent;
u32 div;
u32 mul;
const struct clk_mux_sel *inputs;
u32 reg;
u32 reg_shift;
......@@ -144,7 +128,8 @@ struct clk {
} shared_bus_user;
} u;
spinlock_t spinlock;
void (*reset)(struct clk_hw *, bool);
int (*clk_cfg_ex)(struct clk_hw *, enum tegra_clk_ex_param, u32);
};
struct clk_duplicate {
......@@ -159,13 +144,10 @@ struct tegra_clk_init_table {
bool enabled;
};
void tegra_clk_add(struct clk *c);
void tegra2_init_clocks(void);
void tegra30_init_clocks(void);
void clk_init(struct clk *clk);
struct clk *tegra_get_clock_by_name(const char *name);
int clk_reparent(struct clk *c, struct clk *parent);
void tegra_clk_init_from_table(struct tegra_clk_init_table *table);
unsigned long clk_get_rate_locked(struct clk *c);
int clk_set_rate_locked(struct clk *c, unsigned long rate);
#endif
......@@ -152,6 +152,5 @@ void __init tegra30_init_early(void)
void __init tegra_init_late(void)
{
tegra_clk_debugfs_init();
tegra_powergate_debugfs_init();
}
......@@ -49,6 +49,8 @@ static struct cpufreq_frequency_table freq_table[] = {
#define NUM_CPUS 2
static struct clk *cpu_clk;
static struct clk *pll_x_clk;
static struct clk *pll_p_clk;
static struct clk *emc_clk;
static unsigned long target_cpu_speed[NUM_CPUS];
......@@ -71,6 +73,42 @@ static unsigned int tegra_getspeed(unsigned int cpu)
return rate;
}
static int tegra_cpu_clk_set_rate(unsigned long rate)
{
int ret;
/*
* Take an extra reference to the main pll so it doesn't turn
* off when we move the cpu off of it
*/
clk_prepare_enable(pll_x_clk);
ret = clk_set_parent(cpu_clk, pll_p_clk);
if (ret) {
pr_err("Failed to switch cpu to clock pll_p\n");
goto out;
}
if (rate == clk_get_rate(pll_p_clk))
goto out;
ret = clk_set_rate(pll_x_clk, rate);
if (ret) {
pr_err("Failed to change pll_x to %lu\n", rate);
goto out;
}
ret = clk_set_parent(cpu_clk, pll_x_clk);
if (ret) {
pr_err("Failed to switch cpu to clock pll_x\n");
goto out;
}
out:
clk_disable_unprepare(pll_x_clk);
return ret;
}
static int tegra_update_cpu_speed(unsigned long rate)
{
int ret = 0;
......@@ -101,7 +139,7 @@ static int tegra_update_cpu_speed(unsigned long rate)
freqs.old, freqs.new);
#endif
ret = clk_set_rate(cpu_clk, freqs.new * 1000);
ret = tegra_cpu_clk_set_rate(freqs.new * 1000);
if (ret) {
pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
freqs.new);
......@@ -183,6 +221,14 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
if (IS_ERR(cpu_clk))
return PTR_ERR(cpu_clk);
pll_x_clk = clk_get_sys(NULL, "pll_x");
if (IS_ERR(pll_x_clk))
return PTR_ERR(pll_x_clk);
pll_p_clk = clk_get_sys(NULL, "pll_p");
if (IS_ERR(pll_p_clk))
return PTR_ERR(pll_p_clk);
emc_clk = clk_get_sys("cpu", "emc");
if (IS_ERR(emc_clk)) {
clk_put(cpu_clk);
......
......@@ -34,7 +34,10 @@ enum tegra_clk_ex_param {
void tegra_periph_reset_deassert(struct clk *c);
void tegra_periph_reset_assert(struct clk *c);
#ifndef CONFIG_COMMON_CLK
unsigned long clk_get_rate_all_locked(struct clk *c);
#endif
void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting);
......
/*
* arch/arm/mach-tegra/tegra2_clocks.c
* arch/arm/mach-tegra/tegra20_clocks.c
*
* Copyright (C) 2010 Google, Inc.
* Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@google.com>
......@@ -98,7 +99,7 @@
#define PLL_OUT_CLKEN (1<<1)
#define PLL_OUT_RESET_DISABLE (1<<0)
#define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
#define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
#define PLL_MISC_DCCON_SHIFT 20
#define PLL_MISC_CPCON_SHIFT 8
......@@ -191,7 +192,8 @@ static unsigned long clk_measure_input_freq(void)
} else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) {
return 26000000;
} else {
pr_err("%s: Unexpected clock autodetect value %d", __func__, clock_autodetect);
pr_err("%s: Unexpected clock autodetect value %d",
__func__, clock_autodetect);
BUG();
return 0;
}
......@@ -223,19 +225,38 @@ static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
if (divider_u16 - 1 < 0)
return 0;
if (divider_u16 - 1 > 255)
if (divider_u16 - 1 > 0xFFFF)
return -EINVAL;
return divider_u16 - 1;
}
static unsigned long tegra_clk_fixed_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
return to_clk_tegra(hw)->fixed_rate;
}
struct clk_ops tegra_clk_32k_ops = {
.recalc_rate = tegra_clk_fixed_recalc_rate,
};
/* clk_m functions */
static unsigned long tegra2_clk_m_autodetect_rate(struct clk *c)
static unsigned long tegra20_clk_m_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
if (!to_clk_tegra(hw)->fixed_rate)
to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq();
return to_clk_tegra(hw)->fixed_rate;
}
static void tegra20_clk_m_init(struct clk_hw *hw)
{
u32 auto_clock_control = clk_readl(OSC_CTRL) & ~OSC_CTRL_OSC_FREQ_MASK;
struct clk_tegra *c = to_clk_tegra(hw);
u32 osc_ctrl = clk_readl(OSC_CTRL);
u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK;
c->rate = clk_measure_input_freq();
switch (c->rate) {
switch (c->fixed_rate) {
case 12000000:
auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
break;
......@@ -249,35 +270,14 @@ static unsigned long tegra2_clk_m_autodetect_rate(struct clk *c)
auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ;
break;
default:
pr_err("%s: Unexpected clock rate %ld", __func__, c->rate);
BUG();
}
clk_writel(auto_clock_control, OSC_CTRL);
return c->rate;
}
static void tegra2_clk_m_init(struct clk *c)
{
pr_debug("%s on clock %s\n", __func__, c->name);
tegra2_clk_m_autodetect_rate(c);
}
static int tegra2_clk_m_enable(struct clk *c)
{
pr_debug("%s on clock %s\n", __func__, c->name);
return 0;
}
static void tegra2_clk_m_disable(struct clk *c)
{
pr_debug("%s on clock %s\n", __func__, c->name);
BUG();
}
static struct clk_ops tegra_clk_m_ops = {
.init = tegra2_clk_m_init,
.enable = tegra2_clk_m_enable,
.disable = tegra2_clk_m_disable,
struct clk_ops tegra_clk_m_ops = {
.init = tegra20_clk_m_init,
.recalc_rate = tegra20_clk_m_recalc_rate,
};
/* super clock functions */
......@@ -286,161 +286,127 @@ static struct clk_ops tegra_clk_m_ops = {
* can't lower the voltage when using the clock skip, but we can if we
* lower the PLL frequency.
*/
static void tegra2_super_clk_init(struct clk *c)
static int tegra20_super_clk_is_enabled(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
int source;
int shift;
const struct clk_mux_sel *sel;
val = clk_readl(c->reg + SUPER_CLK_MUX);
c->state = ON;
BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
source = (val >> shift) & SUPER_SOURCE_MASK;
for (sel = c->inputs; sel->input != NULL; sel++) {
if (sel->value == source)
break;
}
BUG_ON(sel->input == NULL);
c->parent = sel->input;
c->state = ON;
return c->state;
}
static int tegra2_super_clk_enable(struct clk *c)
static int tegra20_super_clk_enable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
return 0;
}
static void tegra2_super_clk_disable(struct clk *c)
static void tegra20_super_clk_disable(struct clk_hw *hw)
{
pr_debug("%s on clock %s\n", __func__, c->name);
pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
/* oops - don't disable the CPU clock! */
BUG();
}
static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)
static u8 tegra20_super_clk_get_parent(struct clk_hw *hw)
{
u32 val;
const struct clk_mux_sel *sel;
struct clk_tegra *c = to_clk_tegra(hw);
int val = clk_readl(c->reg + SUPER_CLK_MUX);
int source;
int shift;
val = clk_readl(c->reg + SUPER_CLK_MUX);
BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
for (sel = c->inputs; sel->input != NULL; sel++) {
if (sel->input == p) {
val &= ~(SUPER_SOURCE_MASK << shift);
val |= sel->value << shift;
source = (val >> shift) & SUPER_SOURCE_MASK;
return source;
}
if (c->refcnt)
clk_enable(p);
static int tegra20_super_clk_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg + SUPER_CLK_MUX);
int shift;
clk_writel(val, c->reg);
BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
val &= ~(SUPER_SOURCE_MASK << shift);
val |= index << shift;
if (c->refcnt && c->parent)
clk_disable(c->parent);
clk_writel(val, c->reg);
clk_reparent(c, p);
return 0;
}
}
return -EINVAL;
return 0;
}
/*
* Super clocks have "clock skippers" instead of dividers. Dividing using
* a clock skipper does not allow the voltage to be scaled down, so instead
* adjust the rate of the parent clock. This requires that the parent of a
* super clock have no other children, otherwise the rate will change
* underneath the other children.
*/
static int tegra2_super_clk_set_rate(struct clk *c, unsigned long rate)
/* FIX ME: Need to switch parents to change the source PLL rate */
static unsigned long tegra20_super_clk_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
return clk_set_rate(c->parent, rate);
return prate;
}
static struct clk_ops tegra_super_ops = {
.init = tegra2_super_clk_init,
.enable = tegra2_super_clk_enable,
.disable = tegra2_super_clk_disable,
.set_parent = tegra2_super_clk_set_parent,
.set_rate = tegra2_super_clk_set_rate,
};
/* virtual cpu clock functions */
/* some clocks can not be stopped (cpu, memory bus) while the SoC is running.
To change the frequency of these clocks, the parent pll may need to be
reprogrammed, so the clock must be moved off the pll, the pll reprogrammed,
and then the clock moved back to the pll. To hide this sequence, a virtual
clock handles it.
*/
static void tegra2_cpu_clk_init(struct clk *c)
static long tegra20_super_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
return *prate;
}
static int tegra2_cpu_clk_enable(struct clk *c)
static int tegra20_super_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
return 0;
}
static void tegra2_cpu_clk_disable(struct clk *c)
{
pr_debug("%s on clock %s\n", __func__, c->name);
/* oops - don't disable the CPU clock! */
BUG();
}
struct clk_ops tegra_super_ops = {
.is_enabled = tegra20_super_clk_is_enabled,
.enable = tegra20_super_clk_enable,
.disable = tegra20_super_clk_disable,
.set_parent = tegra20_super_clk_set_parent,
.get_parent = tegra20_super_clk_get_parent,
.set_rate = tegra20_super_clk_set_rate,
.round_rate = tegra20_super_clk_round_rate,
.recalc_rate = tegra20_super_clk_recalc_rate,
};
static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate)
static unsigned long tegra20_twd_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
int ret;
/*
* Take an extra reference to the main pll so it doesn't turn
* off when we move the cpu off of it
*/
clk_enable(c->u.cpu.main);
struct clk_tegra *c = to_clk_tegra(hw);
u64 rate = parent_rate;
ret = clk_set_parent(c->parent, c->u.cpu.backup);
if (ret) {
pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.backup->name);
goto out;
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
if (rate == clk_get_rate(c->u.cpu.backup))
goto out;
ret = clk_set_rate(c->u.cpu.main, rate);
if (ret) {
pr_err("Failed to change cpu pll to %lu\n", rate);
goto out;
}
return rate;
}
ret = clk_set_parent(c->parent, c->u.cpu.main);
if (ret) {
pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.main->name);
goto out;
}
struct clk_ops tegra_twd_ops = {
.recalc_rate = tegra20_twd_clk_recalc_rate,
};
out:
clk_disable(c->u.cpu.main);
return ret;
static u8 tegra20_cop_clk_get_parent(struct clk_hw *hw)
{
return 0;
}
static struct clk_ops tegra_cpu_ops = {
.init = tegra2_cpu_clk_init,
.enable = tegra2_cpu_clk_enable,
.disable = tegra2_cpu_clk_disable,
.set_rate = tegra2_cpu_clk_set_rate,
struct clk_ops tegra_cop_ops = {
.get_parent = tegra20_cop_clk_get_parent,
};
/* virtual cop clock functions. Used to acquire the fake 'cop' clock to
* reset the COP block (i.e. AVP) */
static void tegra2_cop_clk_reset(struct clk *c, bool assert)
void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert)
{
unsigned long reg = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
......@@ -448,23 +414,21 @@ static void tegra2_cop_clk_reset(struct clk *c, bool assert)
clk_writel(1 << 1, reg);
}
static struct clk_ops tegra_cop_ops = {
.reset = tegra2_cop_clk_reset,
};
/* bus clock functions */
static void tegra2_bus_clk_init(struct clk *c)
static int tegra20_bus_clk_is_enabled(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
c->mul = 1;
return c->state;
}
static int tegra2_bus_clk_enable(struct clk *c)
static int tegra20_bus_clk_enable(struct clk_hw *hw)
{
u32 val;
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long flags;
u32 val;
spin_lock_irqsave(&clock_register_lock, flags);
......@@ -477,10 +441,11 @@ static int tegra2_bus_clk_enable(struct clk *c)
return 0;
}
static void tegra2_bus_clk_disable(struct clk *c)
static void tegra20_bus_clk_disable(struct clk_hw *hw)
{
u32 val;
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long flags;
u32 val;
spin_lock_irqsave(&clock_register_lock, flags);
......@@ -491,12 +456,31 @@ static void tegra2_bus_clk_disable(struct clk *c)
spin_unlock_irqrestore(&clock_register_lock, flags);
}
static int tegra2_bus_clk_set_rate(struct clk *c, unsigned long rate)
static unsigned long tegra20_bus_clk_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
u32 val;
unsigned long parent_rate = clk_get_rate(c->parent);
unsigned long flags;
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
u64 rate = prate;
c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
c->mul = 1;
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
return rate;
}
static int tegra20_bus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_tegra *c = to_clk_tegra(hw);
int ret = -EINVAL;
unsigned long flags;
u32 val;
int i;
spin_lock_irqsave(&clock_register_lock, flags);
......@@ -519,21 +503,56 @@ static int tegra2_bus_clk_set_rate(struct clk *c, unsigned long rate)
return ret;
}
static struct clk_ops tegra_bus_ops = {
.init = tegra2_bus_clk_init,
.enable = tegra2_bus_clk_enable,
.disable = tegra2_bus_clk_disable,
.set_rate = tegra2_bus_clk_set_rate,
static long tegra20_bus_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
unsigned long parent_rate = *prate;
s64 divider;
if (rate >= parent_rate)
return rate;
divider = parent_rate;
divider += rate - 1;
do_div(divider, rate);
if (divider < 0)
return divider;
if (divider > 4)
divider = 4;
do_div(parent_rate, divider);
return parent_rate;
}
struct clk_ops tegra_bus_ops = {
.is_enabled = tegra20_bus_clk_is_enabled,
.enable = tegra20_bus_clk_enable,
.disable = tegra20_bus_clk_disable,
.set_rate = tegra20_bus_clk_set_rate,
.round_rate = tegra20_bus_clk_round_rate,
.recalc_rate = tegra20_bus_clk_recalc_rate,
};
/* Blink output functions */
static void tegra2_blink_clk_init(struct clk *c)
static int tegra20_blink_clk_is_enabled(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
val = pmc_readl(PMC_CTRL);
c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
return c->state;
}
static unsigned long tegra20_blink_clk_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u64 rate = prate;
u32 val;
c->mul = 1;
val = pmc_readl(c->reg);
......@@ -550,9 +569,16 @@ static void tegra2_blink_clk_init(struct clk *c)
} else {
c->div = 1;
}
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
return rate;
}
static int tegra2_blink_clk_enable(struct clk *c)
static int tegra20_blink_clk_enable(struct clk_hw *hw)
{
u32 val;
......@@ -565,7 +591,7 @@ static int tegra2_blink_clk_enable(struct clk *c)
return 0;
}
static void tegra2_blink_clk_disable(struct clk *c)
static void tegra20_blink_clk_disable(struct clk_hw *hw)
{
u32 val;
......@@ -576,9 +602,11 @@ static void tegra2_blink_clk_disable(struct clk *c)
pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
}
static int tegra2_blink_clk_set_rate(struct clk *c, unsigned long rate)
static int tegra20_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
unsigned long parent_rate = clk_get_rate(c->parent);
struct clk_tegra *c = to_clk_tegra(hw);
if (rate >= parent_rate) {
c->div = 1;
pmc_writel(0, c->reg);
......@@ -601,31 +629,74 @@ static int tegra2_blink_clk_set_rate(struct clk *c, unsigned long rate)
return 0;
}
static struct clk_ops tegra_blink_clk_ops = {
.init = &tegra2_blink_clk_init,
.enable = &tegra2_blink_clk_enable,
.disable = &tegra2_blink_clk_disable,
.set_rate = &tegra2_blink_clk_set_rate,
static long tegra20_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
int div;
int mul;
long round_rate = *prate;
mul = 1;
if (rate >= *prate) {
div = 1;
} else {
div = DIV_ROUND_UP(*prate / 8, rate);
div *= 8;
}
round_rate *= mul;
round_rate += div - 1;
do_div(round_rate, div);
return round_rate;
}
struct clk_ops tegra_blink_clk_ops = {
.is_enabled = tegra20_blink_clk_is_enabled,
.enable = tegra20_blink_clk_enable,
.disable = tegra20_blink_clk_disable,
.set_rate = tegra20_blink_clk_set_rate,
.round_rate = tegra20_blink_clk_round_rate,
.recalc_rate = tegra20_blink_clk_recalc_rate,
};
/* PLL Functions */
static int tegra2_pll_clk_wait_for_lock(struct clk *c)
static int tegra20_pll_clk_wait_for_lock(struct clk_tegra *c)
{
udelay(c->u.pll.lock_delay);
return 0;
}
static void tegra2_pll_clk_init(struct clk *c)
static int tegra20_pll_clk_is_enabled(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg + PLL_BASE);
c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
return c->state;
}
static unsigned long tegra20_pll_clk_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg + PLL_BASE);
u64 rate = prate;
if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
pr_warning("Clock %s has unknown fixed frequency\n", c->name);
c->mul = 1;
c->div = 1;
const struct clk_pll_freq_table *sel;
for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
if (sel->input_rate == prate &&
sel->output_rate == c->u.pll.fixed_rate) {
c->mul = sel->n;
c->div = sel->m * sel->p;
break;
}
}
pr_err("Clock %s has unknown fixed frequency\n",
__clk_get_name(hw->clk));
BUG();
} else if (val & PLL_BASE_BYPASS) {
c->mul = 1;
c->div = 1;
......@@ -637,42 +708,63 @@ static void tegra2_pll_clk_init(struct clk *c)
else
c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
}
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
return rate;
}
static int tegra2_pll_clk_enable(struct clk *c)
static int tegra20_pll_clk_enable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
pr_debug("%s on clock %s\n", __func__, c->name);
pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
val = clk_readl(c->reg + PLL_BASE);
val &= ~PLL_BASE_BYPASS;
val |= PLL_BASE_ENABLE;
clk_writel(val, c->reg + PLL_BASE);
tegra2_pll_clk_wait_for_lock(c);
tegra20_pll_clk_wait_for_lock(c);
return 0;
}
static void tegra2_pll_clk_disable(struct clk *c)
static void tegra20_pll_clk_disable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
pr_debug("%s on clock %s\n", __func__, c->name);
pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
val = clk_readl(c->reg);
val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
clk_writel(val, c->reg);
}
static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)
static int tegra20_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
u32 val;
unsigned long input_rate;
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long input_rate = parent_rate;
const struct clk_pll_freq_table *sel;
u32 val;
pr_debug("%s: %s %lu\n", __func__, c->name, rate);
pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
if (c->flags & PLL_FIXED) {
int ret = 0;
if (rate != c->u.pll.fixed_rate) {
pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
__func__, __clk_get_name(hw->clk),
c->u.pll.fixed_rate, rate);
ret = -EINVAL;
}
return ret;
}
input_rate = clk_get_rate(c->parent);
for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
if (sel->input_rate == input_rate && sel->output_rate == rate) {
c->mul = sel->n;
......@@ -703,41 +795,76 @@ static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)
}
if (c->state == ON)
tegra2_pll_clk_enable(c);
tegra20_pll_clk_enable(hw);
return 0;
}
}
return -EINVAL;
}
static struct clk_ops tegra_pll_ops = {
.init = tegra2_pll_clk_init,
.enable = tegra2_pll_clk_enable,
.disable = tegra2_pll_clk_disable,
.set_rate = tegra2_pll_clk_set_rate,
static long tegra20_pll_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_tegra *c = to_clk_tegra(hw);
const struct clk_pll_freq_table *sel;
unsigned long input_rate = *prate;
u64 output_rate = *prate;
int mul;
int div;
if (c->flags & PLL_FIXED)
return c->u.pll.fixed_rate;
for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++)
if (sel->input_rate == input_rate && sel->output_rate == rate) {
mul = sel->n;
div = sel->m * sel->p;
break;
}
if (sel->input_rate == 0)
return -EINVAL;
output_rate *= mul;
output_rate += div - 1; /* round up */
do_div(output_rate, div);
return output_rate;
}
struct clk_ops tegra_pll_ops = {
.is_enabled = tegra20_pll_clk_is_enabled,
.enable = tegra20_pll_clk_enable,
.disable = tegra20_pll_clk_disable,
.set_rate = tegra20_pll_clk_set_rate,
.recalc_rate = tegra20_pll_clk_recalc_rate,
.round_rate = tegra20_pll_clk_round_rate,
};
static void tegra2_pllx_clk_init(struct clk *c)
static void tegra20_pllx_clk_init(struct clk_hw *hw)
{
tegra2_pll_clk_init(c);
struct clk_tegra *c = to_clk_tegra(hw);
if (tegra_sku_id == 7)
c->max_rate = 750000000;
}
static struct clk_ops tegra_pllx_ops = {
.init = tegra2_pllx_clk_init,
.enable = tegra2_pll_clk_enable,
.disable = tegra2_pll_clk_disable,
.set_rate = tegra2_pll_clk_set_rate,
struct clk_ops tegra_pllx_ops = {
.init = tegra20_pllx_clk_init,
.is_enabled = tegra20_pll_clk_is_enabled,
.enable = tegra20_pll_clk_enable,
.disable = tegra20_pll_clk_disable,
.set_rate = tegra20_pll_clk_set_rate,
.recalc_rate = tegra20_pll_clk_recalc_rate,
.round_rate = tegra20_pll_clk_round_rate,
};
static int tegra2_plle_clk_enable(struct clk *c)
static int tegra20_plle_clk_enable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
pr_debug("%s on clock %s\n", __func__, c->name);
pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
mdelay(1);
......@@ -752,21 +879,36 @@ static int tegra2_plle_clk_enable(struct clk *c)
return 0;
}
static struct clk_ops tegra_plle_ops = {
.init = tegra2_pll_clk_init,
.enable = tegra2_plle_clk_enable,
.set_rate = tegra2_pll_clk_set_rate,
struct clk_ops tegra_plle_ops = {
.is_enabled = tegra20_pll_clk_is_enabled,
.enable = tegra20_plle_clk_enable,
.set_rate = tegra20_pll_clk_set_rate,
.recalc_rate = tegra20_pll_clk_recalc_rate,
.round_rate = tegra20_pll_clk_round_rate,
};
/* Clock divider ops */
static void tegra2_pll_div_clk_init(struct clk *c)
static int tegra20_pll_div_clk_is_enabled(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
u32 divu71;
val >>= c->reg_shift;
c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
if (!(val & PLL_OUT_RESET_DISABLE))
c->state = OFF;
return c->state;
}
static unsigned long tegra20_pll_div_clk_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u64 rate = prate;
u32 val = clk_readl(c->reg);
u32 divu71;
val >>= c->reg_shift;
if (c->flags & DIV_U71) {
divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
......@@ -779,15 +921,23 @@ static void tegra2_pll_div_clk_init(struct clk *c)
c->div = 1;
c->mul = 1;
}
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
return rate;
}
static int tegra2_pll_div_clk_enable(struct clk *c)
static int tegra20_pll_div_clk_enable(struct clk_hw *hw)
{
u32 val;
u32 new_val;
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long flags;
u32 new_val;
u32 val;
pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
pr_debug("%s: %s\n", __func__, c->name);
if (c->flags & DIV_U71) {
spin_lock_irqsave(&clock_register_lock, flags);
val = clk_readl(c->reg);
......@@ -813,13 +963,15 @@ static int tegra2_pll_div_clk_enable(struct clk *c)
return -EINVAL;
}
static void tegra2_pll_div_clk_disable(struct clk *c)
static void tegra20_pll_div_clk_disable(struct clk_hw *hw)
{
u32 val;
u32 new_val;
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long flags;
u32 new_val;
u32 val;
pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
pr_debug("%s: %s\n", __func__, c->name);
if (c->flags & DIV_U71) {
spin_lock_irqsave(&clock_register_lock, flags);
val = clk_readl(c->reg);
......@@ -842,15 +994,17 @@ static void tegra2_pll_div_clk_disable(struct clk *c)
}
}
static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
static int tegra20_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
u32 val;
u32 new_val;
int divider_u71;
unsigned long parent_rate = clk_get_rate(c->parent);
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long flags;
int divider_u71;
u32 new_val;
u32 val;
pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
pr_debug("%s: %s %lu\n", __func__, c->name, rate);
if (c->flags & DIV_U71) {
divider_u71 = clk_div71_get_divider(parent_rate, rate);
if (divider_u71 >= 0) {
......@@ -878,11 +1032,14 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
return -EINVAL;
}
static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
static long tegra20_pll_div_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long parent_rate = *prate;
int divider;
unsigned long parent_rate = clk_get_rate(c->parent);
pr_debug("%s: %s %lu\n", __func__, c->name, rate);
pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
if (c->flags & DIV_U71) {
divider = clk_div71_get_divider(parent_rate, rate);
......@@ -895,61 +1052,25 @@ static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
return -EINVAL;
}
static struct clk_ops tegra_pll_div_ops = {
.init = tegra2_pll_div_clk_init,
.enable = tegra2_pll_div_clk_enable,
.disable = tegra2_pll_div_clk_disable,
.set_rate = tegra2_pll_div_clk_set_rate,
.round_rate = tegra2_pll_div_clk_round_rate,
struct clk_ops tegra_pll_div_ops = {
.is_enabled = tegra20_pll_div_clk_is_enabled,
.enable = tegra20_pll_div_clk_enable,
.disable = tegra20_pll_div_clk_disable,
.set_rate = tegra20_pll_div_clk_set_rate,
.round_rate = tegra20_pll_div_clk_round_rate,
.recalc_rate = tegra20_pll_div_clk_recalc_rate,
};
/* Periph clk ops */
static void tegra2_periph_clk_init(struct clk *c)
static int tegra20_periph_clk_is_enabled(struct clk_hw *hw)
{
u32 val = clk_readl(c->reg);
const struct clk_mux_sel *mux = NULL;
const struct clk_mux_sel *sel;
u32 shift;
u32 mask;
if (c->flags & MUX_PWM) {
shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
mask = PERIPH_CLK_SOURCE_PWM_MASK;
} else {
shift = PERIPH_CLK_SOURCE_SHIFT;
mask = PERIPH_CLK_SOURCE_MASK;
}
if (c->flags & MUX) {
for (sel = c->inputs; sel->input != NULL; sel++) {
if ((val & mask) >> shift == sel->value)
mux = sel;
}
BUG_ON(!mux);
c->parent = mux->input;
} else {
c->parent = c->inputs[0].input;
}
if (c->flags & DIV_U71) {
u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
c->div = divu71 + 2;
c->mul = 2;
} else if (c->flags & DIV_U16) {
u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
c->div = divu16 + 1;
c->mul = 1;
} else {
c->div = 1;
c->mul = 1;
}
struct clk_tegra *c = to_clk_tegra(hw);
c->state = ON;
if (!c->u.periph.clk_num)
return;
goto out;
if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
PERIPH_CLK_TO_ENB_BIT(c)))
......@@ -959,24 +1080,27 @@ static void tegra2_periph_clk_init(struct clk *c)
if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) &
PERIPH_CLK_TO_ENB_BIT(c))
c->state = OFF;
out:
return c->state;
}
static int tegra2_periph_clk_enable(struct clk *c)
static int tegra20_periph_clk_enable(struct clk_hw *hw)
{
u32 val;
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long flags;
int refcount;
pr_debug("%s on clock %s\n", __func__, c->name);
u32 val;
pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
if (!c->u.periph.clk_num)
return 0;
spin_lock_irqsave(&clock_register_lock, flags);
refcount = tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
return 0;
if (refcount > 1)
goto out;
spin_lock_irqsave(&clock_register_lock, flags);
clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
......@@ -991,39 +1115,41 @@ static int tegra2_periph_clk_enable(struct clk *c)
clk_writel(val, c->reg);
}
out:
spin_unlock_irqrestore(&clock_register_lock, flags);
return 0;
}
static void tegra2_periph_clk_disable(struct clk *c)
static void tegra20_periph_clk_disable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long flags;
pr_debug("%s on clock %s\n", __func__, c->name);
pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
if (!c->u.periph.clk_num)
return;
spin_lock_irqsave(&clock_register_lock, flags);
tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
if (c->refcnt)
tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0)
return;
if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0)
clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
spin_lock_irqsave(&clock_register_lock, flags);
clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
spin_unlock_irqrestore(&clock_register_lock, flags);
}
static void tegra2_periph_clk_reset(struct clk *c, bool assert)
void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert)
{
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long base = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
pr_debug("%s %s on clock %s\n", __func__,
assert ? "assert" : "deassert", c->name);
assert ? "assert" : "deassert", __clk_get_name(hw->clk));
BUG_ON(!c->u.periph.clk_num);
......@@ -1032,13 +1158,14 @@ static void tegra2_periph_clk_reset(struct clk *c, bool assert)
base + PERIPH_CLK_TO_ENB_SET_REG(c));
}
static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
static int tegra20_periph_clk_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
const struct clk_mux_sel *sel;
u32 mask, shift;
u32 mask;
u32 shift;
pr_debug("%s: %s %s\n", __func__, c->name, p->name);
pr_debug("%s: %s %d\n", __func__, __clk_get_name(hw->clk), index);
if (c->flags & MUX_PWM) {
shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
......@@ -1048,36 +1175,78 @@ static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
mask = PERIPH_CLK_SOURCE_MASK;
}
for (sel = c->inputs; sel->input != NULL; sel++) {
if (sel->input == p) {
val = clk_readl(c->reg);
val &= ~mask;
val |= (sel->value) << shift;
val = clk_readl(c->reg);
val &= ~mask;
val |= (index) << shift;
if (c->refcnt)
clk_enable(p);
clk_writel(val, c->reg);
clk_writel(val, c->reg);
return 0;
}
if (c->refcnt && c->parent)
clk_disable(c->parent);
static u8 tegra20_periph_clk_get_parent(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
u32 mask;
u32 shift;
clk_reparent(c, p);
return 0;
}
if (c->flags & MUX_PWM) {
shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
mask = PERIPH_CLK_SOURCE_PWM_MASK;
} else {
shift = PERIPH_CLK_SOURCE_SHIFT;
mask = PERIPH_CLK_SOURCE_MASK;
}
return -EINVAL;
if (c->flags & MUX)
return (val & mask) >> shift;
else
return 0;
}
static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
static unsigned long tegra20_periph_clk_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
u32 val;
int divider;
unsigned long parent_rate = clk_get_rate(c->parent);
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long rate = prate;
u32 val = clk_readl(c->reg);
if (c->flags & DIV_U71) {
u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
c->div = divu71 + 2;
c->mul = 2;
} else if (c->flags & DIV_U16) {
u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
c->div = divu16 + 1;
c->mul = 1;
} else {
c->div = 1;
c->mul = 1;
return rate;
}
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
return rate;
}
static int tegra20_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
int divider;
val = clk_readl(c->reg);
if (c->flags & DIV_U71) {
divider = clk_div71_get_divider(parent_rate, rate);
if (divider >= 0) {
val = clk_readl(c->reg);
val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
......@@ -1103,15 +1272,21 @@ static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
c->mul = 1;
return 0;
}
return -EINVAL;
}
static long tegra2_periph_clk_round_rate(struct clk *c,
unsigned long rate)
static long tegra20_periph_clk_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long *prate)
{
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
int divider;
unsigned long parent_rate = clk_get_rate(c->parent);
pr_debug("%s: %s %lu\n", __func__, c->name, rate);
pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
if (prate)
parent_rate = *prate;
if (c->flags & DIV_U71) {
divider = clk_div71_get_divider(parent_rate, rate);
......@@ -1128,45 +1303,28 @@ static long tegra2_periph_clk_round_rate(struct clk *c,
return -EINVAL;
}
static struct clk_ops tegra_periph_clk_ops = {
.init = &tegra2_periph_clk_init,
.enable = &tegra2_periph_clk_enable,
.disable = &tegra2_periph_clk_disable,
.set_parent = &tegra2_periph_clk_set_parent,
.set_rate = &tegra2_periph_clk_set_rate,
.round_rate = &tegra2_periph_clk_round_rate,
.reset = &tegra2_periph_clk_reset,
struct clk_ops tegra_periph_clk_ops = {
.is_enabled = tegra20_periph_clk_is_enabled,
.enable = tegra20_periph_clk_enable,
.disable = tegra20_periph_clk_disable,
.set_parent = tegra20_periph_clk_set_parent,
.get_parent = tegra20_periph_clk_get_parent,
.set_rate = tegra20_periph_clk_set_rate,
.round_rate = tegra20_periph_clk_round_rate,
.recalc_rate = tegra20_periph_clk_recalc_rate,
};
/* The SDMMC controllers have extra bits in the clock source register that
* adjust the delay between the clock and data to compenstate for delays
* on the PCB. */
void tegra2_sdmmc_tap_delay(struct clk *c, int delay)
{
u32 reg;
unsigned long flags;
spin_lock_irqsave(&c->spinlock, flags);
delay = clamp(delay, 0, 15);
reg = clk_readl(c->reg);
reg &= ~SDMMC_CLK_INT_FB_DLY_MASK;
reg |= SDMMC_CLK_INT_FB_SEL;
reg |= delay << SDMMC_CLK_INT_FB_DLY_SHIFT;
clk_writel(reg, c->reg);
spin_unlock_irqrestore(&c->spinlock, flags);
}
/* External memory controller clock ops */
static void tegra2_emc_clk_init(struct clk *c)
static void tegra20_emc_clk_init(struct clk_hw *hw)
{
tegra2_periph_clk_init(c);
c->max_rate = clk_get_rate_locked(c);
struct clk_tegra *c = to_clk_tegra(hw);
c->max_rate = __clk_get_rate(hw->clk);
}
static long tegra2_emc_clk_round_rate(struct clk *c, unsigned long rate)
static long tegra20_emc_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_tegra *c = to_clk_tegra(hw);
long emc_rate;
long clk_rate;
......@@ -1182,7 +1340,7 @@ static long tegra2_emc_clk_round_rate(struct clk *c, unsigned long rate)
* The fastest rate the PLL will generate that is at most the
* requested rate.
*/
clk_rate = tegra2_periph_clk_round_rate(c, emc_rate);
clk_rate = tegra20_periph_clk_round_rate(hw, emc_rate, NULL);
/*
* If this fails, and emc_rate > clk_rate, it's because the maximum
......@@ -1198,9 +1356,11 @@ static long tegra2_emc_clk_round_rate(struct clk *c, unsigned long rate)
return emc_rate;
}
static int tegra2_emc_clk_set_rate(struct clk *c, unsigned long rate)
static int tegra20_emc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
int ret;
/*
* The Tegra2 memory controller has an interlock with the clock
* block that allows memory shadowed registers to be updated,
......@@ -1211,116 +1371,145 @@ static int tegra2_emc_clk_set_rate(struct clk *c, unsigned long rate)
if (ret < 0)
return ret;
ret = tegra2_periph_clk_set_rate(c, rate);
ret = tegra20_periph_clk_set_rate(hw, rate, parent_rate);
udelay(1);
return ret;
}
static struct clk_ops tegra_emc_clk_ops = {
.init = &tegra2_emc_clk_init,
.enable = &tegra2_periph_clk_enable,
.disable = &tegra2_periph_clk_disable,
.set_parent = &tegra2_periph_clk_set_parent,
.set_rate = &tegra2_emc_clk_set_rate,
.round_rate = &tegra2_emc_clk_round_rate,
.reset = &tegra2_periph_clk_reset,
struct clk_ops tegra_emc_clk_ops = {
.init = tegra20_emc_clk_init,
.is_enabled = tegra20_periph_clk_is_enabled,
.enable = tegra20_periph_clk_enable,
.disable = tegra20_periph_clk_disable,
.set_parent = tegra20_periph_clk_set_parent,
.get_parent = tegra20_periph_clk_get_parent,
.set_rate = tegra20_emc_clk_set_rate,
.round_rate = tegra20_emc_clk_round_rate,
.recalc_rate = tegra20_periph_clk_recalc_rate,
};
/* Clock doubler ops */
static void tegra2_clk_double_init(struct clk *c)
static int tegra20_clk_double_is_enabled(struct clk_hw *hw)
{
c->mul = 2;
c->div = 1;
struct clk_tegra *c = to_clk_tegra(hw);
c->state = ON;
if (!c->u.periph.clk_num)
return;
goto out;
if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
PERIPH_CLK_TO_ENB_BIT(c)))
c->state = OFF;
out:
return c->state;
};
static int tegra2_clk_double_set_rate(struct clk *c, unsigned long rate)
static unsigned long tegra20_clk_double_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
if (rate != 2 * clk_get_rate(c->parent))
return -EINVAL;
struct clk_tegra *c = to_clk_tegra(hw);
u64 rate = prate;
c->mul = 2;
c->div = 1;
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
return rate;
}
static long tegra20_clk_double_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
unsigned long output_rate = *prate;
do_div(output_rate, 2);
return output_rate;
}
static int tegra20_clk_double_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
if (rate != 2 * parent_rate)
return -EINVAL;
return 0;
}
static struct clk_ops tegra_clk_double_ops = {
.init = &tegra2_clk_double_init,
.enable = &tegra2_periph_clk_enable,
.disable = &tegra2_periph_clk_disable,
.set_rate = &tegra2_clk_double_set_rate,
struct clk_ops tegra_clk_double_ops = {
.is_enabled = tegra20_clk_double_is_enabled,
.enable = tegra20_periph_clk_enable,
.disable = tegra20_periph_clk_disable,
.set_rate = tegra20_clk_double_set_rate,
.recalc_rate = tegra20_clk_double_recalc_rate,
.round_rate = tegra20_clk_double_round_rate,
};
/* Audio sync clock ops */
static void tegra2_audio_sync_clk_init(struct clk *c)
static int tegra20_audio_sync_clk_is_enabled(struct clk_hw *hw)
{
int source;
const struct clk_mux_sel *sel;
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
c->state = (val & (1<<4)) ? OFF : ON;
source = val & 0xf;
for (sel = c->inputs; sel->input != NULL; sel++)
if (sel->value == source)
break;
BUG_ON(sel->input == NULL);
c->parent = sel->input;
return c->state;
}
static int tegra2_audio_sync_clk_enable(struct clk *c)
static int tegra20_audio_sync_clk_enable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
clk_writel(0, c->reg);
return 0;
}
static void tegra2_audio_sync_clk_disable(struct clk *c)
static void tegra20_audio_sync_clk_disable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
clk_writel(1, c->reg);
}
static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
static u8 tegra20_audio_sync_clk_get_parent(struct clk_hw *hw)
{
u32 val;
const struct clk_mux_sel *sel;
for (sel = c->inputs; sel->input != NULL; sel++) {
if (sel->input == p) {
val = clk_readl(c->reg);
val &= ~0xf;
val |= sel->value;
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
int source;
if (c->refcnt)
clk_enable(p);
source = val & 0xf;
return source;
}
clk_writel(val, c->reg);
static int tegra20_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
if (c->refcnt && c->parent)
clk_disable(c->parent);
val = clk_readl(c->reg);
val &= ~0xf;
val |= index;
clk_reparent(c, p);
return 0;
}
}
clk_writel(val, c->reg);
return -EINVAL;
return 0;
}
static struct clk_ops tegra_audio_sync_clk_ops = {
.init = tegra2_audio_sync_clk_init,
.enable = tegra2_audio_sync_clk_enable,
.disable = tegra2_audio_sync_clk_disable,
.set_parent = tegra2_audio_sync_clk_set_parent,
struct clk_ops tegra_audio_sync_clk_ops = {
.is_enabled = tegra20_audio_sync_clk_is_enabled,
.enable = tegra20_audio_sync_clk_enable,
.disable = tegra20_audio_sync_clk_disable,
.set_parent = tegra20_audio_sync_clk_set_parent,
.get_parent = tegra20_audio_sync_clk_get_parent,
};
/* cdev1 and cdev2 (dap_mclk1 and dap_mclk2) ops */
static void tegra2_cdev_clk_init(struct clk *c)
static int tegra20_cdev_clk_is_enabled(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
/* We could un-tristate the cdev1 or cdev2 pingroup here; this is
* currently done in the pinmux code. */
c->state = ON;
......@@ -1330,10 +1519,12 @@ static void tegra2_cdev_clk_init(struct clk *c)
if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
PERIPH_CLK_TO_ENB_BIT(c)))
c->state = OFF;
return c->state;
}
static int tegra2_cdev_clk_enable(struct clk *c)
static int tegra20_cdev_clk_enable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
BUG_ON(!c->u.periph.clk_num);
clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
......@@ -1341,1144 +1532,24 @@ static int tegra2_cdev_clk_enable(struct clk *c)
return 0;
}
static void tegra2_cdev_clk_disable(struct clk *c)
static void tegra20_cdev_clk_disable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
BUG_ON(!c->u.periph.clk_num);
clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
}
static struct clk_ops tegra_cdev_clk_ops = {
.init = &tegra2_cdev_clk_init,
.enable = &tegra2_cdev_clk_enable,
.disable = &tegra2_cdev_clk_disable,
};
/* shared bus ops */
/*
* Some clocks may have multiple downstream users that need to request a
* higher clock rate. Shared bus clocks provide a unique shared_bus_user
* clock to each user. The frequency of the bus is set to the highest
* enabled shared_bus_user clock, with a minimum value set by the
* shared bus.
*/
static int tegra_clk_shared_bus_update(struct clk *bus)
{
struct clk *c;
unsigned long rate = bus->min_rate;
list_for_each_entry(c, &bus->shared_bus_list, u.shared_bus_user.node)
if (c->u.shared_bus_user.enabled)
rate = max(c->u.shared_bus_user.rate, rate);
if (rate == clk_get_rate_locked(bus))
return 0;
return clk_set_rate_locked(bus, rate);
};
static void tegra_clk_shared_bus_init(struct clk *c)
{
unsigned long flags;
c->max_rate = c->parent->max_rate;
c->u.shared_bus_user.rate = c->parent->max_rate;
c->state = OFF;
c->set = true;
spin_lock_irqsave(&c->parent->spinlock, flags);
list_add_tail(&c->u.shared_bus_user.node,
&c->parent->shared_bus_list);
spin_unlock_irqrestore(&c->parent->spinlock, flags);
}
static int tegra_clk_shared_bus_set_rate(struct clk *c, unsigned long rate)
{
unsigned long flags;
int ret;
long new_rate = rate;
new_rate = clk_round_rate(c->parent, new_rate);
if (new_rate < 0)
return new_rate;
spin_lock_irqsave(&c->parent->spinlock, flags);
c->u.shared_bus_user.rate = new_rate;
ret = tegra_clk_shared_bus_update(c->parent);
spin_unlock_irqrestore(&c->parent->spinlock, flags);
return ret;
}
static long tegra_clk_shared_bus_round_rate(struct clk *c, unsigned long rate)
{
return clk_round_rate(c->parent, rate);
}
static int tegra_clk_shared_bus_enable(struct clk *c)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&c->parent->spinlock, flags);
c->u.shared_bus_user.enabled = true;
ret = tegra_clk_shared_bus_update(c->parent);
spin_unlock_irqrestore(&c->parent->spinlock, flags);
return ret;
}
static void tegra_clk_shared_bus_disable(struct clk *c)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&c->parent->spinlock, flags);
c->u.shared_bus_user.enabled = false;
ret = tegra_clk_shared_bus_update(c->parent);
WARN_ON_ONCE(ret);
spin_unlock_irqrestore(&c->parent->spinlock, flags);
}
static struct clk_ops tegra_clk_shared_bus_ops = {
.init = tegra_clk_shared_bus_init,
.enable = tegra_clk_shared_bus_enable,
.disable = tegra_clk_shared_bus_disable,
.set_rate = tegra_clk_shared_bus_set_rate,
.round_rate = tegra_clk_shared_bus_round_rate,
};
/* Clock definitions */
static struct clk tegra_clk_32k = {
.name = "clk_32k",
.rate = 32768,
.ops = NULL,
.max_rate = 32768,
};
static struct clk_pll_freq_table tegra_pll_s_freq_table[] = {
{32768, 12000000, 366, 1, 1, 0},
{32768, 13000000, 397, 1, 1, 0},
{32768, 19200000, 586, 1, 1, 0},
{32768, 26000000, 793, 1, 1, 0},
{0, 0, 0, 0, 0, 0},
};
static struct clk tegra_pll_s = {
.name = "pll_s",
.flags = PLL_ALT_MISC_REG,
.ops = &tegra_pll_ops,
.parent = &tegra_clk_32k,
.max_rate = 26000000,
.reg = 0xf0,
.u.pll = {
.input_min = 32768,
.input_max = 32768,
.cf_min = 0, /* FIXME */
.cf_max = 0, /* FIXME */
.vco_min = 12000000,
.vco_max = 26000000,
.freq_table = tegra_pll_s_freq_table,
.lock_delay = 300,
},
};
static struct clk_mux_sel tegra_clk_m_sel[] = {
{ .input = &tegra_clk_32k, .value = 0},
{ .input = &tegra_pll_s, .value = 1},
{ NULL , 0},
};
static struct clk tegra_clk_m = {
.name = "clk_m",
.flags = ENABLE_ON_INIT,
.ops = &tegra_clk_m_ops,
.inputs = tegra_clk_m_sel,
.reg = 0x1fc,
.reg_shift = 28,
.max_rate = 26000000,
};
static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
{ 12000000, 600000000, 600, 12, 1, 8 },
{ 13000000, 600000000, 600, 13, 1, 8 },
{ 19200000, 600000000, 500, 16, 1, 6 },
{ 26000000, 600000000, 600, 26, 1, 8 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_c = {
.name = "pll_c",
.flags = PLL_HAS_CPCON,
.ops = &tegra_pll_ops,
.reg = 0x80,
.parent = &tegra_clk_m,
.max_rate = 600000000,
.u.pll = {
.input_min = 2000000,
.input_max = 31000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 20000000,
.vco_max = 1400000000,
.freq_table = tegra_pll_c_freq_table,
.lock_delay = 300,
},
};
static struct clk tegra_pll_c_out1 = {
.name = "pll_c_out1",
.ops = &tegra_pll_div_ops,
.flags = DIV_U71,
.parent = &tegra_pll_c,
.reg = 0x84,
.reg_shift = 0,
.max_rate = 600000000,
};
static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
{ 12000000, 666000000, 666, 12, 1, 8},
{ 13000000, 666000000, 666, 13, 1, 8},
{ 19200000, 666000000, 555, 16, 1, 8},
{ 26000000, 666000000, 666, 26, 1, 8},
{ 12000000, 600000000, 600, 12, 1, 8},
{ 13000000, 600000000, 600, 13, 1, 8},
{ 19200000, 600000000, 375, 12, 1, 6},
{ 26000000, 600000000, 600, 26, 1, 8},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_m = {
.name = "pll_m",
.flags = PLL_HAS_CPCON,
.ops = &tegra_pll_ops,
.reg = 0x90,
.parent = &tegra_clk_m,
.max_rate = 800000000,
.u.pll = {
.input_min = 2000000,
.input_max = 31000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 20000000,
.vco_max = 1200000000,
.freq_table = tegra_pll_m_freq_table,
.lock_delay = 300,
},
};
static struct clk tegra_pll_m_out1 = {
.name = "pll_m_out1",
.ops = &tegra_pll_div_ops,
.flags = DIV_U71,
.parent = &tegra_pll_m,
.reg = 0x94,
.reg_shift = 0,
.max_rate = 600000000,
};
static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
{ 12000000, 216000000, 432, 12, 2, 8},
{ 13000000, 216000000, 432, 13, 2, 8},
{ 19200000, 216000000, 90, 4, 2, 1},
{ 26000000, 216000000, 432, 26, 2, 8},
{ 12000000, 432000000, 432, 12, 1, 8},
{ 13000000, 432000000, 432, 13, 1, 8},
{ 19200000, 432000000, 90, 4, 1, 1},
{ 26000000, 432000000, 432, 26, 1, 8},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_p = {
.name = "pll_p",
.flags = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
.ops = &tegra_pll_ops,
.reg = 0xa0,
.parent = &tegra_clk_m,
.max_rate = 432000000,
.u.pll = {
.input_min = 2000000,
.input_max = 31000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 20000000,
.vco_max = 1400000000,
.freq_table = tegra_pll_p_freq_table,
.lock_delay = 300,
},
};
static struct clk tegra_pll_p_out1 = {
.name = "pll_p_out1",
.ops = &tegra_pll_div_ops,
.flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
.parent = &tegra_pll_p,
.reg = 0xa4,
.reg_shift = 0,
.max_rate = 432000000,
};
static struct clk tegra_pll_p_out2 = {
.name = "pll_p_out2",
.ops = &tegra_pll_div_ops,
.flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
.parent = &tegra_pll_p,
.reg = 0xa4,
.reg_shift = 16,
.max_rate = 432000000,
};
static struct clk tegra_pll_p_out3 = {
.name = "pll_p_out3",
.ops = &tegra_pll_div_ops,
.flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
.parent = &tegra_pll_p,
.reg = 0xa8,
.reg_shift = 0,
.max_rate = 432000000,
};
static struct clk tegra_pll_p_out4 = {
.name = "pll_p_out4",
.ops = &tegra_pll_div_ops,
.flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
.parent = &tegra_pll_p,
.reg = 0xa8,
.reg_shift = 16,
.max_rate = 432000000,
};
static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
{ 28800000, 56448000, 49, 25, 1, 1},
{ 28800000, 73728000, 64, 25, 1, 1},
{ 28800000, 24000000, 5, 6, 1, 1},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_a = {
.name = "pll_a",
.flags = PLL_HAS_CPCON,
.ops = &tegra_pll_ops,
.reg = 0xb0,
.parent = &tegra_pll_p_out1,
.max_rate = 73728000,
.u.pll = {
.input_min = 2000000,
.input_max = 31000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 20000000,
.vco_max = 1400000000,
.freq_table = tegra_pll_a_freq_table,
.lock_delay = 300,
},
};
static struct clk tegra_pll_a_out0 = {
.name = "pll_a_out0",
.ops = &tegra_pll_div_ops,
.flags = DIV_U71,
.parent = &tegra_pll_a,
.reg = 0xb4,
.reg_shift = 0,
.max_rate = 73728000,
};
static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
{ 12000000, 216000000, 216, 12, 1, 4},
{ 13000000, 216000000, 216, 13, 1, 4},
{ 19200000, 216000000, 135, 12, 1, 3},
{ 26000000, 216000000, 216, 26, 1, 4},
{ 12000000, 594000000, 594, 12, 1, 8},
{ 13000000, 594000000, 594, 13, 1, 8},
{ 19200000, 594000000, 495, 16, 1, 8},
{ 26000000, 594000000, 594, 26, 1, 8},
{ 12000000, 1000000000, 1000, 12, 1, 12},
{ 13000000, 1000000000, 1000, 13, 1, 12},
{ 19200000, 1000000000, 625, 12, 1, 8},
{ 26000000, 1000000000, 1000, 26, 1, 12},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_d = {
.name = "pll_d",
.flags = PLL_HAS_CPCON | PLLD,
.ops = &tegra_pll_ops,
.reg = 0xd0,
.parent = &tegra_clk_m,
.max_rate = 1000000000,
.u.pll = {
.input_min = 2000000,
.input_max = 40000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 40000000,
.vco_max = 1000000000,
.freq_table = tegra_pll_d_freq_table,
.lock_delay = 1000,
},
};
static struct clk tegra_pll_d_out0 = {
.name = "pll_d_out0",
.ops = &tegra_pll_div_ops,
.flags = DIV_2 | PLLD,
.parent = &tegra_pll_d,
.max_rate = 500000000,
};
static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
{ 12000000, 480000000, 960, 12, 2, 0},
{ 13000000, 480000000, 960, 13, 2, 0},
{ 19200000, 480000000, 200, 4, 2, 0},
{ 26000000, 480000000, 960, 26, 2, 0},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_u = {
.name = "pll_u",
.flags = PLLU,
.ops = &tegra_pll_ops,
.reg = 0xc0,
.parent = &tegra_clk_m,
.max_rate = 480000000,
.u.pll = {
.input_min = 2000000,
.input_max = 40000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 480000000,
.vco_max = 960000000,
.freq_table = tegra_pll_u_freq_table,
.lock_delay = 1000,
},
};
static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
/* 1 GHz */
{ 12000000, 1000000000, 1000, 12, 1, 12},
{ 13000000, 1000000000, 1000, 13, 1, 12},
{ 19200000, 1000000000, 625, 12, 1, 8},
{ 26000000, 1000000000, 1000, 26, 1, 12},
/* 912 MHz */
{ 12000000, 912000000, 912, 12, 1, 12},
{ 13000000, 912000000, 912, 13, 1, 12},
{ 19200000, 912000000, 760, 16, 1, 8},
{ 26000000, 912000000, 912, 26, 1, 12},
/* 816 MHz */
{ 12000000, 816000000, 816, 12, 1, 12},
{ 13000000, 816000000, 816, 13, 1, 12},
{ 19200000, 816000000, 680, 16, 1, 8},
{ 26000000, 816000000, 816, 26, 1, 12},
/* 760 MHz */
{ 12000000, 760000000, 760, 12, 1, 12},
{ 13000000, 760000000, 760, 13, 1, 12},
{ 19200000, 760000000, 950, 24, 1, 8},
{ 26000000, 760000000, 760, 26, 1, 12},
/* 750 MHz */
{ 12000000, 750000000, 750, 12, 1, 12},
{ 13000000, 750000000, 750, 13, 1, 12},
{ 19200000, 750000000, 625, 16, 1, 8},
{ 26000000, 750000000, 750, 26, 1, 12},
/* 608 MHz */
{ 12000000, 608000000, 608, 12, 1, 12},
{ 13000000, 608000000, 608, 13, 1, 12},
{ 19200000, 608000000, 380, 12, 1, 8},
{ 26000000, 608000000, 608, 26, 1, 12},
/* 456 MHz */
{ 12000000, 456000000, 456, 12, 1, 12},
{ 13000000, 456000000, 456, 13, 1, 12},
{ 19200000, 456000000, 380, 16, 1, 8},
{ 26000000, 456000000, 456, 26, 1, 12},
/* 312 MHz */
{ 12000000, 312000000, 312, 12, 1, 12},
{ 13000000, 312000000, 312, 13, 1, 12},
{ 19200000, 312000000, 260, 16, 1, 8},
{ 26000000, 312000000, 312, 26, 1, 12},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_x = {
.name = "pll_x",
.flags = PLL_HAS_CPCON | PLL_ALT_MISC_REG,
.ops = &tegra_pllx_ops,
.reg = 0xe0,
.parent = &tegra_clk_m,
.max_rate = 1000000000,
.u.pll = {
.input_min = 2000000,
.input_max = 31000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 20000000,
.vco_max = 1200000000,
.freq_table = tegra_pll_x_freq_table,
.lock_delay = 300,
},
};
static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
{ 12000000, 100000000, 200, 24, 1, 0 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_e = {
.name = "pll_e",
.flags = PLL_ALT_MISC_REG,
.ops = &tegra_plle_ops,
.parent = &tegra_clk_m,
.reg = 0xe8,
.max_rate = 100000000,
.u.pll = {
.input_min = 12000000,
.input_max = 12000000,
.freq_table = tegra_pll_e_freq_table,
},
};
static struct clk tegra_clk_d = {
.name = "clk_d",
.flags = PERIPH_NO_RESET,
.ops = &tegra_clk_double_ops,
.reg = 0x34,
.reg_shift = 12,
.parent = &tegra_clk_m,
.max_rate = 52000000,
.u.periph = {
.clk_num = 90,
},
};
/* dap_mclk1, belongs to the cdev1 pingroup. */
static struct clk tegra_clk_cdev1 = {
.name = "cdev1",
.ops = &tegra_cdev_clk_ops,
.rate = 26000000,
.max_rate = 26000000,
.u.periph = {
.clk_num = 94,
},
};
/* dap_mclk2, belongs to the cdev2 pingroup. */
static struct clk tegra_clk_cdev2 = {
.name = "cdev2",
.ops = &tegra_cdev_clk_ops,
.rate = 26000000,
.max_rate = 26000000,
.u.periph = {
.clk_num = 93,
},
};
/* initialized before peripheral clocks */
static struct clk_mux_sel mux_audio_sync_clk[8+1];
static const struct audio_sources {
const char *name;
int value;
} mux_audio_sync_clk_sources[] = {
{ .name = "spdif_in", .value = 0 },
{ .name = "i2s1", .value = 1 },
{ .name = "i2s2", .value = 2 },
{ .name = "pll_a_out0", .value = 4 },
#if 0 /* FIXME: not implemented */
{ .name = "ac97", .value = 3 },
{ .name = "ext_audio_clk2", .value = 5 },
{ .name = "ext_audio_clk1", .value = 6 },
{ .name = "ext_vimclk", .value = 7 },
#endif
{ NULL, 0 }
};
static struct clk tegra_clk_audio = {
.name = "audio",
.inputs = mux_audio_sync_clk,
.reg = 0x38,
.max_rate = 73728000,
.ops = &tegra_audio_sync_clk_ops
};
static struct clk tegra_clk_audio_2x = {
.name = "audio_2x",
.flags = PERIPH_NO_RESET,
.max_rate = 48000000,
.ops = &tegra_clk_double_ops,
.reg = 0x34,
.reg_shift = 8,
.parent = &tegra_clk_audio,
.u.periph = {
.clk_num = 89,
},
};
static struct clk_lookup tegra_audio_clk_lookups[] = {
{ .con_id = "audio", .clk = &tegra_clk_audio },
{ .con_id = "audio_2x", .clk = &tegra_clk_audio_2x }
};
/* This is called after peripheral clocks are initialized, as the
* audio_sync clock depends on some of the peripheral clocks.
*/
static void init_audio_sync_clock_mux(void)
static unsigned long tegra20_cdev_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
int i;
struct clk_mux_sel *sel = mux_audio_sync_clk;
const struct audio_sources *src = mux_audio_sync_clk_sources;
struct clk_lookup *lookup;
for (i = 0; src->name; i++, sel++, src++) {
sel->input = tegra_get_clock_by_name(src->name);
if (!sel->input)
pr_err("%s: could not find clk %s\n", __func__,
src->name);
sel->value = src->value;
}
lookup = tegra_audio_clk_lookups;
for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) {
clk_init(lookup->clk);
clkdev_add(lookup);
}
return to_clk_tegra(hw)->fixed_rate;
}
static struct clk_mux_sel mux_cclk[] = {
{ .input = &tegra_clk_m, .value = 0},
{ .input = &tegra_pll_c, .value = 1},
{ .input = &tegra_clk_32k, .value = 2},
{ .input = &tegra_pll_m, .value = 3},
{ .input = &tegra_pll_p, .value = 4},
{ .input = &tegra_pll_p_out4, .value = 5},
{ .input = &tegra_pll_p_out3, .value = 6},
{ .input = &tegra_clk_d, .value = 7},
{ .input = &tegra_pll_x, .value = 8},
{ NULL, 0},
struct clk_ops tegra_cdev_clk_ops = {
.is_enabled = tegra20_cdev_clk_is_enabled,
.enable = tegra20_cdev_clk_enable,
.disable = tegra20_cdev_clk_disable,
.recalc_rate = tegra20_cdev_recalc_rate,
};
static struct clk_mux_sel mux_sclk[] = {
{ .input = &tegra_clk_m, .value = 0},
{ .input = &tegra_pll_c_out1, .value = 1},
{ .input = &tegra_pll_p_out4, .value = 2},
{ .input = &tegra_pll_p_out3, .value = 3},
{ .input = &tegra_pll_p_out2, .value = 4},
{ .input = &tegra_clk_d, .value = 5},
{ .input = &tegra_clk_32k, .value = 6},
{ .input = &tegra_pll_m_out1, .value = 7},
{ NULL, 0},
};
static struct clk tegra_clk_cclk = {
.name = "cclk",
.inputs = mux_cclk,
.reg = 0x20,
.ops = &tegra_super_ops,
.max_rate = 1000000000,
};
static struct clk tegra_clk_sclk = {
.name = "sclk",
.inputs = mux_sclk,
.reg = 0x28,
.ops = &tegra_super_ops,
.max_rate = 240000000,
.min_rate = 120000000,
};
static struct clk tegra_clk_virtual_cpu = {
.name = "cpu",
.parent = &tegra_clk_cclk,
.ops = &tegra_cpu_ops,
.max_rate = 1000000000,
.u.cpu = {
.main = &tegra_pll_x,
.backup = &tegra_pll_p,
},
};
static struct clk tegra_clk_cop = {
.name = "cop",
.parent = &tegra_clk_sclk,
.ops = &tegra_cop_ops,
.max_rate = 240000000,
};
static struct clk tegra_clk_hclk = {
.name = "hclk",
.flags = DIV_BUS,
.parent = &tegra_clk_sclk,
.reg = 0x30,
.reg_shift = 4,
.ops = &tegra_bus_ops,
.max_rate = 240000000,
};
static struct clk tegra_clk_pclk = {
.name = "pclk",
.flags = DIV_BUS,
.parent = &tegra_clk_hclk,
.reg = 0x30,
.reg_shift = 0,
.ops = &tegra_bus_ops,
.max_rate = 120000000,
};
static struct clk tegra_clk_blink = {
.name = "blink",
.parent = &tegra_clk_32k,
.reg = 0x40,
.ops = &tegra_blink_clk_ops,
.max_rate = 32768,
};
static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
{ .input = &tegra_pll_m, .value = 0},
{ .input = &tegra_pll_c, .value = 1},
{ .input = &tegra_pll_p, .value = 2},
{ .input = &tegra_pll_a_out0, .value = 3},
{ NULL, 0},
};
static struct clk_mux_sel mux_pllm_pllc_pllp_clkm[] = {
{ .input = &tegra_pll_m, .value = 0},
{ .input = &tegra_pll_c, .value = 1},
{ .input = &tegra_pll_p, .value = 2},
{ .input = &tegra_clk_m, .value = 3},
{ NULL, 0},
};
static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
{ .input = &tegra_pll_p, .value = 0},
{ .input = &tegra_pll_c, .value = 1},
{ .input = &tegra_pll_m, .value = 2},
{ .input = &tegra_clk_m, .value = 3},
{ NULL, 0},
};
static struct clk_mux_sel mux_pllaout0_audio2x_pllp_clkm[] = {
{.input = &tegra_pll_a_out0, .value = 0},
{.input = &tegra_clk_audio_2x, .value = 1},
{.input = &tegra_pll_p, .value = 2},
{.input = &tegra_clk_m, .value = 3},
{ NULL, 0},
};
static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
{.input = &tegra_pll_p, .value = 0},
{.input = &tegra_pll_d_out0, .value = 1},
{.input = &tegra_pll_c, .value = 2},
{.input = &tegra_clk_m, .value = 3},
{ NULL, 0},
};
static struct clk_mux_sel mux_pllp_pllc_audio_clkm_clk32[] = {
{.input = &tegra_pll_p, .value = 0},
{.input = &tegra_pll_c, .value = 1},
{.input = &tegra_clk_audio, .value = 2},
{.input = &tegra_clk_m, .value = 3},
{.input = &tegra_clk_32k, .value = 4},
{ NULL, 0},
};
static struct clk_mux_sel mux_pllp_pllc_pllm[] = {
{.input = &tegra_pll_p, .value = 0},
{.input = &tegra_pll_c, .value = 1},
{.input = &tegra_pll_m, .value = 2},
{ NULL, 0},
};
static struct clk_mux_sel mux_clk_m[] = {
{ .input = &tegra_clk_m, .value = 0},
{ NULL, 0},
};
static struct clk_mux_sel mux_pllp_out3[] = {
{ .input = &tegra_pll_p_out3, .value = 0},
{ NULL, 0},
};
static struct clk_mux_sel mux_plld[] = {
{ .input = &tegra_pll_d, .value = 0},
{ NULL, 0},
};
static struct clk_mux_sel mux_clk_32k[] = {
{ .input = &tegra_clk_32k, .value = 0},
{ NULL, 0},
};
static struct clk_mux_sel mux_pclk[] = {
{ .input = &tegra_clk_pclk, .value = 0},
{ NULL, 0},
};
static struct clk tegra_clk_emc = {
.name = "emc",
.ops = &tegra_emc_clk_ops,
.reg = 0x19c,
.max_rate = 800000000,
.inputs = mux_pllm_pllc_pllp_clkm,
.flags = MUX | DIV_U71 | PERIPH_EMC_ENB,
.u.periph = {
.clk_num = 57,
},
};
#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
{ \
.name = _name, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
.ops = &tegra_periph_clk_ops, \
.reg = _reg, \
.inputs = _inputs, \
.flags = _flags, \
.max_rate = _max, \
.u.periph = { \
.clk_num = _clk_num, \
}, \
}
#define SHARED_CLK(_name, _dev, _con, _parent) \
{ \
.name = _name, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
.ops = &tegra_clk_shared_bus_ops, \
.parent = _parent, \
}
static struct clk tegra_list_clks[] = {
PERIPH_CLK("apbdma", "tegra-apbdma", NULL, 34, 0, 108000000, mux_pclk, 0),
PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET),
PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0),
PERIPH_CLK("i2s1", "tegra20-i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
PERIPH_CLK("i2s2", "tegra20-i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
PERIPH_CLK("spdif_out", "spdif_out", NULL, 10, 0x108, 100000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
PERIPH_CLK("spdif_in", "spdif_in", NULL, 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71),
PERIPH_CLK("pwm", "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71 | MUX_PWM),
PERIPH_CLK("spi", "spi", NULL, 43, 0x114, 40000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("xio", "xio", NULL, 45, 0x120, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("twc", "twc", NULL, 16, 0x12c, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("sbc1", "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("sbc2", "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("sbc3", "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("sbc4", "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("ide", "ide", NULL, 25, 0x144, 100000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("ndflash", "tegra_nand", NULL, 13, 0x160, 164000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
PERIPH_CLK("vfir", "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("sdmmc1", "sdhci-tegra.0", NULL, 14, 0x150, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
PERIPH_CLK("sdmmc3", "sdhci-tegra.2", NULL, 69, 0x1bc, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
PERIPH_CLK("sdmmc4", "sdhci-tegra.3", NULL, 15, 0x164, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
PERIPH_CLK("vcp", "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0),
PERIPH_CLK("bsea", "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0),
PERIPH_CLK("bsev", "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0),
PERIPH_CLK("vde", "tegra-avp", "vde", 61, 0x1c8, 250000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage and process_id */
PERIPH_CLK("csite", "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* max rate ??? */
/* FIXME: what is la? */
PERIPH_CLK("la", "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("owr", "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("nor", "nor", NULL, 42, 0x1d0, 92000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("mipi", "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
PERIPH_CLK("i2c1", "tegra-i2c.0", NULL, 12, 0x124, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16),
PERIPH_CLK("i2c2", "tegra-i2c.1", NULL, 54, 0x198, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16),
PERIPH_CLK("i2c3", "tegra-i2c.2", NULL, 67, 0x1b8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16),
PERIPH_CLK("dvc", "tegra-i2c.3", NULL, 47, 0x128, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16),
PERIPH_CLK("i2c1_i2c", "tegra-i2c.0", "i2c", 0, 0, 72000000, mux_pllp_out3, 0),
PERIPH_CLK("i2c2_i2c", "tegra-i2c.1", "i2c", 0, 0, 72000000, mux_pllp_out3, 0),
PERIPH_CLK("i2c3_i2c", "tegra-i2c.2", "i2c", 0, 0, 72000000, mux_pllp_out3, 0),
PERIPH_CLK("dvc_i2c", "tegra-i2c.3", "i2c", 0, 0, 72000000, mux_pllp_out3, 0),
PERIPH_CLK("uarta", "tegra-uart.0", NULL, 6, 0x178, 600000000, mux_pllp_pllc_pllm_clkm, MUX),
PERIPH_CLK("uartb", "tegra-uart.1", NULL, 7, 0x17c, 600000000, mux_pllp_pllc_pllm_clkm, MUX),
PERIPH_CLK("uartc", "tegra-uart.2", NULL, 55, 0x1a0, 600000000, mux_pllp_pllc_pllm_clkm, MUX),
PERIPH_CLK("uartd", "tegra-uart.3", NULL, 65, 0x1c0, 600000000, mux_pllp_pllc_pllm_clkm, MUX),
PERIPH_CLK("uarte", "tegra-uart.4", NULL, 66, 0x1c4, 600000000, mux_pllp_pllc_pllm_clkm, MUX),
PERIPH_CLK("3d", "3d", NULL, 24, 0x158, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_MANUAL_RESET), /* scales with voltage and process_id */
PERIPH_CLK("2d", "2d", NULL, 21, 0x15c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
PERIPH_CLK("vi", "tegra_camera", "vi", 20, 0x148, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
PERIPH_CLK("vi_sensor", "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET), /* scales with voltage and process_id */
PERIPH_CLK("epp", "epp", NULL, 19, 0x16c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
PERIPH_CLK("mpe", "mpe", NULL, 60, 0x170, 250000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
PERIPH_CLK("host1x", "host1x", NULL, 28, 0x180, 166000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
PERIPH_CLK("cve", "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("tvo", "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, 600000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("disp1", "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_plld_pllc_clkm, MUX), /* scales with voltage and process_id */
PERIPH_CLK("disp2", "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_plld_pllc_clkm, MUX), /* scales with voltage and process_id */
PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb2", "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb3", "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("dsi", "dsi", NULL, 48, 0, 500000000, mux_plld, 0), /* scales with voltage */
PERIPH_CLK("csi", "tegra_camera", "csi", 52, 0, 72000000, mux_pllp_out3, 0),
PERIPH_CLK("isp", "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0), /* same frequency as VI */
PERIPH_CLK("csus", "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET),
PERIPH_CLK("pex", NULL, "pex", 70, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET),
PERIPH_CLK("afi", NULL, "afi", 72, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET),
PERIPH_CLK("pcie_xclk", NULL, "pcie_xclk", 74, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET),
SHARED_CLK("avp.sclk", "tegra-avp", "sclk", &tegra_clk_sclk),
SHARED_CLK("avp.emc", "tegra-avp", "emc", &tegra_clk_emc),
SHARED_CLK("cpu.emc", "cpu", "emc", &tegra_clk_emc),
SHARED_CLK("disp1.emc", "tegradc.0", "emc", &tegra_clk_emc),
SHARED_CLK("disp2.emc", "tegradc.1", "emc", &tegra_clk_emc),
SHARED_CLK("hdmi.emc", "hdmi", "emc", &tegra_clk_emc),
SHARED_CLK("host.emc", "tegra_grhost", "emc", &tegra_clk_emc),
SHARED_CLK("usbd.emc", "fsl-tegra-udc", "emc", &tegra_clk_emc),
SHARED_CLK("usb1.emc", "tegra-ehci.0", "emc", &tegra_clk_emc),
SHARED_CLK("usb2.emc", "tegra-ehci.1", "emc", &tegra_clk_emc),
SHARED_CLK("usb3.emc", "tegra-ehci.2", "emc", &tegra_clk_emc),
};
#define CLK_DUPLICATE(_name, _dev, _con) \
{ \
.name = _name, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
}
/* Some clocks may be used by different drivers depending on the board
* configuration. List those here to register them twice in the clock lookup
* table under two names.
*/
static struct clk_duplicate tegra_clk_duplicates[] = {
CLK_DUPLICATE("uarta", "serial8250.0", NULL),
CLK_DUPLICATE("uartb", "serial8250.1", NULL),
CLK_DUPLICATE("uartc", "serial8250.2", NULL),
CLK_DUPLICATE("uartd", "serial8250.3", NULL),
CLK_DUPLICATE("uarte", "serial8250.4", NULL),
CLK_DUPLICATE("usbd", "utmip-pad", NULL),
CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
CLK_DUPLICATE("usbd", "tegra-otg", NULL),
CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
CLK_DUPLICATE("host1x", "tegra_grhost", "host1x"),
CLK_DUPLICATE("2d", "tegra_grhost", "gr2d"),
CLK_DUPLICATE("3d", "tegra_grhost", "gr3d"),
CLK_DUPLICATE("epp", "tegra_grhost", "epp"),
CLK_DUPLICATE("mpe", "tegra_grhost", "mpe"),
CLK_DUPLICATE("cop", "tegra-avp", "cop"),
CLK_DUPLICATE("vde", "tegra-aes", "vde"),
};
#define CLK(dev, con, ck) \
{ \
.dev_id = dev, \
.con_id = con, \
.clk = ck, \
}
static struct clk *tegra_ptr_clks[] = {
&tegra_clk_32k,
&tegra_pll_s,
&tegra_clk_m,
&tegra_pll_m,
&tegra_pll_m_out1,
&tegra_pll_c,
&tegra_pll_c_out1,
&tegra_pll_p,
&tegra_pll_p_out1,
&tegra_pll_p_out2,
&tegra_pll_p_out3,
&tegra_pll_p_out4,
&tegra_pll_a,
&tegra_pll_a_out0,
&tegra_pll_d,
&tegra_pll_d_out0,
&tegra_pll_u,
&tegra_pll_x,
&tegra_pll_e,
&tegra_clk_cclk,
&tegra_clk_sclk,
&tegra_clk_hclk,
&tegra_clk_pclk,
&tegra_clk_d,
&tegra_clk_cdev1,
&tegra_clk_cdev2,
&tegra_clk_virtual_cpu,
&tegra_clk_blink,
&tegra_clk_cop,
&tegra_clk_emc,
};
static void tegra2_init_one_clock(struct clk *c)
{
clk_init(c);
INIT_LIST_HEAD(&c->shared_bus_list);
if (!c->lookup.dev_id && !c->lookup.con_id)
c->lookup.con_id = c->name;
c->lookup.clk = c;
clkdev_add(&c->lookup);
}
void __init tegra2_init_clocks(void)
{
int i;
struct clk *c;
for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
tegra2_init_one_clock(tegra_ptr_clks[i]);
for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
tegra2_init_one_clock(&tegra_list_clks[i]);
for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
if (!c) {
pr_err("%s: Unknown duplicate clock %s\n", __func__,
tegra_clk_duplicates[i].name);
continue;
}
tegra_clk_duplicates[i].lookup.clk = c;
clkdev_add(&tegra_clk_duplicates[i].lookup);
}
init_audio_sync_clock_mux();
}
#ifdef CONFIG_PM
static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +
PERIPH_CLK_SOURCE_NUM + 22];
void tegra_clk_suspend(void)
{
unsigned long off, i;
u32 *ctx = clk_rst_suspend;
*ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK;
*ctx++ = clk_readl(tegra_pll_c.reg + PLL_BASE);
*ctx++ = clk_readl(tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
*ctx++ = clk_readl(tegra_pll_a.reg + PLL_BASE);
*ctx++ = clk_readl(tegra_pll_a.reg + PLL_MISC(&tegra_pll_a));
*ctx++ = clk_readl(tegra_pll_s.reg + PLL_BASE);
*ctx++ = clk_readl(tegra_pll_s.reg + PLL_MISC(&tegra_pll_s));
*ctx++ = clk_readl(tegra_pll_d.reg + PLL_BASE);
*ctx++ = clk_readl(tegra_pll_d.reg + PLL_MISC(&tegra_pll_d));
*ctx++ = clk_readl(tegra_pll_u.reg + PLL_BASE);
*ctx++ = clk_readl(tegra_pll_u.reg + PLL_MISC(&tegra_pll_u));
*ctx++ = clk_readl(tegra_pll_m_out1.reg);
*ctx++ = clk_readl(tegra_pll_a_out0.reg);
*ctx++ = clk_readl(tegra_pll_c_out1.reg);
*ctx++ = clk_readl(tegra_clk_cclk.reg);
*ctx++ = clk_readl(tegra_clk_cclk.reg + SUPER_CLK_DIVIDER);
*ctx++ = clk_readl(tegra_clk_sclk.reg);
*ctx++ = clk_readl(tegra_clk_sclk.reg + SUPER_CLK_DIVIDER);
*ctx++ = clk_readl(tegra_clk_pclk.reg);
*ctx++ = clk_readl(tegra_clk_audio.reg);
for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
off += 4) {
if (off == PERIPH_CLK_SOURCE_EMC)
continue;
*ctx++ = clk_readl(off);
}
off = RST_DEVICES;
for (i = 0; i < RST_DEVICES_NUM; i++, off += 4)
*ctx++ = clk_readl(off);
off = CLK_OUT_ENB;
for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4)
*ctx++ = clk_readl(off);
*ctx++ = clk_readl(MISC_CLK_ENB);
*ctx++ = clk_readl(CLK_MASK_ARM);
BUG_ON(ctx - clk_rst_suspend != ARRAY_SIZE(clk_rst_suspend));
}
void tegra_clk_resume(void)
{
unsigned long off, i;
const u32 *ctx = clk_rst_suspend;
u32 val;
val = clk_readl(OSC_CTRL) & ~OSC_CTRL_MASK;
val |= *ctx++;
clk_writel(val, OSC_CTRL);
clk_writel(*ctx++, tegra_pll_c.reg + PLL_BASE);
clk_writel(*ctx++, tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
clk_writel(*ctx++, tegra_pll_a.reg + PLL_BASE);
clk_writel(*ctx++, tegra_pll_a.reg + PLL_MISC(&tegra_pll_a));
clk_writel(*ctx++, tegra_pll_s.reg + PLL_BASE);
clk_writel(*ctx++, tegra_pll_s.reg + PLL_MISC(&tegra_pll_s));
clk_writel(*ctx++, tegra_pll_d.reg + PLL_BASE);
clk_writel(*ctx++, tegra_pll_d.reg + PLL_MISC(&tegra_pll_d));
clk_writel(*ctx++, tegra_pll_u.reg + PLL_BASE);
clk_writel(*ctx++, tegra_pll_u.reg + PLL_MISC(&tegra_pll_u));
udelay(1000);
clk_writel(*ctx++, tegra_pll_m_out1.reg);
clk_writel(*ctx++, tegra_pll_a_out0.reg);
clk_writel(*ctx++, tegra_pll_c_out1.reg);
clk_writel(*ctx++, tegra_clk_cclk.reg);
clk_writel(*ctx++, tegra_clk_cclk.reg + SUPER_CLK_DIVIDER);
clk_writel(*ctx++, tegra_clk_sclk.reg);
clk_writel(*ctx++, tegra_clk_sclk.reg + SUPER_CLK_DIVIDER);
clk_writel(*ctx++, tegra_clk_pclk.reg);
clk_writel(*ctx++, tegra_clk_audio.reg);
/* enable all clocks before configuring clock sources */
clk_writel(0xbffffff9ul, CLK_OUT_ENB);
clk_writel(0xfefffff7ul, CLK_OUT_ENB + 4);
clk_writel(0x77f01bfful, CLK_OUT_ENB + 8);
wmb();
for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
off += 4) {
if (off == PERIPH_CLK_SOURCE_EMC)
continue;
clk_writel(*ctx++, off);
}
wmb();
off = RST_DEVICES;
for (i = 0; i < RST_DEVICES_NUM; i++, off += 4)
clk_writel(*ctx++, off);
wmb();
off = CLK_OUT_ENB;
for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4)
clk_writel(*ctx++, off);
wmb();
clk_writel(*ctx++, MISC_CLK_ENB);
clk_writel(*ctx++, CLK_MASK_ARM);
}
#endif
/*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MACH_TEGRA20_CLOCK_H
#define __MACH_TEGRA20_CLOCK_H
extern struct clk_ops tegra_clk_32k_ops;
extern struct clk_ops tegra_pll_ops;
extern struct clk_ops tegra_clk_m_ops;
extern struct clk_ops tegra_pll_div_ops;
extern struct clk_ops tegra_pllx_ops;
extern struct clk_ops tegra_plle_ops;
extern struct clk_ops tegra_clk_double_ops;
extern struct clk_ops tegra_cdev_clk_ops;
extern struct clk_ops tegra_audio_sync_clk_ops;
extern struct clk_ops tegra_super_ops;
extern struct clk_ops tegra_cpu_ops;
extern struct clk_ops tegra_twd_ops;
extern struct clk_ops tegra_cop_ops;
extern struct clk_ops tegra_bus_ops;
extern struct clk_ops tegra_blink_clk_ops;
extern struct clk_ops tegra_emc_clk_ops;
extern struct clk_ops tegra_periph_clk_ops;
extern struct clk_ops tegra_clk_shared_bus_ops;
void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert);
void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert);
#endif
/*
* arch/arm/mach-tegra/tegra2_clocks.c
*
* Copyright (C) 2010 Google, Inc.
* Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@google.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/clk-private.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <mach/iomap.h>
#include <mach/suspend.h>
#include "clock.h"
#include "fuse.h"
#include "tegra2_emc.h"
#include "tegra20_clocks.h"
/* Clock definitions */
#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \
_parent_names, _parents, _parent) \
static struct clk tegra_##_name = { \
.hw = &tegra_##_name##_hw.hw, \
.name = #_name, \
.rate = _rate, \
.ops = _ops, \
.flags = _flags, \
.parent_names = _parent_names, \
.parents = _parents, \
.num_parents = ARRAY_SIZE(_parent_names), \
.parent = _parent, \
};
static struct clk tegra_clk_32k;
static struct clk_tegra tegra_clk_32k_hw = {
.hw = {
.clk = &tegra_clk_32k,
},
.fixed_rate = 32768,
};
static struct clk tegra_clk_32k = {
.name = "clk_32k",
.rate = 32768,
.ops = &tegra_clk_32k_ops,
.hw = &tegra_clk_32k_hw.hw,
.flags = CLK_IS_ROOT,
};
static struct clk tegra_clk_m;
static struct clk_tegra tegra_clk_m_hw = {
.hw = {
.clk = &tegra_clk_m,
},
.flags = ENABLE_ON_INIT,
.reg = 0x1fc,
.reg_shift = 28,
.max_rate = 26000000,
.fixed_rate = 0,
};
static struct clk tegra_clk_m = {
.name = "clk_m",
.ops = &tegra_clk_m_ops,
.hw = &tegra_clk_m_hw.hw,
.flags = CLK_IS_ROOT,
};
#define DEFINE_PLL(_name, _flags, _reg, _max_rate, _input_min, \
_input_max, _cf_min, _cf_max, _vco_min, \
_vco_max, _freq_table, _lock_delay, _ops, \
_fixed_rate, _parent) \
static const char *tegra_##_name##_parent_names[] = { \
#_parent, \
}; \
static struct clk *tegra_##_name##_parents[] = { \
&tegra_##_parent, \
}; \
static struct clk tegra_##_name; \
static struct clk_tegra tegra_##_name##_hw = { \
.hw = { \
.clk = &tegra_##_name, \
}, \
.flags = _flags, \
.reg = _reg, \
.max_rate = _max_rate, \
.u.pll = { \
.input_min = _input_min, \
.input_max = _input_max, \
.cf_min = _cf_min, \
.cf_max = _cf_max, \
.vco_min = _vco_min, \
.vco_max = _vco_max, \
.freq_table = _freq_table, \
.lock_delay = _lock_delay, \
.fixed_rate = _fixed_rate, \
}, \
}; \
static struct clk tegra_##_name = { \
.name = #_name, \
.ops = &_ops, \
.hw = &tegra_##_name##_hw.hw, \
.parent = &tegra_##_parent, \
.parent_names = tegra_##_name##_parent_names, \
.parents = tegra_##_name##_parents, \
.num_parents = 1, \
};
#define DEFINE_PLL_OUT(_name, _flags, _reg, _reg_shift, \
_max_rate, _ops, _parent, _clk_flags) \
static const char *tegra_##_name##_parent_names[] = { \
#_parent, \
}; \
static struct clk *tegra_##_name##_parents[] = { \
&tegra_##_parent, \
}; \
static struct clk tegra_##_name; \
static struct clk_tegra tegra_##_name##_hw = { \
.hw = { \
.clk = &tegra_##_name, \
}, \
.flags = _flags, \
.reg = _reg, \
.max_rate = _max_rate, \
.reg_shift = _reg_shift, \
}; \
static struct clk tegra_##_name = { \
.name = #_name, \
.ops = &tegra_pll_div_ops, \
.hw = &tegra_##_name##_hw.hw, \
.parent = &tegra_##_parent, \
.parent_names = tegra_##_name##_parent_names, \
.parents = tegra_##_name##_parents, \
.num_parents = 1, \
.flags = _clk_flags, \
};
static struct clk_pll_freq_table tegra_pll_s_freq_table[] = {
{32768, 12000000, 366, 1, 1, 0},
{32768, 13000000, 397, 1, 1, 0},
{32768, 19200000, 586, 1, 1, 0},
{32768, 26000000, 793, 1, 1, 0},
{0, 0, 0, 0, 0, 0},
};
DEFINE_PLL(pll_s, PLL_ALT_MISC_REG, 0xf0, 26000000, 32768, 32768, 0,
0, 12000000, 26000000, tegra_pll_s_freq_table, 300,
tegra_pll_ops, 0, clk_32k);
static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
{ 12000000, 600000000, 600, 12, 1, 8 },
{ 13000000, 600000000, 600, 13, 1, 8 },
{ 19200000, 600000000, 500, 16, 1, 6 },
{ 26000000, 600000000, 600, 26, 1, 8 },
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_c, PLL_HAS_CPCON, 0x80, 600000000, 2000000, 31000000, 1000000,
6000000, 20000000, 1400000000, tegra_pll_c_freq_table, 300,
tegra_pll_ops, 0, clk_m);
DEFINE_PLL_OUT(pll_c_out1, DIV_U71, 0x84, 0, 600000000,
tegra_pll_div_ops, pll_c, 0);
static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
{ 12000000, 666000000, 666, 12, 1, 8},
{ 13000000, 666000000, 666, 13, 1, 8},
{ 19200000, 666000000, 555, 16, 1, 8},
{ 26000000, 666000000, 666, 26, 1, 8},
{ 12000000, 600000000, 600, 12, 1, 8},
{ 13000000, 600000000, 600, 13, 1, 8},
{ 19200000, 600000000, 375, 12, 1, 6},
{ 26000000, 600000000, 600, 26, 1, 8},
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_m, PLL_HAS_CPCON, 0x90, 800000000, 2000000, 31000000, 1000000,
6000000, 20000000, 1200000000, tegra_pll_m_freq_table, 300,
tegra_pll_ops, 0, clk_m);
DEFINE_PLL_OUT(pll_m_out1, DIV_U71, 0x94, 0, 600000000,
tegra_pll_div_ops, pll_m, 0);
static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
{ 12000000, 216000000, 432, 12, 2, 8},
{ 13000000, 216000000, 432, 13, 2, 8},
{ 19200000, 216000000, 90, 4, 2, 1},
{ 26000000, 216000000, 432, 26, 2, 8},
{ 12000000, 432000000, 432, 12, 1, 8},
{ 13000000, 432000000, 432, 13, 1, 8},
{ 19200000, 432000000, 90, 4, 1, 1},
{ 26000000, 432000000, 432, 26, 1, 8},
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_p, ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, 0xa0, 432000000,
2000000, 31000000, 1000000, 6000000, 20000000, 1400000000,
tegra_pll_p_freq_table, 300, tegra_pll_ops, 216000000, clk_m);
DEFINE_PLL_OUT(pll_p_out1, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, 0,
432000000, tegra_pll_div_ops, pll_p, 0);
DEFINE_PLL_OUT(pll_p_out2, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, 16,
432000000, tegra_pll_div_ops, pll_p, 0);
DEFINE_PLL_OUT(pll_p_out3, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, 0,
432000000, tegra_pll_div_ops, pll_p, 0);
DEFINE_PLL_OUT(pll_p_out4, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, 16,
432000000, tegra_pll_div_ops, pll_p, 0);
static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
{ 28800000, 56448000, 49, 25, 1, 1},
{ 28800000, 73728000, 64, 25, 1, 1},
{ 28800000, 24000000, 5, 6, 1, 1},
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_a, PLL_HAS_CPCON, 0xb0, 73728000, 2000000, 31000000, 1000000,
6000000, 20000000, 1400000000, tegra_pll_a_freq_table, 300,
tegra_pll_ops, 0, pll_p_out1);
DEFINE_PLL_OUT(pll_a_out0, DIV_U71, 0xb4, 0, 73728000,
tegra_pll_div_ops, pll_a, 0);
static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
{ 12000000, 216000000, 216, 12, 1, 4},
{ 13000000, 216000000, 216, 13, 1, 4},
{ 19200000, 216000000, 135, 12, 1, 3},
{ 26000000, 216000000, 216, 26, 1, 4},
{ 12000000, 594000000, 594, 12, 1, 8},
{ 13000000, 594000000, 594, 13, 1, 8},
{ 19200000, 594000000, 495, 16, 1, 8},
{ 26000000, 594000000, 594, 26, 1, 8},
{ 12000000, 1000000000, 1000, 12, 1, 12},
{ 13000000, 1000000000, 1000, 13, 1, 12},
{ 19200000, 1000000000, 625, 12, 1, 8},
{ 26000000, 1000000000, 1000, 26, 1, 12},
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_d, PLL_HAS_CPCON | PLLD, 0xd0, 1000000000, 2000000, 40000000,
1000000, 6000000, 40000000, 1000000000, tegra_pll_d_freq_table,
1000, tegra_pll_ops, 0, clk_m);
DEFINE_PLL_OUT(pll_d_out0, DIV_2 | PLLD, 0, 0, 500000000,
tegra_pll_div_ops, pll_d, CLK_SET_RATE_PARENT);
static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
{ 12000000, 480000000, 960, 12, 2, 0},
{ 13000000, 480000000, 960, 13, 2, 0},
{ 19200000, 480000000, 200, 4, 2, 0},
{ 26000000, 480000000, 960, 26, 2, 0},
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_u, PLLU, 0xc0, 480000000, 2000000, 40000000, 1000000, 6000000,
48000000, 960000000, tegra_pll_u_freq_table, 1000,
tegra_pll_ops, 0, clk_m);
static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
/* 1 GHz */
{ 12000000, 1000000000, 1000, 12, 1, 12},
{ 13000000, 1000000000, 1000, 13, 1, 12},
{ 19200000, 1000000000, 625, 12, 1, 8},
{ 26000000, 1000000000, 1000, 26, 1, 12},
/* 912 MHz */
{ 12000000, 912000000, 912, 12, 1, 12},
{ 13000000, 912000000, 912, 13, 1, 12},
{ 19200000, 912000000, 760, 16, 1, 8},
{ 26000000, 912000000, 912, 26, 1, 12},
/* 816 MHz */
{ 12000000, 816000000, 816, 12, 1, 12},
{ 13000000, 816000000, 816, 13, 1, 12},
{ 19200000, 816000000, 680, 16, 1, 8},
{ 26000000, 816000000, 816, 26, 1, 12},
/* 760 MHz */
{ 12000000, 760000000, 760, 12, 1, 12},
{ 13000000, 760000000, 760, 13, 1, 12},
{ 19200000, 760000000, 950, 24, 1, 8},
{ 26000000, 760000000, 760, 26, 1, 12},
/* 750 MHz */
{ 12000000, 750000000, 750, 12, 1, 12},
{ 13000000, 750000000, 750, 13, 1, 12},
{ 19200000, 750000000, 625, 16, 1, 8},
{ 26000000, 750000000, 750, 26, 1, 12},
/* 608 MHz */
{ 12000000, 608000000, 608, 12, 1, 12},
{ 13000000, 608000000, 608, 13, 1, 12},
{ 19200000, 608000000, 380, 12, 1, 8},
{ 26000000, 608000000, 608, 26, 1, 12},
/* 456 MHz */
{ 12000000, 456000000, 456, 12, 1, 12},
{ 13000000, 456000000, 456, 13, 1, 12},
{ 19200000, 456000000, 380, 16, 1, 8},
{ 26000000, 456000000, 456, 26, 1, 12},
/* 312 MHz */
{ 12000000, 312000000, 312, 12, 1, 12},
{ 13000000, 312000000, 312, 13, 1, 12},
{ 19200000, 312000000, 260, 16, 1, 8},
{ 26000000, 312000000, 312, 26, 1, 12},
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_x, PLL_HAS_CPCON | PLL_ALT_MISC_REG, 0xe0, 1000000000, 2000000,
31000000, 1000000, 6000000, 20000000, 1200000000,
tegra_pll_x_freq_table, 300, tegra_pllx_ops, 0, clk_m);
static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
{ 12000000, 100000000, 200, 24, 1, 0 },
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_e, PLL_ALT_MISC_REG, 0xe8, 100000000, 12000000, 12000000, 0, 0,
0, 0, tegra_pll_e_freq_table, 0, tegra_plle_ops, 0, clk_m);
static const char *tegra_common_parent_names[] = {
"clk_m",
};
static struct clk *tegra_common_parents[] = {
&tegra_clk_m,
};
static struct clk tegra_clk_d;
static struct clk_tegra tegra_clk_d_hw = {
.hw = {
.clk = &tegra_clk_d,
},
.flags = PERIPH_NO_RESET,
.reg = 0x34,
.reg_shift = 12,
.max_rate = 52000000,
.u.periph = {
.clk_num = 90,
},
};
static struct clk tegra_clk_d = {
.name = "clk_d",
.hw = &tegra_clk_d_hw.hw,
.ops = &tegra_clk_double_ops,
.parent = &tegra_clk_m,
.parent_names = tegra_common_parent_names,
.parents = tegra_common_parents,
.num_parents = ARRAY_SIZE(tegra_common_parent_names),
};
static struct clk tegra_cdev1;
static struct clk_tegra tegra_cdev1_hw = {
.hw = {
.clk = &tegra_cdev1,
},
.fixed_rate = 26000000,
.u.periph = {
.clk_num = 94,
},
};
static struct clk tegra_cdev1 = {
.name = "cdev1",
.hw = &tegra_cdev1_hw.hw,
.ops = &tegra_cdev_clk_ops,
.flags = CLK_IS_ROOT,
};
/* dap_mclk2, belongs to the cdev2 pingroup. */
static struct clk tegra_cdev2;
static struct clk_tegra tegra_cdev2_hw = {
.hw = {
.clk = &tegra_cdev2,
},
.fixed_rate = 26000000,
.u.periph = {
.clk_num = 93,
},
};
static struct clk tegra_cdev2 = {
.name = "cdev2",
.hw = &tegra_cdev2_hw.hw,
.ops = &tegra_cdev_clk_ops,
.flags = CLK_IS_ROOT,
};
/* initialized before peripheral clocks */
static struct clk_mux_sel mux_audio_sync_clk[8+1];
static const struct audio_sources {
const char *name;
int value;
} mux_audio_sync_clk_sources[] = {
{ .name = "spdif_in", .value = 0 },
{ .name = "i2s1", .value = 1 },
{ .name = "i2s2", .value = 2 },
{ .name = "pll_a_out0", .value = 4 },
#if 0 /* FIXME: not implemented */
{ .name = "ac97", .value = 3 },
{ .name = "ext_audio_clk2", .value = 5 },
{ .name = "ext_audio_clk1", .value = 6 },
{ .name = "ext_vimclk", .value = 7 },
#endif
{ NULL, 0 }
};
static const char *audio_parent_names[] = {
"spdif_in",
"i2s1",
"i2s2",
"dummy",
"pll_a_out0",
"dummy",
"dummy",
"dummy",
};
static struct clk *audio_parents[] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
static struct clk tegra_audio;
static struct clk_tegra tegra_audio_hw = {
.hw = {
.clk = &tegra_audio,
},
.reg = 0x38,
.max_rate = 73728000,
};
DEFINE_CLK_TEGRA(audio, 0, &tegra_audio_sync_clk_ops, 0, audio_parent_names,
audio_parents, NULL);
static const char *audio_2x_parent_names[] = {
"audio",
};
static struct clk *audio_2x_parents[] = {
&tegra_audio,
};
static struct clk tegra_audio_2x;
static struct clk_tegra tegra_audio_2x_hw = {
.hw = {
.clk = &tegra_audio_2x,
},
.flags = PERIPH_NO_RESET,
.max_rate = 48000000,
.reg = 0x34,
.reg_shift = 8,
.u.periph = {
.clk_num = 89,
},
};
DEFINE_CLK_TEGRA(audio_2x, 0, &tegra_clk_double_ops, 0, audio_2x_parent_names,
audio_2x_parents, &tegra_audio);
static struct clk_lookup tegra_audio_clk_lookups[] = {
{ .con_id = "audio", .clk = &tegra_audio },
{ .con_id = "audio_2x", .clk = &tegra_audio_2x }
};
/* This is called after peripheral clocks are initialized, as the
* audio_sync clock depends on some of the peripheral clocks.
*/
static void init_audio_sync_clock_mux(void)
{
int i;
struct clk_mux_sel *sel = mux_audio_sync_clk;
const struct audio_sources *src = mux_audio_sync_clk_sources;
struct clk_lookup *lookup;
for (i = 0; src->name; i++, sel++, src++) {
sel->input = tegra_get_clock_by_name(src->name);
if (!sel->input)
pr_err("%s: could not find clk %s\n", __func__,
src->name);
audio_parents[src->value] = sel->input;
sel->value = src->value;
}
lookup = tegra_audio_clk_lookups;
for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) {
struct clk *c = lookup->clk;
struct clk_tegra *clk = to_clk_tegra(c->hw);
__clk_init(NULL, c);
INIT_LIST_HEAD(&clk->shared_bus_list);
clk->lookup.con_id = lookup->con_id;
clk->lookup.clk = c;
clkdev_add(&clk->lookup);
tegra_clk_add(c);
}
}
static const char *mux_cclk[] = {
"clk_m",
"pll_c",
"clk_32k",
"pll_m",
"pll_p",
"pll_p_out4",
"pll_p_out3",
"clk_d",
"pll_x",
};
static struct clk *mux_cclk_p[] = {
&tegra_clk_m,
&tegra_pll_c,
&tegra_clk_32k,
&tegra_pll_m,
&tegra_pll_p,
&tegra_pll_p_out4,
&tegra_pll_p_out3,
&tegra_clk_d,
&tegra_pll_x,
};
static const char *mux_sclk[] = {
"clk_m",
"pll_c_out1",
"pll_p_out4",
"pllp_p_out3",
"pll_p_out2",
"clk_d",
"clk_32k",
"pll_m_out1",
};
static struct clk *mux_sclk_p[] = {
&tegra_clk_m,
&tegra_pll_c_out1,
&tegra_pll_p_out4,
&tegra_pll_p_out3,
&tegra_pll_p_out2,
&tegra_clk_d,
&tegra_clk_32k,
&tegra_pll_m_out1,
};
static struct clk tegra_cclk;
static struct clk_tegra tegra_cclk_hw = {
.hw = {
.clk = &tegra_cclk,
},
.reg = 0x20,
.max_rate = 1000000000,
};
DEFINE_CLK_TEGRA(cclk, 0, &tegra_super_ops, 0, mux_cclk,
mux_cclk_p, NULL);
static const char *mux_twd[] = {
"cclk",
};
static struct clk *mux_twd_p[] = {
&tegra_cclk,
};
static struct clk tegra_clk_twd;
static struct clk_tegra tegra_clk_twd_hw = {
.hw = {
.clk = &tegra_clk_twd,
},
.max_rate = 1000000000,
.mul = 1,
.div = 4,
};
static struct clk tegra_clk_twd = {
.name = "twd",
.ops = &tegra_twd_ops,
.hw = &tegra_clk_twd_hw.hw,
.parent = &tegra_cclk,
.parent_names = mux_twd,
.parents = mux_twd_p,
.num_parents = ARRAY_SIZE(mux_twd),
};
static struct clk tegra_sclk;
static struct clk_tegra tegra_sclk_hw = {
.hw = {
.clk = &tegra_sclk,
},
.reg = 0x28,
.max_rate = 240000000,
.min_rate = 120000000,
};
DEFINE_CLK_TEGRA(sclk, 0, &tegra_super_ops, 0, mux_sclk,
mux_sclk_p, NULL);
static const char *tegra_cop_parent_names[] = {
"tegra_sclk",
};
static struct clk *tegra_cop_parents[] = {
&tegra_sclk,
};
static struct clk tegra_cop;
static struct clk_tegra tegra_cop_hw = {
.hw = {
.clk = &tegra_cop,
},
.max_rate = 240000000,
.reset = &tegra2_cop_clk_reset,
};
DEFINE_CLK_TEGRA(cop, 0, &tegra_cop_ops, CLK_SET_RATE_PARENT,
tegra_cop_parent_names, tegra_cop_parents, &tegra_sclk);
static const char *tegra_hclk_parent_names[] = {
"tegra_sclk",
};
static struct clk *tegra_hclk_parents[] = {
&tegra_sclk,
};
static struct clk tegra_hclk;
static struct clk_tegra tegra_hclk_hw = {
.hw = {
.clk = &tegra_hclk,
},
.flags = DIV_BUS,
.reg = 0x30,
.reg_shift = 4,
.max_rate = 240000000,
};
DEFINE_CLK_TEGRA(hclk, 0, &tegra_bus_ops, 0, tegra_hclk_parent_names,
tegra_hclk_parents, &tegra_sclk);
static const char *tegra_pclk_parent_names[] = {
"tegra_hclk",
};
static struct clk *tegra_pclk_parents[] = {
&tegra_hclk,
};
static struct clk tegra_pclk;
static struct clk_tegra tegra_pclk_hw = {
.hw = {
.clk = &tegra_pclk,
},
.flags = DIV_BUS,
.reg = 0x30,
.reg_shift = 0,
.max_rate = 120000000,
};
DEFINE_CLK_TEGRA(pclk, 0, &tegra_bus_ops, 0, tegra_pclk_parent_names,
tegra_pclk_parents, &tegra_hclk);
static const char *tegra_blink_parent_names[] = {
"clk_32k",
};
static struct clk *tegra_blink_parents[] = {
&tegra_clk_32k,
};
static struct clk tegra_blink;
static struct clk_tegra tegra_blink_hw = {
.hw = {
.clk = &tegra_blink,
},
.reg = 0x40,
.max_rate = 32768,
};
DEFINE_CLK_TEGRA(blink, 0, &tegra_blink_clk_ops, 0, tegra_blink_parent_names,
tegra_blink_parents, &tegra_clk_32k);
static const char *mux_pllm_pllc_pllp_plla[] = {
"pll_m",
"pll_c",
"pll_p",
"pll_a_out0",
};
static struct clk *mux_pllm_pllc_pllp_plla_p[] = {
&tegra_pll_m,
&tegra_pll_c,
&tegra_pll_p,
&tegra_pll_a_out0,
};
static const char *mux_pllm_pllc_pllp_clkm[] = {
"pll_m",
"pll_c",
"pll_p",
"clk_m",
};
static struct clk *mux_pllm_pllc_pllp_clkm_p[] = {
&tegra_pll_m,
&tegra_pll_c,
&tegra_pll_p,
&tegra_clk_m,
};
static const char *mux_pllp_pllc_pllm_clkm[] = {
"pll_p",
"pll_c",
"pll_m",
"clk_m",
};
static struct clk *mux_pllp_pllc_pllm_clkm_p[] = {
&tegra_pll_p,
&tegra_pll_c,
&tegra_pll_m,
&tegra_clk_m,
};
static const char *mux_pllaout0_audio2x_pllp_clkm[] = {
"pll_a_out0",
"audio_2x",
"pll_p",
"clk_m",
};
static struct clk *mux_pllaout0_audio2x_pllp_clkm_p[] = {
&tegra_pll_a_out0,
&tegra_audio_2x,
&tegra_pll_p,
&tegra_clk_m,
};
static const char *mux_pllp_plld_pllc_clkm[] = {
"pllp",
"pll_d_out0",
"pll_c",
"clk_m",
};
static struct clk *mux_pllp_plld_pllc_clkm_p[] = {
&tegra_pll_p,
&tegra_pll_d_out0,
&tegra_pll_c,
&tegra_clk_m,
};
static const char *mux_pllp_pllc_audio_clkm_clk32[] = {
"pll_p",
"pll_c",
"audio",
"clk_m",
"clk_32k",
};
static struct clk *mux_pllp_pllc_audio_clkm_clk32_p[] = {
&tegra_pll_p,
&tegra_pll_c,
&tegra_audio,
&tegra_clk_m,
&tegra_clk_32k,
};
static const char *mux_pllp_pllc_pllm[] = {
"pll_p",
"pll_c",
"pll_m"
};
static struct clk *mux_pllp_pllc_pllm_p[] = {
&tegra_pll_p,
&tegra_pll_c,
&tegra_pll_m,
};
static const char *mux_clk_m[] = {
"clk_m",
};
static struct clk *mux_clk_m_p[] = {
&tegra_clk_m,
};
static const char *mux_pllp_out3[] = {
"pll_p_out3",
};
static struct clk *mux_pllp_out3_p[] = {
&tegra_pll_p_out3,
};
static const char *mux_plld[] = {
"pll_d",
};
static struct clk *mux_plld_p[] = {
&tegra_pll_d,
};
static const char *mux_clk_32k[] = {
"clk_32k",
};
static struct clk *mux_clk_32k_p[] = {
&tegra_clk_32k,
};
static const char *mux_pclk[] = {
"pclk",
};
static struct clk *mux_pclk_p[] = {
&tegra_pclk,
};
static struct clk tegra_emc;
static struct clk_tegra tegra_emc_hw = {
.hw = {
.clk = &tegra_emc,
},
.reg = 0x19c,
.max_rate = 800000000,
.flags = MUX | DIV_U71 | PERIPH_EMC_ENB,
.reset = &tegra2_periph_clk_reset,
.u.periph = {
.clk_num = 57,
},
};
DEFINE_CLK_TEGRA(emc, 0, &tegra_emc_clk_ops, 0, mux_pllm_pllc_pllp_clkm,
mux_pllm_pllc_pllp_clkm_p, NULL);
#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, \
_max, _inputs, _flags) \
static struct clk tegra_##_name; \
static struct clk_tegra tegra_##_name##_hw = { \
.hw = { \
.clk = &tegra_##_name, \
}, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
.reg = _reg, \
.flags = _flags, \
.max_rate = _max, \
.u.periph = { \
.clk_num = _clk_num, \
}, \
.reset = tegra2_periph_clk_reset, \
}; \
static struct clk tegra_##_name = { \
.name = #_name, \
.ops = &tegra_periph_clk_ops, \
.hw = &tegra_##_name##_hw.hw, \
.parent_names = _inputs, \
.parents = _inputs##_p, \
.num_parents = ARRAY_SIZE(_inputs), \
};
PERIPH_CLK(apbdma, "tegra-apbdma", NULL, 34, 0, 108000000, mux_pclk, 0);
PERIPH_CLK(rtc, "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET);
PERIPH_CLK(timer, "timer", NULL, 5, 0, 26000000, mux_clk_m, 0);
PERIPH_CLK(i2s1, "tegra20-i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71);
PERIPH_CLK(i2s2, "tegra20-i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71);
PERIPH_CLK(spdif_out, "spdif_out", NULL, 10, 0x108, 100000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71);
PERIPH_CLK(spdif_in, "spdif_in", NULL, 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71);
PERIPH_CLK(pwm, "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71 | MUX_PWM);
PERIPH_CLK(spi, "spi", NULL, 43, 0x114, 40000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(xio, "xio", NULL, 45, 0x120, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(twc, "twc", NULL, 16, 0x12c, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(sbc1, "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(sbc2, "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(sbc3, "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(sbc4, "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(ide, "ide", NULL, 25, 0x144, 100000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */
PERIPH_CLK(ndflash, "tegra_nand", NULL, 13, 0x160, 164000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
PERIPH_CLK(vfir, "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(sdmmc1, "sdhci-tegra.0", NULL, 14, 0x150, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
PERIPH_CLK(sdmmc2, "sdhci-tegra.1", NULL, 9, 0x154, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
PERIPH_CLK(sdmmc3, "sdhci-tegra.2", NULL, 69, 0x1bc, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
PERIPH_CLK(sdmmc4, "sdhci-tegra.3", NULL, 15, 0x164, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
PERIPH_CLK(vcp, "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0);
PERIPH_CLK(bsea, "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0);
PERIPH_CLK(bsev, "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0);
PERIPH_CLK(vde, "tegra-avp", "vde", 61, 0x1c8, 250000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage and process_id */
PERIPH_CLK(csite, "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* max rate ??? */
/* FIXME: what is la? */
PERIPH_CLK(la, "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(owr, "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(nor, "nor", NULL, 42, 0x1d0, 92000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */
PERIPH_CLK(mipi, "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
PERIPH_CLK(i2c1, "tegra-i2c.0", NULL, 12, 0x124, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16);
PERIPH_CLK(i2c2, "tegra-i2c.1", NULL, 54, 0x198, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16);
PERIPH_CLK(i2c3, "tegra-i2c.2", NULL, 67, 0x1b8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16);
PERIPH_CLK(dvc, "tegra-i2c.3", NULL, 47, 0x128, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16);
PERIPH_CLK(i2c1_i2c, "tegra-i2c.0", "i2c", 0, 0, 72000000, mux_pllp_out3, 0);
PERIPH_CLK(i2c2_i2c, "tegra-i2c.1", "i2c", 0, 0, 72000000, mux_pllp_out3, 0);
PERIPH_CLK(i2c3_i2c, "tegra-i2c.2", "i2c", 0, 0, 72000000, mux_pllp_out3, 0);
PERIPH_CLK(dvc_i2c, "tegra-i2c.3", "i2c", 0, 0, 72000000, mux_pllp_out3, 0);
PERIPH_CLK(uarta, "tegra-uart.0", NULL, 6, 0x178, 600000000, mux_pllp_pllc_pllm_clkm, MUX);
PERIPH_CLK(uartb, "tegra-uart.1", NULL, 7, 0x17c, 600000000, mux_pllp_pllc_pllm_clkm, MUX);
PERIPH_CLK(uartc, "tegra-uart.2", NULL, 55, 0x1a0, 600000000, mux_pllp_pllc_pllm_clkm, MUX);
PERIPH_CLK(uartd, "tegra-uart.3", NULL, 65, 0x1c0, 600000000, mux_pllp_pllc_pllm_clkm, MUX);
PERIPH_CLK(uarte, "tegra-uart.4", NULL, 66, 0x1c4, 600000000, mux_pllp_pllc_pllm_clkm, MUX);
PERIPH_CLK(3d, "3d", NULL, 24, 0x158, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_MANUAL_RESET); /* scales with voltage and process_id */
PERIPH_CLK(2d, "2d", NULL, 21, 0x15c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
PERIPH_CLK(vi, "tegra_camera", "vi", 20, 0x148, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
PERIPH_CLK(vi_sensor, "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET); /* scales with voltage and process_id */
PERIPH_CLK(epp, "epp", NULL, 19, 0x16c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
PERIPH_CLK(mpe, "mpe", NULL, 60, 0x170, 250000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
PERIPH_CLK(host1x, "host1x", NULL, 28, 0x180, 166000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
PERIPH_CLK(cve, "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
PERIPH_CLK(tvo, "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
PERIPH_CLK(hdmi, "hdmi", NULL, 51, 0x18c, 600000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
PERIPH_CLK(tvdac, "tvdac", NULL, 53, 0x194, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
PERIPH_CLK(disp1, "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_plld_pllc_clkm, MUX); /* scales with voltage and process_id */
PERIPH_CLK(disp2, "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_plld_pllc_clkm, MUX); /* scales with voltage and process_id */
PERIPH_CLK(usbd, "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
PERIPH_CLK(usb2, "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
PERIPH_CLK(usb3, "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
PERIPH_CLK(dsi, "dsi", NULL, 48, 0, 500000000, mux_plld, 0); /* scales with voltage */
PERIPH_CLK(csi, "tegra_camera", "csi", 52, 0, 72000000, mux_pllp_out3, 0);
PERIPH_CLK(isp, "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0); /* same frequency as VI */
PERIPH_CLK(csus, "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET);
PERIPH_CLK(pex, NULL, "pex", 70, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET);
PERIPH_CLK(afi, NULL, "afi", 72, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET);
PERIPH_CLK(pcie_xclk, NULL, "pcie_xclk", 74, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET);
static struct clk *tegra_list_clks[] = {
&tegra_apbdma,
&tegra_rtc,
&tegra_i2s1,
&tegra_i2s2,
&tegra_spdif_out,
&tegra_spdif_in,
&tegra_pwm,
&tegra_spi,
&tegra_xio,
&tegra_twc,
&tegra_sbc1,
&tegra_sbc2,
&tegra_sbc3,
&tegra_sbc4,
&tegra_ide,
&tegra_ndflash,
&tegra_vfir,
&tegra_sdmmc1,
&tegra_sdmmc2,
&tegra_sdmmc3,
&tegra_sdmmc4,
&tegra_vcp,
&tegra_bsea,
&tegra_bsev,
&tegra_vde,
&tegra_csite,
&tegra_la,
&tegra_owr,
&tegra_nor,
&tegra_mipi,
&tegra_i2c1,
&tegra_i2c2,
&tegra_i2c3,
&tegra_dvc,
&tegra_i2c1_i2c,
&tegra_i2c2_i2c,
&tegra_i2c3_i2c,
&tegra_dvc_i2c,
&tegra_uarta,
&tegra_uartb,
&tegra_uartc,
&tegra_uartd,
&tegra_uarte,
&tegra_3d,
&tegra_2d,
&tegra_vi,
&tegra_vi_sensor,
&tegra_epp,
&tegra_mpe,
&tegra_host1x,
&tegra_cve,
&tegra_tvo,
&tegra_hdmi,
&tegra_tvdac,
&tegra_disp1,
&tegra_disp2,
&tegra_usbd,
&tegra_usb2,
&tegra_usb3,
&tegra_dsi,
&tegra_csi,
&tegra_isp,
&tegra_csus,
&tegra_pex,
&tegra_afi,
&tegra_pcie_xclk,
};
#define CLK_DUPLICATE(_name, _dev, _con) \
{ \
.name = _name, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
}
/* Some clocks may be used by different drivers depending on the board
* configuration. List those here to register them twice in the clock lookup
* table under two names.
*/
static struct clk_duplicate tegra_clk_duplicates[] = {
CLK_DUPLICATE("uarta", "serial8250.0", NULL),
CLK_DUPLICATE("uartb", "serial8250.1", NULL),
CLK_DUPLICATE("uartc", "serial8250.2", NULL),
CLK_DUPLICATE("uartd", "serial8250.3", NULL),
CLK_DUPLICATE("uarte", "serial8250.4", NULL),
CLK_DUPLICATE("usbd", "utmip-pad", NULL),
CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
CLK_DUPLICATE("usbd", "tegra-otg", NULL),
CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
CLK_DUPLICATE("host1x", "tegra_grhost", "host1x"),
CLK_DUPLICATE("2d", "tegra_grhost", "gr2d"),
CLK_DUPLICATE("3d", "tegra_grhost", "gr3d"),
CLK_DUPLICATE("epp", "tegra_grhost", "epp"),
CLK_DUPLICATE("mpe", "tegra_grhost", "mpe"),
CLK_DUPLICATE("cop", "tegra-avp", "cop"),
CLK_DUPLICATE("vde", "tegra-aes", "vde"),
CLK_DUPLICATE("cclk", NULL, "cpu"),
CLK_DUPLICATE("twd", "smp_twd", NULL),
};
#define CLK(dev, con, ck) \
{ \
.dev_id = dev, \
.con_id = con, \
.clk = ck, \
}
static struct clk *tegra_ptr_clks[] = {
&tegra_clk_32k,
&tegra_pll_s,
&tegra_clk_m,
&tegra_pll_m,
&tegra_pll_m_out1,
&tegra_pll_c,
&tegra_pll_c_out1,
&tegra_pll_p,
&tegra_pll_p_out1,
&tegra_pll_p_out2,
&tegra_pll_p_out3,
&tegra_pll_p_out4,
&tegra_pll_a,
&tegra_pll_a_out0,
&tegra_pll_d,
&tegra_pll_d_out0,
&tegra_pll_u,
&tegra_pll_x,
&tegra_pll_e,
&tegra_cclk,
&tegra_clk_twd,
&tegra_sclk,
&tegra_hclk,
&tegra_pclk,
&tegra_clk_d,
&tegra_cdev1,
&tegra_cdev2,
&tegra_blink,
&tegra_cop,
&tegra_emc,
};
static void tegra2_init_one_clock(struct clk *c)
{
struct clk_tegra *clk = to_clk_tegra(c->hw);
int ret;
ret = __clk_init(NULL, c);
if (ret)
pr_err("clk init failed %s\n", __clk_get_name(c));
INIT_LIST_HEAD(&clk->shared_bus_list);
if (!clk->lookup.dev_id && !clk->lookup.con_id)
clk->lookup.con_id = c->name;
clk->lookup.clk = c;
clkdev_add(&clk->lookup);
tegra_clk_add(c);
}
void __init tegra2_init_clocks(void)
{
int i;
struct clk *c;
for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
tegra2_init_one_clock(tegra_ptr_clks[i]);
for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
tegra2_init_one_clock(tegra_list_clks[i]);
for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
if (!c) {
pr_err("%s: Unknown duplicate clock %s\n", __func__,
tegra_clk_duplicates[i].name);
continue;
}
tegra_clk_duplicates[i].lookup.clk = c;
clkdev_add(&tegra_clk_duplicates[i].lookup);
}
init_audio_sync_clock_mux();
}
/*
* arch/arm/mach-tegra/tegra30_clocks.c
*
* Copyright (c) 2010-2011 NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved.
*
* 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
......@@ -365,30 +365,32 @@ static void __iomem *misc_gp_hidrev_base = IO_ADDRESS(TEGRA_APB_MISC_BASE);
static int tegra_periph_clk_enable_refcount[CLK_OUT_ENB_NUM * 32];
#define clk_writel(value, reg) \
__raw_writel(value, (u32)reg_clk_base + (reg))
__raw_writel(value, reg_clk_base + (reg))
#define clk_readl(reg) \
__raw_readl((u32)reg_clk_base + (reg))
__raw_readl(reg_clk_base + (reg))
#define pmc_writel(value, reg) \
__raw_writel(value, (u32)reg_pmc_base + (reg))
__raw_writel(value, reg_pmc_base + (reg))
#define pmc_readl(reg) \
__raw_readl((u32)reg_pmc_base + (reg))
__raw_readl(reg_pmc_base + (reg))
#define chipid_readl() \
__raw_readl((u32)misc_gp_hidrev_base + MISC_GP_HIDREV)
__raw_readl(misc_gp_hidrev_base + MISC_GP_HIDREV)
#define clk_writel_delay(value, reg) \
do { \
__raw_writel((value), (u32)reg_clk_base + (reg)); \
__raw_writel((value), reg_clk_base + (reg)); \
udelay(2); \
} while (0)
static inline int clk_set_div(struct clk *c, u32 n)
static inline int clk_set_div(struct clk_tegra *c, u32 n)
{
return clk_set_rate(c, (clk_get_rate(c->parent) + n-1) / n);
struct clk *clk = c->hw.clk;
return clk_set_rate(clk,
(__clk_get_rate(__clk_get_parent(clk)) + n - 1) / n);
}
static inline u32 periph_clk_to_reg(
struct clk *c, u32 reg_L, u32 reg_V, int offs)
struct clk_tegra *c, u32 reg_L, u32 reg_V, int offs)
{
u32 reg = c->u.periph.clk_num / 32;
BUG_ON(reg >= RST_DEVICES_NUM);
......@@ -470,15 +472,32 @@ static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
return divider_u16 - 1;
}
static unsigned long tegra30_clk_fixed_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
return to_clk_tegra(hw)->fixed_rate;
}
struct clk_ops tegra30_clk_32k_ops = {
.recalc_rate = tegra30_clk_fixed_recalc_rate,
};
/* clk_m functions */
static unsigned long tegra30_clk_m_autodetect_rate(struct clk *c)
static unsigned long tegra30_clk_m_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
if (!to_clk_tegra(hw)->fixed_rate)
to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq();
return to_clk_tegra(hw)->fixed_rate;
}
static void tegra30_clk_m_init(struct clk_hw *hw)
{
u32 osc_ctrl = clk_readl(OSC_CTRL);
u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK;
u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK;
c->rate = clk_measure_input_freq();
switch (c->rate) {
switch (to_clk_tegra(hw)->fixed_rate) {
case 12000000:
auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
......@@ -508,46 +527,44 @@ static unsigned long tegra30_clk_m_autodetect_rate(struct clk *c)
BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4);
break;
default:
pr_err("%s: Unexpected clock rate %ld", __func__, c->rate);
pr_err("%s: Unexpected clock rate %ld", __func__,
to_clk_tegra(hw)->fixed_rate);
BUG();
}
clk_writel(auto_clock_control, OSC_CTRL);
return c->rate;
}
static void tegra30_clk_m_init(struct clk *c)
{
pr_debug("%s on clock %s\n", __func__, c->name);
tegra30_clk_m_autodetect_rate(c);
}
struct clk_ops tegra30_clk_m_ops = {
.init = tegra30_clk_m_init,
.recalc_rate = tegra30_clk_m_recalc_rate,
};
static int tegra30_clk_m_enable(struct clk *c)
static unsigned long tegra30_clk_m_div_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
pr_debug("%s on clock %s\n", __func__, c->name);
return 0;
}
struct clk_tegra *c = to_clk_tegra(hw);
u64 rate = parent_rate;
static void tegra30_clk_m_disable(struct clk *c)
{
pr_debug("%s on clock %s\n", __func__, c->name);
WARN(1, "Attempting to disable main SoC clock\n");
}
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
static struct clk_ops tegra_clk_m_ops = {
.init = tegra30_clk_m_init,
.enable = tegra30_clk_m_enable,
.disable = tegra30_clk_m_disable,
};
return rate;
}
static struct clk_ops tegra_clk_m_div_ops = {
.enable = tegra30_clk_m_enable,
struct clk_ops tegra_clk_m_div_ops = {
.recalc_rate = tegra30_clk_m_div_recalc_rate,
};
/* PLL reference divider functions */
static void tegra30_pll_ref_init(struct clk *c)
static unsigned long tegra30_pll_ref_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long rate = parent_rate;
u32 pll_ref_div = clk_readl(OSC_CTRL) & OSC_CTRL_PLL_REF_DIV_MASK;
pr_debug("%s on clock %s\n", __func__, c->name);
switch (pll_ref_div) {
case OSC_CTRL_PLL_REF_DIV_1:
......@@ -564,13 +581,18 @@ static void tegra30_pll_ref_init(struct clk *c)
BUG();
}
c->mul = 1;
c->state = ON;
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
return rate;
}
static struct clk_ops tegra_pll_ref_ops = {
.init = tegra30_pll_ref_init,
.enable = tegra30_clk_m_enable,
.disable = tegra30_clk_m_disable,
struct clk_ops tegra_pll_ref_ops = {
.recalc_rate = tegra30_pll_ref_recalc_rate,
};
/* super clock functions */
......@@ -581,56 +603,50 @@ static struct clk_ops tegra_pll_ref_ops = {
* only when its parent is a fixed rate PLL, since we can't change PLL rate
* in this case.
*/
static void tegra30_super_clk_init(struct clk *c)
static void tegra30_super_clk_init(struct clk_hw *hw)
{
u32 val;
int source;
int shift;
const struct clk_mux_sel *sel;
val = clk_readl(c->reg + SUPER_CLK_MUX);
c->state = ON;
BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
source = (val >> shift) & SUPER_SOURCE_MASK;
if (c->flags & DIV_2)
source |= val & SUPER_LP_DIV2_BYPASS;
for (sel = c->inputs; sel->input != NULL; sel++) {
if (sel->value == source)
break;
}
BUG_ON(sel->input == NULL);
c->parent = sel->input;
struct clk_tegra *c = to_clk_tegra(hw);
struct clk_tegra *p =
to_clk_tegra(__clk_get_hw(__clk_get_parent(hw->clk)));
c->state = ON;
if (c->flags & DIV_U71) {
/* Init safe 7.1 divider value (does not affect PLLX path) */
clk_writel(SUPER_CLOCK_DIV_U71_MIN << SUPER_CLOCK_DIV_U71_SHIFT,
c->reg + SUPER_CLK_DIVIDER);
c->mul = 2;
c->div = 2;
if (!(c->parent->flags & PLLX))
if (!(p->flags & PLLX))
c->div += SUPER_CLOCK_DIV_U71_MIN;
} else
clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
}
static int tegra30_super_clk_enable(struct clk *c)
static u8 tegra30_super_clk_get_parent(struct clk_hw *hw)
{
return 0;
}
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
int source;
int shift;
static void tegra30_super_clk_disable(struct clk *c)
{
/* since tegra 3 has 2 CPU super clocks - low power lp-mode clock and
geared up g-mode super clock - mode switch may request to disable
either of them; accept request with no affect on h/w */
val = clk_readl(c->reg + SUPER_CLK_MUX);
BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
source = (val >> shift) & SUPER_SOURCE_MASK;
if (c->flags & DIV_2)
source |= val & SUPER_LP_DIV2_BYPASS;
return source;
}
static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p)
static int tegra30_super_clk_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_tegra *c = to_clk_tegra(hw);
struct clk_tegra *p =
to_clk_tegra(__clk_get_hw(clk_get_parent(hw->clk)));
u32 val;
const struct clk_mux_sel *sel;
int shift;
val = clk_readl(c->reg + SUPER_CLK_MUX);
......@@ -638,48 +654,36 @@ static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p)
((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
for (sel = c->inputs; sel->input != NULL; sel++) {
if (sel->input == p) {
/* For LP mode super-clock switch between PLLX direct
and divided-by-2 outputs is allowed only when other
than PLLX clock source is current parent */
if ((c->flags & DIV_2) && (p->flags & PLLX) &&
((sel->value ^ val) & SUPER_LP_DIV2_BYPASS)) {
if (c->parent->flags & PLLX)
return -EINVAL;
val ^= SUPER_LP_DIV2_BYPASS;
clk_writel_delay(val, c->reg);
}
val &= ~(SUPER_SOURCE_MASK << shift);
val |= (sel->value & SUPER_SOURCE_MASK) << shift;
/* 7.1 divider for CPU super-clock does not affect
PLLX path */
if (c->flags & DIV_U71) {
u32 div = 0;
if (!(p->flags & PLLX)) {
div = clk_readl(c->reg +
SUPER_CLK_DIVIDER);
div &= SUPER_CLOCK_DIV_U71_MASK;
div >>= SUPER_CLOCK_DIV_U71_SHIFT;
}
c->div = div + 2;
c->mul = 2;
}
if (c->refcnt)
clk_enable(p);
clk_writel_delay(val, c->reg);
if (c->refcnt && c->parent)
clk_disable(c->parent);
/* For LP mode super-clock switch between PLLX direct
and divided-by-2 outputs is allowed only when other
than PLLX clock source is current parent */
if ((c->flags & DIV_2) && (p->flags & PLLX) &&
((index ^ val) & SUPER_LP_DIV2_BYPASS)) {
if (p->flags & PLLX)
return -EINVAL;
val ^= SUPER_LP_DIV2_BYPASS;
clk_writel_delay(val, c->reg);
}
val &= ~(SUPER_SOURCE_MASK << shift);
val |= (index & SUPER_SOURCE_MASK) << shift;
clk_reparent(c, p);
return 0;
/* 7.1 divider for CPU super-clock does not affect
PLLX path */
if (c->flags & DIV_U71) {
u32 div = 0;
if (!(p->flags & PLLX)) {
div = clk_readl(c->reg +
SUPER_CLK_DIVIDER);
div &= SUPER_CLOCK_DIV_U71_MASK;
div >>= SUPER_CLOCK_DIV_U71_SHIFT;
}
c->div = div + 2;
c->mul = 2;
}
return -EINVAL;
clk_writel_delay(val, c->reg);
return 0;
}
/*
......@@ -691,10 +695,15 @@ static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p)
* rate of this PLL can't be changed, and it has many other children. In
* this case use 7.1 fractional divider to adjust the super clock rate.
*/
static int tegra30_super_clk_set_rate(struct clk *c, unsigned long rate)
static int tegra30_super_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
if ((c->flags & DIV_U71) && (c->parent->flags & PLL_FIXED)) {
int div = clk_div71_get_divider(c->parent->u.pll.fixed_rate,
struct clk_tegra *c = to_clk_tegra(hw);
struct clk *parent = __clk_get_parent(hw->clk);
struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent));
if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) {
int div = clk_div71_get_divider(parent_rate,
rate, c->flags, ROUND_DIVIDER_DOWN);
div = max(div, SUPER_CLOCK_DIV_U71_MIN);
......@@ -704,55 +713,86 @@ static int tegra30_super_clk_set_rate(struct clk *c, unsigned long rate)
c->mul = 2;
return 0;
}
return clk_set_rate(c->parent, rate);
return 0;
}
static unsigned long tegra30_super_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u64 rate = parent_rate;
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
return rate;
}
static long tegra30_super_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_tegra *c = to_clk_tegra(hw);
struct clk *parent = __clk_get_parent(hw->clk);
struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent));
int mul = 2;
int div;
if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) {
div = clk_div71_get_divider(*prate,
rate, c->flags, ROUND_DIVIDER_DOWN);
div = max(div, SUPER_CLOCK_DIV_U71_MIN) + 2;
rate = *prate * mul;
rate += div - 1; /* round up */
do_div(rate, c->div);
return rate;
}
return *prate;
}
static struct clk_ops tegra_super_ops = {
.init = tegra30_super_clk_init,
.enable = tegra30_super_clk_enable,
.disable = tegra30_super_clk_disable,
.set_parent = tegra30_super_clk_set_parent,
.set_rate = tegra30_super_clk_set_rate,
struct clk_ops tegra30_super_ops = {
.init = tegra30_super_clk_init,
.set_parent = tegra30_super_clk_set_parent,
.get_parent = tegra30_super_clk_get_parent,
.recalc_rate = tegra30_super_clk_recalc_rate,
.round_rate = tegra30_super_clk_round_rate,
.set_rate = tegra30_super_clk_set_rate,
};
static int tegra30_twd_clk_set_rate(struct clk *c, unsigned long rate)
static unsigned long tegra30_twd_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
/* The input value 'rate' is the clock rate of the CPU complex. */
c->rate = (rate * c->mul) / c->div;
return 0;
struct clk_tegra *c = to_clk_tegra(hw);
u64 rate = parent_rate;
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
return rate;
}
static struct clk_ops tegra30_twd_ops = {
.set_rate = tegra30_twd_clk_set_rate,
struct clk_ops tegra30_twd_ops = {
.recalc_rate = tegra30_twd_clk_recalc_rate,
};
/* Blink output functions */
static void tegra30_blink_clk_init(struct clk *c)
static int tegra30_blink_clk_is_enabled(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
val = pmc_readl(PMC_CTRL);
c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
c->mul = 1;
val = pmc_readl(c->reg);
if (val & PMC_BLINK_TIMER_ENB) {
unsigned int on_off;
on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
PMC_BLINK_TIMER_DATA_ON_MASK;
val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
on_off += val;
/* each tick in the blink timer is 4 32KHz clocks */
c->div = on_off * 4;
} else {
c->div = 1;
}
return c->state;
}
static int tegra30_blink_clk_enable(struct clk *c)
static int tegra30_blink_clk_enable(struct clk_hw *hw)
{
u32 val;
......@@ -765,7 +805,7 @@ static int tegra30_blink_clk_enable(struct clk *c)
return 0;
}
static void tegra30_blink_clk_disable(struct clk *c)
static void tegra30_blink_clk_disable(struct clk_hw *hw)
{
u32 val;
......@@ -776,9 +816,11 @@ static void tegra30_blink_clk_disable(struct clk *c)
pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
}
static int tegra30_blink_clk_set_rate(struct clk *c, unsigned long rate)
static int tegra30_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
unsigned long parent_rate = clk_get_rate(c->parent);
struct clk_tegra *c = to_clk_tegra(hw);
if (rate >= parent_rate) {
c->div = 1;
pmc_writel(0, c->reg);
......@@ -801,41 +843,77 @@ static int tegra30_blink_clk_set_rate(struct clk *c, unsigned long rate)
return 0;
}
static struct clk_ops tegra_blink_clk_ops = {
.init = &tegra30_blink_clk_init,
.enable = &tegra30_blink_clk_enable,
.disable = &tegra30_blink_clk_disable,
.set_rate = &tegra30_blink_clk_set_rate,
};
static unsigned long tegra30_blink_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u64 rate = parent_rate;
u32 val;
u32 mul;
u32 div;
u32 on_off;
/* PLL Functions */
static int tegra30_pll_clk_wait_for_lock(struct clk *c, u32 lock_reg,
u32 lock_bit)
mul = 1;
val = pmc_readl(c->reg);
if (val & PMC_BLINK_TIMER_ENB) {
on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
PMC_BLINK_TIMER_DATA_ON_MASK;
val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
on_off += val;
/* each tick in the blink timer is 4 32KHz clocks */
div = on_off * 4;
} else {
div = 1;
}
if (mul != 0 && div != 0) {
rate *= mul;
rate += div - 1; /* round up */
do_div(rate, div);
}
return rate;
}
static long tegra30_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
#if USE_PLL_LOCK_BITS
int i;
for (i = 0; i < c->u.pll.lock_delay; i++) {
if (clk_readl(lock_reg) & lock_bit) {
udelay(PLL_POST_LOCK_DELAY);
return 0;
}
udelay(2); /* timeout = 2 * lock time */
int div;
int mul;
long round_rate = *prate;
mul = 1;
if (rate >= *prate) {
div = 1;
} else {
div = DIV_ROUND_UP(*prate / 8, rate);
div *= 8;
}
pr_err("Timed out waiting for lock bit on pll %s", c->name);
return -1;
#endif
udelay(c->u.pll.lock_delay);
return 0;
round_rate *= mul;
round_rate += div - 1;
do_div(round_rate, div);
return round_rate;
}
struct clk_ops tegra30_blink_clk_ops = {
.is_enabled = tegra30_blink_clk_is_enabled,
.enable = tegra30_blink_clk_enable,
.disable = tegra30_blink_clk_disable,
.recalc_rate = tegra30_blink_clk_recalc_rate,
.round_rate = tegra30_blink_clk_round_rate,
.set_rate = tegra30_blink_clk_set_rate,
};
static void tegra30_utmi_param_configure(struct clk *c)
static void tegra30_utmi_param_configure(struct clk_hw *hw)
{
unsigned long main_rate =
__clk_get_rate(__clk_get_parent(__clk_get_parent(hw->clk)));
u32 reg;
int i;
unsigned long main_rate =
clk_get_rate(c->parent->parent);
for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
if (main_rate == utmi_parameters[i].osc_frequency)
......@@ -886,50 +964,52 @@ static void tegra30_utmi_param_configure(struct clk *c)
clk_writel(reg, UTMIP_PLL_CFG1);
}
static void tegra30_pll_clk_init(struct clk *c)
/* PLL Functions */
static int tegra30_pll_clk_wait_for_lock(struct clk_tegra *c, u32 lock_reg,
u32 lock_bit)
{
int ret = 0;
#if USE_PLL_LOCK_BITS
int i;
for (i = 0; i < c->u.pll.lock_delay; i++) {
if (clk_readl(lock_reg) & lock_bit) {
udelay(PLL_POST_LOCK_DELAY);
return 0;
}
udelay(2); /* timeout = 2 * lock time */
}
pr_err("Timed out waiting for lock bit on pll %s",
__clk_get_name(hw->clk));
ret = -1;
#else
udelay(c->u.pll.lock_delay);
#endif
return ret;
}
static int tegra30_pll_clk_is_enabled(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg + PLL_BASE);
c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
return c->state;
}
if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
const struct clk_pll_freq_table *sel;
unsigned long input_rate = clk_get_rate(c->parent);
for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
if (sel->input_rate == input_rate &&
sel->output_rate == c->u.pll.fixed_rate) {
c->mul = sel->n;
c->div = sel->m * sel->p;
return;
}
}
pr_err("Clock %s has unknown fixed frequency\n", c->name);
BUG();
} else if (val & PLL_BASE_BYPASS) {
c->mul = 1;
c->div = 1;
} else {
c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
if (c->flags & PLLU)
c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
else
c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >>
PLL_BASE_DIVP_SHIFT));
if (c->flags & PLL_FIXED) {
unsigned long rate = clk_get_rate_locked(c);
BUG_ON(rate != c->u.pll.fixed_rate);
}
}
static void tegra30_pll_clk_init(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
if (c->flags & PLLU)
tegra30_utmi_param_configure(c);
tegra30_utmi_param_configure(hw);
}
static int tegra30_pll_clk_enable(struct clk *c)
static int tegra30_pll_clk_enable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
pr_debug("%s on clock %s\n", __func__, c->name);
pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
#if USE_PLL_LOCK_BITS
val = clk_readl(c->reg + PLL_MISC(c));
......@@ -952,10 +1032,11 @@ static int tegra30_pll_clk_enable(struct clk *c)
return 0;
}
static void tegra30_pll_clk_disable(struct clk *c)
static void tegra30_pll_clk_disable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
pr_debug("%s on clock %s\n", __func__, c->name);
pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
val = clk_readl(c->reg);
val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
......@@ -968,36 +1049,36 @@ static void tegra30_pll_clk_disable(struct clk *c)
}
}
static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
static int tegra30_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val, p_div, old_base;
unsigned long input_rate;
const struct clk_pll_freq_table *sel;
struct clk_pll_freq_table cfg;
pr_debug("%s: %s %lu\n", __func__, c->name, rate);
if (c->flags & PLL_FIXED) {
int ret = 0;
if (rate != c->u.pll.fixed_rate) {
pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
__func__, c->name, c->u.pll.fixed_rate, rate);
__func__, __clk_get_name(hw->clk),
c->u.pll.fixed_rate, rate);
ret = -EINVAL;
}
return ret;
}
if (c->flags & PLLM) {
if (rate != clk_get_rate_locked(c)) {
if (rate != __clk_get_rate(hw->clk)) {
pr_err("%s: Can not change memory %s rate in flight\n",
__func__, c->name);
__func__, __clk_get_name(hw->clk));
return -EINVAL;
}
return 0;
}
p_div = 0;
input_rate = clk_get_rate(c->parent);
input_rate = parent_rate;
/* Check if the target rate is tabulated */
for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
......@@ -1055,7 +1136,7 @@ static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
(p_div > (PLL_BASE_DIVP_MASK >> PLL_BASE_DIVP_SHIFT)) ||
(cfg.output_rate > c->u.pll.vco_max)) {
pr_err("%s: Failed to set %s out-of-table rate %lu\n",
__func__, c->name, rate);
__func__, __clk_get_name(hw->clk), rate);
return -EINVAL;
}
p_div <<= PLL_BASE_DIVP_SHIFT;
......@@ -1073,7 +1154,7 @@ static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
return 0;
if (c->state == ON) {
tegra30_pll_clk_disable(c);
tegra30_pll_clk_disable(hw);
val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
}
clk_writel(val, c->reg + PLL_BASE);
......@@ -1095,89 +1176,203 @@ static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
}
if (c->state == ON)
tegra30_pll_clk_enable(c);
return 0;
}
static struct clk_ops tegra_pll_ops = {
.init = tegra30_pll_clk_init,
.enable = tegra30_pll_clk_enable,
.disable = tegra30_pll_clk_disable,
.set_rate = tegra30_pll_clk_set_rate,
};
static int
tegra30_plld_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
{
u32 val, mask, reg;
tegra30_pll_clk_enable(hw);
switch (p) {
case TEGRA_CLK_PLLD_CSI_OUT_ENB:
mask = PLLD_BASE_CSI_CLKENABLE;
reg = c->reg + PLL_BASE;
break;
case TEGRA_CLK_PLLD_DSI_OUT_ENB:
mask = PLLD_MISC_DSI_CLKENABLE;
reg = c->reg + PLL_MISC(c);
break;
case TEGRA_CLK_PLLD_MIPI_MUX_SEL:
if (!(c->flags & PLL_ALT_MISC_REG)) {
mask = PLLD_BASE_DSIB_MUX_MASK;
reg = c->reg + PLL_BASE;
break;
}
/* fall through - error since PLLD2 does not have MUX_SEL control */
default:
return -EINVAL;
}
c->u.pll.fixed_rate = rate;
val = clk_readl(reg);
if (setting)
val |= mask;
else
val &= ~mask;
clk_writel(val, reg);
return 0;
}
static struct clk_ops tegra_plld_ops = {
.init = tegra30_pll_clk_init,
.enable = tegra30_pll_clk_enable,
.disable = tegra30_pll_clk_disable,
.set_rate = tegra30_pll_clk_set_rate,
.clk_cfg_ex = tegra30_plld_clk_cfg_ex,
};
static void tegra30_plle_clk_init(struct clk *c)
static long tegra30_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long input_rate = *prate;
unsigned long output_rate = *prate;
const struct clk_pll_freq_table *sel;
struct clk_pll_freq_table cfg;
int mul;
int div;
u32 p_div;
u32 val;
val = clk_readl(PLLE_AUX);
c->parent = (val & PLLE_AUX_PLLP_SEL) ?
tegra_get_clock_by_name("pll_p") :
tegra_get_clock_by_name("pll_ref");
if (c->flags & PLL_FIXED)
return c->u.pll.fixed_rate;
val = clk_readl(c->reg + PLL_BASE);
c->state = (val & PLLE_BASE_ENABLE) ? ON : OFF;
c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT;
c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT;
c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT;
}
if (c->flags & PLLM)
return __clk_get_rate(hw->clk);
static void tegra30_plle_clk_disable(struct clk *c)
{
u32 val;
pr_debug("%s on clock %s\n", __func__, c->name);
p_div = 0;
/* Check if the target rate is tabulated */
for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
if (sel->input_rate == input_rate && sel->output_rate == rate) {
if (c->flags & PLLU) {
BUG_ON(sel->p < 1 || sel->p > 2);
if (sel->p == 1)
p_div = PLLU_BASE_POST_DIV;
} else {
BUG_ON(sel->p < 1);
for (val = sel->p; val > 1; val >>= 1)
p_div++;
p_div <<= PLL_BASE_DIVP_SHIFT;
}
break;
}
}
val = clk_readl(c->reg + PLL_BASE);
val &= ~(PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
clk_writel(val, c->reg + PLL_BASE);
}
if (sel->input_rate == 0) {
unsigned long cfreq;
BUG_ON(c->flags & PLLU);
sel = &cfg;
static void tegra30_plle_training(struct clk *c)
{
u32 val;
switch (input_rate) {
case 12000000:
case 26000000:
cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000;
break;
case 13000000:
cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000;
break;
case 16800000:
case 19200000:
cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000;
break;
default:
pr_err("%s: Unexpected reference rate %lu\n",
__func__, input_rate);
BUG();
}
/* Raise VCO to guarantee 0.5% accuracy */
for (cfg.output_rate = rate; cfg.output_rate < 200 * cfreq;
cfg.output_rate <<= 1)
p_div++;
cfg.p = 0x1 << p_div;
cfg.m = input_rate / cfreq;
cfg.n = cfg.output_rate / cfreq;
}
mul = sel->n;
div = sel->m * sel->p;
output_rate *= mul;
output_rate += div - 1; /* round up */
do_div(output_rate, div);
return output_rate;
}
static unsigned long tegra30_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u64 rate = parent_rate;
u32 val = clk_readl(c->reg + PLL_BASE);
if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
const struct clk_pll_freq_table *sel;
for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
if (sel->input_rate == parent_rate &&
sel->output_rate == c->u.pll.fixed_rate) {
c->mul = sel->n;
c->div = sel->m * sel->p;
break;
}
}
pr_err("Clock %s has unknown fixed frequency\n",
__clk_get_name(hw->clk));
BUG();
} else if (val & PLL_BASE_BYPASS) {
c->mul = 1;
c->div = 1;
} else {
c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
if (c->flags & PLLU)
c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
else
c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >>
PLL_BASE_DIVP_SHIFT));
}
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
return rate;
}
struct clk_ops tegra30_pll_ops = {
.is_enabled = tegra30_pll_clk_is_enabled,
.init = tegra30_pll_clk_init,
.enable = tegra30_pll_clk_enable,
.disable = tegra30_pll_clk_disable,
.recalc_rate = tegra30_pll_recalc_rate,
.round_rate = tegra30_pll_round_rate,
.set_rate = tegra30_pll_clk_set_rate,
};
int tegra30_plld_clk_cfg_ex(struct clk_hw *hw,
enum tegra_clk_ex_param p, u32 setting)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val, mask, reg;
switch (p) {
case TEGRA_CLK_PLLD_CSI_OUT_ENB:
mask = PLLD_BASE_CSI_CLKENABLE;
reg = c->reg + PLL_BASE;
break;
case TEGRA_CLK_PLLD_DSI_OUT_ENB:
mask = PLLD_MISC_DSI_CLKENABLE;
reg = c->reg + PLL_MISC(c);
break;
case TEGRA_CLK_PLLD_MIPI_MUX_SEL:
if (!(c->flags & PLL_ALT_MISC_REG)) {
mask = PLLD_BASE_DSIB_MUX_MASK;
reg = c->reg + PLL_BASE;
break;
}
/* fall through - error since PLLD2 does not have MUX_SEL control */
default:
return -EINVAL;
}
val = clk_readl(reg);
if (setting)
val |= mask;
else
val &= ~mask;
clk_writel(val, reg);
return 0;
}
static int tegra30_plle_clk_is_enabled(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
val = clk_readl(c->reg + PLL_BASE);
c->state = (val & PLLE_BASE_ENABLE) ? ON : OFF;
return c->state;
}
static void tegra30_plle_clk_disable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
val = clk_readl(c->reg + PLL_BASE);
val &= ~(PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
clk_writel(val, c->reg + PLL_BASE);
}
static void tegra30_plle_training(struct clk_tegra *c)
{
u32 val;
/* PLLE is already disabled, and setup cleared;
* create falling edge on PLLE IDDQ input */
......@@ -1198,12 +1393,15 @@ static void tegra30_plle_training(struct clk *c)
} while (!(val & PLLE_MISC_READY));
}
static int tegra30_plle_configure(struct clk *c, bool force_training)
static int tegra30_plle_configure(struct clk_hw *hw, bool force_training)
{
u32 val;
struct clk_tegra *c = to_clk_tegra(hw);
struct clk *parent = __clk_get_parent(hw->clk);
const struct clk_pll_freq_table *sel;
u32 val;
unsigned long rate = c->u.pll.fixed_rate;
unsigned long input_rate = clk_get_rate(c->parent);
unsigned long input_rate = __clk_get_rate(parent);
for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
if (sel->input_rate == input_rate && sel->output_rate == rate)
......@@ -1214,7 +1412,7 @@ static int tegra30_plle_configure(struct clk *c, bool force_training)
return -ENOSYS;
/* disable PLLE, clear setup fiels */
tegra30_plle_clk_disable(c);
tegra30_plle_clk_disable(hw);
val = clk_readl(c->reg + PLL_MISC(c));
val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK);
......@@ -1252,52 +1450,64 @@ static int tegra30_plle_configure(struct clk *c, bool force_training)
return 0;
}
static int tegra30_plle_clk_enable(struct clk *c)
static int tegra30_plle_clk_enable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
return tegra30_plle_configure(hw, !c->set);
}
static unsigned long tegra30_plle_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
pr_debug("%s on clock %s\n", __func__, c->name);
return tegra30_plle_configure(c, !c->set);
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long rate = parent_rate;
u32 val;
val = clk_readl(c->reg + PLL_BASE);
c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT;
c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT;
c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT;
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
return rate;
}
static struct clk_ops tegra_plle_ops = {
.init = tegra30_plle_clk_init,
.enable = tegra30_plle_clk_enable,
.disable = tegra30_plle_clk_disable,
struct clk_ops tegra30_plle_ops = {
.is_enabled = tegra30_plle_clk_is_enabled,
.enable = tegra30_plle_clk_enable,
.disable = tegra30_plle_clk_disable,
.recalc_rate = tegra30_plle_clk_recalc_rate,
};
/* Clock divider ops */
static void tegra30_pll_div_clk_init(struct clk *c)
static int tegra30_pll_div_clk_is_enabled(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
if (c->flags & DIV_U71) {
u32 divu71;
u32 val = clk_readl(c->reg);
val >>= c->reg_shift;
c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
if (!(val & PLL_OUT_RESET_DISABLE))
c->state = OFF;
divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
c->div = (divu71 + 2);
c->mul = 2;
} else if (c->flags & DIV_2) {
c->state = ON;
if (c->flags & (PLLD | PLLX)) {
c->div = 2;
c->mul = 1;
} else
BUG();
} else {
c->state = ON;
c->div = 1;
c->mul = 1;
}
return c->state;
}
static int tegra30_pll_div_clk_enable(struct clk *c)
static int tegra30_pll_div_clk_enable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
u32 new_val;
pr_debug("%s: %s\n", __func__, c->name);
pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
if (c->flags & DIV_U71) {
val = clk_readl(c->reg);
new_val = val >> c->reg_shift;
......@@ -1315,12 +1525,13 @@ static int tegra30_pll_div_clk_enable(struct clk *c)
return -EINVAL;
}
static void tegra30_pll_div_clk_disable(struct clk *c)
static void tegra30_pll_div_clk_disable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
u32 new_val;
pr_debug("%s: %s\n", __func__, c->name);
pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
if (c->flags & DIV_U71) {
val = clk_readl(c->reg);
new_val = val >> c->reg_shift;
......@@ -1334,14 +1545,14 @@ static void tegra30_pll_div_clk_disable(struct clk *c)
}
}
static int tegra30_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
static int tegra30_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
u32 new_val;
int divider_u71;
unsigned long parent_rate = clk_get_rate(c->parent);
pr_debug("%s: %s %lu\n", __func__, c->name, rate);
if (c->flags & DIV_U71) {
divider_u71 = clk_div71_get_divider(
parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
......@@ -1359,19 +1570,59 @@ static int tegra30_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
clk_writel_delay(val, c->reg);
c->div = divider_u71 + 2;
c->mul = 2;
c->fixed_rate = rate;
return 0;
}
} else if (c->flags & DIV_2)
return clk_set_rate(c->parent, rate * 2);
} else if (c->flags & DIV_2) {
c->fixed_rate = rate;
return 0;
}
return -EINVAL;
}
static long tegra30_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
static unsigned long tegra30_pll_div_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u64 rate = parent_rate;
if (c->flags & DIV_U71) {
u32 divu71;
u32 val = clk_readl(c->reg);
val >>= c->reg_shift;
divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
c->div = (divu71 + 2);
c->mul = 2;
} else if (c->flags & DIV_2) {
if (c->flags & (PLLD | PLLX)) {
c->div = 2;
c->mul = 1;
} else
BUG();
} else {
c->div = 1;
c->mul = 1;
}
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
return rate;
}
static long tegra30_pll_div_clk_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long *prate)
{
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
int divider;
unsigned long parent_rate = clk_get_rate(c->parent);
pr_debug("%s: %s %lu\n", __func__, c->name, rate);
if (prate)
parent_rate = *prate;
if (c->flags & DIV_U71) {
divider = clk_div71_get_divider(
......@@ -1379,23 +1630,25 @@ static long tegra30_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
if (divider < 0)
return divider;
return DIV_ROUND_UP(parent_rate * 2, divider + 2);
} else if (c->flags & DIV_2)
/* no rounding - fixed DIV_2 dividers pass rate to parent PLL */
} else if (c->flags & DIV_2) {
*prate = rate * 2;
return rate;
}
return -EINVAL;
}
static struct clk_ops tegra_pll_div_ops = {
.init = tegra30_pll_div_clk_init,
.enable = tegra30_pll_div_clk_enable,
.disable = tegra30_pll_div_clk_disable,
.set_rate = tegra30_pll_div_clk_set_rate,
.round_rate = tegra30_pll_div_clk_round_rate,
struct clk_ops tegra30_pll_div_ops = {
.is_enabled = tegra30_pll_div_clk_is_enabled,
.enable = tegra30_pll_div_clk_enable,
.disable = tegra30_pll_div_clk_disable,
.set_rate = tegra30_pll_div_clk_set_rate,
.recalc_rate = tegra30_pll_div_clk_recalc_rate,
.round_rate = tegra30_pll_div_clk_round_rate,
};
/* Periph clk ops */
static inline u32 periph_clk_source_mask(struct clk *c)
static inline u32 periph_clk_source_mask(struct clk_tegra *c)
{
if (c->flags & MUX8)
return 7 << 29;
......@@ -1409,7 +1662,7 @@ static inline u32 periph_clk_source_mask(struct clk *c)
return 3 << 30;
}
static inline u32 periph_clk_source_shift(struct clk *c)
static inline u32 periph_clk_source_shift(struct clk_tegra *c)
{
if (c->flags & MUX8)
return 29;
......@@ -1423,47 +1676,9 @@ static inline u32 periph_clk_source_shift(struct clk *c)
return 30;
}
static void tegra30_periph_clk_init(struct clk *c)
static int tegra30_periph_clk_is_enabled(struct clk_hw *hw)
{
u32 val = clk_readl(c->reg);
const struct clk_mux_sel *mux = 0;
const struct clk_mux_sel *sel;
if (c->flags & MUX) {
for (sel = c->inputs; sel->input != NULL; sel++) {
if (((val & periph_clk_source_mask(c)) >>
periph_clk_source_shift(c)) == sel->value)
mux = sel;
}
BUG_ON(!mux);
c->parent = mux->input;
} else {
c->parent = c->inputs[0].input;
}
if (c->flags & DIV_U71) {
u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
if ((c->flags & DIV_U71_UART) &&
(!(val & PERIPH_CLK_UART_DIV_ENB))) {
divu71 = 0;
}
if (c->flags & DIV_U71_IDLE) {
val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK <<
PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL <<
PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
clk_writel(val, c->reg);
}
c->div = divu71 + 2;
c->mul = 2;
} else if (c->flags & DIV_U16) {
u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
c->div = divu16 + 1;
c->mul = 1;
} else {
c->div = 1;
c->mul = 1;
}
struct clk_tegra *c = to_clk_tegra(hw);
c->state = ON;
if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
......@@ -1471,11 +1686,12 @@ static void tegra30_periph_clk_init(struct clk *c)
if (!(c->flags & PERIPH_NO_RESET))
if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c))
c->state = OFF;
return c->state;
}
static int tegra30_periph_clk_enable(struct clk *c)
static int tegra30_periph_clk_enable(struct clk_hw *hw)
{
pr_debug("%s on clock %s\n", __func__, c->name);
struct clk_tegra *c = to_clk_tegra(hw);
tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
......@@ -1494,31 +1710,29 @@ static int tegra30_periph_clk_enable(struct clk *c)
return 0;
}
static void tegra30_periph_clk_disable(struct clk *c)
static void tegra30_periph_clk_disable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long val;
pr_debug("%s on clock %s\n", __func__, c->name);
if (c->refcnt)
tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0)
return;
if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0) {
/* If peripheral is in the APB bus then read the APB bus to
* flush the write operation in apb bus. This will avoid the
* peripheral access after disabling clock*/
if (c->flags & PERIPH_ON_APB)
val = chipid_readl();
/* If peripheral is in the APB bus then read the APB bus to
* flush the write operation in apb bus. This will avoid the
* peripheral access after disabling clock*/
if (c->flags & PERIPH_ON_APB)
val = chipid_readl();
clk_writel_delay(
PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c));
}
clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c));
}
static void tegra30_periph_clk_reset(struct clk *c, bool assert)
void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert)
{
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long val;
pr_debug("%s %s on clock %s\n", __func__,
assert ? "assert" : "deassert", c->name);
if (!(c->flags & PERIPH_NO_RESET)) {
if (assert) {
......@@ -1537,42 +1751,40 @@ static void tegra30_periph_clk_reset(struct clk *c, bool assert)
}
}
static int tegra30_periph_clk_set_parent(struct clk *c, struct clk *p)
static int tegra30_periph_clk_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
const struct clk_mux_sel *sel;
pr_debug("%s: %s %s\n", __func__, c->name, p->name);
if (!(c->flags & MUX))
return (p == c->parent) ? 0 : (-EINVAL);
return (index == 0) ? 0 : (-EINVAL);
for (sel = c->inputs; sel->input != NULL; sel++) {
if (sel->input == p) {
val = clk_readl(c->reg);
val &= ~periph_clk_source_mask(c);
val |= (sel->value << periph_clk_source_shift(c));
if (c->refcnt)
clk_enable(p);
clk_writel_delay(val, c->reg);
val = clk_readl(c->reg);
val &= ~periph_clk_source_mask(c);
val |= (index << periph_clk_source_shift(c));
clk_writel_delay(val, c->reg);
return 0;
}
if (c->refcnt && c->parent)
clk_disable(c->parent);
static u8 tegra30_periph_clk_get_parent(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
int source = (val & periph_clk_source_mask(c)) >>
periph_clk_source_shift(c);
clk_reparent(c, p);
return 0;
}
}
if (!(c->flags & MUX))
return 0;
return -EINVAL;
return source;
}
static int tegra30_periph_clk_set_rate(struct clk *c, unsigned long rate)
static int tegra30_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
int divider;
unsigned long parent_rate = clk_get_rate(c->parent);
if (c->flags & DIV_U71) {
divider = clk_div71_get_divider(
......@@ -1611,12 +1823,15 @@ static int tegra30_periph_clk_set_rate(struct clk *c, unsigned long rate)
return -EINVAL;
}
static long tegra30_periph_clk_round_rate(struct clk *c,
unsigned long rate)
static long tegra30_periph_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_tegra *c = to_clk_tegra(hw);
unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
int divider;
unsigned long parent_rate = clk_get_rate(c->parent);
pr_debug("%s: %s %lu\n", __func__, c->name, rate);
if (prate)
parent_rate = *prate;
if (c->flags & DIV_U71) {
divider = clk_div71_get_divider(
......@@ -1634,21 +1849,85 @@ static long tegra30_periph_clk_round_rate(struct clk *c,
return -EINVAL;
}
static struct clk_ops tegra_periph_clk_ops = {
.init = &tegra30_periph_clk_init,
.enable = &tegra30_periph_clk_enable,
.disable = &tegra30_periph_clk_disable,
.set_parent = &tegra30_periph_clk_set_parent,
.set_rate = &tegra30_periph_clk_set_rate,
.round_rate = &tegra30_periph_clk_round_rate,
.reset = &tegra30_periph_clk_reset,
};
static unsigned long tegra30_periph_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u64 rate = parent_rate;
u32 val = clk_readl(c->reg);
if (c->flags & DIV_U71) {
u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
if ((c->flags & DIV_U71_UART) &&
(!(val & PERIPH_CLK_UART_DIV_ENB))) {
divu71 = 0;
}
if (c->flags & DIV_U71_IDLE) {
val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK <<
PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL <<
PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
clk_writel(val, c->reg);
}
c->div = divu71 + 2;
c->mul = 2;
} else if (c->flags & DIV_U16) {
u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
c->div = divu16 + 1;
c->mul = 1;
} else {
c->div = 1;
c->mul = 1;
}
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
return rate;
}
struct clk_ops tegra30_periph_clk_ops = {
.is_enabled = tegra30_periph_clk_is_enabled,
.enable = tegra30_periph_clk_enable,
.disable = tegra30_periph_clk_disable,
.set_parent = tegra30_periph_clk_set_parent,
.get_parent = tegra30_periph_clk_get_parent,
.set_rate = tegra30_periph_clk_set_rate,
.round_rate = tegra30_periph_clk_round_rate,
.recalc_rate = tegra30_periph_clk_recalc_rate,
};
/* Periph extended clock configuration ops */
static int
tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
static int tegra30_dsib_clk_set_parent(struct clk_hw *hw, u8 index)
{
struct clk *d = clk_get_sys(NULL, "pll_d");
/* The DSIB parent selection bit is in PLLD base
register - can not do direct r-m-w, must be
protected by PLLD lock */
tegra_clk_cfg_ex(
d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, index);
return 0;
}
struct clk_ops tegra30_dsib_clk_ops = {
.is_enabled = tegra30_periph_clk_is_enabled,
.enable = &tegra30_periph_clk_enable,
.disable = &tegra30_periph_clk_disable,
.set_parent = &tegra30_dsib_clk_set_parent,
.get_parent = &tegra30_periph_clk_get_parent,
.set_rate = &tegra30_periph_clk_set_rate,
.round_rate = &tegra30_periph_clk_round_rate,
.recalc_rate = &tegra30_periph_clk_recalc_rate,
};
/* Periph extended clock configuration ops */
int tegra30_vi_clk_cfg_ex(struct clk_hw *hw,
enum tegra_clk_ex_param p, u32 setting)
{
struct clk_tegra *c = to_clk_tegra(hw);
if (p == TEGRA_CLK_VI_INP_SEL) {
u32 val = clk_readl(c->reg);
val &= ~PERIPH_CLK_VI_SEL_EX_MASK;
......@@ -1660,20 +1939,11 @@ tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
return -EINVAL;
}
static struct clk_ops tegra_vi_clk_ops = {
.init = &tegra30_periph_clk_init,
.enable = &tegra30_periph_clk_enable,
.disable = &tegra30_periph_clk_disable,
.set_parent = &tegra30_periph_clk_set_parent,
.set_rate = &tegra30_periph_clk_set_rate,
.round_rate = &tegra30_periph_clk_round_rate,
.clk_cfg_ex = &tegra30_vi_clk_cfg_ex,
.reset = &tegra30_periph_clk_reset,
};
static int
tegra30_nand_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
int tegra30_nand_clk_cfg_ex(struct clk_hw *hw,
enum tegra_clk_ex_param p, u32 setting)
{
struct clk_tegra *c = to_clk_tegra(hw);
if (p == TEGRA_CLK_NAND_PAD_DIV2_ENB) {
u32 val = clk_readl(c->reg);
if (setting)
......@@ -1686,21 +1956,11 @@ tegra30_nand_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
return -EINVAL;
}
static struct clk_ops tegra_nand_clk_ops = {
.init = &tegra30_periph_clk_init,
.enable = &tegra30_periph_clk_enable,
.disable = &tegra30_periph_clk_disable,
.set_parent = &tegra30_periph_clk_set_parent,
.set_rate = &tegra30_periph_clk_set_rate,
.round_rate = &tegra30_periph_clk_round_rate,
.clk_cfg_ex = &tegra30_nand_clk_cfg_ex,
.reset = &tegra30_periph_clk_reset,
};
static int
tegra30_dtv_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw,
enum tegra_clk_ex_param p, u32 setting)
{
struct clk_tegra *c = to_clk_tegra(hw);
if (p == TEGRA_CLK_DTV_INVERT) {
u32 val = clk_readl(c->reg);
if (setting)
......@@ -1713,91 +1973,27 @@ tegra30_dtv_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
return -EINVAL;
}
static struct clk_ops tegra_dtv_clk_ops = {
.init = &tegra30_periph_clk_init,
.enable = &tegra30_periph_clk_enable,
.disable = &tegra30_periph_clk_disable,
.set_parent = &tegra30_periph_clk_set_parent,
.set_rate = &tegra30_periph_clk_set_rate,
.round_rate = &tegra30_periph_clk_round_rate,
.clk_cfg_ex = &tegra30_dtv_clk_cfg_ex,
.reset = &tegra30_periph_clk_reset,
};
static int tegra30_dsib_clk_set_parent(struct clk *c, struct clk *p)
{
const struct clk_mux_sel *sel;
struct clk *d = tegra_get_clock_by_name("pll_d");
pr_debug("%s: %s %s\n", __func__, c->name, p->name);
for (sel = c->inputs; sel->input != NULL; sel++) {
if (sel->input == p) {
if (c->refcnt)
clk_enable(p);
/* The DSIB parent selection bit is in PLLD base
register - can not do direct r-m-w, must be
protected by PLLD lock */
tegra_clk_cfg_ex(
d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, sel->value);
if (c->refcnt && c->parent)
clk_disable(c->parent);
clk_reparent(c, p);
return 0;
}
}
return -EINVAL;
}
static struct clk_ops tegra_dsib_clk_ops = {
.init = &tegra30_periph_clk_init,
.enable = &tegra30_periph_clk_enable,
.disable = &tegra30_periph_clk_disable,
.set_parent = &tegra30_dsib_clk_set_parent,
.set_rate = &tegra30_periph_clk_set_rate,
.round_rate = &tegra30_periph_clk_round_rate,
.reset = &tegra30_periph_clk_reset,
};
/* pciex clock support only reset function */
static struct clk_ops tegra_pciex_clk_ops = {
.reset = tegra30_periph_clk_reset,
};
/* Output clock ops */
static DEFINE_SPINLOCK(clk_out_lock);
static void tegra30_clk_out_init(struct clk *c)
static int tegra30_clk_out_is_enabled(struct clk_hw *hw)
{
const struct clk_mux_sel *mux = 0;
const struct clk_mux_sel *sel;
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = pmc_readl(c->reg);
c->state = (val & (0x1 << c->u.periph.clk_num)) ? ON : OFF;
c->mul = 1;
c->div = 1;
for (sel = c->inputs; sel->input != NULL; sel++) {
if (((val & periph_clk_source_mask(c)) >>
periph_clk_source_shift(c)) == sel->value)
mux = sel;
}
BUG_ON(!mux);
c->parent = mux->input;
return c->state;
}
static int tegra30_clk_out_enable(struct clk *c)
static int tegra30_clk_out_enable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
unsigned long flags;
pr_debug("%s on clock %s\n", __func__, c->name);
spin_lock_irqsave(&clk_out_lock, flags);
val = pmc_readl(c->reg);
val |= (0x1 << c->u.periph.clk_num);
......@@ -1807,13 +2003,12 @@ static int tegra30_clk_out_enable(struct clk *c)
return 0;
}
static void tegra30_clk_out_disable(struct clk *c)
static void tegra30_clk_out_disable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
unsigned long flags;
pr_debug("%s on clock %s\n", __func__, c->name);
spin_lock_irqsave(&clk_out_lock, flags);
val = pmc_readl(c->reg);
val &= ~(0x1 << c->u.periph.clk_num);
......@@ -1821,59 +2016,59 @@ static void tegra30_clk_out_disable(struct clk *c)
spin_unlock_irqrestore(&clk_out_lock, flags);
}
static int tegra30_clk_out_set_parent(struct clk *c, struct clk *p)
static int tegra30_clk_out_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
unsigned long flags;
const struct clk_mux_sel *sel;
pr_debug("%s: %s %s\n", __func__, c->name, p->name);
for (sel = c->inputs; sel->input != NULL; sel++) {
if (sel->input == p) {
if (c->refcnt)
clk_enable(p);
spin_lock_irqsave(&clk_out_lock, flags);
val = pmc_readl(c->reg);
val &= ~periph_clk_source_mask(c);
val |= (index << periph_clk_source_shift(c));
pmc_writel(val, c->reg);
spin_unlock_irqrestore(&clk_out_lock, flags);
spin_lock_irqsave(&clk_out_lock, flags);
val = pmc_readl(c->reg);
val &= ~periph_clk_source_mask(c);
val |= (sel->value << periph_clk_source_shift(c));
pmc_writel(val, c->reg);
spin_unlock_irqrestore(&clk_out_lock, flags);
return 0;
}
if (c->refcnt && c->parent)
clk_disable(c->parent);
static u8 tegra30_clk_out_get_parent(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = pmc_readl(c->reg);
int source;
clk_reparent(c, p);
return 0;
}
}
return -EINVAL;
source = (val & periph_clk_source_mask(c)) >>
periph_clk_source_shift(c);
return source;
}
static struct clk_ops tegra_clk_out_ops = {
.init = &tegra30_clk_out_init,
.enable = &tegra30_clk_out_enable,
.disable = &tegra30_clk_out_disable,
.set_parent = &tegra30_clk_out_set_parent,
struct clk_ops tegra_clk_out_ops = {
.is_enabled = tegra30_clk_out_is_enabled,
.enable = tegra30_clk_out_enable,
.disable = tegra30_clk_out_disable,
.set_parent = tegra30_clk_out_set_parent,
.get_parent = tegra30_clk_out_get_parent,
.recalc_rate = tegra30_clk_fixed_recalc_rate,
};
/* Clock doubler ops */
static void tegra30_clk_double_init(struct clk *c)
static int tegra30_clk_double_is_enabled(struct clk_hw *hw)
{
u32 val = clk_readl(c->reg);
c->mul = val & (0x1 << c->reg_shift) ? 1 : 2;
c->div = 1;
struct clk_tegra *c = to_clk_tegra(hw);
c->state = ON;
if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
c->state = OFF;
return c->state;
};
static int tegra30_clk_double_set_rate(struct clk *c, unsigned long rate)
static int tegra30_clk_double_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
unsigned long parent_rate = clk_get_rate(c->parent);
if (rate == parent_rate) {
val = clk_readl(c->reg) | (0x1 << c->reg_shift);
clk_writel(val, c->reg);
......@@ -1890,1215 +2085,139 @@ static int tegra30_clk_double_set_rate(struct clk *c, unsigned long rate)
return -EINVAL;
}
static struct clk_ops tegra_clk_double_ops = {
.init = &tegra30_clk_double_init,
.enable = &tegra30_periph_clk_enable,
.disable = &tegra30_periph_clk_disable,
.set_rate = &tegra30_clk_double_set_rate,
};
static unsigned long tegra30_clk_double_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_tegra *c = to_clk_tegra(hw);
u64 rate = parent_rate;
/* Audio sync clock ops */
static int tegra30_sync_source_set_rate(struct clk *c, unsigned long rate)
u32 val = clk_readl(c->reg);
c->mul = val & (0x1 << c->reg_shift) ? 1 : 2;
c->div = 1;
if (c->mul != 0 && c->div != 0) {
rate *= c->mul;
rate += c->div - 1; /* round up */
do_div(rate, c->div);
}
return rate;
}
static long tegra30_clk_double_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
c->rate = rate;
return 0;
unsigned long output_rate = *prate;
do_div(output_rate, 2);
return output_rate;
}
static struct clk_ops tegra_sync_source_ops = {
.set_rate = &tegra30_sync_source_set_rate,
struct clk_ops tegra30_clk_double_ops = {
.is_enabled = tegra30_clk_double_is_enabled,
.enable = tegra30_periph_clk_enable,
.disable = tegra30_periph_clk_disable,
.recalc_rate = tegra30_clk_double_recalc_rate,
.round_rate = tegra30_clk_double_round_rate,
.set_rate = tegra30_clk_double_set_rate,
};
static void tegra30_audio_sync_clk_init(struct clk *c)
/* Audio sync clock ops */
struct clk_ops tegra_sync_source_ops = {
.recalc_rate = tegra30_clk_fixed_recalc_rate,
};
static int tegra30_audio_sync_clk_is_enabled(struct clk_hw *hw)
{
int source;
const struct clk_mux_sel *sel;
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
c->state = (val & AUDIO_SYNC_DISABLE_BIT) ? OFF : ON;
source = val & AUDIO_SYNC_SOURCE_MASK;
for (sel = c->inputs; sel->input != NULL; sel++)
if (sel->value == source)
break;
BUG_ON(sel->input == NULL);
c->parent = sel->input;
return c->state;
}
static int tegra30_audio_sync_clk_enable(struct clk *c)
static int tegra30_audio_sync_clk_enable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
clk_writel((val & (~AUDIO_SYNC_DISABLE_BIT)), c->reg);
return 0;
}
static void tegra30_audio_sync_clk_disable(struct clk *c)
static void tegra30_audio_sync_clk_disable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
clk_writel((val | AUDIO_SYNC_DISABLE_BIT), c->reg);
}
static int tegra30_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
static int tegra30_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
const struct clk_mux_sel *sel;
for (sel = c->inputs; sel->input != NULL; sel++) {
if (sel->input == p) {
val = clk_readl(c->reg);
val &= ~AUDIO_SYNC_SOURCE_MASK;
val |= sel->value;
if (c->refcnt)
clk_enable(p);
clk_writel(val, c->reg);
val = clk_readl(c->reg);
val &= ~AUDIO_SYNC_SOURCE_MASK;
val |= index;
if (c->refcnt && c->parent)
clk_disable(c->parent);
clk_writel(val, c->reg);
return 0;
}
clk_reparent(c, p);
return 0;
}
}
static u8 tegra30_audio_sync_clk_get_parent(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
int source;
return -EINVAL;
source = val & AUDIO_SYNC_SOURCE_MASK;
return source;
}
static struct clk_ops tegra_audio_sync_clk_ops = {
.init = tegra30_audio_sync_clk_init,
.enable = tegra30_audio_sync_clk_enable,
.disable = tegra30_audio_sync_clk_disable,
struct clk_ops tegra30_audio_sync_clk_ops = {
.is_enabled = tegra30_audio_sync_clk_is_enabled,
.enable = tegra30_audio_sync_clk_enable,
.disable = tegra30_audio_sync_clk_disable,
.set_parent = tegra30_audio_sync_clk_set_parent,
.get_parent = tegra30_audio_sync_clk_get_parent,
.recalc_rate = tegra30_clk_fixed_recalc_rate,
};
/* cml0 (pcie), and cml1 (sata) clock ops */
static void tegra30_cml_clk_init(struct clk *c)
static int tegra30_cml_clk_is_enabled(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
c->state = val & (0x1 << c->u.periph.clk_num) ? ON : OFF;
return c->state;
}
static int tegra30_cml_clk_enable(struct clk *c)
static int tegra30_cml_clk_enable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
val |= (0x1 << c->u.periph.clk_num);
clk_writel(val, c->reg);
return 0;
}
static void tegra30_cml_clk_disable(struct clk *c)
static void tegra30_cml_clk_disable(struct clk_hw *hw)
{
struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
val &= ~(0x1 << c->u.periph.clk_num);
clk_writel(val, c->reg);
}
static struct clk_ops tegra_cml_clk_ops = {
.init = &tegra30_cml_clk_init,
.enable = &tegra30_cml_clk_enable,
.disable = &tegra30_cml_clk_disable,
};
/* Clock definitions */
static struct clk tegra_clk_32k = {
.name = "clk_32k",
.rate = 32768,
.ops = NULL,
.max_rate = 32768,
};
static struct clk tegra_clk_m = {
.name = "clk_m",
.flags = ENABLE_ON_INIT,
.ops = &tegra_clk_m_ops,
.reg = 0x1fc,
.reg_shift = 28,
.max_rate = 48000000,
};
static struct clk tegra_clk_m_div2 = {
.name = "clk_m_div2",
.ops = &tegra_clk_m_div_ops,
.parent = &tegra_clk_m,
.mul = 1,
.div = 2,
.state = ON,
.max_rate = 24000000,
};
static struct clk tegra_clk_m_div4 = {
.name = "clk_m_div4",
.ops = &tegra_clk_m_div_ops,
.parent = &tegra_clk_m,
.mul = 1,
.div = 4,
.state = ON,
.max_rate = 12000000,
};
static struct clk tegra_pll_ref = {
.name = "pll_ref",
.flags = ENABLE_ON_INIT,
.ops = &tegra_pll_ref_ops,
.parent = &tegra_clk_m,
.max_rate = 26000000,
};
static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
{ 12000000, 1040000000, 520, 6, 1, 8},
{ 13000000, 1040000000, 480, 6, 1, 8},
{ 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */
{ 19200000, 1040000000, 325, 6, 1, 6},
{ 26000000, 1040000000, 520, 13, 1, 8},
{ 12000000, 832000000, 416, 6, 1, 8},
{ 13000000, 832000000, 832, 13, 1, 8},
{ 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */
{ 19200000, 832000000, 260, 6, 1, 8},
{ 26000000, 832000000, 416, 13, 1, 8},
{ 12000000, 624000000, 624, 12, 1, 8},
{ 13000000, 624000000, 624, 13, 1, 8},
{ 16800000, 600000000, 520, 14, 1, 8},
{ 19200000, 624000000, 520, 16, 1, 8},
{ 26000000, 624000000, 624, 26, 1, 8},
{ 12000000, 600000000, 600, 12, 1, 8},
{ 13000000, 600000000, 600, 13, 1, 8},
{ 16800000, 600000000, 500, 14, 1, 8},
{ 19200000, 600000000, 375, 12, 1, 6},
{ 26000000, 600000000, 600, 26, 1, 8},
{ 12000000, 520000000, 520, 12, 1, 8},
{ 13000000, 520000000, 520, 13, 1, 8},
{ 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */
{ 19200000, 520000000, 325, 12, 1, 6},
{ 26000000, 520000000, 520, 26, 1, 8},
{ 12000000, 416000000, 416, 12, 1, 8},
{ 13000000, 416000000, 416, 13, 1, 8},
{ 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */
{ 19200000, 416000000, 260, 12, 1, 6},
{ 26000000, 416000000, 416, 26, 1, 8},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_c = {
.name = "pll_c",
.flags = PLL_HAS_CPCON,
.ops = &tegra_pll_ops,
.reg = 0x80,
.parent = &tegra_pll_ref,
.max_rate = 1400000000,
.u.pll = {
.input_min = 2000000,
.input_max = 31000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 20000000,
.vco_max = 1400000000,
.freq_table = tegra_pll_c_freq_table,
.lock_delay = 300,
},
};
static struct clk tegra_pll_c_out1 = {
.name = "pll_c_out1",
.ops = &tegra_pll_div_ops,
.flags = DIV_U71,
.parent = &tegra_pll_c,
.reg = 0x84,
.reg_shift = 0,
.max_rate = 700000000,
};
static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
{ 12000000, 666000000, 666, 12, 1, 8},
{ 13000000, 666000000, 666, 13, 1, 8},
{ 16800000, 666000000, 555, 14, 1, 8},
{ 19200000, 666000000, 555, 16, 1, 8},
{ 26000000, 666000000, 666, 26, 1, 8},
{ 12000000, 600000000, 600, 12, 1, 8},
{ 13000000, 600000000, 600, 13, 1, 8},
{ 16800000, 600000000, 500, 14, 1, 8},
{ 19200000, 600000000, 375, 12, 1, 6},
{ 26000000, 600000000, 600, 26, 1, 8},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_m = {
.name = "pll_m",
.flags = PLL_HAS_CPCON | PLLM,
.ops = &tegra_pll_ops,
.reg = 0x90,
.parent = &tegra_pll_ref,
.max_rate = 800000000,
.u.pll = {
.input_min = 2000000,
.input_max = 31000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 20000000,
.vco_max = 1200000000,
.freq_table = tegra_pll_m_freq_table,
.lock_delay = 300,
},
};
static struct clk tegra_pll_m_out1 = {
.name = "pll_m_out1",
.ops = &tegra_pll_div_ops,
.flags = DIV_U71,
.parent = &tegra_pll_m,
.reg = 0x94,
.reg_shift = 0,
.max_rate = 600000000,
};
static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
{ 12000000, 216000000, 432, 12, 2, 8},
{ 13000000, 216000000, 432, 13, 2, 8},
{ 16800000, 216000000, 360, 14, 2, 8},
{ 19200000, 216000000, 360, 16, 2, 8},
{ 26000000, 216000000, 432, 26, 2, 8},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_p = {
.name = "pll_p",
.flags = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
.ops = &tegra_pll_ops,
.reg = 0xa0,
.parent = &tegra_pll_ref,
.max_rate = 432000000,
.u.pll = {
.input_min = 2000000,
.input_max = 31000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 20000000,
.vco_max = 1400000000,
.freq_table = tegra_pll_p_freq_table,
.lock_delay = 300,
.fixed_rate = 408000000,
},
};
static struct clk tegra_pll_p_out1 = {
.name = "pll_p_out1",
.ops = &tegra_pll_div_ops,
.flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
.parent = &tegra_pll_p,
.reg = 0xa4,
.reg_shift = 0,
.max_rate = 432000000,
};
static struct clk tegra_pll_p_out2 = {
.name = "pll_p_out2",
.ops = &tegra_pll_div_ops,
.flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
.parent = &tegra_pll_p,
.reg = 0xa4,
.reg_shift = 16,
.max_rate = 432000000,
};
static struct clk tegra_pll_p_out3 = {
.name = "pll_p_out3",
.ops = &tegra_pll_div_ops,
.flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
.parent = &tegra_pll_p,
.reg = 0xa8,
.reg_shift = 0,
.max_rate = 432000000,
};
static struct clk tegra_pll_p_out4 = {
.name = "pll_p_out4",
.ops = &tegra_pll_div_ops,
.flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
.parent = &tegra_pll_p,
.reg = 0xa8,
.reg_shift = 16,
.max_rate = 432000000,
};
static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
{ 9600000, 564480000, 294, 5, 1, 4},
{ 9600000, 552960000, 288, 5, 1, 4},
{ 9600000, 24000000, 5, 2, 1, 1},
{ 28800000, 56448000, 49, 25, 1, 1},
{ 28800000, 73728000, 64, 25, 1, 1},
{ 28800000, 24000000, 5, 6, 1, 1},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_a = {
.name = "pll_a",
.flags = PLL_HAS_CPCON,
.ops = &tegra_pll_ops,
.reg = 0xb0,
.parent = &tegra_pll_p_out1,
.max_rate = 700000000,
.u.pll = {
.input_min = 2000000,
.input_max = 31000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 20000000,
.vco_max = 1400000000,
.freq_table = tegra_pll_a_freq_table,
.lock_delay = 300,
},
};
static struct clk tegra_pll_a_out0 = {
.name = "pll_a_out0",
.ops = &tegra_pll_div_ops,
.flags = DIV_U71,
.parent = &tegra_pll_a,
.reg = 0xb4,
.reg_shift = 0,
.max_rate = 100000000,
};
static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
{ 12000000, 216000000, 216, 12, 1, 4},
{ 13000000, 216000000, 216, 13, 1, 4},
{ 16800000, 216000000, 180, 14, 1, 4},
{ 19200000, 216000000, 180, 16, 1, 4},
{ 26000000, 216000000, 216, 26, 1, 4},
{ 12000000, 594000000, 594, 12, 1, 8},
{ 13000000, 594000000, 594, 13, 1, 8},
{ 16800000, 594000000, 495, 14, 1, 8},
{ 19200000, 594000000, 495, 16, 1, 8},
{ 26000000, 594000000, 594, 26, 1, 8},
{ 12000000, 1000000000, 1000, 12, 1, 12},
{ 13000000, 1000000000, 1000, 13, 1, 12},
{ 19200000, 1000000000, 625, 12, 1, 8},
{ 26000000, 1000000000, 1000, 26, 1, 12},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_d = {
.name = "pll_d",
.flags = PLL_HAS_CPCON | PLLD,
.ops = &tegra_plld_ops,
.reg = 0xd0,
.parent = &tegra_pll_ref,
.max_rate = 1000000000,
.u.pll = {
.input_min = 2000000,
.input_max = 40000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 40000000,
.vco_max = 1000000000,
.freq_table = tegra_pll_d_freq_table,
.lock_delay = 1000,
},
};
static struct clk tegra_pll_d_out0 = {
.name = "pll_d_out0",
.ops = &tegra_pll_div_ops,
.flags = DIV_2 | PLLD,
.parent = &tegra_pll_d,
.max_rate = 500000000,
};
static struct clk tegra_pll_d2 = {
.name = "pll_d2",
.flags = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD,
.ops = &tegra_plld_ops,
.reg = 0x4b8,
.parent = &tegra_pll_ref,
.max_rate = 1000000000,
.u.pll = {
.input_min = 2000000,
.input_max = 40000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 40000000,
.vco_max = 1000000000,
.freq_table = tegra_pll_d_freq_table,
.lock_delay = 1000,
},
};
static struct clk tegra_pll_d2_out0 = {
.name = "pll_d2_out0",
.ops = &tegra_pll_div_ops,
.flags = DIV_2 | PLLD,
.parent = &tegra_pll_d2,
.max_rate = 500000000,
};
static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
{ 12000000, 480000000, 960, 12, 2, 12},
{ 13000000, 480000000, 960, 13, 2, 12},
{ 16800000, 480000000, 400, 7, 2, 5},
{ 19200000, 480000000, 200, 4, 2, 3},
{ 26000000, 480000000, 960, 26, 2, 12},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_u = {
.name = "pll_u",
.flags = PLL_HAS_CPCON | PLLU,
.ops = &tegra_pll_ops,
.reg = 0xc0,
.parent = &tegra_pll_ref,
.max_rate = 480000000,
.u.pll = {
.input_min = 2000000,
.input_max = 40000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 480000000,
.vco_max = 960000000,
.freq_table = tegra_pll_u_freq_table,
.lock_delay = 1000,
},
};
static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
/* 1.7 GHz */
{ 12000000, 1700000000, 850, 6, 1, 8},
{ 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */
{ 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */
{ 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */
{ 26000000, 1700000000, 850, 13, 1, 8},
/* 1.6 GHz */
{ 12000000, 1600000000, 800, 6, 1, 8},
{ 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */
{ 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */
{ 19200000, 1600000000, 500, 6, 1, 8},
{ 26000000, 1600000000, 800, 13, 1, 8},
/* 1.5 GHz */
{ 12000000, 1500000000, 750, 6, 1, 8},
{ 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */
{ 16800000, 1500000000, 625, 7, 1, 8},
{ 19200000, 1500000000, 625, 8, 1, 8},
{ 26000000, 1500000000, 750, 13, 1, 8},
/* 1.4 GHz */
{ 12000000, 1400000000, 700, 6, 1, 8},
{ 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */
{ 16800000, 1400000000, 1000, 12, 1, 8},
{ 19200000, 1400000000, 875, 12, 1, 8},
{ 26000000, 1400000000, 700, 13, 1, 8},
/* 1.3 GHz */
{ 12000000, 1300000000, 975, 9, 1, 8},
{ 13000000, 1300000000, 1000, 10, 1, 8},
{ 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */
{ 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */
{ 26000000, 1300000000, 650, 13, 1, 8},
/* 1.2 GHz */
{ 12000000, 1200000000, 1000, 10, 1, 8},
{ 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */
{ 16800000, 1200000000, 1000, 14, 1, 8},
{ 19200000, 1200000000, 1000, 16, 1, 8},
{ 26000000, 1200000000, 600, 13, 1, 8},
/* 1.1 GHz */
{ 12000000, 1100000000, 825, 9, 1, 8},
{ 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */
{ 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */
{ 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */
{ 26000000, 1100000000, 550, 13, 1, 8},
/* 1 GHz */
{ 12000000, 1000000000, 1000, 12, 1, 8},
{ 13000000, 1000000000, 1000, 13, 1, 8},
{ 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */
{ 19200000, 1000000000, 625, 12, 1, 8},
{ 26000000, 1000000000, 1000, 26, 1, 8},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_x = {
.name = "pll_x",
.flags = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX,
.ops = &tegra_pll_ops,
.reg = 0xe0,
.parent = &tegra_pll_ref,
.max_rate = 1700000000,
.u.pll = {
.input_min = 2000000,
.input_max = 31000000,
.cf_min = 1000000,
.cf_max = 6000000,
.vco_min = 20000000,
.vco_max = 1700000000,
.freq_table = tegra_pll_x_freq_table,
.lock_delay = 300,
},
};
static struct clk tegra_pll_x_out0 = {
.name = "pll_x_out0",
.ops = &tegra_pll_div_ops,
.flags = DIV_2 | PLLX,
.parent = &tegra_pll_x,
.max_rate = 850000000,
};
static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
/* PLLE special case: use cpcon field to store cml divider value */
{ 12000000, 100000000, 150, 1, 18, 11},
{ 216000000, 100000000, 200, 18, 24, 13},
{ 0, 0, 0, 0, 0, 0 },
};
static struct clk tegra_pll_e = {
.name = "pll_e",
.flags = PLL_ALT_MISC_REG,
.ops = &tegra_plle_ops,
.reg = 0xe8,
.max_rate = 100000000,
.u.pll = {
.input_min = 12000000,
.input_max = 216000000,
.cf_min = 12000000,
.cf_max = 12000000,
.vco_min = 1200000000,
.vco_max = 2400000000U,
.freq_table = tegra_pll_e_freq_table,
.lock_delay = 300,
.fixed_rate = 100000000,
},
};
static struct clk tegra_cml0_clk = {
.name = "cml0",
.parent = &tegra_pll_e,
.ops = &tegra_cml_clk_ops,
.reg = PLLE_AUX,
.max_rate = 100000000,
.u.periph = {
.clk_num = 0,
},
};
static struct clk tegra_cml1_clk = {
.name = "cml1",
.parent = &tegra_pll_e,
.ops = &tegra_cml_clk_ops,
.reg = PLLE_AUX,
.max_rate = 100000000,
.u.periph = {
.clk_num = 1,
},
};
static struct clk tegra_pciex_clk = {
.name = "pciex",
.parent = &tegra_pll_e,
.ops = &tegra_pciex_clk_ops,
.max_rate = 100000000,
.u.periph = {
.clk_num = 74,
},
};
/* Audio sync clocks */
#define SYNC_SOURCE(_id) \
{ \
.name = #_id "_sync", \
.rate = 24000000, \
.max_rate = 24000000, \
.ops = &tegra_sync_source_ops \
}
static struct clk tegra_sync_source_list[] = {
SYNC_SOURCE(spdif_in),
SYNC_SOURCE(i2s0),
SYNC_SOURCE(i2s1),
SYNC_SOURCE(i2s2),
SYNC_SOURCE(i2s3),
SYNC_SOURCE(i2s4),
SYNC_SOURCE(vimclk),
};
static struct clk_mux_sel mux_audio_sync_clk[] = {
{ .input = &tegra_sync_source_list[0], .value = 0},
{ .input = &tegra_sync_source_list[1], .value = 1},
{ .input = &tegra_sync_source_list[2], .value = 2},
{ .input = &tegra_sync_source_list[3], .value = 3},
{ .input = &tegra_sync_source_list[4], .value = 4},
{ .input = &tegra_sync_source_list[5], .value = 5},
{ .input = &tegra_pll_a_out0, .value = 6},
{ .input = &tegra_sync_source_list[6], .value = 7},
{ 0, 0 }
};
#define AUDIO_SYNC_CLK(_id, _index) \
{ \
.name = #_id, \
.inputs = mux_audio_sync_clk, \
.reg = 0x4A0 + (_index) * 4, \
.max_rate = 24000000, \
.ops = &tegra_audio_sync_clk_ops \
}
static struct clk tegra_clk_audio_list[] = {
AUDIO_SYNC_CLK(audio0, 0),
AUDIO_SYNC_CLK(audio1, 1),
AUDIO_SYNC_CLK(audio2, 2),
AUDIO_SYNC_CLK(audio3, 3),
AUDIO_SYNC_CLK(audio4, 4),
AUDIO_SYNC_CLK(audio, 5), /* SPDIF */
};
#define AUDIO_SYNC_2X_CLK(_id, _index) \
{ \
.name = #_id "_2x", \
.flags = PERIPH_NO_RESET, \
.max_rate = 48000000, \
.ops = &tegra_clk_double_ops, \
.reg = 0x49C, \
.reg_shift = 24 + (_index), \
.parent = &tegra_clk_audio_list[(_index)], \
.u.periph = { \
.clk_num = 113 + (_index), \
}, \
}
static struct clk tegra_clk_audio_2x_list[] = {
AUDIO_SYNC_2X_CLK(audio0, 0),
AUDIO_SYNC_2X_CLK(audio1, 1),
AUDIO_SYNC_2X_CLK(audio2, 2),
AUDIO_SYNC_2X_CLK(audio3, 3),
AUDIO_SYNC_2X_CLK(audio4, 4),
AUDIO_SYNC_2X_CLK(audio, 5), /* SPDIF */
};
#define MUX_I2S_SPDIF(_id, _index) \
static struct clk_mux_sel mux_pllaout0_##_id##_2x_pllp_clkm[] = { \
{.input = &tegra_pll_a_out0, .value = 0}, \
{.input = &tegra_clk_audio_2x_list[(_index)], .value = 1}, \
{.input = &tegra_pll_p, .value = 2}, \
{.input = &tegra_clk_m, .value = 3}, \
{ 0, 0}, \
}
MUX_I2S_SPDIF(audio0, 0);
MUX_I2S_SPDIF(audio1, 1);
MUX_I2S_SPDIF(audio2, 2);
MUX_I2S_SPDIF(audio3, 3);
MUX_I2S_SPDIF(audio4, 4);
MUX_I2S_SPDIF(audio, 5); /* SPDIF */
/* External clock outputs (through PMC) */
#define MUX_EXTERN_OUT(_id) \
static struct clk_mux_sel mux_clkm_clkm2_clkm4_extern##_id[] = { \
{.input = &tegra_clk_m, .value = 0}, \
{.input = &tegra_clk_m_div2, .value = 1}, \
{.input = &tegra_clk_m_div4, .value = 2}, \
{.input = NULL, .value = 3}, /* placeholder */ \
{ 0, 0}, \
}
MUX_EXTERN_OUT(1);
MUX_EXTERN_OUT(2);
MUX_EXTERN_OUT(3);
static struct clk_mux_sel *mux_extern_out_list[] = {
mux_clkm_clkm2_clkm4_extern1,
mux_clkm_clkm2_clkm4_extern2,
mux_clkm_clkm2_clkm4_extern3,
};
#define CLK_OUT_CLK(_id) \
{ \
.name = "clk_out_" #_id, \
.lookup = { \
.dev_id = "clk_out_" #_id, \
.con_id = "extern" #_id, \
}, \
.ops = &tegra_clk_out_ops, \
.reg = 0x1a8, \
.inputs = mux_clkm_clkm2_clkm4_extern##_id, \
.flags = MUX_CLK_OUT, \
.max_rate = 216000000, \
.u.periph = { \
.clk_num = (_id - 1) * 8 + 2, \
}, \
}
static struct clk tegra_clk_out_list[] = {
CLK_OUT_CLK(1),
CLK_OUT_CLK(2),
CLK_OUT_CLK(3),
};
/* called after peripheral external clocks are initialized */
static void init_clk_out_mux(void)
{
int i;
struct clk *c;
/* output clock con_id is the name of peripheral
external clock connected to input 3 of the output mux */
for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++) {
c = tegra_get_clock_by_name(
tegra_clk_out_list[i].lookup.con_id);
if (!c)
pr_err("%s: could not find clk %s\n", __func__,
tegra_clk_out_list[i].lookup.con_id);
mux_extern_out_list[i][3].input = c;
}
}
/* Peripheral muxes */
static struct clk_mux_sel mux_sclk[] = {
{ .input = &tegra_clk_m, .value = 0},
{ .input = &tegra_pll_c_out1, .value = 1},
{ .input = &tegra_pll_p_out4, .value = 2},
{ .input = &tegra_pll_p_out3, .value = 3},
{ .input = &tegra_pll_p_out2, .value = 4},
/* { .input = &tegra_clk_d, .value = 5}, - no use on tegra30 */
{ .input = &tegra_clk_32k, .value = 6},
{ .input = &tegra_pll_m_out1, .value = 7},
{ 0, 0},
};
static struct clk tegra_clk_sclk = {
.name = "sclk",
.inputs = mux_sclk,
.reg = 0x28,
.ops = &tegra_super_ops,
.max_rate = 334000000,
.min_rate = 40000000,
};
static struct clk tegra_clk_blink = {
.name = "blink",
.parent = &tegra_clk_32k,
.reg = 0x40,
.ops = &tegra_blink_clk_ops,
.max_rate = 32768,
};
static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
{ .input = &tegra_pll_m, .value = 0},
{ .input = &tegra_pll_c, .value = 1},
{ .input = &tegra_pll_p, .value = 2},
{ .input = &tegra_pll_a_out0, .value = 3},
{ 0, 0},
};
static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
{ .input = &tegra_pll_p, .value = 0},
{ .input = &tegra_pll_c, .value = 1},
{ .input = &tegra_pll_m, .value = 2},
{ .input = &tegra_clk_m, .value = 3},
{ 0, 0},
};
static struct clk_mux_sel mux_pllp_clkm[] = {
{ .input = &tegra_pll_p, .value = 0},
{ .input = &tegra_clk_m, .value = 3},
{ 0, 0},
};
static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
{.input = &tegra_pll_p, .value = 0},
{.input = &tegra_pll_d_out0, .value = 1},
{.input = &tegra_pll_c, .value = 2},
{.input = &tegra_clk_m, .value = 3},
{ 0, 0},
};
static struct clk_mux_sel mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = {
{.input = &tegra_pll_p, .value = 0},
{.input = &tegra_pll_m, .value = 1},
{.input = &tegra_pll_d_out0, .value = 2},
{.input = &tegra_pll_a_out0, .value = 3},
{.input = &tegra_pll_c, .value = 4},
{.input = &tegra_pll_d2_out0, .value = 5},
{.input = &tegra_clk_m, .value = 6},
{ 0, 0},
};
static struct clk_mux_sel mux_plla_pllc_pllp_clkm[] = {
{ .input = &tegra_pll_a_out0, .value = 0},
/* { .input = &tegra_pll_c, .value = 1}, no use on tegra30 */
{ .input = &tegra_pll_p, .value = 2},
{ .input = &tegra_clk_m, .value = 3},
{ 0, 0},
};
static struct clk_mux_sel mux_pllp_pllc_clk32_clkm[] = {
{.input = &tegra_pll_p, .value = 0},
{.input = &tegra_pll_c, .value = 1},
{.input = &tegra_clk_32k, .value = 2},
{.input = &tegra_clk_m, .value = 3},
{ 0, 0},
};
static struct clk_mux_sel mux_pllp_pllc_clkm_clk32[] = {
{.input = &tegra_pll_p, .value = 0},
{.input = &tegra_pll_c, .value = 1},
{.input = &tegra_clk_m, .value = 2},
{.input = &tegra_clk_32k, .value = 3},
{ 0, 0},
};
static struct clk_mux_sel mux_pllp_pllc_pllm[] = {
{.input = &tegra_pll_p, .value = 0},
{.input = &tegra_pll_c, .value = 1},
{.input = &tegra_pll_m, .value = 2},
{ 0, 0},
};
static struct clk_mux_sel mux_clk_m[] = {
{ .input = &tegra_clk_m, .value = 0},
{ 0, 0},
};
static struct clk_mux_sel mux_pllp_out3[] = {
{ .input = &tegra_pll_p_out3, .value = 0},
{ 0, 0},
};
static struct clk_mux_sel mux_plld_out0[] = {
{ .input = &tegra_pll_d_out0, .value = 0},
{ 0, 0},
};
static struct clk_mux_sel mux_plld_out0_plld2_out0[] = {
{ .input = &tegra_pll_d_out0, .value = 0},
{ .input = &tegra_pll_d2_out0, .value = 1},
{ 0, 0},
};
static struct clk_mux_sel mux_clk_32k[] = {
{ .input = &tegra_clk_32k, .value = 0},
{ 0, 0},
struct clk_ops tegra_cml_clk_ops = {
.is_enabled = tegra30_cml_clk_is_enabled,
.enable = tegra30_cml_clk_enable,
.disable = tegra30_cml_clk_disable,
.recalc_rate = tegra30_clk_fixed_recalc_rate,
};
static struct clk_mux_sel mux_plla_clk32_pllp_clkm_plle[] = {
{ .input = &tegra_pll_a_out0, .value = 0},
{ .input = &tegra_clk_32k, .value = 1},
{ .input = &tegra_pll_p, .value = 2},
{ .input = &tegra_clk_m, .value = 3},
{ .input = &tegra_pll_e, .value = 4},
{ 0, 0},
struct clk_ops tegra_pciex_clk_ops = {
.recalc_rate = tegra30_clk_fixed_recalc_rate,
};
static struct clk_mux_sel mux_cclk_g[] = {
{ .input = &tegra_clk_m, .value = 0},
{ .input = &tegra_pll_c, .value = 1},
{ .input = &tegra_clk_32k, .value = 2},
{ .input = &tegra_pll_m, .value = 3},
{ .input = &tegra_pll_p, .value = 4},
{ .input = &tegra_pll_p_out4, .value = 5},
{ .input = &tegra_pll_p_out3, .value = 6},
{ .input = &tegra_pll_x, .value = 8},
{ 0, 0},
};
static struct clk tegra_clk_cclk_g = {
.name = "cclk_g",
.flags = DIV_U71 | DIV_U71_INT,
.inputs = mux_cclk_g,
.reg = 0x368,
.ops = &tegra_super_ops,
.max_rate = 1700000000,
};
static struct clk tegra30_clk_twd = {
.parent = &tegra_clk_cclk_g,
.name = "twd",
.ops = &tegra30_twd_ops,
.max_rate = 1400000000, /* Same as tegra_clk_cpu_cmplx.max_rate */
.mul = 1,
.div = 2,
};
#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
{ \
.name = _name, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
.ops = &tegra_periph_clk_ops, \
.reg = _reg, \
.inputs = _inputs, \
.flags = _flags, \
.max_rate = _max, \
.u.periph = { \
.clk_num = _clk_num, \
}, \
}
#define PERIPH_CLK_EX(_name, _dev, _con, _clk_num, _reg, _max, _inputs, \
_flags, _ops) \
{ \
.name = _name, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
.ops = _ops, \
.reg = _reg, \
.inputs = _inputs, \
.flags = _flags, \
.max_rate = _max, \
.u.periph = { \
.clk_num = _clk_num, \
}, \
}
#define SHARED_CLK(_name, _dev, _con, _parent, _id, _div, _mode)\
{ \
.name = _name, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
.ops = &tegra_clk_shared_bus_ops, \
.parent = _parent, \
.u.shared_bus_user = { \
.client_id = _id, \
.client_div = _div, \
.mode = _mode, \
}, \
}
struct clk tegra_list_clks[] = {
PERIPH_CLK("apbdma", "tegra-apbdma", NULL, 34, 0, 26000000, mux_clk_m, 0),
PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB),
PERIPH_CLK("kbc", "tegra-kbc", NULL, 36, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB),
PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0),
PERIPH_CLK("kfuse", "kfuse-tegra", NULL, 40, 0, 26000000, mux_clk_m, 0),
PERIPH_CLK("fuse", "fuse-tegra", "fuse", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB),
PERIPH_CLK("fuse_burn", "fuse-tegra", "fuse_burn", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB),
PERIPH_CLK("apbif", "tegra30-ahub", "apbif", 107, 0, 26000000, mux_clk_m, 0),
PERIPH_CLK("i2s0", "tegra30-i2s.0", NULL, 30, 0x1d8, 26000000, mux_pllaout0_audio0_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("i2s1", "tegra30-i2s.1", NULL, 11, 0x100, 26000000, mux_pllaout0_audio1_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("i2s2", "tegra30-i2s.2", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("i2s3", "tegra30-i2s.3", NULL, 101, 0x3bc, 26000000, mux_pllaout0_audio3_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("i2s4", "tegra30-i2s.4", NULL, 102, 0x3c0, 26000000, mux_pllaout0_audio4_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("spdif_out", "tegra30-spdif", "spdif_out", 10, 0x108, 100000000, mux_pllaout0_audio_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("spdif_in", "tegra30-spdif", "spdif_in", 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("pwm", "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_clk32_clkm, MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("d_audio", "tegra30-ahub", "d_audio", 106, 0x3d0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
PERIPH_CLK("dam0", "tegra30-dam.0", NULL, 108, 0x3d8, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
PERIPH_CLK("dam1", "tegra30-dam.1", NULL, 109, 0x3dc, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
PERIPH_CLK("dam2", "tegra30-dam.2", NULL, 110, 0x3e0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
PERIPH_CLK("hda", "tegra30-hda", "hda", 125, 0x428, 108000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("hda2codec_2x", "tegra30-hda", "hda2codec", 111, 0x3e4, 48000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("hda2hdmi", "tegra30-hda", "hda2hdmi", 128, 0, 48000000, mux_clk_m, 0),
PERIPH_CLK("sbc1", "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("sbc2", "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("sbc3", "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("sbc4", "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("sbc5", "spi_tegra.4", NULL, 104, 0x3c8, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("sbc6", "spi_tegra.5", NULL, 105, 0x3cc, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("sata_oob", "tegra_sata_oob", NULL, 123, 0x420, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("sata", "tegra_sata", NULL, 124, 0x424, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("sata_cold", "tegra_sata_cold", NULL, 129, 0, 48000000, mux_clk_m, 0),
PERIPH_CLK_EX("ndflash", "tegra_nand", NULL, 13, 0x160, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71, &tegra_nand_clk_ops),
PERIPH_CLK("ndspeed", "tegra_nand_speed", NULL, 80, 0x3f8, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("vfir", "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("sdmmc1", "sdhci-tegra.0", NULL, 14, 0x150, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
PERIPH_CLK("sdmmc3", "sdhci-tegra.2", NULL, 69, 0x1bc, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
PERIPH_CLK("sdmmc4", "sdhci-tegra.3", NULL, 15, 0x164, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
PERIPH_CLK("vcp", "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0),
PERIPH_CLK("bsea", "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0),
PERIPH_CLK("bsev", "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0),
PERIPH_CLK("vde", "vde", NULL, 61, 0x1c8, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT),
PERIPH_CLK("csite", "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* max rate ??? */
PERIPH_CLK("la", "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("owr", "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("nor", "nor", NULL, 42, 0x1d0, 127000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("mipi", "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB), /* scales with voltage */
PERIPH_CLK("i2c1", "tegra-i2c.0", NULL, 12, 0x124, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
PERIPH_CLK("i2c2", "tegra-i2c.1", NULL, 54, 0x198, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
PERIPH_CLK("i2c3", "tegra-i2c.2", NULL, 67, 0x1b8, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
PERIPH_CLK("i2c4", "tegra-i2c.3", NULL, 103, 0x3c4, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
PERIPH_CLK("i2c5", "tegra-i2c.4", NULL, 47, 0x128, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
PERIPH_CLK("uarta", "tegra-uart.0", NULL, 6, 0x178, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
PERIPH_CLK("uartb", "tegra-uart.1", NULL, 7, 0x17c, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
PERIPH_CLK("uartc", "tegra-uart.2", NULL, 55, 0x1a0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
PERIPH_CLK("uartd", "tegra-uart.3", NULL, 65, 0x1c0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
PERIPH_CLK("uarte", "tegra-uart.4", NULL, 66, 0x1c4, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
PERIPH_CLK_EX("vi", "tegra_camera", "vi", 20, 0x148, 425000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT, &tegra_vi_clk_ops),
PERIPH_CLK("3d", "3d", NULL, 24, 0x158, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
PERIPH_CLK("3d2", "3d2", NULL, 98, 0x3b0, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
PERIPH_CLK("2d", "2d", NULL, 21, 0x15c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE),
PERIPH_CLK("vi_sensor", "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET),
PERIPH_CLK("epp", "epp", NULL, 19, 0x16c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT),
PERIPH_CLK("mpe", "mpe", NULL, 60, 0x170, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT),
PERIPH_CLK("host1x", "host1x", NULL, 28, 0x180, 260000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT),
PERIPH_CLK("cve", "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("tvo", "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK_EX("dtv", "dtv", NULL, 79, 0x1dc, 250000000, mux_clk_m, 0, &tegra_dtv_clk_ops),
PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, 148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8 | DIV_U71),
PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, 220000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("disp1", "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8),
PERIPH_CLK("disp2", "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8),
PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb2", "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb3", "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("dsia", "tegradc.0", "dsia", 48, 0, 500000000, mux_plld_out0, 0),
PERIPH_CLK_EX("dsib", "tegradc.1", "dsib", 82, 0xd0, 500000000, mux_plld_out0_plld2_out0, MUX | PLLD, &tegra_dsib_clk_ops),
PERIPH_CLK("csi", "tegra_camera", "csi", 52, 0, 102000000, mux_pllp_out3, 0),
PERIPH_CLK("isp", "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0), /* same frequency as VI */
PERIPH_CLK("csus", "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET),
PERIPH_CLK("tsensor", "tegra-tsensor", NULL, 100, 0x3b8, 216000000, mux_pllp_pllc_clkm_clk32, MUX | DIV_U71),
PERIPH_CLK("actmon", "actmon", NULL, 119, 0x3e8, 216000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71),
PERIPH_CLK("extern1", "extern1", NULL, 120, 0x3ec, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71),
PERIPH_CLK("extern2", "extern2", NULL, 121, 0x3f0, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71),
PERIPH_CLK("extern3", "extern3", NULL, 122, 0x3f4, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71),
PERIPH_CLK("i2cslow", "i2cslow", NULL, 81, 0x3fc, 26000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("pcie", "tegra-pcie", "pcie", 70, 0, 250000000, mux_clk_m, 0),
PERIPH_CLK("afi", "tegra-pcie", "afi", 72, 0, 250000000, mux_clk_m, 0),
PERIPH_CLK("se", "se", NULL, 127, 0x42c, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT),
};
#define CLK_DUPLICATE(_name, _dev, _con) \
{ \
.name = _name, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
}
/* Some clocks may be used by different drivers depending on the board
* configuration. List those here to register them twice in the clock lookup
* table under two names.
*/
struct clk_duplicate tegra_clk_duplicates[] = {
CLK_DUPLICATE("uarta", "serial8250.0", NULL),
CLK_DUPLICATE("uartb", "serial8250.1", NULL),
CLK_DUPLICATE("uartc", "serial8250.2", NULL),
CLK_DUPLICATE("uartd", "serial8250.3", NULL),
CLK_DUPLICATE("uarte", "serial8250.4", NULL),
CLK_DUPLICATE("usbd", "utmip-pad", NULL),
CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
CLK_DUPLICATE("usbd", "tegra-otg", NULL),
CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
CLK_DUPLICATE("dsib", "tegradc.0", "dsib"),
CLK_DUPLICATE("dsia", "tegradc.1", "dsia"),
CLK_DUPLICATE("bsev", "tegra-avp", "bsev"),
CLK_DUPLICATE("bsev", "nvavp", "bsev"),
CLK_DUPLICATE("vde", "tegra-aes", "vde"),
CLK_DUPLICATE("bsea", "tegra-aes", "bsea"),
CLK_DUPLICATE("bsea", "nvavp", "bsea"),
CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL),
CLK_DUPLICATE("cml0", "tegra_pcie", "cml"),
CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"),
CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL),
CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL),
CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL),
CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL),
CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL),
CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL),
CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL),
CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL),
CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL),
CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL),
CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL),
CLK_DUPLICATE("twd", "smp_twd", NULL),
CLK_DUPLICATE("vcp", "nvavp", "vcp"),
CLK_DUPLICATE("i2s0", NULL, "i2s0"),
CLK_DUPLICATE("i2s1", NULL, "i2s1"),
CLK_DUPLICATE("i2s2", NULL, "i2s2"),
CLK_DUPLICATE("i2s3", NULL, "i2s3"),
CLK_DUPLICATE("i2s4", NULL, "i2s4"),
CLK_DUPLICATE("dam0", NULL, "dam0"),
CLK_DUPLICATE("dam1", NULL, "dam1"),
CLK_DUPLICATE("dam2", NULL, "dam2"),
CLK_DUPLICATE("spdif_in", NULL, "spdif_in"),
};
struct clk *tegra_ptr_clks[] = {
&tegra_clk_32k,
&tegra_clk_m,
&tegra_clk_m_div2,
&tegra_clk_m_div4,
&tegra_pll_ref,
&tegra_pll_m,
&tegra_pll_m_out1,
&tegra_pll_c,
&tegra_pll_c_out1,
&tegra_pll_p,
&tegra_pll_p_out1,
&tegra_pll_p_out2,
&tegra_pll_p_out3,
&tegra_pll_p_out4,
&tegra_pll_a,
&tegra_pll_a_out0,
&tegra_pll_d,
&tegra_pll_d_out0,
&tegra_pll_d2,
&tegra_pll_d2_out0,
&tegra_pll_u,
&tegra_pll_x,
&tegra_pll_x_out0,
&tegra_pll_e,
&tegra_clk_cclk_g,
&tegra_cml0_clk,
&tegra_cml1_clk,
&tegra_pciex_clk,
&tegra_clk_sclk,
&tegra_clk_blink,
&tegra30_clk_twd,
};
static void tegra30_init_one_clock(struct clk *c)
{
clk_init(c);
INIT_LIST_HEAD(&c->shared_bus_list);
if (!c->lookup.dev_id && !c->lookup.con_id)
c->lookup.con_id = c->name;
c->lookup.clk = c;
clkdev_add(&c->lookup);
}
void __init tegra30_init_clocks(void)
{
int i;
struct clk *c;
for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
tegra30_init_one_clock(tegra_ptr_clks[i]);
for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
tegra30_init_one_clock(&tegra_list_clks[i]);
for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
if (!c) {
pr_err("%s: Unknown duplicate clock %s\n", __func__,
tegra_clk_duplicates[i].name);
continue;
}
tegra_clk_duplicates[i].lookup.clk = c;
clkdev_add(&tegra_clk_duplicates[i].lookup);
}
for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++)
tegra30_init_one_clock(&tegra_sync_source_list[i]);
for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++)
tegra30_init_one_clock(&tegra_clk_audio_list[i]);
for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++)
tegra30_init_one_clock(&tegra_clk_audio_2x_list[i]);
init_clk_out_mux();
for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++)
tegra30_init_one_clock(&tegra_clk_out_list[i]);
}
/*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MACH_TEGRA30_CLOCK_H
#define __MACH_TEGRA30_CLOCK_H
extern struct clk_ops tegra30_clk_32k_ops;
extern struct clk_ops tegra30_clk_m_ops;
extern struct clk_ops tegra_clk_m_div_ops;
extern struct clk_ops tegra_pll_ref_ops;
extern struct clk_ops tegra30_pll_ops;
extern struct clk_ops tegra30_pll_div_ops;
extern struct clk_ops tegra_plld_ops;
extern struct clk_ops tegra30_plle_ops;
extern struct clk_ops tegra_cml_clk_ops;
extern struct clk_ops tegra_pciex_clk_ops;
extern struct clk_ops tegra_sync_source_ops;
extern struct clk_ops tegra30_audio_sync_clk_ops;
extern struct clk_ops tegra30_clk_double_ops;
extern struct clk_ops tegra_clk_out_ops;
extern struct clk_ops tegra30_super_ops;
extern struct clk_ops tegra30_blink_clk_ops;
extern struct clk_ops tegra30_twd_ops;
extern struct clk_ops tegra30_periph_clk_ops;
extern struct clk_ops tegra30_dsib_clk_ops;
extern struct clk_ops tegra_nand_clk_ops;
extern struct clk_ops tegra_vi_clk_ops;
extern struct clk_ops tegra_dtv_clk_ops;
extern struct clk_ops tegra_clk_shared_bus_ops;
int tegra30_plld_clk_cfg_ex(struct clk_hw *hw,
enum tegra_clk_ex_param p, u32 setting);
void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert);
int tegra30_vi_clk_cfg_ex(struct clk_hw *hw,
enum tegra_clk_ex_param p, u32 setting);
int tegra30_nand_clk_cfg_ex(struct clk_hw *hw,
enum tegra_clk_ex_param p, u32 setting);
int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw,
enum tegra_clk_ex_param p, u32 setting);
#endif
/*
* arch/arm/mach-tegra/tegra30_clocks.c
*
* Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved.
*
* 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; version 2 of the License.
*
* 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <linux/clk-private.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include "clock.h"
#include "fuse.h"
#include "tegra30_clocks.h"
#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \
_parent_names, _parents, _parent) \
static struct clk tegra_##_name = { \
.hw = &tegra_##_name##_hw.hw, \
.name = #_name, \
.rate = _rate, \
.ops = _ops, \
.flags = _flags, \
.parent_names = _parent_names, \
.parents = _parents, \
.num_parents = ARRAY_SIZE(_parent_names), \
.parent = _parent, \
};
static struct clk tegra_clk_32k;
static struct clk_tegra tegra_clk_32k_hw = {
.hw = {
.clk = &tegra_clk_32k,
},
.fixed_rate = 32768,
};
static struct clk tegra_clk_32k = {
.name = "clk_32k",
.hw = &tegra_clk_32k_hw.hw,
.ops = &tegra30_clk_32k_ops,
.flags = CLK_IS_ROOT,
};
static struct clk tegra_clk_m;
static struct clk_tegra tegra_clk_m_hw = {
.hw = {
.clk = &tegra_clk_m,
},
.flags = ENABLE_ON_INIT,
.reg = 0x1fc,
.reg_shift = 28,
.max_rate = 48000000,
};
static struct clk tegra_clk_m = {
.name = "clk_m",
.hw = &tegra_clk_m_hw.hw,
.ops = &tegra30_clk_m_ops,
.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED,
};
static const char *clk_m_div_parent_names[] = {
"clk_m",
};
static struct clk *clk_m_div_parents[] = {
&tegra_clk_m,
};
static struct clk tegra_clk_m_div2;
static struct clk_tegra tegra_clk_m_div2_hw = {
.hw = {
.clk = &tegra_clk_m_div2,
},
.mul = 1,
.div = 2,
.max_rate = 24000000,
};
DEFINE_CLK_TEGRA(clk_m_div2, 0, &tegra_clk_m_div_ops, 0,
clk_m_div_parent_names, clk_m_div_parents, &tegra_clk_m);
static struct clk tegra_clk_m_div4;
static struct clk_tegra tegra_clk_m_div4_hw = {
.hw = {
.clk = &tegra_clk_m_div4,
},
.mul = 1,
.div = 4,
.max_rate = 12000000,
};
DEFINE_CLK_TEGRA(clk_m_div4, 0, &tegra_clk_m_div_ops, 0,
clk_m_div_parent_names, clk_m_div_parents, &tegra_clk_m);
static struct clk tegra_pll_ref;
static struct clk_tegra tegra_pll_ref_hw = {
.hw = {
.clk = &tegra_pll_ref,
},
.flags = ENABLE_ON_INIT,
.max_rate = 26000000,
};
DEFINE_CLK_TEGRA(pll_ref, 0, &tegra_pll_ref_ops, 0, clk_m_div_parent_names,
clk_m_div_parents, &tegra_clk_m);
#define DEFINE_PLL(_name, _flags, _reg, _max_rate, _input_min, \
_input_max, _cf_min, _cf_max, _vco_min, \
_vco_max, _freq_table, _lock_delay, _ops, \
_fixed_rate, _clk_cfg_ex, _parent) \
static struct clk tegra_##_name; \
static const char *_name##_parent_names[] = { \
#_parent, \
}; \
static struct clk *_name##_parents[] = { \
&tegra_##_parent, \
}; \
static struct clk_tegra tegra_##_name##_hw = { \
.hw = { \
.clk = &tegra_##_name, \
}, \
.flags = _flags, \
.reg = _reg, \
.max_rate = _max_rate, \
.u.pll = { \
.input_min = _input_min, \
.input_max = _input_max, \
.cf_min = _cf_min, \
.cf_max = _cf_max, \
.vco_min = _vco_min, \
.vco_max = _vco_max, \
.freq_table = _freq_table, \
.lock_delay = _lock_delay, \
.fixed_rate = _fixed_rate, \
}, \
.clk_cfg_ex = _clk_cfg_ex, \
}; \
DEFINE_CLK_TEGRA(_name, 0, &_ops, CLK_IGNORE_UNUSED, \
_name##_parent_names, _name##_parents, \
&tegra_##_parent);
#define DEFINE_PLL_OUT(_name, _flags, _reg, _reg_shift, \
_max_rate, _ops, _parent, _clk_flags) \
static const char *_name##_parent_names[] = { \
#_parent, \
}; \
static struct clk *_name##_parents[] = { \
&tegra_##_parent, \
}; \
static struct clk tegra_##_name; \
static struct clk_tegra tegra_##_name##_hw = { \
.hw = { \
.clk = &tegra_##_name, \
}, \
.flags = _flags, \
.reg = _reg, \
.max_rate = _max_rate, \
.reg_shift = _reg_shift, \
}; \
DEFINE_CLK_TEGRA(_name, 0, &tegra30_pll_div_ops, \
_clk_flags, _name##_parent_names, \
_name##_parents, &tegra_##_parent);
static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
{ 12000000, 1040000000, 520, 6, 1, 8},
{ 13000000, 1040000000, 480, 6, 1, 8},
{ 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */
{ 19200000, 1040000000, 325, 6, 1, 6},
{ 26000000, 1040000000, 520, 13, 1, 8},
{ 12000000, 832000000, 416, 6, 1, 8},
{ 13000000, 832000000, 832, 13, 1, 8},
{ 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */
{ 19200000, 832000000, 260, 6, 1, 8},
{ 26000000, 832000000, 416, 13, 1, 8},
{ 12000000, 624000000, 624, 12, 1, 8},
{ 13000000, 624000000, 624, 13, 1, 8},
{ 16800000, 600000000, 520, 14, 1, 8},
{ 19200000, 624000000, 520, 16, 1, 8},
{ 26000000, 624000000, 624, 26, 1, 8},
{ 12000000, 600000000, 600, 12, 1, 8},
{ 13000000, 600000000, 600, 13, 1, 8},
{ 16800000, 600000000, 500, 14, 1, 8},
{ 19200000, 600000000, 375, 12, 1, 6},
{ 26000000, 600000000, 600, 26, 1, 8},
{ 12000000, 520000000, 520, 12, 1, 8},
{ 13000000, 520000000, 520, 13, 1, 8},
{ 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */
{ 19200000, 520000000, 325, 12, 1, 6},
{ 26000000, 520000000, 520, 26, 1, 8},
{ 12000000, 416000000, 416, 12, 1, 8},
{ 13000000, 416000000, 416, 13, 1, 8},
{ 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */
{ 19200000, 416000000, 260, 12, 1, 6},
{ 26000000, 416000000, 416, 26, 1, 8},
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_c, PLL_HAS_CPCON, 0x80, 1400000000, 2000000, 31000000, 1000000,
6000000, 20000000, 1400000000, tegra_pll_c_freq_table, 300,
tegra30_pll_ops, 0, NULL, pll_ref);
DEFINE_PLL_OUT(pll_c_out1, DIV_U71, 0x84, 0, 700000000,
tegra30_pll_div_ops, pll_c, CLK_IGNORE_UNUSED);
static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
{ 12000000, 666000000, 666, 12, 1, 8},
{ 13000000, 666000000, 666, 13, 1, 8},
{ 16800000, 666000000, 555, 14, 1, 8},
{ 19200000, 666000000, 555, 16, 1, 8},
{ 26000000, 666000000, 666, 26, 1, 8},
{ 12000000, 600000000, 600, 12, 1, 8},
{ 13000000, 600000000, 600, 13, 1, 8},
{ 16800000, 600000000, 500, 14, 1, 8},
{ 19200000, 600000000, 375, 12, 1, 6},
{ 26000000, 600000000, 600, 26, 1, 8},
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_m, PLL_HAS_CPCON | PLLM, 0x90, 800000000, 2000000, 31000000,
1000000, 6000000, 20000000, 1200000000, tegra_pll_m_freq_table,
300, tegra30_pll_ops, 0, NULL, pll_ref);
DEFINE_PLL_OUT(pll_m_out1, DIV_U71, 0x94, 0, 600000000,
tegra30_pll_div_ops, pll_m, CLK_IGNORE_UNUSED);
static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
{ 12000000, 216000000, 432, 12, 2, 8},
{ 13000000, 216000000, 432, 13, 2, 8},
{ 16800000, 216000000, 360, 14, 2, 8},
{ 19200000, 216000000, 360, 16, 2, 8},
{ 26000000, 216000000, 432, 26, 2, 8},
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_p, ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, 0xa0, 432000000,
2000000, 31000000, 1000000, 6000000, 20000000, 1400000000,
tegra_pll_p_freq_table, 300, tegra30_pll_ops, 408000000, NULL,
pll_ref);
DEFINE_PLL_OUT(pll_p_out1, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4,
0, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
DEFINE_PLL_OUT(pll_p_out2, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4,
16, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
DEFINE_PLL_OUT(pll_p_out3, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8,
0, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
DEFINE_PLL_OUT(pll_p_out4, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8,
16, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
{ 9600000, 564480000, 294, 5, 1, 4},
{ 9600000, 552960000, 288, 5, 1, 4},
{ 9600000, 24000000, 5, 2, 1, 1},
{ 28800000, 56448000, 49, 25, 1, 1},
{ 28800000, 73728000, 64, 25, 1, 1},
{ 28800000, 24000000, 5, 6, 1, 1},
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_a, PLL_HAS_CPCON, 0xb0, 700000000, 2000000, 31000000, 1000000,
6000000, 20000000, 1400000000, tegra_pll_a_freq_table,
300, tegra30_pll_ops, 0, NULL, pll_p_out1);
DEFINE_PLL_OUT(pll_a_out0, DIV_U71, 0xb4, 0, 100000000, tegra30_pll_div_ops,
pll_a, CLK_IGNORE_UNUSED);
static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
{ 12000000, 216000000, 216, 12, 1, 4},
{ 13000000, 216000000, 216, 13, 1, 4},
{ 16800000, 216000000, 180, 14, 1, 4},
{ 19200000, 216000000, 180, 16, 1, 4},
{ 26000000, 216000000, 216, 26, 1, 4},
{ 12000000, 594000000, 594, 12, 1, 8},
{ 13000000, 594000000, 594, 13, 1, 8},
{ 16800000, 594000000, 495, 14, 1, 8},
{ 19200000, 594000000, 495, 16, 1, 8},
{ 26000000, 594000000, 594, 26, 1, 8},
{ 12000000, 1000000000, 1000, 12, 1, 12},
{ 13000000, 1000000000, 1000, 13, 1, 12},
{ 19200000, 1000000000, 625, 12, 1, 8},
{ 26000000, 1000000000, 1000, 26, 1, 12},
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_d, PLL_HAS_CPCON | PLLD, 0xd0, 1000000000, 2000000, 40000000,
1000000, 6000000, 40000000, 1000000000, tegra_pll_d_freq_table,
1000, tegra30_pll_ops, 0, tegra30_plld_clk_cfg_ex, pll_ref);
DEFINE_PLL_OUT(pll_d_out0, DIV_2 | PLLD, 0, 0, 500000000, tegra30_pll_div_ops,
pll_d, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
DEFINE_PLL(pll_d2, PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD, 0x4b8, 1000000000,
2000000, 40000000, 1000000, 6000000, 40000000, 1000000000,
tegra_pll_d_freq_table, 1000, tegra30_pll_ops, 0, NULL,
pll_ref);
DEFINE_PLL_OUT(pll_d2_out0, DIV_2 | PLLD, 0, 0, 500000000, tegra30_pll_div_ops,
pll_d2, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
{ 12000000, 480000000, 960, 12, 2, 12},
{ 13000000, 480000000, 960, 13, 2, 12},
{ 16800000, 480000000, 400, 7, 2, 5},
{ 19200000, 480000000, 200, 4, 2, 3},
{ 26000000, 480000000, 960, 26, 2, 12},
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_u, PLL_HAS_CPCON | PLLU, 0xc0, 480000000, 2000000, 40000000,
1000000, 6000000, 48000000, 960000000, tegra_pll_u_freq_table,
1000, tegra30_pll_ops, 0, NULL, pll_ref);
static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
/* 1.7 GHz */
{ 12000000, 1700000000, 850, 6, 1, 8},
{ 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */
{ 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */
{ 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */
{ 26000000, 1700000000, 850, 13, 1, 8},
/* 1.6 GHz */
{ 12000000, 1600000000, 800, 6, 1, 8},
{ 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */
{ 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */
{ 19200000, 1600000000, 500, 6, 1, 8},
{ 26000000, 1600000000, 800, 13, 1, 8},
/* 1.5 GHz */
{ 12000000, 1500000000, 750, 6, 1, 8},
{ 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */
{ 16800000, 1500000000, 625, 7, 1, 8},
{ 19200000, 1500000000, 625, 8, 1, 8},
{ 26000000, 1500000000, 750, 13, 1, 8},
/* 1.4 GHz */
{ 12000000, 1400000000, 700, 6, 1, 8},
{ 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */
{ 16800000, 1400000000, 1000, 12, 1, 8},
{ 19200000, 1400000000, 875, 12, 1, 8},
{ 26000000, 1400000000, 700, 13, 1, 8},
/* 1.3 GHz */
{ 12000000, 1300000000, 975, 9, 1, 8},
{ 13000000, 1300000000, 1000, 10, 1, 8},
{ 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */
{ 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */
{ 26000000, 1300000000, 650, 13, 1, 8},
/* 1.2 GHz */
{ 12000000, 1200000000, 1000, 10, 1, 8},
{ 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */
{ 16800000, 1200000000, 1000, 14, 1, 8},
{ 19200000, 1200000000, 1000, 16, 1, 8},
{ 26000000, 1200000000, 600, 13, 1, 8},
/* 1.1 GHz */
{ 12000000, 1100000000, 825, 9, 1, 8},
{ 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */
{ 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */
{ 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */
{ 26000000, 1100000000, 550, 13, 1, 8},
/* 1 GHz */
{ 12000000, 1000000000, 1000, 12, 1, 8},
{ 13000000, 1000000000, 1000, 13, 1, 8},
{ 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */
{ 19200000, 1000000000, 625, 12, 1, 8},
{ 26000000, 1000000000, 1000, 26, 1, 8},
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_x, PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX, 0xe0, 1700000000,
2000000, 31000000, 1000000, 6000000, 20000000, 1700000000,
tegra_pll_x_freq_table, 300, tegra30_pll_ops, 0, NULL, pll_ref);
DEFINE_PLL_OUT(pll_x_out0, DIV_2 | PLLX, 0, 0, 850000000, tegra30_pll_div_ops,
pll_x, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
/* PLLE special case: use cpcon field to store cml divider value */
{ 12000000, 100000000, 150, 1, 18, 11},
{ 216000000, 100000000, 200, 18, 24, 13},
{ 0, 0, 0, 0, 0, 0 },
};
DEFINE_PLL(pll_e, PLL_ALT_MISC_REG, 0xe8, 100000000, 2000000, 216000000,
12000000, 12000000, 1200000000, 2400000000U,
tegra_pll_e_freq_table, 300, tegra30_plle_ops, 100000000, NULL,
pll_ref);
static const char *mux_plle[] = {
"pll_e",
};
static struct clk *mux_plle_p[] = {
&tegra_pll_e,
};
static struct clk tegra_cml0;
static struct clk_tegra tegra_cml0_hw = {
.hw = {
.clk = &tegra_cml0,
},
.reg = 0x48c,
.fixed_rate = 100000000,
.u.periph = {
.clk_num = 0,
},
};
DEFINE_CLK_TEGRA(cml0, 0, &tegra_cml_clk_ops, 0, mux_plle,
mux_plle_p, &tegra_pll_e);
static struct clk tegra_cml1;
static struct clk_tegra tegra_cml1_hw = {
.hw = {
.clk = &tegra_cml1,
},
.reg = 0x48c,
.fixed_rate = 100000000,
.u.periph = {
.clk_num = 1,
},
};
DEFINE_CLK_TEGRA(cml1, 0, &tegra_cml_clk_ops, 0, mux_plle,
mux_plle_p, &tegra_pll_e);
static struct clk tegra_pciex;
static struct clk_tegra tegra_pciex_hw = {
.hw = {
.clk = &tegra_pciex,
},
.reg = 0x48c,
.fixed_rate = 100000000,
.reset = tegra30_periph_clk_reset,
.u.periph = {
.clk_num = 74,
},
};
DEFINE_CLK_TEGRA(pciex, 0, &tegra_pciex_clk_ops, 0, mux_plle,
mux_plle_p, &tegra_pll_e);
#define SYNC_SOURCE(_name) \
static struct clk tegra_##_name##_sync; \
static struct clk_tegra tegra_##_name##_sync_hw = { \
.hw = { \
.clk = &tegra_##_name##_sync, \
}, \
.max_rate = 24000000, \
.fixed_rate = 24000000, \
}; \
static struct clk tegra_##_name##_sync = { \
.name = #_name "_sync", \
.hw = &tegra_##_name##_sync_hw.hw, \
.ops = &tegra_sync_source_ops, \
.flags = CLK_IS_ROOT, \
};
SYNC_SOURCE(spdif_in);
SYNC_SOURCE(i2s0);
SYNC_SOURCE(i2s1);
SYNC_SOURCE(i2s2);
SYNC_SOURCE(i2s3);
SYNC_SOURCE(i2s4);
SYNC_SOURCE(vimclk);
static struct clk *tegra_sync_source_list[] = {
&tegra_spdif_in_sync,
&tegra_i2s0_sync,
&tegra_i2s1_sync,
&tegra_i2s2_sync,
&tegra_i2s3_sync,
&tegra_i2s4_sync,
&tegra_vimclk_sync,
};
static const char *mux_audio_sync_clk[] = {
"spdif_in_sync",
"i2s0_sync",
"i2s1_sync",
"i2s2_sync",
"i2s3_sync",
"i2s4_sync",
"vimclk_sync",
};
#define AUDIO_SYNC_CLK(_name, _index) \
static struct clk tegra_##_name; \
static struct clk_tegra tegra_##_name##_hw = { \
.hw = { \
.clk = &tegra_##_name, \
}, \
.max_rate = 24000000, \
.reg = 0x4A0 + (_index) * 4, \
}; \
static struct clk tegra_##_name = { \
.name = #_name, \
.ops = &tegra30_audio_sync_clk_ops, \
.hw = &tegra_##_name##_hw.hw, \
.parent_names = mux_audio_sync_clk, \
.parents = tegra_sync_source_list, \
.num_parents = ARRAY_SIZE(mux_audio_sync_clk), \
};
AUDIO_SYNC_CLK(audio0, 0);
AUDIO_SYNC_CLK(audio1, 1);
AUDIO_SYNC_CLK(audio2, 2);
AUDIO_SYNC_CLK(audio3, 3);
AUDIO_SYNC_CLK(audio4, 4);
AUDIO_SYNC_CLK(audio5, 5);
static struct clk *tegra_clk_audio_list[] = {
&tegra_audio0,
&tegra_audio1,
&tegra_audio2,
&tegra_audio3,
&tegra_audio4,
&tegra_audio5, /* SPDIF */
};
#define AUDIO_SYNC_2X_CLK(_name, _index) \
static const char *_name##_parent_names[] = { \
"tegra_" #_name, \
}; \
static struct clk *_name##_parents[] = { \
&tegra_##_name, \
}; \
static struct clk tegra_##_name##_2x; \
static struct clk_tegra tegra_##_name##_2x_hw = { \
.hw = { \
.clk = &tegra_##_name##_2x, \
}, \
.flags = PERIPH_NO_RESET, \
.max_rate = 48000000, \
.reg = 0x49C, \
.reg_shift = 24 + (_index), \
.u.periph = { \
.clk_num = 113 + (_index), \
}, \
}; \
static struct clk tegra_##_name##_2x = { \
.name = #_name "_2x", \
.ops = &tegra30_clk_double_ops, \
.hw = &tegra_##_name##_2x_hw.hw, \
.parent_names = _name##_parent_names, \
.parents = _name##_parents, \
.parent = &tegra_##_name, \
.num_parents = 1, \
};
AUDIO_SYNC_2X_CLK(audio0, 0);
AUDIO_SYNC_2X_CLK(audio1, 1);
AUDIO_SYNC_2X_CLK(audio2, 2);
AUDIO_SYNC_2X_CLK(audio3, 3);
AUDIO_SYNC_2X_CLK(audio4, 4);
AUDIO_SYNC_2X_CLK(audio5, 5); /* SPDIF */
static struct clk *tegra_clk_audio_2x_list[] = {
&tegra_audio0_2x,
&tegra_audio1_2x,
&tegra_audio2_2x,
&tegra_audio3_2x,
&tegra_audio4_2x,
&tegra_audio5_2x, /* SPDIF */
};
#define MUX_I2S_SPDIF(_id) \
static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { \
"pll_a_out0", \
#_id "_2x", \
"pll_p", \
"clk_m", \
}; \
static struct clk *mux_pllaout0_##_id##_2x_pllp_clkm_p[] = { \
&tegra_pll_a_out0, \
&tegra_##_id##_2x, \
&tegra_pll_p, \
&tegra_clk_m, \
};
MUX_I2S_SPDIF(audio0);
MUX_I2S_SPDIF(audio1);
MUX_I2S_SPDIF(audio2);
MUX_I2S_SPDIF(audio3);
MUX_I2S_SPDIF(audio4);
MUX_I2S_SPDIF(audio5); /* SPDIF */
static struct clk tegra_extern1;
static struct clk tegra_extern2;
static struct clk tegra_extern3;
/* External clock outputs (through PMC) */
#define MUX_EXTERN_OUT(_id) \
static const char *mux_clkm_clkm2_clkm4_extern##_id[] = { \
"clk_m", \
"clk_m_div2", \
"clk_m_div4", \
"extern" #_id, \
}; \
static struct clk *mux_clkm_clkm2_clkm4_extern##_id##_p[] = { \
&tegra_clk_m, \
&tegra_clk_m_div2, \
&tegra_clk_m_div4, \
&tegra_extern##_id, \
};
MUX_EXTERN_OUT(1);
MUX_EXTERN_OUT(2);
MUX_EXTERN_OUT(3);
#define CLK_OUT_CLK(_name, _index) \
static struct clk tegra_##_name; \
static struct clk_tegra tegra_##_name##_hw = { \
.hw = { \
.clk = &tegra_##_name, \
}, \
.lookup = { \
.dev_id = #_name, \
.con_id = "extern" #_index, \
}, \
.flags = MUX_CLK_OUT, \
.fixed_rate = 216000000, \
.reg = 0x1a8, \
.u.periph = { \
.clk_num = (_index - 1) * 8 + 2, \
}, \
}; \
static struct clk tegra_##_name = { \
.name = #_name, \
.ops = &tegra_clk_out_ops, \
.hw = &tegra_##_name##_hw.hw, \
.parent_names = mux_clkm_clkm2_clkm4_extern##_index, \
.parents = mux_clkm_clkm2_clkm4_extern##_index##_p, \
.num_parents = ARRAY_SIZE(mux_clkm_clkm2_clkm4_extern##_index),\
};
CLK_OUT_CLK(clk_out_1, 1);
CLK_OUT_CLK(clk_out_2, 2);
CLK_OUT_CLK(clk_out_3, 3);
static struct clk *tegra_clk_out_list[] = {
&tegra_clk_out_1,
&tegra_clk_out_2,
&tegra_clk_out_3,
};
static const char *mux_sclk[] = {
"clk_m",
"pll_c_out1",
"pll_p_out4",
"pll_p_out3",
"pll_p_out2",
"dummy",
"clk_32k",
"pll_m_out1",
};
static struct clk *mux_sclk_p[] = {
&tegra_clk_m,
&tegra_pll_c_out1,
&tegra_pll_p_out4,
&tegra_pll_p_out3,
&tegra_pll_p_out2,
NULL,
&tegra_clk_32k,
&tegra_pll_m_out1,
};
static struct clk tegra_clk_sclk;
static struct clk_tegra tegra_clk_sclk_hw = {
.hw = {
.clk = &tegra_clk_sclk,
},
.reg = 0x28,
.max_rate = 334000000,
.min_rate = 40000000,
};
static struct clk tegra_clk_sclk = {
.name = "sclk",
.ops = &tegra30_super_ops,
.hw = &tegra_clk_sclk_hw.hw,
.parent_names = mux_sclk,
.parents = mux_sclk_p,
.num_parents = ARRAY_SIZE(mux_sclk),
};
static const char *mux_blink[] = {
"clk_32k",
};
static struct clk *mux_blink_p[] = {
&tegra_clk_32k,
};
static struct clk tegra_clk_blink;
static struct clk_tegra tegra_clk_blink_hw = {
.hw = {
.clk = &tegra_clk_blink,
},
.reg = 0x40,
.max_rate = 32768,
};
static struct clk tegra_clk_blink = {
.name = "blink",
.ops = &tegra30_blink_clk_ops,
.hw = &tegra_clk_blink_hw.hw,
.parent = &tegra_clk_32k,
.parent_names = mux_blink,
.parents = mux_blink_p,
.num_parents = ARRAY_SIZE(mux_blink),
};
static const char *mux_pllm_pllc_pllp_plla[] = {
"pll_m",
"pll_c",
"pll_p",
"pll_a_out0",
};
static const char *mux_pllp_pllc_pllm_clkm[] = {
"pll_p",
"pll_c",
"pll_m",
"clk_m",
};
static const char *mux_pllp_clkm[] = {
"pll_p",
"dummy",
"dummy",
"clk_m",
};
static const char *mux_pllp_plld_pllc_clkm[] = {
"pll_p",
"pll_d_out0",
"pll_c",
"clk_m",
};
static const char *mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = {
"pll_p",
"pll_m",
"pll_d_out0",
"pll_a_out0",
"pll_c",
"pll_d2_out0",
"clk_m",
};
static const char *mux_plla_pllc_pllp_clkm[] = {
"pll_a_out0",
"dummy",
"pll_p",
"clk_m"
};
static const char *mux_pllp_pllc_clk32_clkm[] = {
"pll_p",
"pll_c",
"clk_32k",
"clk_m",
};
static const char *mux_pllp_pllc_clkm_clk32[] = {
"pll_p",
"pll_c",
"clk_m",
"clk_32k",
};
static const char *mux_pllp_pllc_pllm[] = {
"pll_p",
"pll_c",
"pll_m",
};
static const char *mux_clk_m[] = {
"clk_m",
};
static const char *mux_pllp_out3[] = {
"pll_p_out3",
};
static const char *mux_plld_out0[] = {
"pll_d_out0",
};
static const char *mux_plld_out0_plld2_out0[] = {
"pll_d_out0",
"pll_d2_out0",
};
static const char *mux_clk_32k[] = {
"clk_32k",
};
static const char *mux_plla_clk32_pllp_clkm_plle[] = {
"pll_a_out0",
"clk_32k",
"pll_p",
"clk_m",
"pll_e",
};
static const char *mux_cclk_g[] = {
"clk_m",
"pll_c",
"clk_32k",
"pll_m",
"pll_p",
"pll_p_out4",
"pll_p_out3",
"dummy",
"pll_x",
};
static struct clk *mux_pllm_pllc_pllp_plla_p[] = {
&tegra_pll_m,
&tegra_pll_c,
&tegra_pll_p,
&tegra_pll_a_out0,
};
static struct clk *mux_pllp_pllc_pllm_clkm_p[] = {
&tegra_pll_p,
&tegra_pll_c,
&tegra_pll_m,
&tegra_clk_m,
};
static struct clk *mux_pllp_clkm_p[] = {
&tegra_pll_p,
NULL,
NULL,
&tegra_clk_m,
};
static struct clk *mux_pllp_plld_pllc_clkm_p[] = {
&tegra_pll_p,
&tegra_pll_d_out0,
&tegra_pll_c,
&tegra_clk_m,
};
static struct clk *mux_pllp_pllm_plld_plla_pllc_plld2_clkm_p[] = {
&tegra_pll_p,
&tegra_pll_m,
&tegra_pll_d_out0,
&tegra_pll_a_out0,
&tegra_pll_c,
&tegra_pll_d2_out0,
&tegra_clk_m,
};
static struct clk *mux_plla_pllc_pllp_clkm_p[] = {
&tegra_pll_a_out0,
NULL,
&tegra_pll_p,
&tegra_clk_m,
};
static struct clk *mux_pllp_pllc_clk32_clkm_p[] = {
&tegra_pll_p,
&tegra_pll_c,
&tegra_clk_32k,
&tegra_clk_m,
};
static struct clk *mux_pllp_pllc_clkm_clk32_p[] = {
&tegra_pll_p,
&tegra_pll_c,
&tegra_clk_m,
&tegra_clk_32k,
};
static struct clk *mux_pllp_pllc_pllm_p[] = {
&tegra_pll_p,
&tegra_pll_c,
&tegra_pll_m,
};
static struct clk *mux_clk_m_p[] = {
&tegra_clk_m,
};
static struct clk *mux_pllp_out3_p[] = {
&tegra_pll_p_out3,
};
static struct clk *mux_plld_out0_p[] = {
&tegra_pll_d_out0,
};
static struct clk *mux_plld_out0_plld2_out0_p[] = {
&tegra_pll_d_out0,
&tegra_pll_d2_out0,
};
static struct clk *mux_clk_32k_p[] = {
&tegra_clk_32k,
};
static struct clk *mux_plla_clk32_pllp_clkm_plle_p[] = {
&tegra_pll_a_out0,
&tegra_clk_32k,
&tegra_pll_p,
&tegra_clk_m,
&tegra_pll_e,
};
static struct clk *mux_cclk_g_p[] = {
&tegra_clk_m,
&tegra_pll_c,
&tegra_clk_32k,
&tegra_pll_m,
&tegra_pll_p,
&tegra_pll_p_out4,
&tegra_pll_p_out3,
NULL,
&tegra_pll_x,
};
static struct clk tegra_clk_cclk_g;
static struct clk_tegra tegra_clk_cclk_g_hw = {
.hw = {
.clk = &tegra_clk_cclk_g,
},
.flags = DIV_U71 | DIV_U71_INT,
.reg = 0x368,
.max_rate = 1700000000,
};
static struct clk tegra_clk_cclk_g = {
.name = "cclk_g",
.ops = &tegra30_super_ops,
.hw = &tegra_clk_cclk_g_hw.hw,
.parent_names = mux_cclk_g,
.parents = mux_cclk_g_p,
.num_parents = ARRAY_SIZE(mux_cclk_g),
};
static const char *mux_twd[] = {
"cclk_g",
};
static struct clk *mux_twd_p[] = {
&tegra_clk_cclk_g,
};
static struct clk tegra30_clk_twd;
static struct clk_tegra tegra30_clk_twd_hw = {
.hw = {
.clk = &tegra30_clk_twd,
},
.max_rate = 1400000000,
.mul = 1,
.div = 2,
};
static struct clk tegra30_clk_twd = {
.name = "twd",
.ops = &tegra30_twd_ops,
.hw = &tegra30_clk_twd_hw.hw,
.parent = &tegra_clk_cclk_g,
.parent_names = mux_twd,
.parents = mux_twd_p,
.num_parents = ARRAY_SIZE(mux_twd),
};
#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, \
_max, _inputs, _flags) \
static struct clk tegra_##_name; \
static struct clk_tegra tegra_##_name##_hw = { \
.hw = { \
.clk = &tegra_##_name, \
}, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
.reg = _reg, \
.flags = _flags, \
.max_rate = _max, \
.u.periph = { \
.clk_num = _clk_num, \
}, \
.reset = &tegra30_periph_clk_reset, \
}; \
static struct clk tegra_##_name = { \
.name = #_name, \
.ops = &tegra30_periph_clk_ops, \
.hw = &tegra_##_name##_hw.hw, \
.parent_names = _inputs, \
.parents = _inputs##_p, \
.num_parents = ARRAY_SIZE(_inputs), \
};
PERIPH_CLK(apbdma, "tegra-apbdma", NULL, 34, 0, 26000000, mux_clk_m, 0);
PERIPH_CLK(rtc, "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB);
PERIPH_CLK(kbc, "tegra-kbc", NULL, 36, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB);
PERIPH_CLK(timer, "timer", NULL, 5, 0, 26000000, mux_clk_m, 0);
PERIPH_CLK(kfuse, "kfuse-tegra", NULL, 40, 0, 26000000, mux_clk_m, 0);
PERIPH_CLK(fuse, "fuse-tegra", "fuse", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB);
PERIPH_CLK(fuse_burn, "fuse-tegra", "fuse_burn", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB);
PERIPH_CLK(apbif, "tegra30-ahub", "apbif", 107, 0, 26000000, mux_clk_m, 0);
PERIPH_CLK(i2s0, "tegra30-i2s.0", NULL, 30, 0x1d8, 26000000, mux_pllaout0_audio0_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(i2s1, "tegra30-i2s.1", NULL, 11, 0x100, 26000000, mux_pllaout0_audio1_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(i2s2, "tegra30-i2s.2", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(i2s3, "tegra30-i2s.3", NULL, 101, 0x3bc, 26000000, mux_pllaout0_audio3_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(i2s4, "tegra30-i2s.4", NULL, 102, 0x3c0, 26000000, mux_pllaout0_audio4_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(spdif_out, "tegra30-spdif", "spdif_out", 10, 0x108, 100000000, mux_pllaout0_audio5_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(spdif_in, "tegra30-spdif", "spdif_in", 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(pwm, "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_clk32_clkm, MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(d_audio, "tegra30-ahub", "d_audio", 106, 0x3d0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71);
PERIPH_CLK(dam0, "tegra30-dam.0", NULL, 108, 0x3d8, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71);
PERIPH_CLK(dam1, "tegra30-dam.1", NULL, 109, 0x3dc, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71);
PERIPH_CLK(dam2, "tegra30-dam.2", NULL, 110, 0x3e0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71);
PERIPH_CLK(hda, "tegra30-hda", "hda", 125, 0x428, 108000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(hda2codec_2x, "tegra30-hda", "hda2codec", 111, 0x3e4, 48000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(hda2hdmi, "tegra30-hda", "hda2hdmi", 128, 0, 48000000, mux_clk_m, 0);
PERIPH_CLK(sbc1, "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(sbc2, "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(sbc3, "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(sbc4, "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(sbc5, "spi_tegra.4", NULL, 104, 0x3c8, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(sbc6, "spi_tegra.5", NULL, 105, 0x3cc, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(sata_oob, "tegra_sata_oob", NULL, 123, 0x420, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(sata, "tegra_sata", NULL, 124, 0x424, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(sata_cold, "tegra_sata_cold", NULL, 129, 0, 48000000, mux_clk_m, 0);
PERIPH_CLK(ndflash, "tegra_nand", NULL, 13, 0x160, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(ndspeed, "tegra_nand_speed", NULL, 80, 0x3f8, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(vfir, "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(sdmmc1, "sdhci-tegra.0", NULL, 14, 0x150, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
PERIPH_CLK(sdmmc2, "sdhci-tegra.1", NULL, 9, 0x154, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
PERIPH_CLK(sdmmc3, "sdhci-tegra.2", NULL, 69, 0x1bc, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
PERIPH_CLK(sdmmc4, "sdhci-tegra.3", NULL, 15, 0x164, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
PERIPH_CLK(vcp, "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0);
PERIPH_CLK(bsea, "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0);
PERIPH_CLK(bsev, "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0);
PERIPH_CLK(vde, "vde", NULL, 61, 0x1c8, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT);
PERIPH_CLK(csite, "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* max rate ??? */
PERIPH_CLK(la, "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
PERIPH_CLK(owr, "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(nor, "nor", NULL, 42, 0x1d0, 127000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */
PERIPH_CLK(mipi, "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); /* scales with voltage */
PERIPH_CLK(i2c1, "tegra-i2c.0", NULL, 12, 0x124, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB);
PERIPH_CLK(i2c2, "tegra-i2c.1", NULL, 54, 0x198, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB);
PERIPH_CLK(i2c3, "tegra-i2c.2", NULL, 67, 0x1b8, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB);
PERIPH_CLK(i2c4, "tegra-i2c.3", NULL, 103, 0x3c4, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB);
PERIPH_CLK(i2c5, "tegra-i2c.4", NULL, 47, 0x128, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB);
PERIPH_CLK(uarta, "tegra-uart.0", NULL, 6, 0x178, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
PERIPH_CLK(uartb, "tegra-uart.1", NULL, 7, 0x17c, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
PERIPH_CLK(uartc, "tegra-uart.2", NULL, 55, 0x1a0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
PERIPH_CLK(uartd, "tegra-uart.3", NULL, 65, 0x1c0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
PERIPH_CLK(uarte, "tegra-uart.4", NULL, 66, 0x1c4, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
PERIPH_CLK(vi, "tegra_camera", "vi", 20, 0x148, 425000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT);
PERIPH_CLK(3d, "3d", NULL, 24, 0x158, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET);
PERIPH_CLK(3d2, "3d2", NULL, 98, 0x3b0, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET);
PERIPH_CLK(2d, "2d", NULL, 21, 0x15c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE);
PERIPH_CLK(vi_sensor, "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET);
PERIPH_CLK(epp, "epp", NULL, 19, 0x16c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT);
PERIPH_CLK(mpe, "mpe", NULL, 60, 0x170, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT);
PERIPH_CLK(host1x, "host1x", NULL, 28, 0x180, 260000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT);
PERIPH_CLK(cve, "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
PERIPH_CLK(tvo, "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
PERIPH_CLK(dtv, "dtv", NULL, 79, 0x1dc, 250000000, mux_clk_m, 0);
PERIPH_CLK(hdmi, "hdmi", NULL, 51, 0x18c, 148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8 | DIV_U71);
PERIPH_CLK(tvdac, "tvdac", NULL, 53, 0x194, 220000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
PERIPH_CLK(disp1, "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8);
PERIPH_CLK(disp2, "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8);
PERIPH_CLK(usbd, "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
PERIPH_CLK(usb2, "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
PERIPH_CLK(usb3, "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
PERIPH_CLK(dsia, "tegradc.0", "dsia", 48, 0, 500000000, mux_plld_out0, 0);
PERIPH_CLK(csi, "tegra_camera", "csi", 52, 0, 102000000, mux_pllp_out3, 0);
PERIPH_CLK(isp, "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0); /* same frequency as VI */
PERIPH_CLK(csus, "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET);
PERIPH_CLK(tsensor, "tegra-tsensor", NULL, 100, 0x3b8, 216000000, mux_pllp_pllc_clkm_clk32, MUX | DIV_U71);
PERIPH_CLK(actmon, "actmon", NULL, 119, 0x3e8, 216000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71);
PERIPH_CLK(extern1, "extern1", NULL, 120, 0x3ec, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71);
PERIPH_CLK(extern2, "extern2", NULL, 121, 0x3f0, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71);
PERIPH_CLK(extern3, "extern3", NULL, 122, 0x3f4, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71);
PERIPH_CLK(i2cslow, "i2cslow", NULL, 81, 0x3fc, 26000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
PERIPH_CLK(pcie, "tegra-pcie", "pcie", 70, 0, 250000000, mux_clk_m, 0);
PERIPH_CLK(afi, "tegra-pcie", "afi", 72, 0, 250000000, mux_clk_m, 0);
PERIPH_CLK(se, "se", NULL, 127, 0x42c, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT);
static struct clk tegra_dsib;
static struct clk_tegra tegra_dsib_hw = {
.hw = {
.clk = &tegra_dsib,
},
.lookup = {
.dev_id = "tegradc.1",
.con_id = "dsib",
},
.reg = 0xd0,
.flags = MUX | PLLD,
.max_rate = 500000000,
.u.periph = {
.clk_num = 82,
},
.reset = &tegra30_periph_clk_reset,
};
static struct clk tegra_dsib = {
.name = "dsib",
.ops = &tegra30_dsib_clk_ops,
.hw = &tegra_dsib_hw.hw,
.parent_names = mux_plld_out0_plld2_out0,
.parents = mux_plld_out0_plld2_out0_p,
.num_parents = ARRAY_SIZE(mux_plld_out0_plld2_out0),
};
struct clk *tegra_list_clks[] = {
&tegra_apbdma,
&tegra_rtc,
&tegra_kbc,
&tegra_kfuse,
&tegra_fuse,
&tegra_fuse_burn,
&tegra_apbif,
&tegra_i2s0,
&tegra_i2s1,
&tegra_i2s2,
&tegra_i2s3,
&tegra_i2s4,
&tegra_spdif_out,
&tegra_spdif_in,
&tegra_pwm,
&tegra_d_audio,
&tegra_dam0,
&tegra_dam1,
&tegra_dam2,
&tegra_hda,
&tegra_hda2codec_2x,
&tegra_hda2hdmi,
&tegra_sbc1,
&tegra_sbc2,
&tegra_sbc3,
&tegra_sbc4,
&tegra_sbc5,
&tegra_sbc6,
&tegra_sata_oob,
&tegra_sata,
&tegra_sata_cold,
&tegra_ndflash,
&tegra_ndspeed,
&tegra_vfir,
&tegra_sdmmc1,
&tegra_sdmmc2,
&tegra_sdmmc3,
&tegra_sdmmc4,
&tegra_vcp,
&tegra_bsea,
&tegra_bsev,
&tegra_vde,
&tegra_csite,
&tegra_la,
&tegra_owr,
&tegra_nor,
&tegra_mipi,
&tegra_i2c1,
&tegra_i2c2,
&tegra_i2c3,
&tegra_i2c4,
&tegra_i2c5,
&tegra_uarta,
&tegra_uartb,
&tegra_uartc,
&tegra_uartd,
&tegra_uarte,
&tegra_vi,
&tegra_3d,
&tegra_3d2,
&tegra_2d,
&tegra_vi_sensor,
&tegra_epp,
&tegra_mpe,
&tegra_host1x,
&tegra_cve,
&tegra_tvo,
&tegra_dtv,
&tegra_hdmi,
&tegra_tvdac,
&tegra_disp1,
&tegra_disp2,
&tegra_usbd,
&tegra_usb2,
&tegra_usb3,
&tegra_dsia,
&tegra_dsib,
&tegra_csi,
&tegra_isp,
&tegra_csus,
&tegra_tsensor,
&tegra_actmon,
&tegra_extern1,
&tegra_extern2,
&tegra_extern3,
&tegra_i2cslow,
&tegra_pcie,
&tegra_afi,
&tegra_se,
};
#define CLK_DUPLICATE(_name, _dev, _con) \
{ \
.name = _name, \
.lookup = { \
.dev_id = _dev, \
.con_id = _con, \
}, \
}
/* Some clocks may be used by different drivers depending on the board
* configuration. List those here to register them twice in the clock lookup
* table under two names.
*/
struct clk_duplicate tegra_clk_duplicates[] = {
CLK_DUPLICATE("uarta", "serial8250.0", NULL),
CLK_DUPLICATE("uartb", "serial8250.1", NULL),
CLK_DUPLICATE("uartc", "serial8250.2", NULL),
CLK_DUPLICATE("uartd", "serial8250.3", NULL),
CLK_DUPLICATE("uarte", "serial8250.4", NULL),
CLK_DUPLICATE("usbd", "utmip-pad", NULL),
CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
CLK_DUPLICATE("usbd", "tegra-otg", NULL),
CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
CLK_DUPLICATE("dsib", "tegradc.0", "dsib"),
CLK_DUPLICATE("dsia", "tegradc.1", "dsia"),
CLK_DUPLICATE("bsev", "tegra-avp", "bsev"),
CLK_DUPLICATE("bsev", "nvavp", "bsev"),
CLK_DUPLICATE("vde", "tegra-aes", "vde"),
CLK_DUPLICATE("bsea", "tegra-aes", "bsea"),
CLK_DUPLICATE("bsea", "nvavp", "bsea"),
CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL),
CLK_DUPLICATE("cml0", "tegra_pcie", "cml"),
CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"),
CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL),
CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL),
CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL),
CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL),
CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL),
CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL),
CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL),
CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL),
CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL),
CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL),
CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL),
CLK_DUPLICATE("twd", "smp_twd", NULL),
CLK_DUPLICATE("vcp", "nvavp", "vcp"),
CLK_DUPLICATE("i2s0", NULL, "i2s0"),
CLK_DUPLICATE("i2s1", NULL, "i2s1"),
CLK_DUPLICATE("i2s2", NULL, "i2s2"),
CLK_DUPLICATE("i2s3", NULL, "i2s3"),
CLK_DUPLICATE("i2s4", NULL, "i2s4"),
CLK_DUPLICATE("dam0", NULL, "dam0"),
CLK_DUPLICATE("dam1", NULL, "dam1"),
CLK_DUPLICATE("dam2", NULL, "dam2"),
CLK_DUPLICATE("spdif_in", NULL, "spdif_in"),
};
struct clk *tegra_ptr_clks[] = {
&tegra_clk_32k,
&tegra_clk_m,
&tegra_clk_m_div2,
&tegra_clk_m_div4,
&tegra_pll_ref,
&tegra_pll_m,
&tegra_pll_m_out1,
&tegra_pll_c,
&tegra_pll_c_out1,
&tegra_pll_p,
&tegra_pll_p_out1,
&tegra_pll_p_out2,
&tegra_pll_p_out3,
&tegra_pll_p_out4,
&tegra_pll_a,
&tegra_pll_a_out0,
&tegra_pll_d,
&tegra_pll_d_out0,
&tegra_pll_d2,
&tegra_pll_d2_out0,
&tegra_pll_u,
&tegra_pll_x,
&tegra_pll_x_out0,
&tegra_pll_e,
&tegra_clk_cclk_g,
&tegra_cml0,
&tegra_cml1,
&tegra_pciex,
&tegra_clk_sclk,
&tegra_clk_blink,
&tegra30_clk_twd,
};
static void tegra30_init_one_clock(struct clk *c)
{
struct clk_tegra *clk = to_clk_tegra(c->hw);
__clk_init(NULL, c);
INIT_LIST_HEAD(&clk->shared_bus_list);
if (!clk->lookup.dev_id && !clk->lookup.con_id)
clk->lookup.con_id = c->name;
clk->lookup.clk = c;
clkdev_add(&clk->lookup);
tegra_clk_add(c);
}
void __init tegra30_init_clocks(void)
{
int i;
struct clk *c;
for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
tegra30_init_one_clock(tegra_ptr_clks[i]);
for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
tegra30_init_one_clock(tegra_list_clks[i]);
for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
if (!c) {
pr_err("%s: Unknown duplicate clock %s\n", __func__,
tegra_clk_duplicates[i].name);
continue;
}
tegra_clk_duplicates[i].lookup.clk = c;
clkdev_add(&tegra_clk_duplicates[i].lookup);
}
for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++)
tegra30_init_one_clock(tegra_sync_source_list[i]);
for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++)
tegra30_init_one_clock(tegra_clk_audio_list[i]);
for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++)
tegra30_init_one_clock(tegra_clk_audio_2x_list[i]);
for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++)
tegra30_init_one_clock(tegra_clk_out_list[i]);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment