diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2014-11-05 15:47:39 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2014-11-05 15:47:39 +0100 |
commit | 7b4cc54579f12cc6c9586e8c21e729dd220e7f45 (patch) | |
tree | 85adc78e0eb782f805113b2b48dd07be6555e532 /drivers/clk | |
parent | 254b64520b9a729da496cd8bf637d080de7af5a1 (diff) | |
parent | c202b7c8d9e66082853ac1b131ddcedf53e9ca99 (diff) | |
download | barebox-7b4cc54579f12cc6c9586e8c21e729dd220e7f45.tar.gz barebox-7b4cc54579f12cc6c9586e8c21e729dd220e7f45.tar.xz |
Merge branch 'for-next/tegra'
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/tegra/clk-pll.c | 287 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra124.c | 45 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra20.c | 10 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra30.c | 43 | ||||
-rw-r--r-- | drivers/clk/tegra/clk.h | 13 |
5 files changed, 380 insertions, 18 deletions
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index c18c67f705..e677effba2 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -17,12 +17,15 @@ */ #include <common.h> +#include <clock.h> #include <io.h> #include <malloc.h> #include <asm-generic/div64.h> #include <linux/clk.h> #include <linux/err.h> +#include <mach/iomap.h> + #include "clk.h" #define PLL_BASE_BYPASS BIT(31) @@ -60,6 +63,7 @@ #define PLLDU_LFCON_SET_DIVN 600 #define PLLE_BASE_DIVCML_SHIFT 24 +#define PLLE_BASE_DIVCML_MASK 0xf #define PLLE_BASE_DIVCML_WIDTH 4 #define PLLE_BASE_DIVP_SHIFT 16 #define PLLE_BASE_DIVP_WIDTH 7 @@ -78,8 +82,45 @@ PLLE_MISC_SETUP_EX_MASK) #define PLLE_MISC_SETUP_VALUE (7 << PLLE_MISC_SETUP_BASE_SHIFT) -#define PLLE_SS_CTRL 0x68 -#define PLLE_SS_DISABLE (7 << 10) +#define XUSBIO_PLL_CFG0 0x51c +#define XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL (1 << 0) +#define XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL (1 << 2) +#define XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET (1 << 6) +#define XUSBIO_PLL_CFG0_SEQ_ENABLE (1 << 24) +#define XUSBIO_PLL_CFG0_SEQ_START_STATE (1 << 25) + +#define PLLE_SS_CTRL 0x68 +#define PLLE_SS_CNTL_BYPASS_SS (7 << 10) +#define PLLE_SS_CNTL_INTERP_RESET (1 << 11) +#define PLLE_SS_CNTL_SSC_BYP (1 << 12) +#define PLLE_SS_CNTL_CENTER (1 << 14) +#define PLLE_SS_CNTL_INVERT (1 << 15) +#define PLLE_SS_MAX_MASK 0x1ff +#define PLLE_SS_MAX_VAL 0x25 +#define PLLE_SS_INC_MASK (0xff << 16) +#define PLLE_SS_INC_VAL (0x1 << 16) +#define PLLE_SS_INCINTRV_MASK (0x3f << 24) +#define PLLE_SS_INCINTRV_VAL (0x20 << 24) +#define PLLE_SS_COEFFICIENTS_MASK \ + (PLLE_SS_MAX_MASK | PLLE_SS_INC_MASK | PLLE_SS_INCINTRV_MASK) +#define PLLE_SS_COEFFICIENTS_VAL \ + (PLLE_SS_MAX_VAL | PLLE_SS_INC_VAL | PLLE_SS_INCINTRV_VAL) + +#define PLLE_MISC_VREG_CTRL_SHIFT 2 +#define PLLE_MISC_VREG_CTRL_MASK (2 << PLLE_MISC_VREG_CTRL_SHIFT) +#define PLLE_MISC_VREG_BG_CTRL_SHIFT 4 +#define PLLE_MISC_VREG_BG_CTRL_MASK (3 << PLLE_MISC_VREG_BG_CTRL_SHIFT) +#define PLLE_MISC_PLLE_PTS (1 << 8) +#define PLLE_MISC_IDDQ_SW_VALUE (1 << 13) +#define PLLE_MISC_IDDQ_SW_CTRL (1 << 14) + +#define PLLE_AUX_PLLP_SEL (1 << 2) +#define PLLE_AUX_USE_LOCKDET (1 << 3) +#define PLLE_AUX_ENABLE_SWCTL (1 << 4) +#define PLLE_AUX_SS_SWCTL (1 << 6) +#define PLLE_AUX_SEQ_ENABLE (1 << 24) +#define PLLE_AUX_SEQ_START_STATE (1 << 25) +#define PLLE_AUX_PLLRE_SEL (1 << 28) #define PMC_SATA_PWRGT 0x1ac #define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5) @@ -99,10 +140,19 @@ #define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK : \ mask(p->divp_width)) +#define divm_shift(p) (p)->divm_shift +#define divn_shift(p) (p)->divn_shift +#define divp_shift(p) (p)->divp_shift + +#define divm_mask_shifted(p) (divm_mask(p) << divm_shift(p)) +#define divn_mask_shifted(p) (divn_mask(p) << divn_shift(p)) +#define divp_mask_shifted(p) (divp_mask(p) << divp_shift(p)) + #define divm_max(p) (divm_mask(p)) #define divn_max(p) (divn_mask(p)) #define divp_max(p) (1 << (divp_mask(p))) + #define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw) static int clk_pll_is_enabled(struct clk *hw) @@ -393,6 +443,217 @@ const struct clk_ops tegra_clk_pll_ops = { .set_rate = clk_pll_set_rate, }; +static unsigned long clk_plle_recalc_rate(struct clk *hw, + unsigned long parent_rate) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val = pll_readl_base(pll); + u32 divn = 0, divm = 0, divp = 0; + u64 rate = parent_rate; + + divp = (val >> 16) & 0x3f; + divn = (val >> 8) & (0xff); + divm = (val >> 0) & (0xff); + divm *= divp; + + rate *= divn; + do_div(rate, divm); + return rate; +} + +static int clk_plle_training(struct tegra_clk_pll *pll) +{ + u32 val; + + /* + * PLLE is already disabled, and setup cleared; + * create falling edge on PLLE IDDQ input. + */ + val = readl(TEGRA_PMC_BASE + PMC_SATA_PWRGT); + val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; + writel(val, TEGRA_PMC_BASE + PMC_SATA_PWRGT); + + val = readl(TEGRA_PMC_BASE + PMC_SATA_PWRGT); + val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL; + writel(val, TEGRA_PMC_BASE + PMC_SATA_PWRGT); + + val = readl(TEGRA_PMC_BASE + PMC_SATA_PWRGT); + val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; + writel(val, TEGRA_PMC_BASE + PMC_SATA_PWRGT); + + return wait_on_timeout(100 * MSECOND, + (pll_readl_misc(pll) & PLLE_MISC_READY)); +} + +static int clk_plle_enable(struct clk *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long input_rate = clk_get_rate(clk_get_parent(hw)); + struct tegra_clk_pll_freq_table sel; + u32 val; + int err; + + if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate)) + return -EINVAL; + + clk_pll_disable(hw); + + val = pll_readl_misc(pll); + val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK); + pll_writel_misc(val, pll); + + val = pll_readl_misc(pll); + if (!(val & PLLE_MISC_READY)) { + err = clk_plle_training(pll); + if (err) + return err; + } + + /* configure dividers */ + val = pll_readl_base(pll); + val &= ~(0x3fffff); + val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT); + val |= sel.m << 0; + val |= sel.n << 8; + val |= sel.p << 16; + val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT; + pll_writel_base(val, pll); + + val = pll_readl_misc(pll); + val |= PLLE_MISC_SETUP_VALUE; + val |= PLLE_MISC_LOCK_ENABLE; + pll_writel_misc(val, pll); + + val = readl(pll->clk_base + PLLE_SS_CTRL); + val |= PLLE_SS_CNTL_BYPASS_SS; + writel(val, pll->clk_base + PLLE_SS_CTRL); + + val = pll_readl_base(pll); + val |= (PLL_BASE_BYPASS | PLL_BASE_ENABLE); + pll_writel_base(val, pll); + + clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->base_reg, + pll->params->lock_bit_idx); + + return 0; +} + +const struct clk_ops tegra_clk_plle_ops = { + .recalc_rate = clk_plle_recalc_rate, + .is_enabled = clk_pll_is_enabled, + .disable = clk_pll_disable, + .enable = clk_plle_enable, +}; + +static int clk_plle_tegra114_enable(struct clk *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + unsigned long input_rate = clk_get_rate(clk_get_parent(hw)); + struct tegra_clk_pll_freq_table sel; + u32 val; + int ret; + + if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate)) + return -EINVAL; + + val = pll_readl_base(pll); + val &= ~BIT(29); /* Disable lock override */ + pll_writel_base(val, pll); + + val = pll_readl(pll->params->aux_reg, pll); + val |= PLLE_AUX_ENABLE_SWCTL; + val &= ~PLLE_AUX_SEQ_ENABLE; + pll_writel(val, pll->params->aux_reg, pll); + udelay(1); + + val = pll_readl_misc(pll); + val |= PLLE_MISC_LOCK_ENABLE; + val |= PLLE_MISC_IDDQ_SW_CTRL; + val &= ~PLLE_MISC_IDDQ_SW_VALUE; + val |= PLLE_MISC_PLLE_PTS; + val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK; + pll_writel_misc(val, pll); + udelay(5); + + val = pll_readl(PLLE_SS_CTRL, pll); + val |= PLLE_SS_CNTL_BYPASS_SS; + pll_writel(val, PLLE_SS_CTRL, pll); + + val = pll_readl_base(pll); + val &= ~(divp_mask_shifted(pll) | divn_mask_shifted(pll) | + divm_mask_shifted(pll)); + val &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT); + val |= sel.m << divm_shift(pll); + val |= sel.n << divn_shift(pll); + val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT; + pll_writel_base(val, pll); + udelay(1); + + clk_pll_enable(hw); + ret = clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->misc_reg, + pll->params->lock_bit_idx); + + if (ret < 0) + return ret; + + val = pll_readl(PLLE_SS_CTRL, pll); + val &= ~(PLLE_SS_CNTL_CENTER | PLLE_SS_CNTL_INVERT); + val &= ~PLLE_SS_COEFFICIENTS_MASK; + val |= PLLE_SS_COEFFICIENTS_VAL; + pll_writel(val, PLLE_SS_CTRL, pll); + val &= ~(PLLE_SS_CNTL_SSC_BYP | PLLE_SS_CNTL_BYPASS_SS); + pll_writel(val, PLLE_SS_CTRL, pll); + udelay(1); + val &= ~PLLE_SS_CNTL_INTERP_RESET; + pll_writel(val, PLLE_SS_CTRL, pll); + udelay(1); + + /* Enable hw control of xusb brick pll */ + val = pll_readl_misc(pll); + val &= ~PLLE_MISC_IDDQ_SW_CTRL; + pll_writel_misc(val, pll); + + val = pll_readl(pll->params->aux_reg, pll); + val |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SEQ_START_STATE); + val &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL); + pll_writel(val, pll->params->aux_reg, pll); + udelay(1); + val |= PLLE_AUX_SEQ_ENABLE; + pll_writel(val, pll->params->aux_reg, pll); + + val = pll_readl(XUSBIO_PLL_CFG0, pll); + val |= (XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET | + XUSBIO_PLL_CFG0_SEQ_START_STATE); + val &= ~(XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL | + XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL); + pll_writel(val, XUSBIO_PLL_CFG0, pll); + udelay(1); + val |= XUSBIO_PLL_CFG0_SEQ_ENABLE; + pll_writel(val, XUSBIO_PLL_CFG0, pll); + + return ret; +} + +static void clk_plle_tegra114_disable(struct clk *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + u32 val; + + clk_pll_disable(hw); + + val = pll_readl_misc(pll); + val |= PLLE_MISC_IDDQ_SW_CTRL | PLLE_MISC_IDDQ_SW_VALUE; + pll_writel_misc(val, pll); + udelay(1); +} + +const struct clk_ops tegra_clk_plle_tegra114_ops = { + .recalc_rate = clk_pll_recalc_rate, + .is_enabled = clk_pll_is_enabled, + .disable = clk_plle_tegra114_disable, + .enable = clk_plle_tegra114_enable, +}; + static struct clk *_tegra_clk_register_pll(const char *name, const char *parent_name, void __iomem *clk_base, unsigned long flags, unsigned long fixed_rate, @@ -447,3 +708,25 @@ struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, flags, fixed_rate, pll_params, pll_flags, freq_table, &tegra_clk_pll_ops); } + +struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, + void __iomem *clk_base, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table) +{ + return _tegra_clk_register_pll(name, parent_name, clk_base, + flags, fixed_rate, pll_params, pll_flags, freq_table, + &tegra_clk_plle_ops); +} + +struct clk *tegra_clk_register_plle_tegra114(const char *name, + const char *parent_name, void __iomem *clk_base, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table) +{ + return _tegra_clk_register_pll(name, parent_name, clk_base, + flags, fixed_rate, pll_params, pll_flags, freq_table, + &tegra_clk_plle_tegra114_ops); +} diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 514b22a784..7a2f7c081f 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -62,6 +62,15 @@ static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { { 0, 0, 0, 0, 0, 0 }, }; +static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { + /* PLLE special case: use cpcon field to store cml divider value */ + {336000000, 100000000, 100, 21, 16, 11}, + {312000000, 100000000, 200, 26, 24, 13}, + {13000000, 100000000, 200, 1, 26, 13}, + {12000000, 100000000, 200, 1, 24, 13}, + {0, 0, 0, 0, 0, 0}, +}; + static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { {12000000, 408000000, 408, 12, 0, 8}, {13000000, 408000000, 408, 13, 0, 8}, @@ -114,6 +123,21 @@ static struct tegra_clk_pll_params pll_c_params = { .lock_delay = 300, }; +static struct tegra_clk_pll_params pll_e_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 75000000, + .vco_min = 1600000000, + .vco_max = 2400000000U, + .base_reg = CRC_PLLE_BASE, + .misc_reg = CRC_PLLE_MISC, + .aux_reg = CRC_PLLE_AUX, + .lock_bit_idx = CRC_PLLE_MISC_LOCK, + .lock_enable_bit_idx = CRC_PLLE_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + static struct tegra_clk_pll_params pll_p_params = { .input_min = 2000000, .input_max = 31000000, @@ -220,6 +244,11 @@ static void tegra124_pll_init(void) clks[TEGRA124_CLK_PLL_U] = tegra_clk_register_pll("pll_u", "pll_ref", car_base, 0, 0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON, pll_u_freq_table); + + /* PLLE */ + clks[TEGRA124_CLK_PLL_E] = tegra_clk_register_plle_tegra114("pll_e", + "pll_ref", car_base, 0, 100000000, &pll_e_params, + TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK, pll_e_freq_table); } static const char *mux_pllpcm_clkm[] = {"pll_p", "pll_c2", "pll_c", "pll_c3", @@ -244,6 +273,12 @@ static void tegra124_periph_init(void) mux_pllpcm_clkm, ARRAY_SIZE(mux_pllpcm_clkm), car_base, CRC_CLK_SOURCE_UARTD, TEGRA124_CLK_UARTD, TEGRA_PERIPH_ON_APB); + clks[TEGRA124_CLK_PCIE] = clk_gate("pcie", "clk_m", + car_base + CRC_CLK_OUT_ENB_U, 6, 0, 0); + clks[TEGRA124_CLK_AFI] = clk_gate("afi", "clk_m", + car_base + CRC_CLK_OUT_ENB_U, 8, 0, 0); + clks[TEGRA124_CLK_CML0] = clk_gate("cml0", "pll_e", + car_base + CRC_PLLE_AUX, 0, 0, 0); /* peripheral clocks with a divider */ clks[TEGRA124_CLK_MSELECT] = tegra_clk_register_periph("mselect", @@ -286,11 +321,11 @@ static struct tegra_clk_init_table init_table[] = { {TEGRA124_CLK_PLL_P_OUT2, TEGRA124_CLK_CLK_MAX, 48000000, 1}, {TEGRA124_CLK_PLL_P_OUT3, TEGRA124_CLK_CLK_MAX, 102000000, 1}, {TEGRA124_CLK_PLL_P_OUT4, TEGRA124_CLK_CLK_MAX, 204000000, 1}, - {TEGRA124_CLK_MSELECT, TEGRA124_CLK_PLL_P, 204000000, 1}, - {TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 0, 1}, - {TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 0, 1}, - {TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 0, 1}, - {TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 0, 1}, + {TEGRA124_CLK_MSELECT, TEGRA124_CLK_PLL_P, 102000000, 1}, + {TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 0, 0}, + {TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 0, 0}, + {TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 0, 0}, + {TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 0, 0}, {TEGRA124_CLK_SDMMC1, TEGRA124_CLK_PLL_P, 48000000, 0}, {TEGRA124_CLK_SDMMC2, TEGRA124_CLK_PLL_P, 48000000, 0}, {TEGRA124_CLK_SDMMC3, TEGRA124_CLK_PLL_P, 48000000, 0}, diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 5b4365d492..2ff42d8bdb 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -324,11 +324,11 @@ static struct tegra_clk_init_table init_table[] = { {TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1}, {TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 1}, {TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 120000000, 1}, - {TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 1}, - {TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 1}, - {TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 1}, - {TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 1}, - {TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 1}, + {TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 0}, + {TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 0}, + {TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 0}, + {TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 0}, + {TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 0}, {TEGRA20_CLK_SDMMC1, TEGRA20_CLK_PLL_P, 48000000, 0}, {TEGRA20_CLK_SDMMC2, TEGRA20_CLK_PLL_P, 48000000, 0}, {TEGRA20_CLK_SDMMC3, TEGRA20_CLK_PLL_P, 48000000, 0}, diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index ed6d73625c..46fd6dddea 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -130,6 +130,13 @@ static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { { 0, 0, 0, 0, 0, 0 }, }; +static struct tegra_clk_pll_freq_table 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 }, +}; + /* PLL parameters */ static struct tegra_clk_pll_params pll_c_params = { .input_min = 2000000, @@ -201,6 +208,19 @@ static struct tegra_clk_pll_params pll_u_params = { .lock_delay = 1000, }; +static struct tegra_clk_pll_params pll_e_params = { + .input_min = 12000000, + .input_max = 216000000, + .cf_min = 12000000, + .cf_max = 12000000, + .vco_min = 1200000000, + .vco_max = 2400000000U, + .base_reg = CRC_PLLE_BASE, + .misc_reg = CRC_PLLE_MISC, + .lock_enable_bit_idx = CRC_PLLE_MISC_LOCK_ENABLE, + .lock_delay = 300, +}; + static void tegra30_pll_init(void) { /* PLLC */ @@ -251,6 +271,11 @@ static void tegra30_pll_init(void) clks[TEGRA30_CLK_PLL_U] = tegra_clk_register_pll("pll_u", "pll_ref", car_base, 0, 0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON, pll_u_freq_table); + + /* PLLE */ + clks[TEGRA30_CLK_PLL_E] = tegra_clk_register_plle("pll_e", "pll_ref", + car_base, 0, 100000000, &pll_e_params, + TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK, pll_e_freq_table); } static const char *mux_pllpcm_clkm[] = {"pll_p", "pll_c", "pll_m", "clk_m"}; @@ -278,6 +303,12 @@ static void tegra30_periph_init(void) mux_pllpcm_clkm, ARRAY_SIZE(mux_pllpcm_clkm), car_base, CRC_CLK_SOURCE_UARTE, TEGRA30_CLK_UARTE, TEGRA_PERIPH_ON_APB); + clks[TEGRA30_CLK_PCIE] = clk_gate("pcie", "clk_m", + car_base + CRC_CLK_OUT_ENB_U, 6, 0, 0); + clks[TEGRA30_CLK_AFI] = clk_gate("afi", "clk_m", + car_base + CRC_CLK_OUT_ENB_U, 8, 0, 0); + clks[TEGRA30_CLK_CML0] = clk_gate("cml0", "pll_e", + car_base + CRC_PLLE_AUX, 0, 0, 0); /* peripheral clocks with a divider */ clks[TEGRA30_CLK_MSELECT] = tegra_clk_register_periph("mselect", @@ -320,12 +351,12 @@ static struct tegra_clk_init_table init_table[] = { {TEGRA30_CLK_PLL_P_OUT2, TEGRA30_CLK_CLK_MAX, 48000000, 1}, {TEGRA30_CLK_PLL_P_OUT3, TEGRA30_CLK_CLK_MAX, 102000000, 1}, {TEGRA30_CLK_PLL_P_OUT4, TEGRA30_CLK_CLK_MAX, 204000000, 1}, - {TEGRA30_CLK_MSELECT, TEGRA30_CLK_PLL_P, 204000000, 1}, - {TEGRA30_CLK_UARTA, TEGRA30_CLK_PLL_P, 0, 1}, - {TEGRA30_CLK_UARTB, TEGRA30_CLK_PLL_P, 0, 1}, - {TEGRA30_CLK_UARTC, TEGRA30_CLK_PLL_P, 0, 1}, - {TEGRA30_CLK_UARTD, TEGRA30_CLK_PLL_P, 0, 1}, - {TEGRA30_CLK_UARTE, TEGRA30_CLK_PLL_P, 0, 1}, + {TEGRA30_CLK_MSELECT, TEGRA30_CLK_PLL_P, 102000000, 1}, + {TEGRA30_CLK_UARTA, TEGRA30_CLK_PLL_P, 0, 0}, + {TEGRA30_CLK_UARTB, TEGRA30_CLK_PLL_P, 0, 0}, + {TEGRA30_CLK_UARTC, TEGRA30_CLK_PLL_P, 0, 0}, + {TEGRA30_CLK_UARTD, TEGRA30_CLK_PLL_P, 0, 0}, + {TEGRA30_CLK_UARTE, TEGRA30_CLK_PLL_P, 0, 0}, {TEGRA30_CLK_SDMMC1, TEGRA30_CLK_PLL_P, 48000000, 0}, {TEGRA30_CLK_SDMMC2, TEGRA30_CLK_PLL_P, 48000000, 0}, {TEGRA30_CLK_SDMMC3, TEGRA30_CLK_PLL_P, 48000000, 0}, diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index d5d0730602..10d03573fd 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -63,6 +63,7 @@ struct tegra_clk_pll_params { u32 base_reg; u32 misc_reg; + u32 aux_reg; u32 lock_reg; u8 lock_bit_idx; u8 lock_enable_bit_idx; @@ -101,6 +102,18 @@ struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, struct tegra_clk_pll_params *pll_params, u8 pll_flags, struct tegra_clk_pll_freq_table *freq_table); +struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, + void __iomem *clk_base, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table); + +struct clk *tegra_clk_register_plle_tegra114(const char *name, + const char *parent_name, void __iomem *clk_base, + unsigned long flags, unsigned long fixed_rate, + struct tegra_clk_pll_params *pll_params, u8 pll_flags, + struct tegra_clk_pll_freq_table *freq_table); + /* struct tegra_clk_pll_out - PLL output divider */ struct tegra_clk_pll_out { struct clk hw; |