diff options
Diffstat (limited to 'arch/arm/mach-tegra/tegra30_clocks.c')
| -rw-r--r-- | arch/arm/mach-tegra/tegra30_clocks.c | 3099 | 
1 files changed, 3099 insertions, 0 deletions
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]); + +}  |