aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-27 16:14:44 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-27 16:14:44 -0700
commit281b05392fc2cb26209b4d85abaf4889ab1991f3 (patch)
treebbf5000ce7bd739b1ca85e9918741e285d267c7c /arch/arm/mach-tegra
parent48d554418d3bfbba5e9dc1ebdf352f1b1f3ff4ee (diff)
parentbde755679a3ba5af0d16231f8532e8373c5e2ecc (diff)
Merge tag 'soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull "ARM: SoC specific updates" from Arnd Bergmann: "These changes are all specific to an soc family or the code for one soc. Lots of work for Tegra3 this time, but also a lot of other platforms. There will be another (smaller) set of soc patches later in the merge window for stuff that has dependencies on external trees or that was sent just before the merge window opened. The asoc tree added a few devices to the i.mx platform, which conflict with other devices added in the same place here. The tegra Makefile conflicts between a number of branches, mostly because of changes regarding localtimer.c, which was removed in the end. Signed-off-by: Arnd Bergmann <arnd@arndb.de>" Fix up some trivial conflicts, including the mentioned Tegra Makefile. * tag 'soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (51 commits) ARM: EXYNOS: fix cycle count for periodic mode of clock event timers ARM: EXYNOS: add support JPEG ARM: EXYNOS: Add DMC1, allow PPMU access for DMC ARM: SAMSUNG: Correct MIPI-CSIS io memory resource definition ARM: SAMSUNG: fix __init attribute on regarding s3c_set_platdata() ARM: SAMSUNG: Add __init attribute to samsung_bl_set() ARM: S5PV210: Add usb otg phy control ARM: S3C64XX: Add usb otg phy control ARM: EXYNOS: Enable l2 configuration through device tree ARM: EXYNOS: remove useless code to save/restore L2 ARM: EXYNOS: save L2 settings during bootup ARM: S5P: add L2 early resume code ARM: EXYNOS: Add support AFTR mode on EXYNOS4210 ARM: mx35: Setup the AIPS registers ARM: mx5: Use common function for configuring AIPS ARM: mx3: Setup AIPS registers ARM: mx3: Let mx31 and mx35 enter in LPM mode in WFI ARM: defconfig: imx_v6_v7: build in REGULATOR_FIXED_VOLTAGE ARM: imx: update imx_v6_v7_defconfig ARM: tegra: Demote EMC clock inconsistency BUG to WARN ...
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/Makefile3
-rw-r--r--arch/arm/mach-tegra/board-dt-tegra30.c24
-rw-r--r--arch/arm/mach-tegra/clock.c22
-rw-r--r--arch/arm/mach-tegra/clock.h15
-rw-r--r--arch/arm/mach-tegra/common.c1
-rw-r--r--arch/arm/mach-tegra/cpuidle.c107
-rw-r--r--arch/arm/mach-tegra/flowctrl.h37
-rw-r--r--arch/arm/mach-tegra/include/mach/clk.h10
-rw-r--r--arch/arm/mach-tegra/include/mach/iomap.h3
-rw-r--r--arch/arm/mach-tegra/include/mach/irqs.h7
-rw-r--r--arch/arm/mach-tegra/irq.c20
-rw-r--r--arch/arm/mach-tegra/sleep.S91
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c30
-rw-r--r--arch/arm/mach-tegra/tegra30_clocks.c3099
14 files changed, 3456 insertions, 13 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index bcbb4e8d553..76a79b8a172 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -7,12 +7,15 @@ obj-y += clock.o
obj-y += timer.o
obj-y += pinmux.o
obj-y += fuse.o
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+obj-$(CONFIG_CPU_IDLE) += sleep.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += powergate.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pinmux-tegra20-tables.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pinmux-tegra30-tables.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o
diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c
index 3c197e2440b..b4124b12a77 100644
--- a/arch/arm/mach-tegra/board-dt-tegra30.c
+++ b/arch/arm/mach-tegra/board-dt-tegra30.c
@@ -34,16 +34,38 @@
#include <asm/hardware/gic.h>
#include "board.h"
+#include "clock.h"
static struct of_device_id tegra_dt_match_table[] __initdata = {
{ .compatible = "simple-bus", },
{}
};
+struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000000, "sdhci-tegra.0", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000200, "sdhci-tegra.1", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000400, "sdhci-tegra.2", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000600, "sdhci-tegra.3", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C000, "tegra-i2c.0", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C400, "tegra-i2c.1", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C500, "tegra-i2c.2", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C700, "tegra-i2c.3", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL),
+ {}
+};
+
+static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
+ /* name parent rate enabled */
+ { "uartd", "pll_p", 408000000, true },
+ { NULL, NULL, 0, 0},
+};
+
static void __init tegra30_dt_init(void)
{
+ tegra_clk_init_from_table(tegra_dt_clk_init_table);
+
of_platform_populate(NULL, tegra_dt_match_table,
- NULL, NULL);
+ tegra30_auxdata_lookup, NULL);
}
static const char *tegra30_dt_board_compat[] = {
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 8337068a4ab..8dad8d18cb4 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -399,6 +399,28 @@ void tegra_periph_reset_assert(struct clk *c)
}
EXPORT_SYMBOL(tegra_periph_reset_assert);
+/* Several extended clock configuration bits (e.g., clock routing, clock
+ * phase control) are included in PLL and peripheral clock source
+ * registers. */
+int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->spinlock, flags);
+
+ if (!c->ops || !c->ops->clk_cfg_ex) {
+ ret = -ENOSYS;
+ goto out;
+ }
+ ret = c->ops->clk_cfg_ex(c, p, setting);
+
+out:
+ spin_unlock_irqrestore(&c->spinlock, flags);
+
+ return ret;
+}
+
#ifdef CONFIG_DEBUG_FS
static int __clk_lock_all_spinlocks(void)
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index 5c44106616c..bc300657deb 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -24,6 +24,8 @@
#include <linux/list.h>
#include <linux/spinlock.h>
+#include <mach/clk.h>
+
#define DIV_BUS (1 << 0)
#define DIV_U71 (1 << 1)
#define DIV_U71_FIXED (1 << 2)
@@ -39,7 +41,16 @@
#define PERIPH_MANUAL_RESET (1 << 12)
#define PLL_ALT_MISC_REG (1 << 13)
#define PLLU (1 << 14)
+#define PLLX (1 << 15)
+#define MUX_PWM (1 << 16)
+#define MUX8 (1 << 17)
+#define DIV_U71_UART (1 << 18)
+#define MUX_CLK_OUT (1 << 19)
+#define PLLM (1 << 20)
+#define DIV_U71_INT (1 << 21)
+#define DIV_U71_IDLE (1 << 22)
#define ENABLE_ON_INIT (1 << 28)
+#define PERIPH_ON_APB (1 << 29)
struct clk;
@@ -65,6 +76,8 @@ struct clk_ops {
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 {
@@ -114,6 +127,7 @@ struct clk {
unsigned long vco_max;
const struct clk_pll_freq_table *freq_table;
int lock_delay;
+ unsigned long fixed_rate;
} pll;
struct {
u32 sel;
@@ -146,6 +160,7 @@ struct tegra_clk_init_table {
};
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);
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index fac449e84d8..6c93cd0e520 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -104,6 +104,7 @@ void __init tegra20_init_early(void)
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
void __init tegra30_init_early(void)
{
+ tegra30_init_clocks();
tegra_init_cache(0x441, 0x551);
}
#endif
diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c
new file mode 100644
index 00000000000..d83a8c0296f
--- /dev/null
+++ b/arch/arm/mach-tegra/cpuidle.c
@@ -0,0 +1,107 @@
+/*
+ * arch/arm/mach-tegra/cpuidle.c
+ *
+ * CPU idle driver for Tegra CPUs
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation.
+ * Copyright (c) 2011 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ * Gary King <gking@nvidia.com>
+ *
+ * Rework for 3.3 by Peter De Schrijver <pdeschrijver@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/cpuidle.h>
+#include <linux/hrtimer.h>
+
+#include <mach/iomap.h>
+
+extern void tegra_cpu_wfi(void);
+
+static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index);
+
+struct cpuidle_driver tegra_idle_driver = {
+ .name = "tegra_idle",
+ .owner = THIS_MODULE,
+ .state_count = 1,
+ .states = {
+ [0] = {
+ .enter = tegra_idle_enter_lp3,
+ .exit_latency = 10,
+ .target_residency = 10,
+ .power_usage = 600,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "LP3",
+ .desc = "CPU flow-controlled",
+ },
+ },
+};
+
+static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
+
+static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ ktime_t enter, exit;
+ s64 us;
+
+ local_irq_disable();
+ local_fiq_disable();
+
+ enter = ktime_get();
+
+ tegra_cpu_wfi();
+
+ exit = ktime_sub(ktime_get(), enter);
+ us = ktime_to_us(exit);
+
+ local_fiq_enable();
+ local_irq_enable();
+
+ dev->last_residency = us;
+
+ return index;
+}
+
+static int __init tegra_cpuidle_init(void)
+{
+ int ret;
+ unsigned int cpu;
+ struct cpuidle_device *dev;
+ struct cpuidle_driver *drv = &tegra_idle_driver;
+
+ ret = cpuidle_register_driver(&tegra_idle_driver);
+ if (ret) {
+ pr_err("CPUidle driver registration failed\n");
+ return ret;
+ }
+
+ for_each_possible_cpu(cpu) {
+ dev = &per_cpu(tegra_idle_device, cpu);
+ dev->cpu = cpu;
+
+ dev->state_count = drv->state_count;
+ ret = cpuidle_register_device(dev);
+ if (ret) {
+ pr_err("CPU%u: CPUidle device registration failed\n",
+ cpu);
+ return ret;
+ }
+ }
+ return 0;
+}
+device_initcall(tegra_cpuidle_init);
diff --git a/arch/arm/mach-tegra/flowctrl.h b/arch/arm/mach-tegra/flowctrl.h
new file mode 100644
index 00000000000..74c6efbe52f
--- /dev/null
+++ b/arch/arm/mach-tegra/flowctrl.h
@@ -0,0 +1,37 @@
+/*
+ * arch/arm/mach-tegra/flowctrl.h
+ *
+ * functions and macros to control the flowcontroller
+ *
+ * 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 and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA_FLOWCTRL_H
+#define __MACH_TEGRA_FLOWCTRL_H
+
+#define FLOW_CTRL_HALT_CPU0_EVENTS 0x0
+#define FLOW_CTRL_WAITEVENT (2 << 29)
+#define FLOW_CTRL_WAIT_FOR_INTERRUPT (4 << 29)
+#define FLOW_CTRL_JTAG_RESUME (1 << 28)
+#define FLOW_CTRL_HALT_CPU_IRQ (1 << 10)
+#define FLOW_CTRL_HALT_CPU_FIQ (1 << 8)
+#define FLOW_CTRL_CPU0_CSR 0x8
+#define FLOW_CTRL_CSR_INTR_FLAG (1 << 15)
+#define FLOW_CTRL_CSR_EVENT_FLAG (1 << 14)
+#define FLOW_CTRL_CSR_ENABLE (1 << 0)
+#define FLOW_CTRL_HALT_CPU1_EVENTS 0x14
+#define FLOW_CTRL_CPU1_CSR 0x18
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h
index fc3ecb66de0..d97e403303a 100644
--- a/arch/arm/mach-tegra/include/mach/clk.h
+++ b/arch/arm/mach-tegra/include/mach/clk.h
@@ -22,10 +22,20 @@
struct clk;
+enum tegra_clk_ex_param {
+ TEGRA_CLK_VI_INP_SEL,
+ TEGRA_CLK_DTV_INVERT,
+ TEGRA_CLK_NAND_PAD_DIV2_ENB,
+ TEGRA_CLK_PLLD_CSI_OUT_ENB,
+ TEGRA_CLK_PLLD_DSI_OUT_ENB,
+ TEGRA_CLK_PLLD_MIPI_MUX_SEL,
+};
+
void tegra_periph_reset_deassert(struct clk *c);
void tegra_periph_reset_assert(struct clk *c);
unsigned long clk_get_rate_all_locked(struct clk *c);
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);
#endif
diff --git a/arch/arm/mach-tegra/include/mach/iomap.h b/arch/arm/mach-tegra/include/mach/iomap.h
index 19dec3ac085..67644c905d8 100644
--- a/arch/arm/mach-tegra/include/mach/iomap.h
+++ b/arch/arm/mach-tegra/include/mach/iomap.h
@@ -74,6 +74,9 @@
#define TEGRA_QUATERNARY_ICTLR_BASE 0x60004300
#define TEGRA_QUATERNARY_ICTLR_SIZE SZ_64
+#define TEGRA_QUINARY_ICTLR_BASE 0x60004400
+#define TEGRA_QUINARY_ICTLR_SIZE SZ_64
+
#define TEGRA_TMR1_BASE 0x60005000
#define TEGRA_TMR1_SIZE SZ_8
diff --git a/arch/arm/mach-tegra/include/mach/irqs.h b/arch/arm/mach-tegra/include/mach/irqs.h
index a2146cd6867..aad1a2c1d71 100644
--- a/arch/arm/mach-tegra/include/mach/irqs.h
+++ b/arch/arm/mach-tegra/include/mach/irqs.h
@@ -165,11 +165,12 @@
#define INT_QUAD_RES_30 (INT_QUAD_BASE + 30)
#define INT_QUAD_RES_31 (INT_QUAD_BASE + 31)
-#define INT_MAIN_NR (INT_QUAD_BASE + 32 - INT_PRI_BASE)
-
+/* Tegra30 has 5 banks of 32 IRQs */
+#define INT_MAIN_NR (32 * 5)
#define INT_GPIO_BASE (INT_PRI_BASE + INT_MAIN_NR)
-#define INT_GPIO_NR (28 * 8)
+/* Tegra30 has 8 banks of 32 GPIOs */
+#define INT_GPIO_NR (32 * 8)
#define TEGRA_NR_IRQS (INT_GPIO_BASE + INT_GPIO_NR)
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index 4e1afcd54fa..2f5bd2db8e1 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -44,14 +44,16 @@
#define ICTLR_COP_IER_CLR 0x38
#define ICTLR_COP_IEP_CLASS 0x3c
-#define NUM_ICTLRS 4
#define FIRST_LEGACY_IRQ 32
+static int num_ictlrs;
+
static void __iomem *ictlr_reg_base[] = {
IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE),
IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE),
IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE),
IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE),
+ IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE),
};
static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
@@ -60,7 +62,7 @@ static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
u32 mask;
BUG_ON(irq < FIRST_LEGACY_IRQ ||
- irq >= FIRST_LEGACY_IRQ + NUM_ICTLRS * 32);
+ irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32);
base = ictlr_reg_base[(irq - FIRST_LEGACY_IRQ) / 32];
mask = BIT((irq - FIRST_LEGACY_IRQ) % 32);
@@ -113,8 +115,18 @@ static int tegra_retrigger(struct irq_data *d)
void __init tegra_init_irq(void)
{
int i;
+ void __iomem *distbase;
+
+ distbase = IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE);
+ num_ictlrs = readl_relaxed(distbase + GIC_DIST_CTR) & 0x1f;
+
+ if (num_ictlrs > ARRAY_SIZE(ictlr_reg_base)) {
+ WARN(1, "Too many (%d) interrupt controllers found. Maximum is %d.",
+ num_ictlrs, ARRAY_SIZE(ictlr_reg_base));
+ num_ictlrs = ARRAY_SIZE(ictlr_reg_base);
+ }
- for (i = 0; i < NUM_ICTLRS; i++) {
+ for (i = 0; i < num_ictlrs; i++) {
void __iomem *ictlr = ictlr_reg_base[i];
writel(~0, ictlr + ICTLR_CPU_IER_CLR);
writel(0, ictlr + ICTLR_CPU_IEP_CLASS);
@@ -131,6 +143,6 @@ void __init tegra_init_irq(void)
* initialized elsewhere under DT.
*/
if (!of_have_populated_dt())
- gic_init(0, 29, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE),
+ gic_init(0, 29, distbase,
IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
}
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
new file mode 100644
index 00000000000..8f9fde161c3
--- /dev/null
+++ b/arch/arm/mach-tegra/sleep.S
@@ -0,0 +1,91 @@
+/*
+ * arch/arm/mach-tegra/sleep.S
+ *
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
+ * Copyright (c) 2011, Google, Inc.
+ *
+ * Author: Colin Cross <ccross@android.com>
+ * Gary King <gking@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * 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/linkage.h>
+#include <mach/io.h>
+#include <mach/iomap.h>
+
+#include "flowctrl.h"
+
+#define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \
+ + IO_PPSB_VIRT)
+
+/* returns the offset of the flow controller halt register for a cpu */
+.macro cpu_to_halt_reg rd, rcpu
+ cmp \rcpu, #0
+ subne \rd, \rcpu, #1
+ movne \rd, \rd, lsl #3
+ addne \rd, \rd, #0x14
+ moveq \rd, #0
+.endm
+
+/* returns the offset of the flow controller csr register for a cpu */
+.macro cpu_to_csr_reg rd, rcpu
+ cmp \rcpu, #0
+ subne \rd, \rcpu, #1
+ movne \rd, \rd, lsl #3
+ addne \rd, \rd, #0x18
+ moveq \rd, #8
+.endm
+
+/* returns the ID of the current processor */
+.macro cpu_id, rd
+ mrc p15, 0, \rd, c0, c0, 5
+ and \rd, \rd, #0xF
+.endm
+
+/* loads a 32-bit value into a register without a data access */
+.macro mov32, reg, val
+ movw \reg, #:lower16:\val
+ movt \reg, #:upper16:\val
+.endm
+
+/*
+ * tegra_cpu_wfi
+ *
+ * puts current CPU in clock-gated wfi using the flow controller
+ *
+ * corrupts r0-r3
+ * must be called with MMU on
+ */
+
+ENTRY(tegra_cpu_wfi)
+ cpu_id r0
+ cpu_to_halt_reg r1, r0
+ cpu_to_csr_reg r2, r0
+ mov32 r0, TEGRA_FLOW_CTRL_VIRT
+ mov r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
+ str r3, [r0, r2] @ clear event & interrupt status
+ mov r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT | FLOW_CTRL_JTAG_RESUME
+ str r3, [r0, r1] @ put flow controller in wait irq mode
+ dsb
+ wfi
+ mov r3, #0
+ str r3, [r0, r1] @ clear flow controller halt status
+ mov r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
+ str r3, [r0, r2] @ clear event & interrupt status
+ dsb
+ mov pc, lr
+ENDPROC(tegra_cpu_wfi)
+
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index ff9e6b6c046..1976e934cdd 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -1143,15 +1143,35 @@ static void tegra2_emc_clk_init(struct clk *c)
static long tegra2_emc_clk_round_rate(struct clk *c, unsigned long rate)
{
- long new_rate = rate;
+ long emc_rate;
+ long clk_rate;
- new_rate = tegra_emc_round_rate(new_rate);
- if (new_rate < 0)
+ /*
+ * The slowest entry in the EMC clock table that is at least as
+ * fast as rate.
+ */
+ emc_rate = tegra_emc_round_rate(rate);
+ if (emc_rate < 0)
return c->max_rate;
- BUG_ON(new_rate != tegra2_periph_clk_round_rate(c, new_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);
+
+ /*
+ * If this fails, and emc_rate > clk_rate, it's because the maximum
+ * rate in the EMC tables is larger than the maximum rate of the EMC
+ * clock. The EMC clock's max rate is the rate it was running when the
+ * kernel booted. Such a mismatch is probably due to using the wrong
+ * BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25.
+ */
+ WARN_ONCE(emc_rate != clk_rate,
+ "emc_rate %ld != clk_rate %ld",
+ emc_rate, clk_rate);
- return new_rate;
+ return emc_rate;
}
static int tegra2_emc_clk_set_rate(struct clk *c, unsigned long rate)
diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c
new file mode 100644
index 00000000000..6d08b53f92d
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30_clocks.c
@@ -0,0 +1,3099 @@
+/*
+ * arch/arm/mach-tegra/tegra30_clocks.c
+ *
+ * Copyright (c) 2010-2011 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/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 <linux/syscore_ops.h>
+
+#include <asm/clkdev.h>
+
+#include <mach/iomap.h>
+
+#include "clock.h"
+#include "fuse.h"
+
+#define USE_PLL_LOCK_BITS 0
+
+#define RST_DEVICES_L 0x004
+#define RST_DEVICES_H 0x008
+#define RST_DEVICES_U 0x00C
+#define RST_DEVICES_V 0x358
+#define RST_DEVICES_W 0x35C
+#define RST_DEVICES_SET_L 0x300
+#define RST_DEVICES_CLR_L 0x304
+#define RST_DEVICES_SET_V 0x430
+#define RST_DEVICES_CLR_V 0x434
+#define RST_DEVICES_NUM 5
+
+#define CLK_OUT_ENB_L 0x010
+#define CLK_OUT_ENB_H 0x014
+#define CLK_OUT_ENB_U 0x018
+#define CLK_OUT_ENB_V 0x360
+#define CLK_OUT_ENB_W 0x364
+#define CLK_OUT_ENB_SET_L 0x320
+#define CLK_OUT_ENB_CLR_L 0x324
+#define CLK_OUT_ENB_SET_V 0x440
+#define CLK_OUT_ENB_CLR_V 0x444
+#define CLK_OUT_ENB_NUM 5
+
+#define RST_DEVICES_V_SWR_CPULP_RST_DIS (0x1 << 1)
+#define CLK_OUT_ENB_V_CLK_ENB_CPULP_EN (0x1 << 1)
+
+#define PERIPH_CLK_TO_BIT(c) (1 << (c->u.periph.clk_num % 32))
+#define PERIPH_CLK_TO_RST_REG(c) \
+ periph_clk_to_reg((c), RST_DEVICES_L, RST_DEVICES_V, 4)
+#define PERIPH_CLK_TO_RST_SET_REG(c) \
+ periph_clk_to_reg((c), RST_DEVICES_SET_L, RST_DEVICES_SET_V, 8)
+#define PERIPH_CLK_TO_RST_CLR_REG(c) \
+ periph_clk_to_reg((c), RST_DEVICES_CLR_L, RST_DEVICES_CLR_V, 8)
+
+#define PERIPH_CLK_TO_ENB_REG(c) \
+ periph_clk_to_reg((c), CLK_OUT_ENB_L, CLK_OUT_ENB_V, 4)
+#define PERIPH_CLK_TO_ENB_SET_REG(c) \
+ periph_clk_to_reg((c), CLK_OUT_ENB_SET_L, CLK_OUT_ENB_SET_V, 8)
+#define PERIPH_CLK_TO_ENB_CLR_REG(c) \
+ periph_clk_to_reg((c), CLK_OUT_ENB_CLR_L, CLK_OUT_ENB_CLR_V, 8)
+
+#define CLK_MASK_ARM 0x44
+#define MISC_CLK_ENB 0x48
+
+#define OSC_CTRL 0x50
+#define OSC_CTRL_OSC_FREQ_MASK (0xF<<28)
+#define OSC_CTRL_OSC_FREQ_13MHZ (0x0<<28)
+#define OSC_CTRL_OSC_FREQ_19_2MHZ (0x4<<28)
+#define OSC_CTRL_OSC_FREQ_12MHZ (0x8<<28)
+#define OSC_CTRL_OSC_FREQ_26MHZ (0xC<<28)
+#define OSC_CTRL_OSC_FREQ_16_8MHZ (0x1<<28)
+#define OSC_CTRL_OSC_FREQ_38_4MHZ (0x5<<28)
+#define OSC_CTRL_OSC_FREQ_48MHZ (0x9<<28)
+#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
+
+#define OSC_CTRL_PLL_REF_DIV_MASK (3<<26)
+#define OSC_CTRL_PLL_REF_DIV_1 (0<<26)
+#define OSC_CTRL_PLL_REF_DIV_2 (1<<26)
+#define OSC_CTRL_PLL_REF_DIV_4 (2<<26)
+
+#define OSC_FREQ_DET 0x58
+#define OSC_FREQ_DET_TRIG (1<<31)
+
+#define OSC_FREQ_DET_STATUS 0x5C
+#define OSC_FREQ_DET_BUSY (1<<31)
+#define OSC_FREQ_DET_CNT_MASK 0xFFFF
+
+#define PERIPH_CLK_SOURCE_I2S1 0x100
+#define PERIPH_CLK_SOURCE_EMC 0x19c
+#define PERIPH_CLK_SOURCE_OSC 0x1fc
+#define PERIPH_CLK_SOURCE_NUM1 \
+ ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
+
+#define PERIPH_CLK_SOURCE_G3D2 0x3b0
+#define PERIPH_CLK_SOURCE_SE 0x42c
+#define PERIPH_CLK_SOURCE_NUM2 \
+ ((PERIPH_CLK_SOURCE_SE - PERIPH_CLK_SOURCE_G3D2) / 4 + 1)
+
+#define AUDIO_DLY_CLK 0x49c
+#define AUDIO_SYNC_CLK_SPDIF 0x4b4
+#define PERIPH_CLK_SOURCE_NUM3 \
+ ((AUDIO_SYNC_CLK_SPDIF - AUDIO_DLY_CLK) / 4 + 1)
+
+#define PERIPH_CLK_SOURCE_NUM (PERIPH_CLK_SOURCE_NUM1 + \
+ PERIPH_CLK_SOURCE_NUM2 + \
+ PERIPH_CLK_SOURCE_NUM3)
+
+#define CPU_SOFTRST_CTRL 0x380
+
+#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF
+#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF
+#define PERIPH_CLK_SOURCE_DIV_SHIFT 0
+#define PERIPH_CLK_SOURCE_DIVIDLE_SHIFT 8
+#define PERIPH_CLK_SOURCE_DIVIDLE_VAL 50
+#define PERIPH_CLK_UART_DIV_ENB (1<<24)
+#define PERIPH_CLK_VI_SEL_EX_SHIFT 24
+#define PERIPH_CLK_VI_SEL_EX_MASK (0x3<<PERIPH_CLK_VI_SEL_EX_SHIFT)
+#define PERIPH_CLK_NAND_DIV_EX_ENB (1<<8)
+#define PERIPH_CLK_DTV_POLARITY_INV (1<<25)
+
+#define AUDIO_SYNC_SOURCE_MASK 0x0F
+#define AUDIO_SYNC_DISABLE_BIT 0x10
+#define AUDIO_SYNC_TAP_NIBBLE_SHIFT(c) ((c->reg_shift - 24) * 4)
+
+#define PLL_BASE 0x0
+#define PLL_BASE_BYPASS (1<<31)
+#define PLL_BASE_ENABLE (1<<30)
+#define PLL_BASE_REF_ENABLE (1<<29)
+#define PLL_BASE_OVERRIDE (1<<28)
+#define PLL_BASE_LOCK (1<<27)
+#define PLL_BASE_DIVP_MASK (0x7<<20)
+#define PLL_BASE_DIVP_SHIFT 20
+#define PLL_BASE_DIVN_MASK (0x3FF<<8)
+#define PLL_BASE_DIVN_SHIFT 8
+#define PLL_BASE_DIVM_MASK (0x1F)
+#define PLL_BASE_DIVM_SHIFT 0
+
+#define PLL_OUT_RATIO_MASK (0xFF<<8)
+#define PLL_OUT_RATIO_SHIFT 8
+#define PLL_OUT_OVERRIDE (1<<2)
+#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_LOCK_ENABLE(c) \
+ (((c)->flags & (PLLU | PLLD)) ? (1<<22) : (1<<18))
+
+#define PLL_MISC_DCCON_SHIFT 20
+#define PLL_MISC_CPCON_SHIFT 8
+#define PLL_MISC_CPCON_MASK (0xF<<PLL_MISC_CPCON_SHIFT)
+#define PLL_MISC_LFCON_SHIFT 4
+#define PLL_MISC_LFCON_MASK (0xF<<PLL_MISC_LFCON_SHIFT)
+#define PLL_MISC_VCOCON_SHIFT 0
+#define PLL_MISC_VCOCON_MASK (0xF<<PLL_MISC_VCOCON_SHIFT)
+#define PLLD_MISC_CLKENABLE (1<<30)
+
+#define PLLU_BASE_POST_DIV (1<<20)
+
+#define PLLD_BASE_DSIB_MUX_SHIFT 25
+#define PLLD_BASE_DSIB_MUX_MASK (1<<PLLD_BASE_DSIB_MUX_SHIFT)
+#define PLLD_BASE_CSI_CLKENABLE (1<<26)
+#define PLLD_MISC_DSI_CLKENABLE (1<<30)
+#define PLLD_MISC_DIV_RST (1<<23)
+#define PLLD_MISC_DCCON_SHIFT 12
+
+#define PLLDU_LFCON_SET_DIVN 600
+
+/* FIXME: OUT_OF_TABLE_CPCON per pll */
+#define OUT_OF_TABLE_CPCON 0x8
+
+#define SUPER_CLK_MUX 0x00
+#define SUPER_STATE_SHIFT 28
+#define SUPER_STATE_MASK (0xF << SUPER_STATE_SHIFT)
+#define SUPER_STATE_STANDBY (0x0 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_IDLE (0x1 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_RUN (0x2 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_IRQ (0x3 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_FIQ (0x4 << SUPER_STATE_SHIFT)
+#define SUPER_LP_DIV2_BYPASS (0x1 << 16)
+#define SUPER_SOURCE_MASK 0xF
+#define SUPER_FIQ_SOURCE_SHIFT 12
+#define SUPER_IRQ_SOURCE_SHIFT 8
+#define SUPER_RUN_SOURCE_SHIFT 4
+#define SUPER_IDLE_SOURCE_SHIFT 0
+
+#define SUPER_CLK_DIVIDER 0x04
+#define SUPER_CLOCK_DIV_U71_SHIFT 16
+#define SUPER_CLOCK_DIV_U71_MASK (0xff << SUPER_CLOCK_DIV_U71_SHIFT)
+/* guarantees safe cpu backup */
+#define SUPER_CLOCK_DIV_U71_MIN 0x2
+
+#define BUS_CLK_DISABLE (1<<3)
+#define BUS_CLK_DIV_MASK 0x3
+
+#define PMC_CTRL 0x0
+ #define PMC_CTRL_BLINK_ENB (1 << 7)
+
+#define PMC_DPD_PADS_ORIDE 0x1c
+ #define PMC_DPD_PADS_ORIDE_BLINK_ENB (1 << 20)
+
+#define PMC_BLINK_TIMER_DATA_ON_SHIFT 0
+#define PMC_BLINK_TIMER_DATA_ON_MASK 0x7fff
+#define PMC_BLINK_TIMER_ENB (1 << 15)
+#define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16
+#define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff
+
+#define PMC_PLLP_WB0_OVERRIDE 0xf8
+#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE (1 << 12)
+
+#define UTMIP_PLL_CFG2 0x488
+#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xfff) << 6)
+#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN (1 << 0)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN (1 << 2)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN (1 << 4)
+
+#define UTMIP_PLL_CFG1 0x484
+#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
+#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN (1 << 14)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN (1 << 12)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN (1 << 16)
+
+#define PLLE_BASE_CML_ENABLE (1<<31)
+#define PLLE_BASE_ENABLE (1<<30)
+#define PLLE_BASE_DIVCML_SHIFT 24
+#define PLLE_BASE_DIVCML_MASK (0xf<<PLLE_BASE_DIVCML_SHIFT)
+#define PLLE_BASE_DIVP_SHIFT 16
+#define PLLE_BASE_DIVP_MASK (0x3f<<PLLE_BASE_DIVP_SHIFT)
+#define PLLE_BASE_DIVN_SHIFT 8
+#define PLLE_BASE_DIVN_MASK (0xFF<<PLLE_BASE_DIVN_SHIFT)
+#define PLLE_BASE_DIVM_SHIFT 0
+#define PLLE_BASE_DIVM_MASK (0xFF<<PLLE_BASE_DIVM_SHIFT)
+#define PLLE_BASE_DIV_MASK \
+ (PLLE_BASE_DIVCML_MASK | PLLE_BASE_DIVP_MASK | \
+ PLLE_BASE_DIVN_MASK | PLLE_BASE_DIVM_MASK)
+#define PLLE_BASE_DIV(m, n, p, cml) \
+ (((cml)<<PLLE_BASE_DIVCML_SHIFT) | ((p)<<PLLE_BASE_DIVP_SHIFT) | \
+ ((n)<<PLLE_BASE_DIVN_SHIFT) | ((m)<<PLLE_BASE_DIVM_SHIFT))
+
+#define PLLE_MISC_SETUP_BASE_SHIFT 16
+#define PLLE_MISC_SETUP_BASE_MASK (0xFFFF<<PLLE_MISC_SETUP_BASE_SHIFT)
+#define PLLE_MISC_READY (1<<15)
+#define PLLE_MISC_LOCK (1<<11)
+#define PLLE_MISC_LOCK_ENABLE (1<<9)
+#define PLLE_MISC_SETUP_EX_SHIFT 2
+#define PLLE_MISC_SETUP_EX_MASK (0x3<<PLLE_MISC_SETUP_EX_SHIFT)
+#define PLLE_MISC_SETUP_MASK \
+ (PLLE_MISC_SETUP_BASE_MASK | PLLE_MISC_SETUP_EX_MASK)
+#define PLLE_MISC_SETUP_VALUE \
+ ((0x7<<PLLE_MISC_SETUP_BASE_SHIFT) | (0x0<<PLLE_MISC_SETUP_EX_SHIFT))
+
+#define PLLE_SS_CTRL 0x68
+#define PLLE_SS_INCINTRV_SHIFT 24
+#define PLLE_SS_INCINTRV_MASK (0x3f<<PLLE_SS_INCINTRV_SHIFT)
+#define PLLE_SS_INC_SHIFT 16
+#define PLLE_SS_INC_MASK (0xff<<PLLE_SS_INC_SHIFT)
+#define PLLE_SS_MAX_SHIFT 0
+#define PLLE_SS_MAX_MASK (0x1ff<<PLLE_SS_MAX_SHIFT)
+#define PLLE_SS_COEFFICIENTS_MASK \
+ (PLLE_SS_INCINTRV_MASK | PLLE_SS_INC_MASK | PLLE_SS_MAX_MASK)
+#define PLLE_SS_COEFFICIENTS_12MHZ \
+ ((0x18<<PLLE_SS_INCINTRV_SHIFT) | (0x1<<PLLE_SS_INC_SHIFT) | \
+ (0x24<<PLLE_SS_MAX_SHIFT))
+#define PLLE_SS_DISABLE ((1<<12) | (1<<11) | (1<<10))
+
+#define PLLE_AUX 0x48c
+#define PLLE_AUX_PLLP_SEL (1<<2)
+#define PLLE_AUX_CML_SATA_ENABLE (1<<1)
+#define PLLE_AUX_CML_PCIE_ENABLE (1<<0)
+
+#define PMC_SATA_PWRGT 0x1ac
+#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE (1<<5)
+#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL (1<<4)
+
+#define ROUND_DIVIDER_UP 0
+#define ROUND_DIVIDER_DOWN 1
+
+/* FIXME: recommended safety delay after lock is detected */
+#define PLL_POST_LOCK_DELAY 100
+
+/**
+* Structure defining the fields for USB UTMI clocks Parameters.
+*/
+struct utmi_clk_param {
+ /* Oscillator Frequency in KHz */
+ u32 osc_frequency;
+ /* UTMIP PLL Enable Delay Count */
+ u8 enable_delay_count;
+ /* UTMIP PLL Stable count */
+ u8 stable_count;
+ /* UTMIP PLL Active delay count */
+ u8 active_delay_count;
+ /* UTMIP PLL Xtal frequency count */
+ u8 xtal_freq_count;
+};
+
+static const struct utmi_clk_param utmi_parameters[] = {
+ {
+ .osc_frequency = 13000000,
+ .enable_delay_count = 0x02,
+ .stable_count = 0x33,
+ .active_delay_count = 0x05,
+ .xtal_freq_count = 0x7F
+ },
+ {
+ .osc_frequency = 19200000,
+ .enable_delay_count = 0x03,
+ .stable_count = 0x4B,
+ .active_delay_count = 0x06,
+ .xtal_freq_count = 0xBB},
+ {
+ .osc_frequency = 12000000,
+ .enable_delay_count = 0x02,
+ .stable_count = 0x2F,
+ .active_delay_count = 0x04,
+ .xtal_freq_count = 0x76
+ },
+ {
+ .osc_frequency = 26000000,
+ .enable_delay_count = 0x04,
+ .stable_count = 0x66,
+ .active_delay_count = 0x09,
+ .xtal_freq_count = 0xFE
+ },
+ {
+ .osc_frequency = 16800000,
+ .enable_delay_count = 0x03,
+ .stable_count = 0x41,
+ .active_delay_count = 0x0A,
+ .xtal_freq_count = 0xA4
+ },
+};
+
+static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+static void __iomem *misc_gp_hidrev_base = IO_ADDRESS(TEGRA_APB_MISC_BASE);
+
+#define MISC_GP_HIDREV 0x804
+
+/*
+ * Some peripheral clocks share an enable bit, so refcount the enable bits
+ * in registers CLK_ENABLE_L, ... CLK_ENABLE_W
+ */
+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))
+#define clk_readl(reg) \
+ __raw_readl((u32)reg_clk_base + (reg))
+#define pmc_writel(value, reg) \
+ __raw_writel(value, (u32)reg_pmc_base + (reg))
+#define pmc_readl(reg) \
+ __raw_readl((u32)reg_pmc_base + (reg))
+#define chipid_readl() \
+ __raw_readl((u32)misc_gp_hidrev_base + MISC_GP_HIDREV)
+
+#define clk_writel_delay(value, reg) \
+ do { \
+ __raw_writel((value), (u32)reg_clk_base + (reg)); \
+ udelay(2); \
+ } while (0)
+
+
+static inline int clk_set_div(struct clk *c, u32 n)
+{
+ return clk_set_rate(c, (clk_get_rate(c->parent) + n-1) / n);
+}
+
+static inline u32 periph_clk_to_reg(
+ struct clk *c, u32 reg_L, u32 reg_V, int offs)
+{
+ u32 reg = c->u.periph.clk_num / 32;
+ BUG_ON(reg >= RST_DEVICES_NUM);
+ if (reg < 3)
+ reg = reg_L + (reg * offs);
+ else
+ reg = reg_V + ((reg - 3) * offs);
+ return reg;
+}
+
+static unsigned long clk_measure_input_freq(void)
+{
+ u32 clock_autodetect;
+ clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET);
+ do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY);
+ clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS);
+ if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) {
+ return 12000000;
+ } else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) {
+ return 13000000;
+ } else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) {
+ return 19200000;
+ } else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) {
+ return 26000000;
+ } else if (clock_autodetect >= 1025 - 3 && clock_autodetect <= 1025 + 3) {
+ return 16800000;
+ } else if (clock_autodetect >= 2344 - 3 && clock_autodetect <= 2344 + 3) {
+ return 38400000;
+ } else if (clock_autodetect >= 2928 - 3 && clock_autodetect <= 2928 + 3) {
+ return 48000000;
+ } else {
+ pr_err("%s: Unexpected clock autodetect value %d", __func__,
+ clock_autodetect);
+ BUG();
+ return 0;
+ }
+}
+
+static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate,
+ u32 flags, u32 round_mode)
+{
+ s64 divider_u71 = parent_rate;
+ if (!rate)
+ return -EINVAL;
+
+ if (!(flags & DIV_U71_INT))
+ divider_u71 *= 2;
+ if (round_mode == ROUND_DIVIDER_UP)
+ divider_u71 += rate - 1;
+ do_div(divider_u71, rate);
+ if (flags & DIV_U71_INT)
+ divider_u71 *= 2;
+
+ if (divider_u71 - 2 < 0)
+ return 0;
+
+ if (divider_u71 - 2 > 255)
+ return -EINVAL;
+
+ return divider_u71 - 2;
+}
+
+static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
+{
+ s64 divider_u16;
+
+ divider_u16 = parent_rate;
+ if (!rate)
+ return -EINVAL;
+ divider_u16 += rate - 1;
+ do_div(divider_u16, rate);
+
+ if (divider_u16 - 1 < 0)
+ return 0;
+
+ if (divider_u16 - 1 > 0xFFFF)
+ return -EINVAL;
+
+ return divider_u16 - 1;
+}
+
+/* clk_m functions */
+static unsigned long tegra30_clk_m_autodetect_rate(struct clk *c)
+{
+ 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) {
+ case 12000000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ break;
+ case 13000000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ;
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ break;
+ case 19200000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ;
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ break;
+ case 26000000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ;
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ break;
+ case 16800000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_16_8MHZ;
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ break;
+ case 38400000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_38_4MHZ;
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_2);
+ break;
+ case 48000000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_48MHZ;
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4);
+ 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 tegra30_clk_m_init(struct clk *c)
+{
+ pr_debug("%s on clock %s\n", __func__, c->name);
+ tegra30_clk_m_autodetect_rate(c);
+}
+
+static int tegra30_clk_m_enable(struct clk *c)
+{
+ pr_debug("%s on clock %s\n", __func__, c->name);
+ return 0;
+}
+
+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");
+}
+
+static struct clk_ops tegra_clk_m_ops = {
+ .init = tegra30_clk_m_init,
+ .enable = tegra30_clk_m_enable,
+ .disable = tegra30_clk_m_disable,
+};
+
+static struct clk_ops tegra_clk_m_div_ops = {
+ .enable = tegra30_clk_m_enable,
+};
+
+/* PLL reference divider functions */
+static void tegra30_pll_ref_init(struct clk *c)
+{
+ 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:
+ c->div = 1;
+ break;
+ case OSC_CTRL_PLL_REF_DIV_2:
+ c->div = 2;
+ break;
+ case OSC_CTRL_PLL_REF_DIV_4:
+ c->div = 4;
+ break;
+ default:
+ pr_err("%s: Invalid pll ref divider %d", __func__, pll_ref_div);
+ BUG();
+ }
+ c->mul = 1;
+ c->state = ON;
+}
+
+static struct clk_ops tegra_pll_ref_ops = {
+ .init = tegra30_pll_ref_init,
+ .enable = tegra30_clk_m_enable,
+ .disable = tegra30_clk_m_disable,
+};
+
+/* super clock functions */
+/* "super clocks" on tegra30 have two-stage muxes, fractional 7.1 divider and
+ * clock skipping super divider. We will ignore the clock skipping divider,
+ * since we can't lower the voltage when using the clock skip, but we can if
+ * we lower the PLL frequency. We will use 7.1 divider for CPU super-clock
+ * 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)
+{
+ 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;
+
+ 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))
+ 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)
+{
+ return 0;
+}
+
+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 */
+}
+
+static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p)
+{
+ u32 val;
+ const struct clk_mux_sel *sel;
+ 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) {
+ /* 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);
+
+ clk_reparent(c, p);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+/*
+ * Do not use super clocks "skippers", since dividing using a clock skipper
+ * does not allow the voltage to be scaled down. 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. Special case: if fixed rate PLL is CPU super clock parent the
+ * 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)
+{
+ if ((c->flags & DIV_U71) && (c->parent->flags & PLL_FIXED)) {
+ int div = clk_div71_get_divider(c->parent->u.pll.fixed_rate,
+ rate, c->flags, ROUND_DIVIDER_DOWN);
+ div = max(div, SUPER_CLOCK_DIV_U71_MIN);
+
+ clk_writel(div << SUPER_CLOCK_DIV_U71_SHIFT,
+ c->reg + SUPER_CLK_DIVIDER);
+ c->div = div + 2;
+ c->mul = 2;
+ return 0;
+ }
+ return clk_set_rate(c->parent, rate);
+}
+
+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,
+};
+
+static int tegra30_twd_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ /* The input value 'rate' is the clock rate of the CPU complex. */
+ c->rate = (rate * c->mul) / c->div;
+ return 0;
+}
+
+static struct clk_ops tegra30_twd_ops = {
+ .set_rate = tegra30_twd_clk_set_rate,
+};
+
+/* Blink output functions */
+
+static void tegra30_blink_clk_init(struct clk *c)
+{
+ 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;
+ }
+}
+
+static int tegra30_blink_clk_enable(struct clk *c)
+{
+ u32 val;
+
+ val = pmc_readl(PMC_DPD_PADS_ORIDE);
+ pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
+
+ val = pmc_readl(PMC_CTRL);
+ pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL);
+
+ return 0;
+}
+
+static void tegra30_blink_clk_disable(struct clk *c)
+{
+ u32 val;
+
+ val = pmc_readl(PMC_CTRL);
+ pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL);
+
+ val = pmc_readl(PMC_DPD_PADS_ORIDE);
+ 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)
+{
+ unsigned long parent_rate = clk_get_rate(c->parent);
+ if (rate >= parent_rate) {
+ c->div = 1;
+ pmc_writel(0, c->reg);
+ } else {
+ unsigned int on_off;
+ u32 val;
+
+ on_off = DIV_ROUND_UP(parent_rate / 8, rate);
+ c->div = on_off * 8;
+
+ val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) <<
+ PMC_BLINK_TIMER_DATA_ON_SHIFT;
+ on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+ on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+ val |= on_off;
+ val |= PMC_BLINK_TIMER_ENB;
+ pmc_writel(val, c->reg);
+ }
+
+ 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,
+};
+
+/* PLL Functions */
+static int tegra30_pll_clk_wait_for_lock(struct clk *c, u32 lock_reg,
+ u32 lock_bit)
+{
+#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", c->name);
+ return -1;
+#endif
+ udelay(c->u.pll.lock_delay);
+
+ return 0;
+}
+
+
+static void tegra30_utmi_param_configure(struct clk *c)
+{
+ 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)
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(utmi_parameters)) {
+ pr_err("%s: Unexpected main rate %lu\n", __func__, main_rate);
+ return;
+ }
+
+ reg = clk_readl(UTMIP_PLL_CFG2);
+
+ /* Program UTMIP PLL stable and active counts */
+ /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */
+ reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+ reg |= UTMIP_PLL_CFG2_STABLE_COUNT(
+ utmi_parameters[i].stable_count);
+
+ reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+
+ reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
+ utmi_parameters[i].active_delay_count);
+
+ /* Remove power downs from UTMIP PLL control bits */
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
+
+ clk_writel(reg, UTMIP_PLL_CFG2);
+
+ /* Program UTMIP PLL delay and oscillator frequency counts */
+ reg = clk_readl(UTMIP_PLL_CFG1);
+ reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+
+ reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
+ utmi_parameters[i].enable_delay_count);
+
+ reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+ reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
+ utmi_parameters[i].xtal_freq_count);
+
+ /* Remove power downs from UTMIP PLL control bits */
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
+
+ clk_writel(reg, UTMIP_PLL_CFG1);
+}
+
+static void tegra30_pll_clk_init(struct clk *c)
+{
+ u32 val = clk_readl(c->reg + PLL_BASE);
+
+ c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
+
+ 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);
+ }
+ }
+
+ if (c->flags & PLLU)
+ tegra30_utmi_param_configure(c);
+}
+
+static int tegra30_pll_clk_enable(struct clk *c)
+{
+ u32 val;
+ pr_debug("%s on clock %s\n", __func__, c->name);
+
+#if USE_PLL_LOCK_BITS
+ val = clk_readl(c->reg + PLL_MISC(c));
+ val |= PLL_MISC_LOCK_ENABLE(c);
+ clk_writel(val, c->reg + PLL_MISC(c));
+#endif
+ val = clk_readl(c->reg + PLL_BASE);
+ val &= ~PLL_BASE_BYPASS;
+ val |= PLL_BASE_ENABLE;
+ clk_writel(val, c->reg + PLL_BASE);
+
+ if (c->flags & PLLM) {
+ val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
+ val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
+ pmc_writel(val, PMC_PLLP_WB0_OVERRIDE);
+ }
+
+ tegra30_pll_clk_wait_for_lock(c, c->reg + PLL_BASE, PLL_BASE_LOCK);
+
+ return 0;
+}
+
+static void tegra30_pll_clk_disable(struct clk *c)
+{
+ u32 val;
+ pr_debug("%s on clock %s\n", __func__, c->name);
+
+ val = clk_readl(c->reg);
+ val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+ clk_writel(val, c->reg);
+
+ if (c->flags & PLLM) {
+ val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
+ val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
+ pmc_writel(val, PMC_PLLP_WB0_OVERRIDE);
+ }
+}
+
+static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ 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);
+ ret = -EINVAL;
+ }
+ return ret;
+ }
+
+ if (c->flags & PLLM) {
+ if (rate != clk_get_rate_locked(c)) {
+ pr_err("%s: Can not change memory %s rate in flight\n",
+ __func__, c->name);
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ p_div = 0;
+ input_rate = clk_get_rate(c->parent);
+
+ /* 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;
+ }
+ }
+
+ /* Configure out-of-table rate */
+ if (sel->input_rate == 0) {
+ unsigned long cfreq;
+ BUG_ON(c->flags & PLLU);
+ sel = &cfg;
+
+ 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;
+ cfg.cpcon = OUT_OF_TABLE_CPCON;
+
+ if ((cfg.m > (PLL_BASE_DIVM_MASK >> PLL_BASE_DIVM_SHIFT)) ||
+ (cfg.n > (PLL_BASE_DIVN_MASK >> PLL_BASE_DIVN_SHIFT)) ||
+ (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);
+ return -EINVAL;
+ }
+ p_div <<= PLL_BASE_DIVP_SHIFT;
+ }
+
+ c->mul = sel->n;
+ c->div = sel->m * sel->p;
+
+ old_base = val = clk_readl(c->reg + PLL_BASE);
+ val &= ~(PLL_BASE_DIVM_MASK | PLL_BASE_DIVN_MASK |
+ ((c->flags & PLLU) ? PLLU_BASE_POST_DIV : PLL_BASE_DIVP_MASK));
+ val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
+ (sel->n << PLL_BASE_DIVN_SHIFT) | p_div;
+ if (val == old_base)
+ return 0;
+
+ if (c->state == ON) {
+ tegra30_pll_clk_disable(c);
+ val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+ }
+ clk_writel(val, c->reg + PLL_BASE);
+
+ if (c->flags & PLL_HAS_CPCON) {
+ val = clk_readl(c->reg + PLL_MISC(c));
+ val &= ~PLL_MISC_CPCON_MASK;
+ val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
+ if (c->flags & (PLLU | PLLD)) {
+ val &= ~PLL_MISC_LFCON_MASK;
+ if (sel->n >= PLLDU_LFCON_SET_DIVN)
+ val |= 0x1 << PLL_MISC_LFCON_SHIFT;
+ } else if (c->flags & (PLLX | PLLM)) {
+ val &= ~(0x1 << PLL_MISC_DCCON_SHIFT);
+ if (rate >= (c->u.pll.vco_max >> 1))
+ val |= 0x1 << PLL_MISC_DCCON_SHIFT;
+ }
+ clk_writel(val, c->reg + PLL_MISC(c));
+ }
+
+ 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;
+
+ 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 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)
+{
+ 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");
+
+ 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;
+}
+
+static void tegra30_plle_clk_disable(struct clk *c)
+{
+ u32 val;
+ pr_debug("%s on clock %s\n", __func__, c->name);
+
+ 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 *c)
+{
+ u32 val;
+
+ /* PLLE is already disabled, and setup cleared;
+ * create falling edge on PLLE IDDQ input */
+ val = pmc_readl(PMC_SATA_PWRGT);
+ val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
+ pmc_writel(val, PMC_SATA_PWRGT);
+
+ val = pmc_readl(PMC_SATA_PWRGT);
+ val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL;
+ pmc_writel(val, PMC_SATA_PWRGT);
+
+ val = pmc_readl(PMC_SATA_PWRGT);
+ val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
+ pmc_writel(val, PMC_SATA_PWRGT);
+
+ do {
+ val = clk_readl(c->reg + PLL_MISC(c));
+ } while (!(val & PLLE_MISC_READY));
+}
+
+static int tegra30_plle_configure(struct clk *c, bool force_training)
+{
+ u32 val;
+ const struct clk_pll_freq_table *sel;
+ unsigned long rate = c->u.pll.fixed_rate;
+ 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 == rate)
+ break;
+ }
+
+ if (sel->input_rate == 0)
+ return -ENOSYS;
+
+ /* disable PLLE, clear setup fiels */
+ tegra30_plle_clk_disable(c);
+
+ val = clk_readl(c->reg + PLL_MISC(c));
+ val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK);
+ clk_writel(val, c->reg + PLL_MISC(c));
+
+ /* training */
+ val = clk_readl(c->reg + PLL_MISC(c));
+ if (force_training || (!(val & PLLE_MISC_READY)))
+ tegra30_plle_training(c);
+
+ /* configure dividers, setup, disable SS */
+ val = clk_readl(c->reg + PLL_BASE);
+ val &= ~PLLE_BASE_DIV_MASK;
+ val |= PLLE_BASE_DIV(sel->m, sel->n, sel->p, sel->cpcon);
+ clk_writel(val, c->reg + PLL_BASE);
+ c->mul = sel->n;
+ c->div = sel->m * sel->p;
+
+ val = clk_readl(c->reg + PLL_MISC(c));
+ val |= PLLE_MISC_SETUP_VALUE;
+ val |= PLLE_MISC_LOCK_ENABLE;
+ clk_writel(val, c->reg + PLL_MISC(c));
+
+ val = clk_readl(PLLE_SS_CTRL);
+ val |= PLLE_SS_DISABLE;
+ clk_writel(val, PLLE_SS_CTRL);
+
+ /* enable and lock PLLE*/
+ val = clk_readl(c->reg + PLL_BASE);
+ val |= (PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
+ clk_writel(val, c->reg + PLL_BASE);
+
+ tegra30_pll_clk_wait_for_lock(c, c->reg + PLL_MISC(c), PLLE_MISC_LOCK);
+
+ return 0;
+}
+
+static int tegra30_plle_clk_enable(struct clk *c)
+{
+ pr_debug("%s on clock %s\n", __func__, c->name);
+ return tegra30_plle_configure(c, !c->set);
+}
+
+static struct clk_ops tegra_plle_ops = {
+ .init = tegra30_plle_clk_init,
+ .enable = tegra30_plle_clk_enable,
+ .disable = tegra30_plle_clk_disable,
+};
+
+/* Clock divider ops */
+static void tegra30_pll_div_clk_init(struct clk *c)
+{
+ 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;
+ }
+}
+
+static int tegra30_pll_div_clk_enable(struct clk *c)
+{
+ u32 val;
+ u32 new_val;
+
+ pr_debug("%s: %s\n", __func__, c->name);
+ if (c->flags & DIV_U71) {
+ val = clk_readl(c->reg);
+ new_val = val >> c->reg_shift;
+ new_val &= 0xFFFF;
+
+ new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
+
+ val &= ~(0xFFFF << c->reg_shift);
+ val |= new_val << c->reg_shift;
+ clk_writel_delay(val, c->reg);
+ return 0;
+ } else if (c->flags & DIV_2) {
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void tegra30_pll_div_clk_disable(struct clk *c)
+{
+ u32 val;
+ u32 new_val;
+
+ pr_debug("%s: %s\n", __func__, c->name);
+ if (c->flags & DIV_U71) {
+ val = clk_readl(c->reg);
+ new_val = val >> c->reg_shift;
+ new_val &= 0xFFFF;
+
+ new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE);
+
+ val &= ~(0xFFFF << c->reg_shift);
+ val |= new_val << c->reg_shift;
+ clk_writel_delay(val, c->reg);
+ }
+}
+
+static int tegra30_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ 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);
+ if (divider_u71 >= 0) {
+ val = clk_readl(c->reg);
+ new_val = val >> c->reg_shift;
+ new_val &= 0xFFFF;
+ if (c->flags & DIV_U71_FIXED)
+ new_val |= PLL_OUT_OVERRIDE;
+ new_val &= ~PLL_OUT_RATIO_MASK;
+ new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT;
+
+ val &= ~(0xFFFF << c->reg_shift);
+ val |= new_val << c->reg_shift;
+ clk_writel_delay(val, c->reg);
+ c->div = divider_u71 + 2;
+ c->mul = 2;
+ return 0;
+ }
+ } else if (c->flags & DIV_2)
+ return clk_set_rate(c->parent, rate * 2);
+
+ return -EINVAL;
+}
+
+static long tegra30_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
+{
+ int divider;
+ 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 = clk_div71_get_divider(
+ parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+ 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 */
+ 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,
+};
+
+/* Periph clk ops */
+static inline u32 periph_clk_source_mask(struct clk *c)
+{
+ if (c->flags & MUX8)
+ return 7 << 29;
+ else if (c->flags & MUX_PWM)
+ return 3 << 28;
+ else if (c->flags & MUX_CLK_OUT)
+ return 3 << (c->u.periph.clk_num + 4);
+ else if (c->flags & PLLD)
+ return PLLD_BASE_DSIB_MUX_MASK;
+ else
+ return 3 << 30;
+}
+
+static inline u32 periph_clk_source_shift(struct clk *c)
+{
+ if (c->flags & MUX8)
+ return 29;
+ else if (c->flags & MUX_PWM)
+ return 28;
+ else if (c->flags & MUX_CLK_OUT)
+ return c->u.periph.clk_num + 4;
+ else if (c->flags & PLLD)
+ return PLLD_BASE_DSIB_MUX_SHIFT;
+ else
+ return 30;
+}
+
+static void tegra30_periph_clk_init(struct clk *c)
+{
+ 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;
+ }
+
+ c->state = ON;
+ if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
+ c->state = OFF;
+ if (!(c->flags & PERIPH_NO_RESET))
+ if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c))
+ c->state = OFF;
+}
+
+static int tegra30_periph_clk_enable(struct clk *c)
+{
+ pr_debug("%s on clock %s\n", __func__, c->name);
+
+ tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
+ if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
+ return 0;
+
+ clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_SET_REG(c));
+ if (!(c->flags & PERIPH_NO_RESET) &&
+ !(c->flags & PERIPH_MANUAL_RESET)) {
+ if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) &
+ PERIPH_CLK_TO_BIT(c)) {
+ udelay(5); /* reset propagation delay */
+ clk_writel(PERIPH_CLK_TO_BIT(c),
+ PERIPH_CLK_TO_RST_CLR_REG(c));
+ }
+ }
+ return 0;
+}
+
+static void tegra30_periph_clk_disable(struct clk *c)
+{
+ 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]--;
+
+ 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();
+
+ 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)
+{
+ 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) {
+ /* 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(PERIPH_CLK_TO_BIT(c),
+ PERIPH_CLK_TO_RST_SET_REG(c));
+ } else
+ clk_writel(PERIPH_CLK_TO_BIT(c),
+ PERIPH_CLK_TO_RST_CLR_REG(c));
+ }
+}
+
+static int tegra30_periph_clk_set_parent(struct clk *c, struct clk *p)
+{
+ 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);
+
+ 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);
+
+ if (c->refcnt && c->parent)
+ clk_disable(c->parent);
+
+ clk_reparent(c, p);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int tegra30_periph_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ u32 val;
+ int divider;
+ unsigned long parent_rate = clk_get_rate(c->parent);
+
+ if (c->flags & DIV_U71) {
+ divider = clk_div71_get_divider(
+ parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+ if (divider >= 0) {
+ val = clk_readl(c->reg);
+ val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
+ val |= divider;
+ if (c->flags & DIV_U71_UART) {
+ if (divider)
+ val |= PERIPH_CLK_UART_DIV_ENB;
+ else
+ val &= ~PERIPH_CLK_UART_DIV_ENB;
+ }
+ clk_writel_delay(val, c->reg);
+ c->div = divider + 2;
+ c->mul = 2;
+ return 0;
+ }
+ } else if (c->flags & DIV_U16) {
+ divider = clk_div16_get_divider(parent_rate, rate);
+ if (divider >= 0) {
+ val = clk_readl(c->reg);
+ val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
+ val |= divider;
+ clk_writel_delay(val, c->reg);
+ c->div = divider + 1;
+ c->mul = 1;
+ return 0;
+ }
+ } else if (parent_rate <= rate) {
+ c->div = 1;
+ c->mul = 1;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static long tegra30_periph_clk_round_rate(struct clk *c,
+ unsigned long rate)
+{
+ int divider;
+ 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 = clk_div71_get_divider(
+ parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+ if (divider < 0)
+ return divider;
+
+ return DIV_ROUND_UP(parent_rate * 2, divider + 2);
+ } else if (c->flags & DIV_U16) {
+ divider = clk_div16_get_divider(parent_rate, rate);
+ if (divider < 0)
+ return divider;
+ return DIV_ROUND_UP(parent_rate, divider + 1);
+ }
+ 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,
+};
+
+
+/* Periph extended clock configuration ops */
+static int
+tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+ if (p == TEGRA_CLK_VI_INP_SEL) {
+ u32 val = clk_readl(c->reg);
+ val &= ~PERIPH_CLK_VI_SEL_EX_MASK;
+ val |= (setting << PERIPH_CLK_VI_SEL_EX_SHIFT) &
+ PERIPH_CLK_VI_SEL_EX_MASK;
+ clk_writel(val, c->reg);
+ return 0;
+ }
+ 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)
+{
+ if (p == TEGRA_CLK_NAND_PAD_DIV2_ENB) {
+ u32 val = clk_readl(c->reg);
+ if (setting)
+ val |= PERIPH_CLK_NAND_DIV_EX_ENB;
+ else
+ val &= ~PERIPH_CLK_NAND_DIV_EX_ENB;
+ clk_writel(val, c->reg);
+ return 0;
+ }
+ 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)
+{
+ if (p == TEGRA_CLK_DTV_INVERT) {
+ u32 val = clk_readl(c->reg);
+ if (setting)
+ val |= PERIPH_CLK_DTV_POLARITY_INV;
+ else
+ val &= ~PERIPH_CLK_DTV_POLARITY_INV;
+ clk_writel(val, c->reg);
+ return 0;
+ }
+ 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)
+{
+ const struct clk_mux_sel *mux = 0;
+ const struct clk_mux_sel *sel;
+ 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;
+}
+
+static int tegra30_clk_out_enable(struct clk *c)
+{
+ 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);
+ pmc_writel(val, c->reg);
+ spin_unlock_irqrestore(&clk_out_lock, flags);
+
+ return 0;
+}
+
+static void tegra30_clk_out_disable(struct clk *c)
+{
+ 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);
+ pmc_writel(val, c->reg);
+ spin_unlock_irqrestore(&clk_out_lock, flags);
+}
+
+static int tegra30_clk_out_set_parent(struct clk *c, struct clk *p)
+{
+ 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 |= (sel->value << periph_clk_source_shift(c));
+ pmc_writel(val, c->reg);
+ spin_unlock_irqrestore(&clk_out_lock, flags);
+
+ if (c->refcnt && c->parent)
+ clk_disable(c->parent);
+
+ clk_reparent(c, p);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+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,
+};
+
+
+/* Clock doubler ops */
+static void tegra30_clk_double_init(struct clk *c)
+{
+ u32 val = clk_readl(c->reg);
+ c->mul = val & (0x1 << c->reg_shift) ? 1 : 2;
+ c->div = 1;
+ c->state = ON;
+ if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
+ c->state = OFF;
+};
+
+static int tegra30_clk_double_set_rate(struct clk *c, unsigned long rate)
+{
+ 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);
+ c->mul = 1;
+ c->div = 1;
+ return 0;
+ } else if (rate == 2 * parent_rate) {
+ val = clk_readl(c->reg) & (~(0x1 << c->reg_shift));
+ clk_writel(val, c->reg);
+ c->mul = 2;
+ c->div = 1;
+ return 0;
+ }
+ 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,
+};
+
+/* Audio sync clock ops */
+static int tegra30_sync_source_set_rate(struct clk *c, unsigned long rate)
+{
+ c->rate = rate;
+ return 0;
+}
+
+static struct clk_ops tegra_sync_source_ops = {
+ .set_rate = &tegra30_sync_source_set_rate,
+};
+
+static void tegra30_audio_sync_clk_init(struct clk *c)
+{
+ int source;
+ const struct clk_mux_sel *sel;
+ 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;
+}
+
+static int tegra30_audio_sync_clk_enable(struct clk *c)
+{
+ 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)
+{
+ 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)
+{
+ 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);
+
+ if (c->refcnt && c->parent)
+ clk_disable(c->parent);
+
+ clk_reparent(c, p);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+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,
+ .set_parent = tegra30_audio_sync_clk_set_parent,
+};
+
+/* cml0 (pcie), and cml1 (sata) clock ops */
+static void tegra30_cml_clk_init(struct clk *c)
+{
+ u32 val = clk_readl(c->reg);
+ c->state = val & (0x1 << c->u.periph.clk_num) ? ON : OFF;
+}
+
+static int tegra30_cml_clk_enable(struct clk *c)
+{
+ 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)
+{
+ 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},
+};
+
+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},
+};
+
+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-dma", 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", "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("uarta_dbg", "serial8250.0", "uarta", 6, 0x178, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+ PERIPH_CLK("uartb_dbg", "serial8250.0", "uartb", 7, 0x17c, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+ PERIPH_CLK("uartc_dbg", "serial8250.0", "uartc", 55, 0x1a0, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+ PERIPH_CLK("uartd_dbg", "serial8250.0", "uartd", 65, 0x1c0, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+ PERIPH_CLK("uarte_dbg", "serial8250.0", "uarte", 66, 0x1c4, 800000000, mux_pllp_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("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("pwm", "tegra_pwm.0", NULL),
+ CLK_DUPLICATE("pwm", "tegra_pwm.1", NULL),
+ CLK_DUPLICATE("pwm", "tegra_pwm.2", NULL),
+ CLK_DUPLICATE("pwm", "tegra_pwm.3", NULL),
+ 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"),
+};
+
+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]);
+
+}