Tegra124: Add support for the ARM architectural timer.

The kernel knows how to use the ARM architectural timer in a generic way, but
some setup is needed which is specific to the implementation. The tegra code
in the kernel doesn't configure those parts so we need to, or the kernel
behaves poorly.

BUG=None
TEST=Before this change, the kernel would hang, the watch dog timer would go
off and kill the machine, and/or there would be random seeming crashes and
instability. After this change those problems were essentially gone.
BRANCH=None

Change-Id: Ibe0dccc964771b0a4a2376be9940192a4dfa6c43
Signed-off-by: Gabe Black <gabeblack@google.com>
Reviewed-on: https://chromium-review.googlesource.com/174835
Reviewed-by: Gabe Black <gabeblack@chromium.org>
Commit-Queue: Gabe Black <gabeblack@chromium.org>
Tested-by: Gabe Black <gabeblack@chromium.org>
This commit is contained in:
Gabe Black 2013-10-26 07:50:47 -07:00 committed by chrome-internal-fetch
commit 25a91fcf7e
4 changed files with 73 additions and 1 deletions

View file

@ -22,6 +22,7 @@
#include "cpug.h"
#include "flow.h"
#include "pmc.h"
#include "sysctr.h"
/* Warning: Some devices just use different bits for the same sources for no
* apparent reason. *Always* double-check the TRM before trusting this macro. */
@ -32,7 +33,8 @@
static struct clk_rst_ctlr *clk_rst = (void *)TEGRA_CLK_RST_BASE;
static struct flow_ctlr *flow = (void *)TEGRA_FLOW_BASE;
static struct tegra_pmc_regs *pmc = (void*)TEGRA_PMC_BASE;
static struct tegra_pmc_regs *pmc = (void *)TEGRA_PMC_BASE;
static struct sysctr_regs *sysctr = (void *)TEGRA_SYSCTR0_BASE;
struct pll_dividers {
u32 n : 10;
@ -164,6 +166,20 @@ int clock_get_osc_khz(void)
return osc_table[clock_get_osc_bits()].khz;
}
void clock_init_arm_generic_timer(void)
{
uint32_t freq = clock_get_osc_khz() * 1000;
// Set the cntfrq register.
__asm__ __volatile__("mcr p15, 0, %0, c14, c0, 0\n" :: "r"(freq));
// Record the system timer frequency.
write32(freq, &sysctr->cntfid0);
// Enable the system counter.
uint32_t cntcr = read32(&sysctr->cntcr);
cntcr |= SYSCTR_CNTCR_EN | SYSCTR_CNTCR_HDBG;
write32(cntcr, &sysctr->cntcr);
}
static void adjust_pllp_out_freqs(void)
{
u32 reg;

View file

@ -67,6 +67,7 @@ enum {
TEGRA_EMC_BASE = TEGRA_APB_MISC_BASE + 0xF400,
TEGRA_FUSE_BASE = TEGRA_APB_MISC_BASE + 0xF800,
TEGRA_CSITE_BASE = 0x70040000,
TEGRA_SYSCTR0_BASE = 0x700F0000,
TEGRA_USB_ADDR_MASK = 0xFFFFC000,
};

View file

@ -180,4 +180,5 @@ void clock_early_uart(void);
void clock_cpu0_config_and_reset(void * entry);
void clock_config(void);
void clock_init(void);
void clock_init_arm_generic_timer(void);
#endif /* __SOC_NVIDIA_TEGRA124_CLOCK_H__ */

View file

@ -0,0 +1,54 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2013 Google Inc.
*
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __SOC_NVIDIA_TEGRA124_SYSCTR_H__
#define __SOC_NVIDIA_TEGRA124_SYSCTR_H__
#include <stdint.h>
enum {
SYSCTR_CNTCR_EN = 1 << 0,
SYSCTR_CNTCR_HDBG = 1 << 1,
SYSCTR_CNTCR_FCREQ = 1 << 8
};
struct sysctr_regs {
uint32_t cntcr;
uint32_t cntsr;
uint32_t cntcv0;
uint32_t cntcv1;
uint8_t _rsv0[0x10];
uint32_t cntfid0;
uint32_t cntfid1;
uint8_t _rsv1[0xfa8];
uint32_t counterid4;
uint32_t counterid5;
uint32_t counterid6;
uint32_t counterid7;
uint32_t counterid0;
uint32_t counterid1;
uint32_t counterid2;
uint32_t counterid3;
uint32_t counterid8;
uint32_t counterid9;
uint32_t counterid10;
uint32_t counterid11;
};
#endif /* __SOC_NVIDIA_TEGRA124_SYSCTR_H__ */