diff --git a/src/soc/nvidia/tegra132/Kconfig b/src/soc/nvidia/tegra132/Kconfig index 638fb65729..b746037f78 100644 --- a/src/soc/nvidia/tegra132/Kconfig +++ b/src/soc/nvidia/tegra132/Kconfig @@ -113,4 +113,8 @@ config BOOTROM_SDRAM_INIT help Use during Ryu LPDDR3 bringup +# Default to 700MHz. This value is based on nv bootloader setting. +config PLLX_KHZ + int + default 700000 endif diff --git a/src/soc/nvidia/tegra132/clock.c b/src/soc/nvidia/tegra132/clock.c index a8cabe5d82..fb8e85feee 100644 --- a/src/soc/nvidia/tegra132/clock.c +++ b/src/soc/nvidia/tegra132/clock.c @@ -22,12 +22,14 @@ #include #include #include "clk_rst.h" +#include "clst_clk.h" #include "flow.h" #include "maincpu.h" #include "pmc.h" #include "sysctr.h" static struct clk_rst_ctlr *clk_rst = (void *)TEGRA_CLK_RST_BASE; +static struct clst_clk_ctlr *clst_clk = (void *)TEGRA_CLUSTER_CLOCK_BASE; static struct flow_ctlr *flow = (void *)TEGRA_FLOW_BASE; static struct tegra_pmc_regs *pmc = (void *)TEGRA_PMC_BASE; static struct sysctr_regs *sysctr = (void *)TEGRA_SYSCTR0_BASE; @@ -474,6 +476,45 @@ void clock_sdram(u32 m, u32 n, u32 p, u32 setup, u32 ph45, u32 ph90, udelay(IO_STABILIZATION_DELAY); } +void clock_cpu0_config(void) +{ + u32 reg; + u32 osc = clock_get_osc_bits(); + u32 timeout = 0; + + /* disable IDDQ */ + reg = readl(&clst_clk->pllx_misc3); + reg &= ~PLLX_IDDQ; + writel(reg, &clst_clk->pllx_misc3); + + /* init pllx */ + init_pll(&clst_clk->pllx_base, &clst_clk->pllx_misc, + osc_table[osc].pllx, PLLPAXS_MISC_LOCK_ENABLE); + + /* + * Change CPU clock source to PLLX_OUT0_LJ + * when above pllx programming has taken effect. + */ + do { + if (readl(&clst_clk->misc_ctrl) & CLK_SWITCH_MATCH) { + write32((CC_CCLK_BRST_POL_PLLX_OUT0_LJ << 28), + &clst_clk->cclk_brst_pol); + break; + } + + /* wait and try again */ + if (timeout >= CLK_SWITCH_TIMEOUT_US) { + printk(BIOS_ERR, "%s: PLLX programming timeout. " + "Switching cpu clock has falied.\n", + __func__); + break; + } + udelay(10); + timeout += 10; + + } while (1); +} + void clock_halt_avp(void) { for (;;) diff --git a/src/soc/nvidia/tegra132/clst_clk.h b/src/soc/nvidia/tegra132/clst_clk.h new file mode 100644 index 0000000000..151ead6341 --- /dev/null +++ b/src/soc/nvidia/tegra132/clst_clk.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _TEGRA132_CLST_CLK_H_ +#define _TEGRA132_CLST_CLK_H_ + +/* Cluster Clock (CLUSTER_CLOCKS_PUBLIC_) regs */ +struct __attribute__ ((__packed__)) clst_clk_ctlr { + u32 pllx_base; /* _PLLX_BASE, 0x000 */ + u32 pllx_misc; /* _PLLX_MISC, 0x004 */ + u32 pllx_misc1; /* _PLLX_MISC_1, 0x008 */ + u32 pllx_misc2; /* _PLLX_MISC_2, 0x00c */ + u32 pllx_misc3; /* _PLLX_MISC_3, 0x010 */ + u32 pllx_hw_ctrl_cfg; /* _PLLX_HW_CTRL_CFG, 0x014 */ + u32 pllx_sw_ramp_cfg; /* _PLLX_SW_RAMP_CFG, 0x018 */ + u32 pllx_hw_ctrl_status; /* _PLLX_HW_CTRL_STATUS, 0x01c */ + u32 cclk_brst_pol; /* _CCLK_BURST_POLICY, 0x020 */ + u32 super_cclk_div; /* _SUPER_CCLK_DIVIDER, 0x024 */ + u32 _rsv1[10]; /* 0x028-04c */ + u32 shaper; /* _SHAPER, 0x050 */ + u32 shaper1; /* _SHAPER_1, 0x054 */ + u32 _rsv2[80]; /* 0x058-194 */ + u32 misc_ctrl; /* _MISC_CTRL, 0x198 */ +}; +check_member(clst_clk_ctlr, misc_ctrl, 0x198); + +/* CC_CCLK_BRST_POL */ +enum { + CC_CCLK_BRST_POL_PLLX_OUT0_LJ = 0x8, +}; + +/* CC_SUPER_CCLK_DIVIDER */ +enum { + CC_SUPER_CCLK_DIVIDER_SUPER_CDIV_ENB = 1 << 31 +}; + +/* PLLX_MISC3 */ +enum { + PLLX_IDDQ = 1 << 3, +}; + +/* MISC_CTRL */ +enum { + CLK_SWITCH_MATCH = 1 << 5, +}; + +#define CLK_SWITCH_TIMEOUT_US 1000 +#endif /* _TEGRA132_CLST_CLK_H_ */ diff --git a/src/soc/nvidia/tegra132/include/soc/addressmap.h b/src/soc/nvidia/tegra132/include/soc/addressmap.h index 52e4d54356..f5f72db7e4 100644 --- a/src/soc/nvidia/tegra132/include/soc/addressmap.h +++ b/src/soc/nvidia/tegra132/include/soc/addressmap.h @@ -70,7 +70,8 @@ enum { TEGRA_FUSE_BASE = TEGRA_APB_MISC_BASE + 0xF800, TEGRA_MC_BASE = 0x70019000, TEGRA_EMC_BASE = 0x7001B000, - TEGRA_CSITE_BASE = 0x70040000, + TEGRA_CLUSTER_CLOCK_BASE = 0x70040000, + TEGRA_CSITE_BASE = 0x70800000, TEGRA_SYSCTR0_BASE = 0x700F0000, TEGRA_USBD_BASE = 0x7D000000, TEGRA_USB2_BASE = 0x7D004000, diff --git a/src/soc/nvidia/tegra132/include/soc/clock.h b/src/soc/nvidia/tegra132/include/soc/clock.h index 6f69fefbc6..5259c18011 100644 --- a/src/soc/nvidia/tegra132/include/soc/clock.h +++ b/src/soc/nvidia/tegra132/include/soc/clock.h @@ -285,7 +285,7 @@ void clock_external_output(int clk_id); void clock_sdram(u32 m, u32 n, u32 p, u32 setup, u32 ph45, u32 ph90, u32 ph135, u32 kvco, u32 kcp, u32 stable_time, u32 emc_source, u32 same_freq); -void clock_cpu0_config_and_reset(void * entry); +void clock_cpu0_config(void); void clock_halt_avp(void); void clock_enable_clear_reset(u32 l, u32 h, u32 u, u32 v, u32 w, u32 x); void clock_reset_l(u32 l); diff --git a/src/soc/nvidia/tegra132/ramstage.c b/src/soc/nvidia/tegra132/ramstage.c index b3b4db2c86..40d80ff8b8 100644 --- a/src/soc/nvidia/tegra132/ramstage.c +++ b/src/soc/nvidia/tegra132/ramstage.c @@ -20,10 +20,13 @@ #include #include #include "mmu_operations.h" +#include void arm64_soc_init(void) { trustzone_region_init(); tegra132_mmu_init(); + + clock_cpu0_config(); }