diff options
author | Simon Glass <sjg@chromium.org> | 2011-08-30 13:09:35 -0700 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2011-09-09 16:25:32 -0700 |
commit | 3e0b94b7749377b21c6439035095ff27086a8377 (patch) | |
tree | d33c4fc28332f12ea1594c56221a3acbb615fde0 /arch/arm/cpu/armv7/tegra2 | |
parent | 5e233dd81ddde6d72151499e4a7591e8b6332ddb (diff) |
tegra: Move tegra2 files into tegra-common
This code is required for Tegra30 also, so we move it into a common
directory.
BUG=chromium-os:19004
TEST=build and boot on Seaboard
Change-Id: I9af13892861f54c0d7da6d4f9ee0715bc5ab6357
Reviewed-on: http://gerrit.chromium.org/gerrit/7124
Reviewed-by: Yen Lin <yelin@nvidia.com>
Reviewed-by: Tom Warren <twarren@nvidia.com>
Tested-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'arch/arm/cpu/armv7/tegra2')
-rw-r--r-- | arch/arm/cpu/armv7/tegra2/Makefile | 7 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/tegra2/ap20.c | 392 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/tegra2/ap20.h | 112 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/tegra2/board.c | 2 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/tegra2/clock.c | 955 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/tegra2/lowlevel_init.S | 46 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/tegra2/timer.c | 135 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/tegra2/warmboot.c | 2 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/tegra2/warmboot_avp.c | 2 |
9 files changed, 5 insertions, 1648 deletions
diff --git a/arch/arm/cpu/armv7/tegra2/Makefile b/arch/arm/cpu/armv7/tegra2/Makefile index 5812da6cac6..4e0b22f4a68 100644 --- a/arch/arm/cpu/armv7/tegra2/Makefile +++ b/arch/arm/cpu/armv7/tegra2/Makefile @@ -26,17 +26,14 @@ # The AVP is ARMv4T architecture so we must use special compiler # flags for any files it might use. -CFLAGS_arch/arm/cpu/armv7/tegra2/ap20.o += -march=armv4t -CFLAGS_arch/arm/cpu/armv7/tegra2/clock.o += -march=armv4t CFLAGS_arch/arm/cpu/armv7/tegra2/warmboot_avp.o += -march=armv4t include $(TOPDIR)/config.mk LIB = $(obj)lib$(SOC).o -SOBJS-y := lowlevel_init.o -COBJS-y := ap20.o board.o clock.o display.o pinmux.o power.o pwfm.o \ - sys_info.o timer.o +SOBJS-y := +COBJS-y := board.o display.o pinmux.o power.o pwfm.o sys_info.o COBJS-$(CONFIG_TEGRA2_LP0) += warmboot.o COBJS-$(CONFIG_TEGRA2_LP0) += warmboot_avp.o diff --git a/arch/arm/cpu/armv7/tegra2/ap20.c b/arch/arm/cpu/armv7/tegra2/ap20.c deleted file mode 100644 index f9aa610aec1..00000000000 --- a/arch/arm/cpu/armv7/tegra2/ap20.c +++ /dev/null @@ -1,392 +0,0 @@ -/* -* (C) Copyright 2010-2011 -* NVIDIA Corporation <www.nvidia.com> -* -* See file CREDITS for list of people who contributed to this -* project. -* -* 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; either version 2 of -* the License, or (at your option) any later version. -* -* 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., 59 Temple Place, Suite 330, Boston, -* MA 02111-1307 USA -*/ - -#include "ap20.h" -#include <asm/io.h> -#include <asm/arch/tegra.h> -#include <asm/arch/bitfield.h> -#include <asm/arch/clk_rst.h> -#include <asm/arch/clock.h> -#include <asm/arch/pmc.h> -#include <asm/arch/pinmux.h> -#include <asm/arch/scu.h> -#include <common.h> -#include <asm/arch/warmboot.h> -#include "../../../../../board/nvidia/common/board.h" - -struct clk_pll_table { - u16 n; - u16 m; - u8 p; - u8 cpcon; -}; - -/* ~0=uninitialized/unknown, 0=false, 1=true */ -uint32_t is_tegra2_processor_reset = 0xffffffff; - -/* - * Timing tables for each SOC for all four oscillator options. - */ -static struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_COUNT] - [CLOCK_OSC_FREQ_COUNT] = { - /* T20: 1 GHz */ - {{ 1000, 13, 0, 12}, /* OSC 13M */ - { 625, 12, 0, 8}, /* OSC 19.2M */ - { 1000, 12, 0, 12}, /* OSC 12M */ - { 1000, 26, 0, 12}, /* OSC 26M */ - }, - - /* T25: 1.2 GHz */ - {{ 923, 10, 0, 12}, - { 750, 12, 0, 8}, - { 600, 6, 0, 12}, - { 600, 13, 0, 12}, - }, -}; - -int ap20_cpu_is_cortexa9(void) -{ - u32 id = readb(NV_PA_PG_UP_BASE + PG_UP_TAG_0); - return id == (PG_UP_TAG_0_PID_CPU & 0xff); -} - -static int pllx_set_rate(struct clk_pll *pll , u32 divn, u32 divm, u32 divp, - u32 cpcon) -{ - u32 reg; - - /* Set BYPASS, m, n and p to PLLX_BASE */ - reg = bf_pack(PLL_BYPASS, 1) | bf_pack(PLL_DIVM, divm); - reg |= bf_pack(PLL_DIVN, divn) | bf_pack(PLL_DIVP, divp); - writel(reg, &pll->pll_base); - - /* Set cpcon to PLLX_MISC */ - reg = bf_pack(PLL_CPCON, cpcon); - writel(reg, &pll->pll_misc); - - /* Enable PLLX */ - reg = readl(&pll->pll_base); - reg |= bf_pack(PLL_ENABLE, 1); - - /* Disable BYPASS */ - reg &= ~bf_mask(PLL_BYPASS); - writel(reg, &pll->pll_base); - - return 0; -} - -void ap20_init_pllx(int slow) -{ - struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - struct clk_pll *pll = &clkrst->crc_pll[CLOCK_ID_XCPU]; - int chip_type; - enum clock_osc_freq osc; - struct clk_pll_table *sel; - - /* get chip type. If unknown, assign to T20 */ - chip_type = tegra_get_chip_type(); - if (slow || chip_type == TEGRA_SOC_UNKNOWN) - chip_type = TEGRA_SOC_T20; - - /* get osc freq */ - osc = clock_get_osc_freq(); - - /* set pllx */ - sel = &tegra_pll_x_table[chip_type][osc]; - pllx_set_rate(pll, sel->n, sel->m, sel->p, sel->cpcon); -} - -static void enable_cpu_clock(int enable) -{ - struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - u32 clk; - - /* - * NOTE: - * Regardless of whether the request is to enable or disable the CPU - * clock, every processor in the CPU complex except the master (CPU 0) - * will have it's clock stopped because the AVP only talks to the - * master. The AVP does not know (nor does it need to know) that there - * are multiple processors in the CPU complex. - */ - - if (enable) { - /* - * Initialize PLLX to a safe speed, as we are running at - * a lower voltage for now until we get i2c up in board_init(). - */ - ap20_init_pllx(1); - - /* Wait until all clocks are stable */ - udelay(PLL_STABILIZATION_DELAY); - - writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol); - writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div); - } - - /* - * Read the register containing the individual CPU clock enables and - * always stop the clock to CPU 1. - */ - clk = readl(&clkrst->crc_clk_cpu_cmplx); - clk |= bf_pack(CPU1_CLK_STP, 1); - - /* Stop/Unstop the CPU clock */ - bf_update(CPU0_CLK_STP, clk, enable == 0); - writel(clk, &clkrst->crc_clk_cpu_cmplx); - - clock_enable(PERIPH_ID_CPU); -} - -static int is_cpu_powered(void) -{ - struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; - - return (readl(&pmc->pmc_pwrgate_status) & CPU_PWRED) ? 1 : 0; -} - -static void remove_cpu_io_clamps(void) -{ - struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; - u32 reg; - - /* Remove the clamps on the CPU I/O signals */ - reg = readl(&pmc->pmc_remove_clamping); - reg |= CPU_CLMP; - writel(reg, &pmc->pmc_remove_clamping); - - /* Give I/O signals time to stabilize */ - udelay(IO_STABILIZATION_DELAY); -} - -static void powerup_cpu(void) -{ - struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; - u32 reg; - int timeout = IO_STABILIZATION_DELAY; - - if (!is_cpu_powered()) { - /* Toggle the CPU power state (OFF -> ON) */ - reg = readl(&pmc->pmc_pwrgate_toggle); - reg &= PARTID_CP; - reg |= START_CP; - writel(reg, &pmc->pmc_pwrgate_toggle); - - /* Wait for the power to come up */ - while (!is_cpu_powered()) { - if (timeout-- == 0) - printf("CPU failed to power up!\n"); - else - udelay(10); - } - - /* - * Remove the I/O clamps from CPU power partition. - * Recommended only on a Warm boot, if the CPU partition gets - * power gated. Shouldn't cause any harm when called after a - * cold boot according to HW, probably just redundant. - */ - remove_cpu_io_clamps(); - } -} - -static void enable_cpu_power_rail(void) -{ - struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; - u32 reg; - - reg = readl(&pmc->pmc_cntrl); - reg |= CPUPWRREQ_OE; - writel(reg, &pmc->pmc_cntrl); - - /* - * The TI PMU65861C needs a 3.75ms delay between enabling - * the power rail and enabling the CPU clock. This delay - * between SM1EN and SM1 is for switching time + the ramp - * up of the voltage to the CPU (VDD_CPU from PMU). We use 0xf00 as - * is is ARM-friendly (can fit in a single ARMv4T mov immmediate - * instruction). - */ - udelay(3840); -} - -static void reset_A9_cpu(int reset) -{ - /* - * NOTE: Regardless of whether the request is to hold the CPU in reset - * or take it out of reset, every processor in the CPU complex - * except the master (CPU 0) will be held in reset because the - * AVP only talks to the master. The AVP does not know that there - * are multiple processors in the CPU complex. - */ - - /* Hold CPU 1 in reset, and CPU 0 if asked */ - reset_cmplx_set_enable(1, crc_rst_cpu | crc_rst_de | crc_rst_debug, 1); - reset_cmplx_set_enable(0, crc_rst_cpu | crc_rst_de | crc_rst_debug, - reset); - - /* Enable/Disable master CPU reset */ - reset_set_enable(PERIPH_ID_CPU, reset); -} - -static void clock_enable_coresight(int enable) -{ - u32 rst, src; - - clock_set_enable(PERIPH_ID_CORESIGHT, enable); - reset_set_enable(PERIPH_ID_CORESIGHT, !enable); - - if (enable) { - /* - * Put CoreSight on PLLP_OUT0 (216 MHz) and divide it down by - * 1.5, giving an effective frequency of 144MHz. - * Set PLLP_OUT0 [bits31:30 = 00], and use a 7.1 divisor - * (bits 7:0), so 00000001b == 1.5 (n+1 + .5) - */ - src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000); - clock_ll_set_source_divisor(PERIPH_ID_CSI, 0, src); - - /* Unlock the CPU CoreSight interfaces */ - rst = 0xC5ACCE55; - writel(rst, CSITE_CPU_DBG0_LAR); - writel(rst, CSITE_CPU_DBG1_LAR); - } -} - -void start_cpu(u32 reset_vector) -{ - /* Enable VDD_CPU */ - enable_cpu_power_rail(); - - /* Hold the CPUs in reset */ - reset_A9_cpu(1); - - /* Disable the CPU clock */ - enable_cpu_clock(0); - - /* Enable CoreSight */ - clock_enable_coresight(1); - - /* - * Set the entry point for CPU execution from reset, - * if it's a non-zero value. - */ - if (reset_vector) - writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR); - - /* Enable the CPU clock */ - enable_cpu_clock(1); - - /* If the CPU doesn't already have power, power it up */ - powerup_cpu(); - - /* Take the CPU out of reset */ - reset_A9_cpu(0); -} - - -void halt_avp(void) -{ - for (;;) { - writel((HALT_COP_EVENT_JTAG | HALT_COP_EVENT_IRQ_1 \ - | HALT_COP_EVENT_FIQ_1 | (FLOW_MODE_STOP<<29)), - FLOW_CTLR_HALT_COP_EVENTS); - } -} - -void enable_scu(void) -{ - struct scu_ctlr *scu = (struct scu_ctlr *)NV_PA_ARM_PERIPHBASE; - u32 reg; - - /* If SCU already setup/enabled, return */ - if (readl(&scu->scu_ctrl) & SCU_CTRL_ENABLE) - return; - - /* Invalidate all ways for all processors */ - writel(0xFFFF, &scu->scu_inv_all); - - /* Enable SCU - bit 0 */ - reg = readl(&scu->scu_ctrl); - reg |= SCU_CTRL_ENABLE; - writel(reg, &scu->scu_ctrl); -} - -void init_pmc_scratch(void) -{ - struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; - int i; - - /* SCRATCH0 is initialized by the boot ROM and shouldn't be cleared */ - for (i = 0; i < 23; i++) - writel(0, &pmc->pmc_scratch1+i); - - /* ODMDATA is for kernel use to determine RAM size, LP config, etc. */ - writel(CONFIG_SYS_BOARD_ODMDATA, &pmc->pmc_scratch20); - -#ifdef CONFIG_TEGRA2_LP0 - /* save Sdram params to PMC 2, 4, and 24 for WB0 */ - warmboot_save_sdram_params(); -#endif -} - -void tegra_start(void) -{ - struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; - - /* If we are the AVP, start up the first Cortex-A9 */ - if (!ap20_cpu_is_cortexa9()) { - extern void _start(void); - - /* enable JTAG */ - writel(0xC0, &pmt->pmt_cfg_ctl); - - /* - * If we are ARM7 - give it a different stack. We are about to - * start up the A9 which will want to use this one. - */ - asm volatile("ldr sp, =%c0\n" - : : "i"(AVP_EARLY_BOOT_STACK_LIMIT)); - - start_cpu((u32)_start); - halt_avp(); - /* not reached */ - } - - /* Init PMC scratch memory */ - init_pmc_scratch(); - - enable_scu(); - - /* enable SMP mode and FW for CPU0, by writing to Auxiliary Ctl reg */ - asm volatile( - "mrc p15, 0, r0, c1, c0, 1\n" - "orr r0, r0, #0x41\n" - "mcr p15, 0, r0, c1, c0, 1\n"); - - /* FIXME: should have ap20's L2 disabled too? */ - - /* Init is_tegra2_processor_reset */ - is_tegra2_processor_reset = check_is_tegra2_processor_reset(); -} - diff --git a/arch/arm/cpu/armv7/tegra2/ap20.h b/arch/arm/cpu/armv7/tegra2/ap20.h deleted file mode 100644 index 4f7d7ce7148..00000000000 --- a/arch/arm/cpu/armv7/tegra2/ap20.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * (C) Copyright 2010-2011 - * NVIDIA Corporation <www.nvidia.com> - * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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; either version 2 of - * the License, or (at your option) any later version. - * - * 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., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ -#include <asm/types.h> - -/* Stabilization delays, in usec */ -#define PLL_STABILIZATION_DELAY (300) -#define IO_STABILIZATION_DELAY (1000) - -#define NVBL_PLLP_KHZ (216000) - -#define PLLX_ENABLED (1 << 30) -#define CCLK_BURST_POLICY 0x20008888 -#define SUPER_CCLK_DIVIDER 0x80000000 - -/* Calculate clock fractional divider value from ref and target frequencies */ -#define CLK_DIVIDER(REF, FREQ) ((((REF) * 2) / FREQ) - 2) - -/* Calculate clock frequency value from reference and clock divider value */ -#define CLK_FREQUENCY(REF, REG) (((REF) * 2) / (REG + 2)) - -/* AVP/CPU ID */ -#define PG_UP_TAG_0_PID_CPU 0x55555555 /* CPU aka "a9" aka "mpcore" */ -#define PG_UP_TAG_0 0x0 - -#define CORESIGHT_UNLOCK 0xC5ACCE55; - -/* AP20-Specific Base Addresses */ - -/* AP20 Base physical address of SDRAM. */ -#define AP20_BASE_PA_SDRAM 0x00000000 -/* AP20 Base physical address of internal SRAM. */ -#define AP20_BASE_PA_SRAM 0x40000000 -/* AP20 Size of internal SRAM (256KB). */ -#define AP20_BASE_PA_SRAM_SIZE 0x00040000 -/* AP20 Base physical address of flash. */ -#define AP20_BASE_PA_NOR_FLASH 0xD0000000 -/* AP20 Base physical address of boot information table. */ -#define AP20_BASE_PA_BOOT_INFO AP20_BASE_PA_SRAM - -/* - * Super-temporary stacks for EXTREMELY early startup. The values chosen for - * these addresses must be valid on ALL SOCs because this value is used before - * we are able to differentiate between the SOC types. - * - * NOTE: The since CPU's stack will eventually be moved from IRAM to SDRAM, its - * stack is placed below the AVP stack. Once the CPU stack has been moved, - * the AVP is free to use the IRAM the CPU stack previously occupied if - * it should need to do so. - * - * NOTE: In multi-processor CPU complex configurations, each processor will have - * its own stack of size CPU_EARLY_BOOT_STACK_SIZE. CPU 0 will have a - * limit of CPU_EARLY_BOOT_STACK_LIMIT. Each successive CPU will have a - * stack limit that is CPU_EARLY_BOOT_STACK_SIZE less then the previous - * CPU. - */ - -/* Common AVP early boot stack limit */ -#define AVP_EARLY_BOOT_STACK_LIMIT \ - (AP20_BASE_PA_SRAM + (AP20_BASE_PA_SRAM_SIZE/2)) -/* Common AVP early boot stack size */ -#define AVP_EARLY_BOOT_STACK_SIZE 0x1000 -/* Common CPU early boot stack limit */ -#define CPU_EARLY_BOOT_STACK_LIMIT \ - (AVP_EARLY_BOOT_STACK_LIMIT - AVP_EARLY_BOOT_STACK_SIZE) -/* Common CPU early boot stack size */ -#define CPU_EARLY_BOOT_STACK_SIZE 0x1000 - -#define EXCEP_VECTOR_CPU_RESET_VECTOR (NV_PA_EVP_BASE + 0x100) -#define CSITE_CPU_DBG0_LAR (NV_PA_CSITE_BASE + 0x10FB0) -#define CSITE_CPU_DBG1_LAR (NV_PA_CSITE_BASE + 0x12FB0) - -#define FLOW_CTLR_HALT_COP_EVENTS (NV_PA_FLOW_BASE + 4) -#define FLOW_MODE_STOP 2 -#define HALT_COP_EVENT_JTAG (1 << 28) -#define HALT_COP_EVENT_IRQ_1 (1 << 11) -#define HALT_COP_EVENT_FIQ_1 (1 << 9) - -/* Called by the ARM7 to start up the Cortex-A9, and by the A9 to do init */ -void tegra_start(void); - -/* Returns 1 if the current CPU executing is a Cortex-A9, else 0 */ -int ap20_cpu_is_cortexa9(void); - -/** - * Init the PLLX which clocks the CPU. - * - * The 'slow' option is used when the CPU voltage has not yet been increased - * to allow running at full speed. - * - * @param slow 1 to run in safe/slow mode, 0 to run at full speed - */ -void ap20_init_pllx(int slow); diff --git a/arch/arm/cpu/armv7/tegra2/board.c b/arch/arm/cpu/armv7/tegra2/board.c index 0d71b6157f5..cc3d8dd86fb 100644 --- a/arch/arm/cpu/armv7/tegra2/board.c +++ b/arch/arm/cpu/armv7/tegra2/board.c @@ -23,7 +23,7 @@ #include <common.h> #include <asm/io.h> -#include "ap20.h" +#include <asm/arch-tegra/ap20.h> #include <asm/arch/sys_proto.h> #include <asm/arch/tegra.h> #include <asm/arch/pmc.h> diff --git a/arch/arm/cpu/armv7/tegra2/clock.c b/arch/arm/cpu/armv7/tegra2/clock.c deleted file mode 100644 index fd5393086fb..00000000000 --- a/arch/arm/cpu/armv7/tegra2/clock.c +++ /dev/null @@ -1,955 +0,0 @@ -/* - * Copyright (c) 2011 The Chromium OS Authors. - * See file CREDITS for list of people who contributed to this - * project. - * - * 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; either version 2 of - * the License, or (at your option) any later version. - * - * 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., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -/* Tegra2 Clock control functions */ - -#include <asm/io.h> -#include <asm/arch/bitfield.h> -#include <asm/arch/clk_rst.h> -#include <asm/arch/clock.h> -#include <asm/arch/timer.h> -#include <asm/arch/tegra.h> -#include <common.h> -#include <div64.h> - -/* - * This is our record of the current clock rate of each clock. We don't - * fill all of these in since we are only really interested in clocks which - * we use as parents. - */ -static unsigned pll_rate[CLOCK_ID_COUNT]; - -/* - * The oscillator frequency is fixed to one of four set values. Based on this - * the other clocks are set up appropriately. - */ -static unsigned osc_freq[CLOCK_OSC_FREQ_COUNT] = { - 13000000, - 19200000, - 12000000, - 26000000, -}; - -/* - * Clock types that we can use as a source. The Tegra2 has muxes for the - * peripheral clocks, and in most cases there are four options for the clock - * source. This gives us a clock 'type' and exploits what commonality exists - * in the device. - * - * Letters are obvious, except for T which means CLK_M, and S which means the - * clock derived from 32KHz. Beware that CLK_M (also called OSC in the - * datasheet) and PLL_M are different things. The former is the basic - * clock supplied to the SOC from an external oscillator. The latter is the - * memory clock PLL. - * - * See definitions in clock_id in the header file. - */ -enum clock_type_id { - CLOCK_TYPE_AXPT, /* PLL_A, PLL_X, PLL_P, CLK_M */ - CLOCK_TYPE_MCPA, /* and so on */ - CLOCK_TYPE_MCPT, - CLOCK_TYPE_PCM, - CLOCK_TYPE_PCMT, - CLOCK_TYPE_PCXTS, - CLOCK_TYPE_PDCT, - - CLOCK_TYPE_COUNT, - CLOCK_TYPE_NONE = -1, /* invalid clock type */ -}; - -/* return 1 if a peripheral ID is in range */ -#define clock_type_id_isvalid(id) ((id) >= 0 && \ - (id) < CLOCK_TYPE_COUNT) - -char pllp_valid = 1; /* PLLP is set up correctly */ - -enum { - CLOCK_MAX_MUX = 4 /* number of source options for each clock */ -}; - -/* - * Clock source mux for each clock type. This just converts our enum into - * a list of mux sources for use by the code. Note that CLOCK_TYPE_PCXTS - * is special as it has 5 sources. Since it also has a different number of - * bits in its register for the source, we just handle it with a special - * case in the code. - */ -#define CLK(x) CLOCK_ID_ ## x -static enum clock_id clock_source[CLOCK_TYPE_COUNT] [CLOCK_MAX_MUX] = { - { CLK(AUDIO), CLK(XCPU), CLK(PERIPH), CLK(OSC) }, - { CLK(MEMORY), CLK(CGENERAL), CLK(PERIPH), CLK(AUDIO) }, - { CLK(MEMORY), CLK(CGENERAL), CLK(PERIPH), CLK(OSC) }, - { CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY), CLK(NONE) }, - { CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY), CLK(OSC) }, - { CLK(PERIPH), CLK(CGENERAL), CLK(XCPU), CLK(OSC) }, - { CLK(PERIPH), CLK(DISPLAY), CLK(CGENERAL), CLK(OSC) }, -}; - -/* - * Clock peripheral IDs which sadly don't match up with PERIPH_ID. This is - * not in the header file since it is for purely internal use - we want - * callers to use the PERIPH_ID for all access to peripheral clocks to avoid - * confusion bewteen PERIPH_ID_... and PERIPHC_... - * - * We don't call this CLOCK_PERIPH_ID or PERIPH_CLOCK_ID as it would just be - * confusing. - * - * Note to SOC vendors: perhaps define a unified numbering for peripherals and - * use it for reset, clock enable, clock source/divider and even pinmuxing - * if you can. - */ -enum periphc_internal_id { - /* 0x00 */ - PERIPHC_I2S1, - PERIPHC_I2S2, - PERIPHC_SPDIF_OUT, - PERIPHC_SPDIF_IN, - PERIPHC_PWM, - PERIPHC_SPI1, - PERIPHC_SPI2, - PERIPHC_SPI3, - - /* 0x08 */ - PERIPHC_XIO, - PERIPHC_I2C1, - PERIPHC_DVC_I2C, - PERIPHC_TWC, - PERIPHC_0c, - PERIPHC_10, /* PERIPHC_SPI1, what is this really? */ - PERIPHC_DISP1, - PERIPHC_DISP2, - - /* 0x10 */ - PERIPHC_CVE, - PERIPHC_IDE0, - PERIPHC_VI, - PERIPHC_1c, - PERIPHC_SDMMC1, - PERIPHC_SDMMC2, - PERIPHC_G3D, - PERIPHC_G2D, - - /* 0x18 */ - PERIPHC_NDFLASH, - PERIPHC_SDMMC4, - PERIPHC_VFIR, - PERIPHC_EPP, - PERIPHC_MPE, - PERIPHC_MIPI, - PERIPHC_UART1, - PERIPHC_UART2, - - /* 0x20 */ - PERIPHC_HOST1X, - PERIPHC_21, - PERIPHC_TVO, - PERIPHC_HDMI, - PERIPHC_24, - PERIPHC_TVDAC, - PERIPHC_I2C2, - PERIPHC_EMC, - - /* 0x28 */ - PERIPHC_UART3, - PERIPHC_29, - PERIPHC_VI_SENSOR, - PERIPHC_2b, - PERIPHC_2c, - PERIPHC_SPI4, - PERIPHC_I2C3, - PERIPHC_SDMMC3, - - /* 0x30 */ - PERIPHC_UART4, - PERIPHC_UART5, - PERIPHC_VDE, - PERIPHC_OWR, - PERIPHC_NOR, - PERIPHC_CSITE, - - PERIPHC_COUNT, - - PERIPHC_NONE = -1, -}; - -/* return 1 if a periphc_internal_id is in range */ -#define periphc_internal_id_isvalid(id) ((id) >= 0 && \ - (id) < PERIPHC_COUNT) - -/* - * Clock type for each peripheral clock source. We put the name in each - * record just so it is easy to match things up - */ -#define TYPE(name, type) type -static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { - /* 0x00 */ - TYPE(PERIPHC_I2S1, CLOCK_TYPE_AXPT), - TYPE(PERIPHC_I2S2, CLOCK_TYPE_AXPT), - TYPE(PERIPHC_SPDIF_OUT, CLOCK_TYPE_AXPT), - TYPE(PERIPHC_SPDIF_IN, CLOCK_TYPE_PCM), - TYPE(PERIPHC_PWM, CLOCK_TYPE_PCXTS), - TYPE(PERIPHC_SPI1, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_SPI22, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_SPI3, CLOCK_TYPE_PCMT), - - /* 0x08 */ - TYPE(PERIPHC_XIO, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_I2C1, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_DVC_I2C, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_TWC, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), - TYPE(PERIPHC_SPI1, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_DISP1, CLOCK_TYPE_PDCT), - TYPE(PERIPHC_DISP2, CLOCK_TYPE_PDCT), - - /* 0x10 */ - TYPE(PERIPHC_CVE, CLOCK_TYPE_PDCT), - TYPE(PERIPHC_IDE0, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_VI, CLOCK_TYPE_MCPA), - TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), - TYPE(PERIPHC_SDMMC1, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_SDMMC2, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_G3D, CLOCK_TYPE_MCPA), - TYPE(PERIPHC_G2D, CLOCK_TYPE_MCPA), - - /* 0x18 */ - TYPE(PERIPHC_NDFLASH, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_SDMMC4, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_VFIR, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_EPP, CLOCK_TYPE_MCPA), - TYPE(PERIPHC_MPE, CLOCK_TYPE_MCPA), - TYPE(PERIPHC_MIPI, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_UART1, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_UART2, CLOCK_TYPE_PCMT), - - /* 0x20 */ - TYPE(PERIPHC_HOST1X, CLOCK_TYPE_MCPA), - TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), - TYPE(PERIPHC_TVO, CLOCK_TYPE_PDCT), - TYPE(PERIPHC_HDMI, CLOCK_TYPE_PDCT), - TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), - TYPE(PERIPHC_TVDAC, CLOCK_TYPE_PDCT), - TYPE(PERIPHC_I2C2, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_EMC, CLOCK_TYPE_MCPT), - - /* 0x28 */ - TYPE(PERIPHC_UART3, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), - TYPE(PERIPHC_VI, CLOCK_TYPE_MCPA), - TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), - TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), - TYPE(PERIPHC_SPI4, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_I2C3, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_SDMMC3, CLOCK_TYPE_PCMT), - - /* 0x30 */ - TYPE(PERIPHC_UART4, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_UART5, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_VDE, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_OWR, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_NOR, CLOCK_TYPE_PCMT), - TYPE(PERIPHC_CSITE, CLOCK_TYPE_PCMT), -}; - -/* - * This array translates a periph_id to a periphc_internal_id - * - * Not present/matched up: - * uint vi_sensor; _VI_SENSOR_0, 0x1A8 - * SPDIF - which is both 0x08 and 0x0c - * - */ -#define NONE(name) (-1) -#define OFFSET(name, value) PERIPHC_ ## name -static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = { - /* Low word: 31:0 */ - NONE(CPU), - NONE(RESERVED1), - NONE(RESERVED2), - NONE(AC97), - NONE(RTC), - NONE(TMR), - PERIPHC_UART1, - PERIPHC_UART2, /* and vfir 0x68 */ - - /* 0x08 */ - NONE(GPIO), - PERIPHC_SDMMC2, - NONE(SPDIF), /* 0x08 and 0x0c, unclear which to use */ - PERIPHC_I2S1, - PERIPHC_I2C1, - PERIPHC_NDFLASH, - PERIPHC_SDMMC1, - PERIPHC_SDMMC4, - - /* 0x10 */ - PERIPHC_TWC, - PERIPHC_PWM, - PERIPHC_I2S2, - PERIPHC_EPP, - PERIPHC_VI, - PERIPHC_G2D, - NONE(USBD), - NONE(ISP), - - /* 0x18 */ - PERIPHC_G3D, - PERIPHC_IDE0, - PERIPHC_DISP2, - PERIPHC_DISP1, - PERIPHC_HOST1X, - NONE(VCP), - NONE(RESERVED30), - NONE(CACHE2), - - /* Middle word: 63:32 */ - NONE(MEM), - NONE(AHBDMA), - NONE(APBDMA), - NONE(RESERVED35), - NONE(KBC), - NONE(STAT_MON), - NONE(PMC), - NONE(FUSE), - - /* 0x28 */ - NONE(KFUSE), - NONE(SBC1), /* SBC1, 0x34, is this SPI1? */ - PERIPHC_NOR, - PERIPHC_SPI1, - PERIPHC_SPI2, - PERIPHC_XIO, - PERIPHC_SPI3, - PERIPHC_DVC_I2C, - - /* 0x30 */ - NONE(DSI), - PERIPHC_TVO, /* also CVE 0x40 */ - PERIPHC_MIPI, - PERIPHC_HDMI, - PERIPHC_CSITE, - PERIPHC_TVDAC, - PERIPHC_I2C2, - PERIPHC_UART3, - - /* 0x38 */ - NONE(RESERVED56), - PERIPHC_EMC, - NONE(USB2), - NONE(USB3), - PERIPHC_MPE, - PERIPHC_VDE, - NONE(BSEA), - NONE(BSEV), - - /* Upper word 95:64 */ - NONE(SPEEDO), - PERIPHC_UART4, - PERIPHC_UART5, - PERIPHC_I2C3, - PERIPHC_SPI4, - PERIPHC_SDMMC3, - NONE(PCIE), - PERIPHC_OWR, - - /* 0x48 */ - NONE(AFI), - NONE(CORESIGHT), - NONE(RESERVED74), - NONE(AVPUCQ), - NONE(RESERVED76), - NONE(RESERVED77), - NONE(RESERVED78), - NONE(RESERVED79), - - /* 0x50 */ - NONE(RESERVED80), - NONE(RESERVED81), - NONE(RESERVED82), - NONE(RESERVED83), - NONE(IRAMA), - NONE(IRAMB), - NONE(IRAMC), - NONE(IRAMD), - - /* 0x58 */ - NONE(CRAM2), -}; - -/* - * Get the oscillator frequency, from the corresponding hardware configuration - * field. - */ -enum clock_osc_freq clock_get_osc_freq(void) -{ - struct clk_rst_ctlr *clkrst = - (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - u32 reg; - - reg = readl(&clkrst->crc_osc_ctrl); - return bf_unpack(OSC_FREQ, reg); -} - -/* Returns a pointer to the registers of the given pll */ -static struct clk_pll *get_pll(enum clock_id clkid) -{ - struct clk_rst_ctlr *clkrst = - (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - - assert(clock_id_isvalid(clkid)); - return &clkrst->crc_pll[clkid]; -} - -unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn, - u32 divp, u32 cpcon, u32 lfcon) -{ - struct clk_pll *pll = get_pll(clkid); - u32 data; - - /* - * 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 - */ - - data = bf_pack(PLL_CPCON, cpcon) | - bf_pack(PLL_LFCON, lfcon); - writel(data, &pll->pll_misc); - - data = bf_pack(PLL_DIVM, divm) | - bf_pack(PLL_DIVN, divn) | - bf_pack(PLL_BYPASS, 0) | - bf_pack(PLL_ENABLE, 1); - - if (clkid == CLOCK_ID_USB) - data |= bf_pack(PLL_VCO_FREQ, divp); - else - data |= bf_pack(PLL_DIVP, divp); - writel(data, &pll->pll_base); - - /* calculate the stable time */ - return timer_get_future_us(CLOCK_PLL_STABLE_DELAY_US); -} - -/* return 1 if a peripheral ID is in range and valid */ -static int clock_periph_id_isvalid(enum periph_id id) -{ - if (id < PERIPH_ID_FIRST || id >= PERIPH_ID_COUNT) - printf("Peripheral id %d out of range\n", id); - else switch (id) { - case PERIPH_ID_RESERVED1: - case PERIPH_ID_RESERVED2: - case PERIPH_ID_RESERVED30: - case PERIPH_ID_RESERVED35: - case PERIPH_ID_RESERVED56: - case PERIPH_ID_RESERVED74: - case PERIPH_ID_RESERVED76: - case PERIPH_ID_RESERVED77: - case PERIPH_ID_RESERVED78: - case PERIPH_ID_RESERVED79: - case PERIPH_ID_RESERVED80: - case PERIPH_ID_RESERVED81: - case PERIPH_ID_RESERVED82: - case PERIPH_ID_RESERVED83: - printf("Peripheral id %d is reserved\n", id); - break; - default: - return 1; - } - return 0; -} - -/* Returns a pointer to the clock source register for a peripheral */ -static u32 *get_periph_source_reg(enum periph_id periph_id) -{ - struct clk_rst_ctlr *clkrst = - (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - enum periphc_internal_id internal_id; - - assert(clock_periph_id_isvalid(periph_id)); - internal_id = periph_id_to_internal_id[periph_id]; - assert(internal_id != -1); - return &clkrst->crc_clk_src[internal_id]; -} - -void clock_ll_set_source_divisor(enum periph_id periph_id, int source, - unsigned divisor) -{ - u32 *reg = get_periph_source_reg(periph_id); - u32 value; - - value = readl(reg); - bf_update(OUT_CLK_SOURCE, value, source); - bf_update(OUT_CLK_DIVISOR, value, divisor); - writel(value, reg); -} - -void clock_ll_set_source(enum periph_id periph_id, int source) -{ - u32 *reg = get_periph_source_reg(periph_id); - - bf_writel(OUT_CLK_SOURCE, source, reg); -} - -/** - * Given the parent's rate and the required rate for the children, this works - * out the peripheral clock divider to use, in 7.1 binary format. - * - * @param parent_rate clock rate of parent clock in Hz - * @param rate required clock rate for this clock - * @return divider which should be used - */ -static int clk_div7_1_get_divider(unsigned long parent_rate, - unsigned long rate) -{ - u64 divider = parent_rate * 2; - - divider += rate - 1; - do_div(divider, rate); - - if ((s64)divider - 2 < 0) - return 0; - - if ((s64)divider - 2 > 255) - return -1; - - return divider - 2; -} - -/** - * Given the parent's rate and the divider in 7.1 format, this works out the - * resulting peripheral clock rate. - * - * @param parent_rate clock rate of parent clock in Hz - * @param divider which should be used in 7.1 format - * @return effective clock rate of peripheral - */ -static unsigned long get_rate_from_divider(unsigned long parent_rate, - int divider) -{ - u64 rate; - - rate = (u64)parent_rate * 2; - do_div (rate, divider + 2); - return rate; -} - -unsigned long clock_get_periph_rate(enum periph_id periph_id, - enum clock_id parent) -{ - u32 *reg = get_periph_source_reg(periph_id); - - return get_rate_from_divider(pll_rate[parent], - bf_readl(OUT_CLK_DIVISOR, reg)); -} - -/** - * Find the best available 7.1 format divisor given a parent clock rate and - * required child clock rate. This function assumes that a second-stage - * divisor is available which can divide by powers of 2 from 1 to 256. - * - * @param parent_rate clock rate of parent clock in Hz - * @param rate required clock rate for this clock - * @param extra_div value for the second-stage divisor (not set if this - * function returns -1. - * @return divider which should be used, or -1 if nothing is valid - * - */ -static int find_best_divider(unsigned long parent_rate, unsigned long rate, - int *extra_div) -{ - int shift; - int best_divider = -1; - int best_error = rate; - - /* try dividers from 1 to 256 and find closest match */ - for (shift = 0; shift <= 8 && best_error > 0; shift++) { - unsigned divided_parent = parent_rate >> shift; - int divider = clk_div7_1_get_divider(divided_parent, rate); - unsigned effective_rate = get_rate_from_divider(divided_parent, - divider); - int error = rate - effective_rate; - - /* Given a valid divider, look for the lowest error */ - if (divider != -1 && error < best_error) { - best_error = error; - *extra_div = 1 << shift; - best_divider = divider; - } - } - - /* return what we found - *extra_div will already be set */ - return best_divider; -} - -/** - * Given a peripheral ID and the required source clock, this returns which - * value should be programmed into the source mux for that peripheral. - * - * There is special code here to handle the one source type with 5 sources. - * - * @param periph_id peripheral to start - * @param source PLL id of required parent clock - * @param mux_bits Set to number of bits in mux register: 2 or 4 - * @return mux value (0-4, or -1 if not found) - */ -static int get_periph_clock_source(enum periph_id periph_id, - enum clock_id parent, int *mux_bits) -{ - enum clock_type_id type; - enum periphc_internal_id internal_id; - int mux; - - assert(clock_periph_id_isvalid(periph_id)); - - internal_id = periph_id_to_internal_id[periph_id]; - assert(periphc_internal_id_isvalid(internal_id)); - - type = clock_periph_type[internal_id]; - assert(clock_type_id_isvalid(type)); - - /* Special case here for the clock with a 4-bit source mux */ - if (type == CLOCK_TYPE_PCXTS) - *mux_bits = 4; - else - *mux_bits = 2; - - for (mux = 0; mux < CLOCK_MAX_MUX; mux++) - if (clock_source[type][mux] == parent) - return mux; - - /* - * Not found: it might be looking for the 'S' in CLOCK_TYPE_PCXTS - * which is not in our table. If not, then they are asking for a - * source which this peripheral can't access through its mux. - */ - assert(type == CLOCK_TYPE_PCXTS); - assert(parent == CLOCK_ID_SFROM32KHZ); - if (type == CLOCK_TYPE_PCXTS && parent == CLOCK_ID_SFROM32KHZ); - return 4; /* mux value for this clock */ - - /* if we get here, either us or the caller has made a mistake */ - printf("Caller requested bad clock: periph=%d, parent=%d\n", periph_id, - parent); - return -1; -} - -/** - * Adjust peripheral PLL to use the given divider and source. - * - * @param periph_id peripheral to adjust - * @param parent Required parent clock (for source mux) - * @param divider Required divider in 7.1 format - * @return 0 if ok, -1 on error (requesting a parent clock which is not valid - * for this peripheral) - */ -static int adjust_periph_pll(enum periph_id periph_id, - enum clock_id parent, int divider) -{ - u32 *reg = get_periph_source_reg(periph_id); - int source, mux_bits; - - bf_writel(OUT_CLK_DIVISOR, divider, reg); - udelay(1); - - /* work out the source clock and set it */ - source = get_periph_clock_source(periph_id, parent, &mux_bits); - if (source < 0) - return -1; - if (mux_bits == 4) - bf_writel(OUT_CLK_SOURCE4, source, reg); - else - bf_writel(OUT_CLK_SOURCE, source, reg); - udelay(2); - return 0; -} - -unsigned clock_adjust_periph_pll_div(enum periph_id periph_id, - enum clock_id parent, unsigned rate, int *extra_div) -{ - unsigned effective_rate; - int divider; - - if (extra_div) - divider = find_best_divider(pll_rate[parent], rate, extra_div); - else - divider = clk_div7_1_get_divider(pll_rate[parent], rate); - assert(divider >= 0); - if (adjust_periph_pll(periph_id, parent, divider)) - return -1U; - debug("periph %d, rate=%d, reg=%p = %x\n", periph_id, rate, - get_periph_source_reg(periph_id), - readl(get_periph_source_reg(periph_id))); - - /* Check what we ended up with. This shouldn't matter though */ - effective_rate = clock_get_periph_rate(periph_id, parent); - if (extra_div) - effective_rate /= *extra_div; - if (rate != effective_rate) - debug("Requested clock rate %u not honored (got %u)\n", - rate, effective_rate); - return effective_rate; -} - -unsigned clock_start_periph_pll(enum periph_id periph_id, - enum clock_id parent, unsigned rate) -{ - unsigned effective_rate; - - reset_set_enable(periph_id, 1); - clock_enable(periph_id); - - effective_rate = clock_adjust_periph_pll_div(periph_id, parent, rate, - NULL); - - reset_set_enable(periph_id, 0); - return effective_rate; -} - -void clock_set_enable(enum periph_id periph_id, int enable) -{ - struct clk_rst_ctlr *clkrst = - (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - u32 *clk = &clkrst->crc_clk_out_enb[PERIPH_REG(periph_id)]; - u32 reg; - - /* Enable/disable the clock to this peripheral */ - assert(clock_periph_id_isvalid(periph_id)); - reg = readl(clk); - if (enable) - reg |= PERIPH_MASK(periph_id); - else - reg &= ~PERIPH_MASK(periph_id); - writel(reg, clk); -} - -void clock_enable(enum periph_id clkid) -{ - clock_set_enable(clkid, 1); -} - -void clock_disable(enum periph_id clkid) -{ - clock_set_enable(clkid, 0); -} - -void reset_set_enable(enum periph_id periph_id, int enable) -{ - struct clk_rst_ctlr *clkrst = - (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - u32 *reset = &clkrst->crc_rst_dev[PERIPH_REG(periph_id)]; - u32 reg; - - /* Enable/disable reset to the peripheral */ - assert(clock_periph_id_isvalid(periph_id)); - reg = readl(reset); - if (enable) - reg |= PERIPH_MASK(periph_id); - else - reg &= ~PERIPH_MASK(periph_id); - writel(reg, reset); -} - -void reset_periph(enum periph_id periph_id, int us_delay) -{ - /* Put peripheral into reset */ - reset_set_enable(periph_id, 1); - udelay(us_delay); - - /* Remove reset */ - reset_set_enable(periph_id, 0); - - udelay(us_delay); -} - -void reset_cmplx_set_enable(int cpu, int which, int reset) -{ - struct clk_rst_ctlr *clkrst = - (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - u32 mask; - - /* Form the mask, which depends on the cpu chosen. Tegra2 has 2 */ - assert(cpu >= 0 && cpu < 2); - mask = which << cpu; - - /* either enable or disable those reset for that CPU */ - if (reset) - writel(mask, &clkrst->crc_cpu_cmplx_set); - else - writel(mask, &clkrst->crc_cpu_cmplx_clr); -} - -unsigned clock_get_rate(enum clock_id clkid) -{ - struct clk_pll *pll; - u32 base; - u32 divm; - u64 parent_rate; - u64 rate; - - parent_rate = osc_freq[clock_get_osc_freq()]; - if (clkid == CLOCK_ID_OSC) - return parent_rate; - - pll = get_pll(clkid); - base = readl(&pll->pll_base); - rate = parent_rate * bf_unpack(PLL_DIVN, base); - divm = bf_unpack(PLL_DIVM, base); - if (clkid == CLOCK_ID_USB) - divm <<= bf_unpack(PLLU_VCO_FREQ, base); - else - divm <<= bf_unpack(PLL_DIVP, base); - do_div(rate, divm); - return rate; -} - -/** - * Set the output frequency you want for each PLL clock. - * PLL output frequencies are programmed by setting their N, M and P values. - * The governing equations are: - * VCO = (Fi / m) * n, Fo = VCO / (2^p) - * where Fo is the output frequency from the PLL. - * Example: Set the output frequency to 216Mhz(Fo) with 12Mhz OSC(Fi) - * 216Mhz = ((12Mhz / m) * n) / (2^p) so n=432,m=12,p=1 - * Please see Tegra TRM section 5.3 to get the detail for PLL Programming - * - * @param n PLL feedback divider(DIVN) - * @param m PLL input divider(DIVN) - * @param p post divider(DIVP) - * @param cpcon base PLL charge pump(CPCON) - * @return 0 if ok, -1 on error (the requested PLL is incorrect and cannot - * be overriden), 1 if PLL is already correct - */ -static int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon) -{ - u32 base_reg; - u32 misc_reg; - struct clk_pll *pll; - - pll = get_pll(clkid); - - base_reg = readl(&pll->pll_base); - - /* Set BYPASS, m, n and p to PLL_BASE */ - bf_update(PLL_DIVM, base_reg, m); - bf_update(PLL_DIVN, base_reg, n); - bf_update(PLL_DIVP, base_reg, p); - if (clkid == CLOCK_ID_PERIPH) { - /* - * If the PLL is already set up, check that it is correct - * and record this info for clock_verify() to check. - */ - if (base_reg & bf_mask(PLL_BASE_OVRRIDE)) { - base_reg |= bf_ones(PLL_ENABLE); - if (base_reg != readl(&pll->pll_base)) - pllp_valid = 0; - return pllp_valid ? 1 : -1; - } - bf_update(PLL_BASE_OVRRIDE, base_reg, 1); - } - - bf_update(PLL_BYPASS, base_reg, 1); - writel(base_reg, &pll->pll_base); - - /* Set cpcon to PLL_MISC */ - misc_reg = readl(&pll->pll_misc); - bf_update(PLL_CPCON, misc_reg, cpcon); - writel(misc_reg, &pll->pll_misc); - - /* Enable PLL */ - bf_update(PLL_ENABLE, base_reg, 1); - writel(base_reg, &pll->pll_base); - - /* Disable BYPASS */ - bf_update(PLL_BYPASS, base_reg, 0); - writel(base_reg, &pll->pll_base); - - return 0; -} - -int clock_verify(void) -{ - struct clk_pll *pll = get_pll(CLOCK_ID_PERIPH); - u32 reg = readl(&pll->pll_base); - - if (!pllp_valid) { - printf("Warning: PLLP %x is not correct\n", reg); - return -1; - } - debug("PLLX %x is correct\n", reg); - return 0; -} - -uint32_t check_is_tegra2_processor_reset(void) -{ - u32 base_reg; - struct clk_pll *pll; - - pll = get_pll(CLOCK_ID_PERIPH); - base_reg = readl(&pll->pll_base); - - return (base_reg & bf_mask(PLL_BASE_OVRRIDE)) ? 0 : 1; -} - -void clock_early_init(void) -{ - /* - * PLLP output frequency set to 216Mh - * PLLC output frequency set to 600Mhz - * - * TODO: Can we calculate these values instead of hard-coding? - */ - switch (clock_get_osc_freq()) { - case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */ - clock_set_rate(CLOCK_ID_PERIPH, 432, 12, 1, 8); - clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8); - break; - - case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */ - clock_set_rate(CLOCK_ID_PERIPH, 432, 26, 1, 8); - clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8); - break; - - case CLOCK_OSC_FREQ_13_0: - case CLOCK_OSC_FREQ_19_2: - default: - /* - * These are not supported. It is too early to print a - * message and the UART likely won't work anyway due to the - * oscillator being wrong. - */ - break; - } -} - -void clock_init(void) -{ - pll_rate[CLOCK_ID_MEMORY] = clock_get_rate(CLOCK_ID_MEMORY); - pll_rate[CLOCK_ID_PERIPH] = clock_get_rate(CLOCK_ID_PERIPH); - pll_rate[CLOCK_ID_CGENERAL] = clock_get_rate(CLOCK_ID_CGENERAL); - pll_rate[CLOCK_ID_OSC] = clock_get_rate(CLOCK_ID_OSC); - pll_rate[CLOCK_ID_SFROM32KHZ] = 32768; - debug("Osc = %d\n", pll_rate[CLOCK_ID_OSC]); - debug("PLLM = %d\n", pll_rate[CLOCK_ID_MEMORY]); - debug("PLLP = %d\n", pll_rate[CLOCK_ID_PERIPH]); -} diff --git a/arch/arm/cpu/armv7/tegra2/lowlevel_init.S b/arch/arm/cpu/armv7/tegra2/lowlevel_init.S deleted file mode 100644 index 333f1b7c8e2..00000000000 --- a/arch/arm/cpu/armv7/tegra2/lowlevel_init.S +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SoC-specific setup info - * - * (C) Copyright 2010,2011 - * NVIDIA Corporation <www.nvidia.com> - * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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; either version 2 of - * the License, or (at your option) any later version. - * - * 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., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include <config.h> -#include <version.h> - - .align 5 -.global reset_cpu -reset_cpu: - ldr r1, rstctl @ get addr for global reset - @ reg - ldr r3, [r1] - orr r3, r3, #0x10 - str r3, [r1] @ force reset - mov r0, r0 -_loop_forever: - b _loop_forever -rstctl: - .word PRM_RSTCTRL - -.globl lowlevel_init -lowlevel_init: - @ Nothing to do here on Tegra2 - mov pc, lr @ back to arch calling code diff --git a/arch/arm/cpu/armv7/tegra2/timer.c b/arch/arm/cpu/armv7/tegra2/timer.c deleted file mode 100644 index 552c9adcbb1..00000000000 --- a/arch/arm/cpu/armv7/tegra2/timer.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * (C) Copyright 2010,2011 - * NVIDIA Corporation <www.nvidia.com> - * - * (C) Copyright 2008 - * Texas Instruments - * - * Richard Woodruff <r-woodruff2@ti.com> - * Syed Moahmmed Khasim <khasim@ti.com> - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Marius Groeger <mgroeger@sysgo.de> - * Alex Zuepke <azu@sysgo.de> - * - * (C) Copyright 2002 - * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> - * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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; either version 2 of - * the License, or (at your option) any later version. - * - * 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., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include <common.h> -#include <asm/io.h> -#include <asm/arch/tegra.h> -#include <asm/arch/timer.h> - -DECLARE_GLOBAL_DATA_PTR; - -/* counter runs at 1MHz */ -#define TIMER_CLK 1000000 -#define TIMER_LOAD_VAL 0xffffffff - -/* timer without interrupts */ -void reset_timer(void) -{ - reset_timer_masked(); -} - -ulong get_timer(ulong base) -{ - return get_timer_masked() - base; -} - -void set_timer(ulong t) -{ - gd->tbl = t; -} - -/* delay x useconds */ -void __udelay(unsigned long usec) -{ - long tmo = usec * (TIMER_CLK / 1000) / 1000; - unsigned long now, last = timer_get_us(); - - while (tmo > 0) { - now = timer_get_us(); - if (last > now) /* count up timer overflow */ - tmo -= TIMER_LOAD_VAL - last + now; - else - tmo -= now - last; - last = now; - } -} - -void reset_timer_masked(void) -{ - /* reset time, capture current incrementer value time */ - gd->lastinc = timer_get_us() / (TIMER_CLK/CONFIG_SYS_HZ); - gd->tbl = 0; /* start "advancing" time stamp from 0 */ -} - -ulong get_timer_masked(void) -{ - ulong now; - - /* current tick value */ - now = timer_get_us() / (TIMER_CLK / CONFIG_SYS_HZ); - - if (now >= gd->lastinc) /* normal mode (non roll) */ - /* move stamp forward with absolute diff ticks */ - gd->tbl += (now - gd->lastinc); - else /* we have rollover of incrementer */ - gd->tbl += ((TIMER_LOAD_VAL / (TIMER_CLK / CONFIG_SYS_HZ)) - - gd->lastinc) + now; - gd->lastinc = now; - return gd->tbl; -} - -/* - * This function is derived from PowerPC code (read timebase as long long). - * On ARM it just returns the timer value. - */ -unsigned long long get_ticks(void) -{ - return get_timer(0); -} - -/* - * This function is derived from PowerPC code (timebase clock frequency). - * On ARM it returns the number of timer ticks per second. - */ -ulong get_tbclk(void) -{ - return CONFIG_SYS_HZ; -} - - -unsigned long timer_get_us(void) -{ - struct timerus *timer_base = (struct timerus *)NV_PA_TMRUS_BASE; - - return readl(&timer_base->cntr_1us); -} - -unsigned long timer_get_future_us(u32 delay) -{ - return timer_get_us() + delay; -} - diff --git a/arch/arm/cpu/armv7/tegra2/warmboot.c b/arch/arm/cpu/armv7/tegra2/warmboot.c index 8c2ddf7cdb2..3ee72c4ec1e 100644 --- a/arch/arm/cpu/armv7/tegra2/warmboot.c +++ b/arch/arm/cpu/armv7/tegra2/warmboot.c @@ -35,7 +35,7 @@ #include <asm/arch/gp_padctrl.h> #include <asm/arch/warmboot.h> #include <asm/arch/sdram_param.h> -#include "ap20.h" +#include <asm/arch-tegra/ap20.h> #define BCT_OFFSET 0x100 /* BCT starts at 0x100 */ #define BCT_SDRAM_PARAMS_OFFSET (BCT_OFFSET + 0x88) diff --git a/arch/arm/cpu/armv7/tegra2/warmboot_avp.c b/arch/arm/cpu/armv7/tegra2/warmboot_avp.c index 4a22caf06bc..a3db98907f4 100644 --- a/arch/arm/cpu/armv7/tegra2/warmboot_avp.c +++ b/arch/arm/cpu/armv7/tegra2/warmboot_avp.c @@ -30,7 +30,7 @@ #include <asm/arch/tegra.h> #include <asm/arch/flow.h> #include <asm/arch/warmboot.h> -#include "ap20.h" +#include <asm/arch-tegra/ap20.h> #include "warmboot_avp.h" #define DEBUG_RESET_CORESIGHT |