Tegra: PLL: use per-SoC pllinfo table instead of PLL_DIVM/N/P, etc.

Added PLL variables (dividers mask/shift, lock enable/detect, etc.)
to new pllinfo struct for each Soc/PLL. PLLA/C/D/E/M/P/U/X.

Used pllinfo struct in all clock functions, validated on T210.
Should be equivalent to prior code on T124/114/30/20. Thanks
to Marcel Ziswiler for corrections to the T20/T30 values.

Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
Tested-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
Signed-off-by: Tom Warren <twarren@nvidia.com>
This commit is contained in:
Tom Warren 2015-06-25 09:50:44 -07:00
parent 3e8650c0f9
commit 722e000ccd
12 changed files with 283 additions and 172 deletions

View File

@ -249,17 +249,6 @@ struct clk_rst_ctlr {
#define PLL_LOCK_SHIFT 27
#define PLL_LOCK_MASK (1U << PLL_LOCK_SHIFT)
#define PLL_DIVP_SHIFT 20
#define PLL_DIVP_MASK (7U << PLL_DIVP_SHIFT)
/* Special case for T210 PLLU DIVP */
#define PLLU_DIVP_SHIFT 16
#define PLL_DIVN_SHIFT 8
#define PLL_DIVN_MASK (0x3ffU << PLL_DIVN_SHIFT)
#define PLL_DIVM_SHIFT 0
#define PLL_DIVM_MASK (0x1f << PLL_DIVM_SHIFT)
/* CLK_RST_CONTROLLER_PLLx_OUTx_0 */
#define PLL_OUT_RSTN (1 << 0)
#define PLL_OUT_CLKEN (1 << 1)
@ -272,24 +261,6 @@ struct clk_rst_ctlr {
#define PLL_DCCON_SHIFT 20
#define PLL_DCCON_MASK (1U << PLL_DCCON_SHIFT)
#define PLL_LOCK_ENABLE_SHIFT 18
#define PLL_LOCK_ENABLE_MASK (1U << PLL_LOCK_ENABLE_SHIFT)
#define PLL_CPCON_SHIFT 8
#define PLL_CPCON_MASK (15U << PLL_CPCON_SHIFT)
#define PLL_LFCON_SHIFT 4
#define PLL_LFCON_MASK (15U << PLL_LFCON_SHIFT)
/* CPCON/LFCON replaced by KCP/KVCO in T210 PLLU */
#define PLLU_KVCO_SHIFT 24
#define PLLU_KVCO_MASK (3U << PLLU_KVCO_SHIFT)
#define PLLU_KCP_SHIFT 25
#define PLLU_KCP_MASK (1U << PLLU_KCP_SHIFT)
#define PLLU_VCO_FREQ_SHIFT 20
#define PLLU_VCO_FREQ_MASK (1U << PLLU_VCO_FREQ_SHIFT)
#define PLLP_OUT1_OVR (1 << 2)
#define PLLP_OUT2_OVR (1 << 18)
#define PLLP_OUT3_OVR (1 << 2)
@ -475,4 +446,7 @@ enum {
#define PLLDP_SS_CFG_UNDOCUMENTED (1 << 24)
#define PLLDP_SS_CFG_DITHER (1 << 28)
/* CLK_RST_PLLD_MISC */
#define PLLD_CLKENABLE 30
#endif /* _TEGRA_CLK_RST_H_ */

View File

@ -338,6 +338,27 @@ void arch_timer_init(void);
void tegra30_set_up_pllp(void);
/* Number of PLL-based clocks (i.e. not OSC or 32KHz) */
#define CLOCK_ID_PLL_COUNT (CLOCK_ID_COUNT - 2)
struct clk_pll_info {
u32 m_shift:5; /* DIVM_SHIFT */
u32 n_shift:5; /* DIVN_SHIFT */
u32 p_shift:5; /* DIVP_SHIFT */
u32 kcp_shift:5; /* KCP/cpcon SHIFT */
u32 kvco_shift:5; /* KVCO/lfcon SHIFT */
u32 lock_ena:6; /* LOCK_ENABLE/EN_LOCKDET shift */
u32 rsvd:1;
u32 m_mask:10; /* DIVM_MASK */
u32 n_mask:12; /* DIVN_MASK */
u32 p_mask:10; /* DIVP_MASK or VCO_MASK */
u32 kcp_mask:10; /* KCP/CPCON MASK */
u32 kvco_mask:10; /* KVCO/LFCON MASK */
u32 lock_det:6; /* LOCK_DETECT/LOCKED shift */
u32 rsvd2:6;
};
extern struct clk_pll_info tegra_pll_info_table[CLOCK_ID_PLL_COUNT];
/**
* Enable output clock for external peripherals
*

View File

@ -25,6 +25,7 @@ enum clock_id {
CLOCK_ID_XCPU = CLOCK_ID_FIRST_SIMPLE,
CLOCK_ID_EPCI,
CLOCK_ID_SFROM32KHZ,
CLOCK_ID_DP,
/* These are the base clocks (inputs to the Tegra SoC) */
CLOCK_ID_32KHZ,

View File

@ -101,6 +101,7 @@ int clock_ll_read_pll(enum clock_id clkid, u32 *divm, u32 *divn,
u32 *divp, u32 *cpcon, u32 *lfcon)
{
struct clk_pll *pll = get_pll(clkid);
struct clk_pll_info *pllinfo = &tegra_pll_info_table[clkid];
u32 data;
assert(clkid != CLOCK_ID_USB);
@ -109,17 +110,14 @@ int clock_ll_read_pll(enum clock_id clkid, u32 *divm, u32 *divn,
if (!clock_id_is_pll(clkid) || clkid == CLOCK_ID_USB)
return -1;
data = readl(&pll->pll_base);
*divm = (data & PLL_DIVM_MASK) >> PLL_DIVM_SHIFT;
*divn = (data & PLL_DIVN_MASK) >> PLL_DIVN_SHIFT;
*divp = (data & PLL_DIVP_MASK) >> PLL_DIVP_SHIFT;
*divm = (data >> pllinfo->m_shift) & pllinfo->m_mask;
*divn = (data >> pllinfo->n_shift) & pllinfo->n_mask;
*divp = (data >> pllinfo->p_shift) & pllinfo->p_mask;
data = readl(&pll->pll_misc);
*cpcon = (data & PLL_CPCON_MASK) >> PLL_CPCON_SHIFT;
*lfcon = (data & PLL_LFCON_MASK) >> PLL_LFCON_SHIFT;
#if defined(CONFIG_TEGRA210)
/* T210 PLLU uses KCP/KVCO instead of CPCON/LFCON */
*cpcon = (data & PLLU_KCP_MASK) >> PLLU_KCP_SHIFT;
*lfcon = (data & PLLU_KVCO_MASK) >> PLLU_KVCO_SHIFT;
#endif
/* NOTE: On T210, cpcon/lfcon no longer exist, moved to KCP/KVCO */
*cpcon = (data >> pllinfo->kcp_shift) & pllinfo->kcp_mask;
*lfcon = (data >> pllinfo->kvco_shift) & pllinfo->kvco_mask;
return 0;
}
@ -127,41 +125,25 @@ unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn,
u32 divp, u32 cpcon, u32 lfcon)
{
struct clk_pll *pll = NULL;
struct clk_pll_info *pllinfo = &tegra_pll_info_table[clkid];
u32 misc_data, data;
if (clkid < (enum clock_id)TEGRA_CLK_PLLS)
pll = get_pll(clkid);
/*
* We cheat by treating all PLL (except PLLU) in the same fashion.
* This works only because:
* - same fields are always mapped at same offsets, except DCCON
* - DCCON is always 0, doesn't conflict
* - M,N, P of PLLP values are ignored for PLLP
* NOTE: Above is no longer true with T210 - TBD: FIX THIS
* pllinfo has the m/n/p and kcp/kvco mask and shift
* values for all of the PLLs used in U-Boot, with any
* SoC differences accounted for.
*/
misc_data = (cpcon << PLL_CPCON_SHIFT) | (lfcon << PLL_LFCON_SHIFT);
misc_data = readl(&pll->pll_misc); /* preserve EN_LOCKDET, etc. */
misc_data &= ~(pllinfo->kcp_mask << pllinfo->kcp_shift) | (cpcon << pllinfo->kcp_shift);
misc_data &= ~(pllinfo->kvco_mask << pllinfo->kvco_shift) | (lfcon << pllinfo->kvco_shift);
#if defined(CONFIG_TEGRA210)
/* T210 PLLU uses KCP/KVCO instead of cpcon/lfcon */
if (clkid == CLOCK_ID_USB) {
/* preserve EN_LOCKDET, set by default */
misc_data = readl(&pll->pll_misc);
misc_data |= (cpcon << PLLU_KCP_SHIFT) |
(lfcon << PLLU_KVCO_SHIFT);
}
#endif
data = (divm << PLL_DIVM_SHIFT) | (divn << PLL_DIVN_SHIFT) |
(0 << PLL_BYPASS_SHIFT) | (1 << PLL_ENABLE_SHIFT);
data = (divm << pllinfo->m_shift) | (divn << pllinfo->n_shift);
data |= divp << pllinfo->p_shift;
data |= (1 << PLL_ENABLE_SHIFT); /* BYPASS s/b 0 already */
if (clkid == CLOCK_ID_USB)
#if defined(CONFIG_TEGRA210)
data |= divp << PLLU_DIVP_SHIFT;
#else
data |= divp << PLLU_VCO_FREQ_SHIFT;
#endif
else
data |= divp << PLL_DIVP_SHIFT;
if (pll) {
writel(misc_data, &pll->pll_misc);
writel(data, &pll->pll_base);
@ -473,10 +455,9 @@ void reset_cmplx_set_enable(int cpu, int which, int reset)
unsigned clock_get_rate(enum clock_id clkid)
{
struct clk_pll *pll;
u32 base;
u32 divm;
u64 parent_rate;
u64 rate;
u32 base, divm;
u64 parent_rate, rate;
struct clk_pll_info *pllinfo = &tegra_pll_info_table[clkid];
parent_rate = osc_freq[clock_get_osc_freq()];
if (clkid == CLOCK_ID_OSC)
@ -487,13 +468,13 @@ unsigned clock_get_rate(enum clock_id clkid)
return 0;
base = readl(&pll->pll_base);
/* Oh for bf_unpack()... */
rate = parent_rate * ((base & PLL_DIVN_MASK) >> PLL_DIVN_SHIFT);
divm = (base & PLL_DIVM_MASK) >> PLL_DIVM_SHIFT;
if (clkid == CLOCK_ID_USB)
divm <<= (base & PLLU_VCO_FREQ_MASK) >> PLLU_VCO_FREQ_SHIFT;
else
divm <<= (base & PLL_DIVP_MASK) >> PLL_DIVP_SHIFT;
rate = parent_rate * ((base >> pllinfo->n_shift) & pllinfo->n_mask);
divm = (base >> pllinfo->m_shift) & pllinfo->m_mask;
/*
* PLLU uses p_mask/p_shift for VCO on all but T210,
* T210 uses normal DIVP. Handled in pllinfo table.
*/
divm <<= (base >> pllinfo->p_shift) & pllinfo->p_mask;
do_div(rate, divm);
return rate;
}
@ -517,23 +498,23 @@ unsigned clock_get_rate(enum clock_id clkid)
*/
int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon)
{
u32 base_reg;
u32 misc_reg;
u32 base_reg, misc_reg;
struct clk_pll *pll;
struct clk_pll_info *pllinfo = &tegra_pll_info_table[clkid];
pll = get_pll(clkid);
base_reg = readl(&pll->pll_base);
/* Set BYPASS, m, n and p to PLL_BASE */
base_reg &= ~PLL_DIVM_MASK;
base_reg |= m << PLL_DIVM_SHIFT;
base_reg &= ~(pllinfo->m_mask << pllinfo->m_shift);
base_reg |= m << pllinfo->m_shift;
base_reg &= ~PLL_DIVN_MASK;
base_reg |= n << PLL_DIVN_SHIFT;
base_reg &= ~(pllinfo->n_mask << pllinfo->n_shift);
base_reg |= n << pllinfo->n_shift;
base_reg &= ~PLL_DIVP_MASK;
base_reg |= p << PLL_DIVP_SHIFT;
base_reg &= ~(pllinfo->p_mask << pllinfo->p_shift);
base_reg |= p << pllinfo->p_shift;
if (clkid == CLOCK_ID_PERIPH) {
/*
@ -552,17 +533,10 @@ int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon)
base_reg |= PLL_BYPASS_MASK;
writel(base_reg, &pll->pll_base);
/* Set cpcon to PLL_MISC */
/* Set cpcon (KCP) to PLL_MISC */
misc_reg = readl(&pll->pll_misc);
#if !defined(CONFIG_TEGRA210)
misc_reg &= ~PLL_CPCON_MASK;
misc_reg |= cpcon << PLL_CPCON_SHIFT;
#else
/* T210 uses KCP instead, use the most common bit shift (PLLA/U/D2) */
misc_reg &= ~PLLU_KCP_MASK;
misc_reg |= cpcon << PLLU_KCP_SHIFT;
#endif
misc_reg &= ~(pllinfo->kcp_mask << pllinfo->kcp_shift);
misc_reg |= cpcon << pllinfo->kcp_shift;
writel(misc_reg, &pll->pll_misc);
/* Enable PLL */

View File

@ -181,6 +181,7 @@ static inline void pllx_set_iddq(void)
int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,
u32 divp, u32 cpcon)
{
struct clk_pll_info *pllinfo = &tegra_pll_info_table[CLOCK_ID_XCPU];
int chip = tegra_get_chip();
u32 reg;
debug("%s entry\n", __func__);
@ -194,17 +195,21 @@ int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,
pllx_set_iddq();
/* Set BYPASS, m, n and p to PLLX_BASE */
reg = PLL_BYPASS_MASK | (divm << PLL_DIVM_SHIFT);
reg |= ((divn << PLL_DIVN_SHIFT) | (divp << PLL_DIVP_SHIFT));
reg = PLL_BYPASS_MASK | (divm << pllinfo->m_shift);
reg |= (divn << pllinfo->n_shift) | (divp << pllinfo->p_shift);
writel(reg, &pll->pll_base);
/* Set cpcon to PLLX_MISC */
if (chip == CHIPID_TEGRA20 || chip == CHIPID_TEGRA30)
reg = (cpcon << PLL_CPCON_SHIFT);
reg = (cpcon << pllinfo->kcp_shift);
else
reg = 0;
/* Set dccon to PLLX_MISC if freq > 600MHz */
/*
* TODO(twarren@nvidia.com) Check which SoCs use DCCON
* and add to pllinfo table if needed!
*/
/* Set dccon to PLLX_MISC if freq > 600MHz */
if (divn > 600)
reg |= (1 << PLL_DCCON_SHIFT);
writel(reg, &pll->pll_misc);
@ -215,9 +220,10 @@ int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,
writel(reg, &pll->pll_base);
debug("%s: base = 0x%08X\n", __func__, reg);
/* Set lock_enable to PLLX_MISC */
/* Set lock_enable to PLLX_MISC if lock_ena is valid (i.e. 0-31) */
reg = readl(&pll->pll_misc);
reg |= PLL_LOCK_ENABLE_MASK;
if (pllinfo->lock_ena < 32)
reg |= (1 << pllinfo->lock_ena);
writel(reg, &pll->pll_misc);
debug("%s: misc = 0x%08X\n", __func__, reg);

View File

@ -1,17 +1,8 @@
/*
* Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved.
* (C) Copyright 2010-2015
* NVIDIA Corporation <www.nvidia.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-2.0+
*/
/* Tegra114 Clock control functions */
@ -434,6 +425,36 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
NONE(EMC1),
};
/*
* PLL divider shift/mask tables for all PLL IDs.
*/
struct clk_pll_info tegra_pll_info_table[CLOCK_ID_PLL_COUNT] = {
/*
* T114: some deviations from T2x/T30.
* NOTE: If kcp_mask/kvco_mask == 0, they're not used in that PLL (PLLX, etc.)
* If lock_ena or lock_det are >31, they're not used in that PLL.
*/
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x0F,
.lock_ena = 24, .lock_det = 27, .kcp_shift = 28, .kcp_mask = 3, .kvco_shift = 27, .kvco_mask = 1 }, /* PLLC */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 0, .p_mask = 0,
.lock_ena = 0, .lock_det = 27, .kcp_shift = 1, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLM */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLP */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLA */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x01,
.lock_ena = 22, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLU */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 22, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLD */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x0F,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 0, .kcp_mask = 0, .kvco_shift = 0, .kvco_mask = 0 }, /* PLLX */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 0, .p_mask = 0,
.lock_ena = 9, .lock_det = 11, .kcp_shift = 6, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLE */
{ .m_shift = 0, .m_mask = 0x0F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLS (RESERVED) */
};
/*
* Get the oscillator frequency, from the corresponding hardware configuration
* field. Note that T30/T114 support 3 new higher freqs, but we map back
@ -603,6 +624,8 @@ void clock_early_init(void)
{
struct clk_rst_ctlr *clkrst =
(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
struct clk_pll_info *pllinfo;
u32 data;
tegra30_set_up_pllp();
@ -639,11 +662,15 @@ void clock_early_init(void)
writel(0x00561600, &clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_out[1]);
/* PLLC_MISC: Set LOCK_ENABLE */
writel(0x01000000, &clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_misc);
pllinfo = &tegra_pll_info_table[CLOCK_ID_CGENERAL];
setbits_le32(&clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_misc, (1 << pllinfo->lock_ena));
udelay(2);
/* PLLD_MISC: Set CLKENABLE, CPCON 12, LFCON 1 */
writel(0x40000C10, &clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_misc);
/* PLLD_MISC: Set CLKENABLE, CPCON 12, LFCON 1, and enable lock */
pllinfo = &tegra_pll_info_table[CLOCK_ID_DISPLAY];
data = (12 << pllinfo->kcp_shift) | (1 << pllinfo->kvco_shift);
data |= (1 << PLLD_CLKENABLE) | (1 << pllinfo->lock_ena);
writel(data, &clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_misc);
udelay(2);
}

View File

@ -1,17 +1,8 @@
/*
* Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved.
* (C) Copyright 2010-2014
* NVIDIA Corporation <www.nvidia.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
@ -31,7 +22,7 @@ static void enable_cpu_power_rail(void)
struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
u32 reg;
debug("enable_cpu_power_rail entry\n");
debug("%s entry\n", __func__);
/* un-tristate PWR_I2C SCL/SDA, rest of the defaults are correct */
pinmux_tristate_disable(PMUX_PINGRP_PWR_I2C_SCL_PZ6);
@ -61,14 +52,15 @@ static void enable_cpu_power_rail(void)
static void enable_cpu_clocks(void)
{
struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
struct clk_pll_info *pllinfo = &tegra_pll_info_table[CLOCK_ID_XCPU];
u32 reg;
debug("enable_cpu_clocks entry\n");
debug("%s entry\n", __func__);
/* Wait for PLL-X to lock */
do {
reg = readl(&clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base);
} while ((reg & PLL_LOCK_MASK) == 0);
} while ((reg & (1 << pllinfo->lock_det)) == 0);
/* Wait until all clocks are stable */
udelay(PLL_STABILIZATION_DELAY);
@ -87,7 +79,7 @@ static void remove_cpu_resets(void)
struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
u32 reg;
debug("remove_cpu_resets entry\n");
debug("%s entry\n", __func__);
/* Take the slow non-CPU partition out of reset */
reg = readl(&clkrst->crc_rst_cpulp_cmplx_clr);
writel((reg | CLR_NONCPURESET), &clkrst->crc_rst_cpulp_cmplx_clr);
@ -111,7 +103,7 @@ static void remove_cpu_resets(void)
}
/**
* The T114 requires some special clock initialization, including setting up
* Tegra114 requires some special clock initialization, including setting up
* the DVC I2C, turning on MSELECT and selecting the G CPU cluster
*/
void t114_init_clocks(void)
@ -121,7 +113,7 @@ void t114_init_clocks(void)
struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
u32 val;
debug("t114_init_clocks entry\n");
debug("%s entry\n", __func__);
/* Set active CPU cluster to G */
clrbits_le32(&flow->cluster_control, 1);
@ -189,7 +181,7 @@ void t114_init_clocks(void)
reset_set_enable(PERIPH_ID_MC1, 0);
reset_set_enable(PERIPH_ID_DVFS, 0);
debug("t114_init_clocks exit\n");
debug("%s exit\n", __func__);
}
static bool is_partition_powered(u32 partid)
@ -238,10 +230,9 @@ static void power_partition(u32 partid)
void powerup_cpus(void)
{
debug("powerup_cpus entry\n");
/* We boot to the fast cluster */
debug("powerup_cpus entry: G cluster\n");
debug("%s entry: G cluster\n", __func__);
/* Power up the fast cluster rail partition */
power_partition(CRAIL);
@ -256,7 +247,7 @@ void start_cpu(u32 reset_vector)
{
u32 imme, inst;
debug("start_cpu entry, reset_vector = %x\n", reset_vector);
debug("%s entry, reset_vector = %x\n", __func__, reset_vector);
t114_init_clocks();
@ -302,7 +293,7 @@ void start_cpu(u32 reset_vector)
inst |= 0xea000000;
writel(inst, 0x4003fffc);
/* Write to orignal location for compatibility */
/* Write to original location for compatibility */
writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR);
/* If the CPU(s) don't already have power, power 'em up */

View File

@ -1,5 +1,5 @@
/*
* (C) Copyright 2013
* (C) Copyright 2013-2015
* NVIDIA Corporation <www.nvidia.com>
*
* SPDX-License-Identifier: GPL-2.0+
@ -565,6 +565,36 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
NONE(X_RESERVED31),
};
/*
* PLL divider shift/mask tables for all PLL IDs.
*/
struct clk_pll_info tegra_pll_info_table[CLOCK_ID_PLL_COUNT] = {
/*
* T124: same as T114, some deviations from T2x/T30.
* NOTE: If kcp_mask/kvco_mask == 0, they're not used in that PLL (PLLX, etc.)
* If lock_ena or lock_det are >31, they're not used in that PLL.
*/
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x0F,
.lock_ena = 24, .lock_det = 27, .kcp_shift = 28, .kcp_mask = 3, .kvco_shift = 27, .kvco_mask = 1 }, /* PLLC */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 0, .p_mask = 0,
.lock_ena = 0, .lock_det = 27, .kcp_shift = 1, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLM */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLP */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLA */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x01,
.lock_ena = 22, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLU */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 22, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLD */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x0F,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 0, .kcp_mask = 0, .kvco_shift = 0, .kvco_mask = 0 }, /* PLLX */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 0, .p_mask = 0,
.lock_ena = 9, .lock_det = 11, .kcp_shift = 6, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLE */
{ .m_shift = 0, .m_mask = 0x0F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLS (RESERVED) */
};
/*
* Get the oscillator frequency, from the corresponding hardware configuration
* field. Note that Tegra30+ support 3 new higher freqs, but we map back
@ -772,6 +802,8 @@ void clock_early_init(void)
{
struct clk_rst_ctlr *clkrst =
(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
struct clk_pll_info *pllinfo;
u32 data;
tegra30_set_up_pllp();
@ -808,11 +840,15 @@ void clock_early_init(void)
writel(0x00561600, &clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_out[1]);
/* PLLC_MISC: Set LOCK_ENABLE */
writel(0x01000000, &clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_misc);
pllinfo = &tegra_pll_info_table[CLOCK_ID_CGENERAL];
setbits_le32(&clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_misc, (1 << pllinfo->lock_ena));
udelay(2);
/* PLLD_MISC: Set CLKENABLE, CPCON 12, LFCON 1 */
writel(0x40000C10, &clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_misc);
/* PLLD_MISC: Set CLKENABLE, CPCON 12, LFCON 1, and enable lock */
pllinfo = &tegra_pll_info_table[CLOCK_ID_DISPLAY];
data = (12 << pllinfo->kcp_shift) | (1 << pllinfo->kvco_shift);
data |= (1 << PLLD_CLKENABLE) | (1 << pllinfo->lock_ena);
writel(data, &clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_misc);
udelay(2);
}

View File

@ -23,7 +23,7 @@ static void enable_cpu_power_rail(void)
{
struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
debug("enable_cpu_power_rail entry\n");
debug("%s entry\n", __func__);
/* un-tristate PWR_I2C SCL/SDA, rest of the defaults are correct */
pinmux_tristate_disable(PMUX_PINGRP_PWR_I2C_SCL_PZ6);
@ -45,15 +45,16 @@ static void enable_cpu_power_rail(void)
static void enable_cpu_clocks(void)
{
struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
struct clk_pll_info *pllinfo = &tegra_pll_info_table[CLOCK_ID_XCPU];
u32 reg;
debug("enable_cpu_clocks entry\n");
debug("%s entry\n", __func__);
/* Wait for PLL-X to lock */
do {
reg = readl(&clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base);
debug("%s: PLLX base = 0x%08X\n", __func__, reg);
} while ((reg & PLL_LOCK_MASK) == 0);
} while ((reg & (1 << pllinfo->lock_det)) == 0);
debug("%s: PLLX locked, delay for stable clocks\n", __func__);
/* Wait until all clocks are stable */
@ -83,7 +84,7 @@ static void remove_cpu_resets(void)
struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
u32 reg;
debug("remove_cpu_resets entry\n");
debug("%s entry\n", __func__);
/* Take the slow and fast partitions out of reset */
reg = CLR_NONCPURESET;
@ -105,7 +106,7 @@ static void remove_cpu_resets(void)
}
/**
* The Tegra124 requires some special clock initialization, including setting up
* Tegra124 requires some special clock initialization, including setting up
* the DVC I2C, turning on MSELECT and selecting the G CPU cluster
*/
void tegra124_init_clocks(void)
@ -116,7 +117,7 @@ void tegra124_init_clocks(void)
(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
u32 val;
debug("tegra124_init_clocks entry\n");
debug("%s entry\n", __func__);
/* Set active CPU cluster to G */
clrbits_le32(&flow->cluster_control, 1);
@ -188,7 +189,7 @@ void tegra124_init_clocks(void)
reset_set_enable(PERIPH_ID_MSELECT, 0);
reset_set_enable(PERIPH_ID_DVFS, 0);
debug("tegra124_init_clocks exit\n");
debug("%s exit\n", __func__);
}
static bool is_partition_powered(u32 partid)
@ -223,31 +224,29 @@ static void power_partition(u32 partid)
void powerup_cpus(void)
{
debug("powerup_cpus entry\n");
/* We boot to the fast cluster */
debug("powerup_cpus entry: G cluster\n");
debug("%s entry: G cluster\n", __func__);
/* Power up the fast cluster rail partition */
debug("powerup_cpus: CRAIL\n");
debug("%s: CRAIL\n", __func__);
power_partition(CRAIL);
/* Power up the fast cluster non-CPU partition */
debug("powerup_cpus: C0NC\n");
debug("%s: C0NC\n", __func__);
power_partition(C0NC);
/* Power up the fast cluster CPU0 partition */
debug("powerup_cpus: CE0\n");
debug("%s: CE0\n", __func__);
power_partition(CE0);
debug("powerup_cpus: done\n");
debug("%s: done\n", __func__);
}
void start_cpu(u32 reset_vector)
{
struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
debug("start_cpu entry, reset_vector = %x\n", reset_vector);
debug("%s entry, reset_vector = %x\n", __func__, reset_vector);
tegra124_init_clocks();
@ -261,5 +260,5 @@ void start_cpu(u32 reset_vector)
remove_cpu_resets();
writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR);
powerup_cpus();
debug("start_cpu exit, should continue @ reset_vector\n");
debug("%s exit, should continue @ reset_vector\n", __func__);
}

View File

@ -1,5 +1,7 @@
/*
* Copyright (c) 2011 The Chromium OS Authors.
* (C) Copyright 2010-2015
* NVIDIA Corporation <www.nvidia.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
@ -354,6 +356,36 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
NONE(CRAM2),
};
/*
* PLL divider shift/mask tables for all PLL IDs.
*/
struct clk_pll_info tegra_pll_info_table[CLOCK_ID_PLL_COUNT] = {
/*
* T20 and T25
* NOTE: If kcp_mask/kvco_mask == 0, they're not used in that PLL (PLLX, etc.)
* If lock_ena or lock_det are >31, they're not used in that PLL.
*/
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x0F,
.lock_ena = 24, .lock_det = 27, .kcp_shift = 28, .kcp_mask = 3, .kvco_shift = 27, .kvco_mask = 1 }, /* PLLC */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 0, .p_mask = 0,
.lock_ena = 0, .lock_det = 27, .kcp_shift = 1, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLM */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLP */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLA */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x01,
.lock_ena = 22, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLU */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 22, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLD */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x0F,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 0, .kvco_mask = 0 }, /* PLLX */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 0, .p_mask = 0,
.lock_ena = 9, .lock_det = 11, .kcp_shift = 6, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLE */
{ .m_shift = 0, .m_mask = 0x0F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 18, .lock_det = 0, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLS */
};
/*
* Get the oscillator frequency, from the corresponding hardware configuration
* field. T20 has 4 frequencies that it supports.

View File

@ -630,6 +630,34 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
NONE(Y_RESERVED31),
};
/*
* PLL divider shift/mask tables for all PLL IDs.
*/
struct clk_pll_info tegra_pll_info_table[CLOCK_ID_PLL_COUNT] = {
/*
* NOTE: If kcp_mask/kvco_mask == 0, they're not used in that PLL (PLLC, etc.)
* If lock_ena or lock_det are >31, they're not used in that PLL (PLLC, etc.)
*/
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 10, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x1F,
.lock_ena = 32, .lock_det = 27, .kcp_shift = 0, .kcp_mask = 0, .kvco_shift = 0, .kvco_mask = 0 }, /* PLLC */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x1F,
.lock_ena = 4, .lock_det = 27, .kcp_shift = 1, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLM */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 10, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x1F,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 0, .kcp_mask = 3, .kvco_shift = 2, .kvco_mask = 1 }, /* PLLP */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x1F,
.lock_ena = 28, .lock_det = 27, .kcp_shift = 25, .kcp_mask = 3, .kvco_shift = 24, .kvco_mask = 1 }, /* PLLA */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 16, .p_mask = 0x1F,
.lock_ena = 29, .lock_det = 27, .kcp_shift = 25, .kcp_mask = 3, .kvco_shift = 24, .kvco_mask = 1 }, /* PLLU */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 11, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 23, .kcp_mask = 3, .kvco_shift = 22, .kvco_mask = 1 }, /* PLLD */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x1F,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 1, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLX */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 0, .p_mask = 0,
.lock_ena = 9, .lock_det = 11, .kcp_shift = 6, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLE */
{ .m_shift = 0, .m_mask = 0, .n_shift = 0, .n_mask = 0, .p_shift = 0, .p_mask = 0,
.lock_ena = 0, .lock_det = 0, .kcp_shift = 0, .kcp_mask = 0, .kvco_shift = 0, .kvco_mask = 0 }, /* PLLS (gone)*/
};
/*
* Get the oscillator frequency, from the corresponding hardware configuration
* field. Note that Tegra30+ support 3 new higher freqs, but we map back
@ -903,6 +931,7 @@ void clock_early_init(void)
{
struct clk_rst_ctlr *clkrst =
(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
struct clk_pll_info *pllinfo = &tegra_pll_info_table[CLOCK_ID_DISPLAY];
u32 data;
tegra210_setup_pllp();
@ -957,7 +986,7 @@ void clock_early_init(void)
udelay(2);
/* PLLD_MISC: Set CLKENABLE and LOCK_DETECT bits */
data = (1 << PLLD_ENABLE_CLK) | (1 << PLLD_EN_LCKDET);
data = (1 << PLLD_ENABLE_CLK) | (1 << pllinfo->lock_ena);
writel(data, &clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_misc);
udelay(2);
}

View File

@ -1,17 +1,8 @@
/*
* Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved.
* (C) Copyright 2010-2015
* NVIDIA Corporation <www.nvidia.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-2.0+
*/
/* Tegra30 Clock control functions */
@ -414,6 +405,36 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
NONE(EX_RESERVED47),
};
/*
* PLL divider shift/mask tables for all PLL IDs.
*/
struct clk_pll_info tegra_pll_info_table[CLOCK_ID_PLL_COUNT] = {
/*
* T30: some deviations from T2x.
* NOTE: If kcp_mask/kvco_mask == 0, they're not used in that PLL (PLLX, etc.)
* If lock_ena or lock_det are >31, they're not used in that PLL.
*/
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x0F,
.lock_ena = 24, .lock_det = 27, .kcp_shift = 28, .kcp_mask = 3, .kvco_shift = 27, .kvco_mask = 1 }, /* PLLC */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 0, .p_mask = 0,
.lock_ena = 0, .lock_det = 27, .kcp_shift = 1, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLM */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLP */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLA */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x01,
.lock_ena = 22, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLU */
{ .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 22, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLD */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x0F,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 0, .kvco_mask = 0 }, /* PLLX */
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 0, .p_mask = 0,
.lock_ena = 9, .lock_det = 11, .kcp_shift = 6, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLE */
{ .m_shift = 0, .m_mask = 0x0F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
.lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLS (RESERVED) */
};
/*
* Get the oscillator frequency, from the corresponding hardware configuration
* field. Note that T30 supports 3 new higher freqs, but we map back