[U-Boot] [PATCH v2 0/5] Add basic clock and pinmux functions to the Tegra2

This patch series adds basic clock and pinmux functions to the Tegra2, and modifies the ap20 and board code to use them. It includes a few very simple required bitfield helper macros for ARM Tegra2 only.
Changes for v2: - Removed use of bitfield macros in C code - Now uses manual shifts and masks
Simon Glass (5): Tegra2: Add macros to calculate bitfield shifts and masks Tegra2: Add microsecond timer functions Tegra2: Add more clock support Tegra2: add additional pin multiplexing features Tegra2: Use clock and pinmux functions to simplify code
arch/arm/cpu/armv7/tegra2/Makefile | 2 +- arch/arm/cpu/armv7/tegra2/ap20.c | 91 +++------- arch/arm/cpu/armv7/tegra2/clock.c | 158 ++++++++++++++++ arch/arm/cpu/armv7/tegra2/pinmux.c | 53 ++++++ arch/arm/cpu/armv7/tegra2/timer.c | 27 ++- arch/arm/include/asm/arch-tegra2/bitfield.h | 96 ++++++++++ arch/arm/include/asm/arch-tegra2/clk_rst.h | 140 +++++++------- arch/arm/include/asm/arch-tegra2/clock.h | 264 +++++++++++++++++++++++++++ arch/arm/include/asm/arch-tegra2/pinmux.h | 155 +++++++++++++++- arch/arm/include/asm/arch-tegra2/timer.h | 34 ++++ board/nvidia/common/board.c | 64 +++---- 11 files changed, 893 insertions(+), 191 deletions(-) create mode 100644 arch/arm/cpu/armv7/tegra2/clock.c create mode 100644 arch/arm/cpu/armv7/tegra2/pinmux.c create mode 100644 arch/arm/include/asm/arch-tegra2/bitfield.h create mode 100644 arch/arm/include/asm/arch-tegra2/clock.h create mode 100644 arch/arm/include/asm/arch-tegra2/timer.h

Changes for v2: - Removed all bitfield access macros
Signed-off-by: Simon Glass sjg@chromium.org --- arch/arm/include/asm/arch-tegra2/bitfield.h | 96 +++++++++++++++++++++++++++ 1 files changed, 96 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/arch-tegra2/bitfield.h
diff --git a/arch/arm/include/asm/arch-tegra2/bitfield.h b/arch/arm/include/asm/arch-tegra2/bitfield.h new file mode 100644 index 0000000..494087c --- /dev/null +++ b/arch/arm/include/asm/arch-tegra2/bitfield.h @@ -0,0 +1,96 @@ +/* + * 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 + */ + +#ifndef __TEGRA2_BITFIELD_H +#define __TEGRA2_BITFIELD_H + +/* + * Basic macros for easily getting mask and shift values for bit fields on + * ARM. + * + * You use these to reliably create shifts and masks from a bit field + * definition. Bit fields are defined like this: + * + * #define NAME_BITS MSB : LSB + * + * where MSB is the most significant bit, and LSB the least sig, bit. This + * notation is chosen since it is commonly used in CPU / SOC datasheets. + * + * For example: + * + * #define UART_FBCON_BITS 5:3 Bit range for the FBCON field + * + * Note that if you are using a big-endian machine there is no consistent + * notion of big numbers, since bit 3 is a different bit depending on whether + * the access is 32-bits or 64-bits. For this reason these macros should not + * be used as it would probably be too confusing to have to specify your + * access width all the time. + * + * This defines a bit field extending between bits 3 and 5. + * + * Then in your header file you can set up the shift and mask like this: + * + * #define UART_FBCON_SHIFT bf_shift(UART_FBCON) + * #define UART_FBCON_MASK bf_mask(UART_FBCON) + * + * Then you can use these macros in your code (there is no bitfield support + * in the C file and these macros MUST NOT be used directly in C code). + * + * To write, overwriting other fields too: + * writel(3 << UART_FBCON_SHIFT, &uart->fbcon); + * + * To read: + * int fbcon = (readl(&uart->fbcon) & UART_FBCON_MASK) >> + * UART_FBCON_SHIFT; + * + * To update just this field (for example): + * clrsetbits_le32(&uart->fbcon, UART_FBCON_MASK, 3 << UART_FBCON_SHIFT); + */ + +#include "compiler.h" + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +/* Returns the bit number of the LSB */ +#define _LSB(range) ((0 ? range) & 0x1f) + +/* Returns the bit number of the MSB */ +#define _MSB(range) (1 ? range) + +/* Returns the width of the bitfield (in bits) */ +#define _BITFIELD_WIDTH(range) (_MSB(range) - _LSB(range) + 1) + + +/* + * Returns the number of bits the bitfield needs to be shifted left to pack it. + * This is just the same as the low bit. + */ +#define bf_shift(field) _LSB(field) + +/* Returns the unshifted mask for the field (i.e. LSB of mask is bit 0) */ +#define bf_rawmask(field) ((1UL << _BITFIELD_WIDTH(field)) - 1) + +/* Returns the mask for a field. Clear these bits to zero the field */ +#define bf_mask(field) (bf_rawmask(field) << (bf_shift(field))) + +#endif /* __BYTE_ORDER == __LITTLE_ENDIAN */ + +#endif

These functions provide access to the high resolution microsecond timer and tidy up a global variable in the code.
Signed-off-by: Simon Glass sjg@chromium.org --- arch/arm/cpu/armv7/tegra2/timer.c | 27 +++++++++++++++++------ arch/arm/include/asm/arch-tegra2/timer.h | 34 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 arch/arm/include/asm/arch-tegra2/timer.h
diff --git a/arch/arm/cpu/armv7/tegra2/timer.c b/arch/arm/cpu/armv7/tegra2/timer.c index fb061d0..b69c172 100644 --- a/arch/arm/cpu/armv7/tegra2/timer.c +++ b/arch/arm/cpu/armv7/tegra2/timer.c @@ -38,13 +38,12 @@ #include <common.h> #include <asm/io.h> #include <asm/arch/tegra2.h> +#include <asm/arch/timer.h>
DECLARE_GLOBAL_DATA_PTR;
-struct timerus *timer_base = (struct timerus *)NV_PA_TMRUS_BASE; - /* counter runs at 1MHz */ -#define TIMER_CLK (1000000) +#define TIMER_CLK 1000000 #define TIMER_LOAD_VAL 0xffffffff
/* timer without interrupts */ @@ -67,10 +66,10 @@ void set_timer(ulong t) void __udelay(unsigned long usec) { long tmo = usec * (TIMER_CLK / 1000) / 1000; - unsigned long now, last = readl(&timer_base->cntr_1us); + unsigned long now, last = timer_get_us();
while (tmo > 0) { - now = readl(&timer_base->cntr_1us); + now = timer_get_us(); if (last > now) /* count up timer overflow */ tmo -= TIMER_LOAD_VAL - last + now; else @@ -82,7 +81,7 @@ void __udelay(unsigned long usec) void reset_timer_masked(void) { /* reset time, capture current incrementer value time */ - gd->lastinc = readl(&timer_base->cntr_1us) / (TIMER_CLK/CONFIG_SYS_HZ); + gd->lastinc = timer_get_us() / (TIMER_CLK/CONFIG_SYS_HZ); gd->tbl = 0; /* start "advancing" time stamp from 0 */ }
@@ -91,7 +90,7 @@ ulong get_timer_masked(void) ulong now;
/* current tick value */ - now = readl(&timer_base->cntr_1us) / (TIMER_CLK / CONFIG_SYS_HZ); + now = timer_get_us() / (TIMER_CLK / CONFIG_SYS_HZ);
if (now >= gd->lastinc) /* normal mode (non roll) */ /* move stamp forward with absolute diff ticks */ @@ -120,3 +119,17 @@ 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/include/asm/arch-tegra2/timer.h b/arch/arm/include/asm/arch-tegra2/timer.h new file mode 100644 index 0000000..5d5445e --- /dev/null +++ b/arch/arm/include/asm/arch-tegra2/timer.h @@ -0,0 +1,34 @@ +/* + * 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 timer functions */ + +#ifndef _TEGRA2_TIMER_H +#define _TEGRA2_TIMER_H + +/* returns the current monotonic timer value in microseconds */ +unsigned long timer_get_us(void); + +/* returns what the time will likely be some microseconds into the future */ +unsigned long timer_get_future_us(u32 delay); + +#endif +

This adds functions to enable/disable clocks and reset to on-chip peripherals.
Changes for v2: - Removed use of bitfield access macros
Signed-off-by: Simon Glass sjg@chromium.org --- arch/arm/cpu/armv7/tegra2/Makefile | 2 +- arch/arm/cpu/armv7/tegra2/ap20.c | 52 ++---- arch/arm/cpu/armv7/tegra2/clock.c | 158 +++++++++++++++++ arch/arm/include/asm/arch-tegra2/clk_rst.h | 125 +++++++++----- arch/arm/include/asm/arch-tegra2/clock.h | 264 ++++++++++++++++++++++++++++ board/nvidia/common/board.c | 46 ++--- 6 files changed, 536 insertions(+), 111 deletions(-) create mode 100644 arch/arm/cpu/armv7/tegra2/clock.c create mode 100644 arch/arm/include/asm/arch-tegra2/clock.h
diff --git a/arch/arm/cpu/armv7/tegra2/Makefile b/arch/arm/cpu/armv7/tegra2/Makefile index f1ea915..b35764c 100644 --- a/arch/arm/cpu/armv7/tegra2/Makefile +++ b/arch/arm/cpu/armv7/tegra2/Makefile @@ -28,7 +28,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(SOC).o
SOBJS := lowlevel_init.o -COBJS := ap20.o board.o sys_info.o timer.o +COBJS := ap20.o board.o clock.o sys_info.o timer.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) diff --git a/arch/arm/cpu/armv7/tegra2/ap20.c b/arch/arm/cpu/armv7/tegra2/ap20.c index 60dd5df..e3832e2 100644 --- a/arch/arm/cpu/armv7/tegra2/ap20.c +++ b/arch/arm/cpu/armv7/tegra2/ap20.c @@ -25,6 +25,7 @@ #include <asm/io.h> #include <asm/arch/tegra2.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> @@ -35,33 +36,34 @@ u32 s_first_boot = 1; void init_pllx(void) { struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + struct clk_pll *pll = &clkrst->crc_pll[CLOCK_PLL_ID_XCPU]; u32 reg;
/* If PLLX is already enabled, just return */ - reg = readl(&clkrst->crc_pllx_base); + reg = readl(&pll->pll_base); if (reg & PLL_ENABLE) return;
/* Set PLLX_MISC */ reg = CPCON; /* CPCON[11:8] = 0001 */ - writel(reg, &clkrst->crc_pllx_misc); + writel(reg, &pll->pll_misc);
/* Use 12MHz clock here */ - reg = (PLL_BYPASS | PLL_DIVM); + reg = (PLL_BYPASS | PLL_DIVM_VALUE); reg |= (1000 << 8); /* DIVN = 0x3E8 */ - writel(reg, &clkrst->crc_pllx_base); + writel(reg, &pll->pll_base);
reg |= PLL_ENABLE; - writel(reg, &clkrst->crc_pllx_base); + writel(reg, &pll->pll_base);
reg &= ~PLL_BYPASS; - writel(reg, &clkrst->crc_pllx_base); + writel(reg, &pll->pll_base); }
static void enable_cpu_clock(int enable) { struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - u32 reg, clk; + u32 clk;
/* * NOTE: @@ -83,10 +85,6 @@ static void enable_cpu_clock(int enable) writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div); }
- /* Fetch the register containing the main CPU complex clock enable */ - reg = readl(&clkrst->crc_clk_out_enb_l); - reg |= CLK_ENB_CPU; - /* * Read the register containing the individual CPU clock enables and * always stop the clock to CPU 1. @@ -103,7 +101,8 @@ static void enable_cpu_clock(int enable) }
writel(clk, &clkrst->crc_clk_cpu_cmplx); - writel(reg, &clkrst->crc_clk_out_enb_l); + + clock_enable(PERIPH_ID_CPU); }
static int is_cpu_powered(void) @@ -179,7 +178,7 @@ static void enable_cpu_power_rail(void) static void reset_A9_cpu(int reset) { struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - u32 reg, cpu; + u32 cpu;
/* * NOTE: Regardless of whether the request is to hold the CPU in reset @@ -193,44 +192,27 @@ static void reset_A9_cpu(int reset) cpu = SET_DBGRESET1 | SET_DERESET1 | SET_CPURESET1; writel(cpu, &clkrst->crc_cpu_cmplx_set);
- reg = readl(&clkrst->crc_rst_dev_l); if (reset) { /* Now place CPU0 into reset */ cpu |= SET_DBGRESET0 | SET_DERESET0 | SET_CPURESET0; writel(cpu, &clkrst->crc_cpu_cmplx_set); - - /* Enable master CPU reset */ - reg |= SWR_CPU_RST; } else { /* Take CPU0 out of reset */ cpu = CLR_DBGRESET0 | CLR_DERESET0 | CLR_CPURESET0; writel(cpu, &clkrst->crc_cpu_cmplx_clr); - - /* Disable master CPU reset */ - reg &= ~SWR_CPU_RST; }
- writel(reg, &clkrst->crc_rst_dev_l); + /* Enable/Disable master CPU reset */ + reset_set_enable(PERIPH_ID_CPU, reset); }
static void clock_enable_coresight(int enable) { struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - u32 rst, clk, src; - - rst = readl(&clkrst->crc_rst_dev_u); - clk = readl(&clkrst->crc_clk_out_enb_u); - - if (enable) { - rst &= ~SWR_CSITE_RST; - clk |= CLK_ENB_CSITE; - } else { - rst |= SWR_CSITE_RST; - clk &= ~CLK_ENB_CSITE; - } + u32 rst, src;
- writel(clk, &clkrst->crc_clk_out_enb_u); - writel(rst, &clkrst->crc_rst_dev_u); + clock_set_enable(PERIPH_ID_CORESIGHT, enable); + reset_set_enable(PERIPH_ID_CORESIGHT, !enable);
if (enable) { /* diff --git a/arch/arm/cpu/armv7/tegra2/clock.c b/arch/arm/cpu/armv7/tegra2/clock.c new file mode 100644 index 0000000..9a7ded0 --- /dev/null +++ b/arch/arm/cpu/armv7/tegra2/clock.c @@ -0,0 +1,158 @@ +/* + * 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/clk_rst.h> +#include <asm/arch/clock.h> +#include <asm/arch/timer.h> +#include <asm/arch/tegra2.h> +#include <common.h> + +#ifdef DEBUG +#define assert(x) \ + ({ if (!(x)) printf("Assertion failure '%s' %s line %d\n", \ + #x, __FILE__, __LINE__); }) +#else +#define assert(x) +#endif + +/* + * 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 (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT; +} + +unsigned long clock_start_pll(enum clock_pll_id clkid, u32 divm, u32 divn, + u32 divp, u32 cpcon, u32 lfcon) +{ + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + u32 data; + struct clk_pll *pll; + + assert(clock_pll_id_isvalid(clkid)); + pll = &clkrst->crc_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 + */ + data = (cpcon << PLL_CPCON_SHIFT) | (lfcon << PLL_LFCON_SHIFT); + writel(data, &pll->pll_misc); + + data = (divm << PLL_DIVM_SHIFT) | (divn << PLL_DIVN_SHIFT) | + (0 << PLL_BYPASS_SHIFT) | (1 << PLL_ENABLE_SHIFT); + + if (clkid == CLOCK_PLL_ID_USB) + data |= divp << PLLU_VCO_FREQ_SHIFT; + else + data |= divp << PLL_DIVP_SHIFT; + writel(data, &pll->pll_base); + + /* calculate the stable time */ + return timer_get_future_us(CLOCK_PLL_STABLE_DELAY_US); +} + +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); +} diff --git a/arch/arm/include/asm/arch-tegra2/clk_rst.h b/arch/arm/include/asm/arch-tegra2/clk_rst.h index bd8ad2c..6c74410 100644 --- a/arch/arm/include/asm/arch-tegra2/clk_rst.h +++ b/arch/arm/include/asm/arch-tegra2/clk_rst.h @@ -24,15 +24,36 @@ #ifndef _CLK_RST_H_ #define _CLK_RST_H_
+#include <asm/arch/bitfield.h> + +/* PLL registers - there are several PLLs in the clock controller */ +struct clk_pll { + uint pll_base; /* the control register */ + uint pll_out; /* output control */ + uint reserved; + uint pll_misc; /* other misc things */ +}; + +/* PLL registers - there are several PLLs in the clock controller */ +struct clk_pll_simple { + uint pll_base; /* the control register */ + uint pll_misc; /* other misc things */ +}; + +/* + * Most PLLs use the clk_pll structure, but some have a simpler two-member + * structure for which we use clk_pll_simple. The reason for this non- + * othogonal setup is not stated. + */ +#define TEGRA_CLK_PLLS 6 +#define TEGRA_CLK_SIMPLE_PLLS 3 /* Number of simple PLLs */ +#define TEGRA_CLK_REGS 3 /* Number of clock enable registers */ + /* Clock/Reset Controller (CLK_RST_CONTROLLER_) regs */ struct clk_rst_ctlr { - uint crc_rst_src; /* _RST_SOURCE_0, 0x00 */ - uint crc_rst_dev_l; /* _RST_DEVICES_L_0, 0x04 */ - uint crc_rst_dev_h; /* _RST_DEVICES_H_0, 0x08 */ - uint crc_rst_dev_u; /* _RST_DEVICES_U_0, 0x0C */ - uint crc_clk_out_enb_l; /* _CLK_OUT_ENB_L_0, 0x10 */ - uint crc_clk_out_enb_h; /* _CLK_OUT_ENB_H_0, 0x14 */ - uint crc_clk_out_enb_u; /* _CLK_OUT_ENB_U_0, 0x18 */ + uint crc_rst_src; /* _RST_SOURCE_0,0x00 */ + uint crc_rst_dev[TEGRA_CLK_REGS]; /* _RST_DEVICES_L/H/U_0 */ + uint crc_clk_out_enb[TEGRA_CLK_REGS]; /* _CLK_OUT_ENB_L/H/U_0 */ uint crc_reserved0; /* reserved_0, 0x1C */ uint crc_cclk_brst_pol; /* _CCLK_BURST_POLICY_0,0x20 */ uint crc_super_cclk_div; /* _SUPER_CCLK_DIVIDER_0,0x24 */ @@ -52,44 +73,11 @@ struct clk_rst_ctlr { uint crc_osc_freq_det_stat; /* _OSC_FREQ_DET_STATUS_0,0x5C */ uint crc_reserved2[8]; /* reserved_2[8], 0x60-7C */
- uint crc_pllc_base; /* _PLLC_BASE_0, 0x80 */ - uint crc_pllc_out; /* _PLLC_OUT_0, 0x84 */ - uint crc_reserved3; /* reserved_3, 0x88 */ - uint crc_pllc_misc; /* _PLLC_MISC_0, 0x8C */ - - uint crc_pllm_base; /* _PLLM_BASE_0, 0x90 */ - uint crc_pllm_out; /* _PLLM_OUT_0, 0x94 */ - uint crc_reserved4; /* reserved_4, 0x98 */ - uint crc_pllm_misc; /* _PLLM_MISC_0, 0x9C */ - - uint crc_pllp_base; /* _PLLP_BASE_0, 0xA0 */ - uint crc_pllp_outa; /* _PLLP_OUTA_0, 0xA4 */ - uint crc_pllp_outb; /* _PLLP_OUTB_0, 0xA8 */ - uint crc_pllp_misc; /* _PLLP_MISC_0, 0xAC */ - - uint crc_plla_base; /* _PLLA_BASE_0, 0xB0 */ - uint crc_plla_out; /* _PLLA_OUT_0, 0xB4 */ - uint crc_reserved5; /* reserved_5, 0xB8 */ - uint crc_plla_misc; /* _PLLA_MISC_0, 0xBC */ - - uint crc_pllu_base; /* _PLLU_BASE_0, 0xC0 */ - uint crc_reserved6; /* _reserved_6, 0xC4 */ - uint crc_reserved7; /* _reserved_7, 0xC8 */ - uint crc_pllu_misc; /* _PLLU_MISC_0, 0xCC */ - - uint crc_plld_base; /* _PLLD_BASE_0, 0xD0 */ - uint crc_reserved8; /* _reserved_8, 0xD4 */ - uint crc_reserved9; /* _reserved_9, 0xD8 */ - uint crc_plld_misc; /* _PLLD_MISC_0, 0xDC */ - - uint crc_pllx_base; /* _PLLX_BASE_0, 0xE0 */ - uint crc_pllx_misc; /* _PLLX_MISC_0, 0xE4 */ + struct clk_pll crc_pll[TEGRA_CLK_PLLS]; /* PLLs from 0x80 to 0xdc */
- uint crc_plle_base; /* _PLLE_BASE_0, 0xE8 */ - uint crc_plle_misc; /* _PLLE_MISC_0, 0xEC */ + /* PLLs from 0xe0 to 0xf4 */ + struct clk_pll_simple crc_pll_simple[TEGRA_CLK_SIMPLE_PLLS];
- uint crc_plls_base; /* _PLLS_BASE_0, 0xF0 */ - uint crc_plls_misc; /* _PLLS_MISC_0, 0xF4 */ uint crc_reserved10; /* _reserved_10, 0xF8 */ uint crc_reserved11; /* _reserved_11, 0xFC */
@@ -157,8 +145,8 @@ struct clk_rst_ctlr { #define PLL_BYPASS (1 << 31) #define PLL_ENABLE (1 << 30) #define PLL_BASE_OVRRIDE (1 << 28) -#define PLL_DIVP (1 << 20) /* post divider, b22:20 */ -#define PLL_DIVM 0x0C /* input divider, b4:0 */ +#define PLL_DIVP_VALUE (1 << 20) /* post divider, b22:20 */ +#define PLL_DIVM_VALUE 0x0C /* input divider, b4:0 */
#define SWR_UARTD_RST (1 << 1) #define CLK_ENB_UARTD (1 << 1) @@ -191,4 +179,51 @@ struct clk_rst_ctlr {
#define CPCON (1 << 8)
+/* CLK_RST_CONTROLLER_CLK_CPU_CMPLX_0 */ +#define CPU1_CLK_STP_BITS 9 : 9 +#define CPU1_CLK_STP_SHIFT bf_shift(CPU1_CLK_STP_BITS) + +#define CPU0_CLK_STP_BITS 8 : 8 +#define CPU0_CLK_STP_SHIFT bf_shift(CPU0_CLK_STP_BITS) +#define CPU0_CLK_STP_MASK bf_mask(CPU0_CLK_STP_BITS) + +/* CLK_RST_CONTROLLER_PLLx_BASE_0 */ +#define PLL_BYPASS_BITS 31 : 31 +#define PLL_BYPASS_MASK bf_mask(PLL_BYPASS_BITS) +#define PLL_BYPASS_SHIFT bf_shift(PLL_BYPASS_BITS) + +#define PLL_ENABLE_BITS 30 : 30 +#define PLL_ENABLE_MASK bf_mask(PLL_ENABLE_BITS) +#define PLL_ENABLE_SHIFT bf_shift(PLL_ENABLE_BITS) + +#define PLL_BASE_OVRRIDE_BITS 28 : 28 +#define PLL_BASE_OVRRIDE_MASK bf_mask(PLL_BASE_OVRRIDE_BITS) + +#define PLL_DIVP_BITS 22 : 20 +#define PLL_DIVP_SHIFT bf_shift(PLL_DIVP_BITS) + +#define PLL_DIVN_BITS 17 : 8 +#define PLL_DIVN_SHIFT bf_shift(PLL_DIVN_BITS) + +#define PLL_DIVM_BITS 4 : 0 +#define PLL_DIVM_SHIFT bf_shift(PLL_DIVM_BITS) + +/* CLK_RST_CONTROLLER_PLLx_MISC_0 */ +#define PLL_CPCON_BITS 11 : 8 +#define PLL_CPCON_MASK bf_mask(PLL_CPCON_BITS) +#define PLL_CPCON_SHIFT bf_shift(PLL_CPCON_BITS) + +#define PLL_LFCON_BITS 7 : 4 +#define PLL_LFCON_SHIFT bf_shift(PLL_LFCON_BITS) + +#define PLLU_VCO_FREQ_BITS 20 : 20 +#define PLLU_VCO_FREQ_SHIFT bf_shift(PLLU_VCO_FREQ_BITS) + +#define PLL_VCO_FREQ_BITS 3 : 0 + +/* CLK_RST_CONTROLLER_OSC_CTRL_0 */ +#define OSC_FREQ_BITS 31 : 30 +#define OSC_FREQ_SHIFT bf_shift(OSC_FREQ_BITS) +#define OSC_FREQ_MASK bf_mask(OSC_FREQ_BITS) + #endif /* CLK_RST_H */ diff --git a/arch/arm/include/asm/arch-tegra2/clock.h b/arch/arm/include/asm/arch-tegra2/clock.h new file mode 100644 index 0000000..81a9f02 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra2/clock.h @@ -0,0 +1,264 @@ +/* + * 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 */ + +#ifndef _CLOCK_H + + +/* Set of oscillator frequencies supported in the internal API. */ +enum clock_osc_freq { + /* All in MHz, so 13_0 is 13.0MHz */ + CLOCK_OSC_FREQ_13_0, + CLOCK_OSC_FREQ_19_2, + CLOCK_OSC_FREQ_12_0, + CLOCK_OSC_FREQ_26_0, + + CLOCK_OSC_FREQ_COUNT, +}; + +/* The PLLs supported by the hardware */ +enum clock_pll_id { + CLOCK_PLL_ID_FIRST, + CLOCK_PLL_ID_CGENERAL = CLOCK_PLL_ID_FIRST, + CLOCK_PLL_ID_MEMORY, + CLOCK_PLL_ID_PERIPH, + CLOCK_PLL_ID_AUDIO, + CLOCK_PLL_ID_USB, + CLOCK_PLL_ID_DISPLAY, + + /* now the simple ones */ + CLOCK_PLL_ID_FIRST_SIMPLE, + CLOCK_PLL_ID_XCPU = CLOCK_PLL_ID_FIRST_SIMPLE, + CLOCK_PLL_ID_EPCI, + CLOCK_PLL_ID_SFROM32KHZ, + + CLOCK_PLL_ID_COUNT, +}; + +/* The clocks supported by the hardware */ +enum periph_id { + PERIPH_ID_FIRST, + + /* Low word: 31:0 */ + PERIPH_ID_CPU = PERIPH_ID_FIRST, + PERIPH_ID_RESERVED1, + PERIPH_ID_RESERVED2, + PERIPH_ID_AC97, + PERIPH_ID_RTC, + PERIPH_ID_TMR, + PERIPH_ID_UART1, + PERIPH_ID_UART2, + + /* 8 */ + PERIPH_ID_GPIO, + PERIPH_ID_SDMMC2, + PERIPH_ID_SPDIF, + PERIPH_ID_I2S1, + PERIPH_ID_I2C1, + PERIPH_ID_NDFLASH, + PERIPH_ID_SDMMC1, + PERIPH_ID_SDMMC4, + + /* 16 */ + PERIPH_ID_TWC, + PERIPH_ID_PWC, + PERIPH_ID_I2S2, + PERIPH_ID_EPP, + PERIPH_ID_VI, + PERIPH_ID_2D, + PERIPH_ID_USBD, + PERIPH_ID_ISP, + + /* 24 */ + PERIPH_ID_3D, + PERIPH_ID_IDE, + PERIPH_ID_DISP2, + PERIPH_ID_DISP1, + PERIPH_ID_HOST1X, + PERIPH_ID_VCP, + PERIPH_ID_RESERVED30, + PERIPH_ID_CACHE2, + + /* Middle word: 63:32 */ + PERIPH_ID_MEM, + PERIPH_ID_AHBDMA, + PERIPH_ID_APBDMA, + PERIPH_ID_RESERVED35, + PERIPH_ID_KBC, + PERIPH_ID_STAT_MON, + PERIPH_ID_PMC, + PERIPH_ID_FUSE, + + /* 40 */ + PERIPH_ID_KFUSE, + PERIPH_ID_SBC1, + PERIPH_ID_SNOR, + PERIPH_ID_SPI1, + PERIPH_ID_SBC2, + PERIPH_ID_XIO, + PERIPH_ID_SBC3, + PERIPH_ID_DVC_I2C, + + /* 48 */ + PERIPH_ID_DSI, + PERIPH_ID_TVO, + PERIPH_ID_MIPI, + PERIPH_ID_HDMI, + PERIPH_ID_CSI, + PERIPH_ID_TVDAC, + PERIPH_ID_I2C2, + PERIPH_ID_UART3, + + /* 56 */ + PERIPH_ID_RESERVED56, + PERIPH_ID_EMC, + PERIPH_ID_USB2, + PERIPH_ID_USB3, + PERIPH_ID_MPE, + PERIPH_ID_VDE, + PERIPH_ID_BSEA, + PERIPH_ID_BSEV, + + /* Upper word 95:64 */ + PERIPH_ID_SPEEDO, + PERIPH_ID_UART4, + PERIPH_ID_UART5, + PERIPH_ID_I2C3, + PERIPH_ID_SBC4, + PERIPH_ID_SDMMC3, + PERIPH_ID_PCIE, + PERIPH_ID_OWR, + + /* 72 */ + PERIPH_ID_AFI, + PERIPH_ID_CORESIGHT, + PERIPH_ID_RESERVED74, + PERIPH_ID_AVPUCQ, + PERIPH_ID_RESERVED76, + PERIPH_ID_RESERVED77, + PERIPH_ID_RESERVED78, + PERIPH_ID_RESERVED79, + + /* 80 */ + PERIPH_ID_RESERVED80, + PERIPH_ID_RESERVED81, + PERIPH_ID_RESERVED82, + PERIPH_ID_RESERVED83, + PERIPH_ID_IRAMA, + PERIPH_ID_IRAMB, + PERIPH_ID_IRAMC, + PERIPH_ID_IRAMD, + + /* 88 */ + PERIPH_ID_CRAM2, + + PERIPH_ID_COUNT, +}; + +/* Converts a clock number to a clock register: 0=L, 1=H, 2=U */ +#define PERIPH_REG(id) ((id) >> 5) + +/* Mask value for a clock (within PERIPH_REG(id)) */ +#define PERIPH_MASK(id) (1 << ((id) & 0x1f)) + +/* return 1 if a PLL ID is in range */ +#define clock_pll_id_isvalid(id) ((id) >= CLOCK_PLL_ID_FIRST && \ + (id) < CLOCK_PLL_ID_COUNT) + +/* return 1 if a peripheral ID is in range */ +#define clock_periph_id_isvalid(id) ((id) >= PERIPH_ID_FIRST && \ + (id) < PERIPH_ID_COUNT) + +/* PLL stabilization delay in usec */ +#define CLOCK_PLL_STABLE_DELAY_US 300 + +/* return the current oscillator clock frequency */ +enum clock_osc_freq clock_get_osc_freq(void); + +/* + * Start PLL using the provided configuration parameters. + * + * @param id clock id + * @param divm input divider + * @param divn feedback divider + * @param divp post divider 2^n + * @param cpcon charge pump setup control + * @param lfcon loop filter setup control + * + * @returns monotonic time in us that the PLL will be stable + */ +unsigned long clock_start_pll(enum clock_pll_id id, u32 divm, u32 divn, + u32 divp, u32 cpcon, u32 lfcon); + +/* + * Enable a clock + * + * @param id clock id + */ +void clock_enable(enum periph_id clkid); + +/* + * Set whether a clock is enabled or disabled. + * + * @param id clock id + * @param enable 1 to enable, 0 to disable + */ +void clock_set_enable(enum periph_id clkid, int enable); + +/* + * Reset a peripheral. This puts it in reset, waits for a delay, then takes + * it out of reset and waits for th delay again. + * + * @param periph_id peripheral to reset + * @param us_delay time to delay in microseconds + */ +void reset_periph(enum periph_id periph_id, int us_delay); + +/* + * Put a peripheral into or out of reset. + * + * @param periph_id peripheral to reset + * @param enable 1 to put into reset, 0 to take out of reset + */ +void reset_set_enable(enum periph_id periph_id, int enable); + + +/* CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET/CLR_0 */ +enum crc_reset_id { + /* Things we can hold in reset for each CPU */ + crc_rst_cpu = 1, + crc_rst_de = 1 << 2, /* What is de? */ + crc_rst_watchdog = 1 << 3, + crc_rst_debug = 1 << 4, +}; + +/* + * Put parts of the CPU complex into or out of reset.\ + * + * @param cpu cpu number (0 or 1 on Tegra2) + * @param which which parts of the complex to affect (OR of crc_reset_id) + * @param reset 1 to assert reset, 0 to de-assert + */ +void reset_cmplx_set_enable(int cpu, int which, int reset); + +#endif + diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index 3d6c248..fa8243f 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -28,6 +28,7 @@ #include <asm/arch/sys_proto.h>
#include <asm/arch/clk_rst.h> +#include <asm/arch/clock.h> #include <asm/arch/pinmux.h> #include <asm/arch/uart.h> #include "board.h" @@ -73,33 +74,28 @@ int timer_init(void) static void clock_init_uart(void) { struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + struct clk_pll *pll = &clkrst->crc_pll[CLOCK_PLL_ID_PERIPH]; u32 reg;
- reg = readl(&clkrst->crc_pllp_base); + reg = readl(&pll->pll_base); if (!(reg & PLL_BASE_OVRRIDE)) { /* Override pllp setup for 216MHz operation. */ - reg = (PLL_BYPASS | PLL_BASE_OVRRIDE | PLL_DIVP); - reg |= (((NVRM_PLLP_FIXED_FREQ_KHZ/500) << 8) | PLL_DIVM); - writel(reg, &clkrst->crc_pllp_base); + reg = (PLL_BYPASS | PLL_BASE_OVRRIDE | PLL_DIVP_VALUE); + reg |= (((NVRM_PLLP_FIXED_FREQ_KHZ/500) << 8) | PLL_DIVM_VALUE); + writel(reg, &pll->pll_base);
reg |= PLL_ENABLE; - writel(reg, &clkrst->crc_pllp_base); + writel(reg, &pll->pll_base);
reg &= ~PLL_BYPASS; - writel(reg, &clkrst->crc_pllp_base); + writel(reg, &pll->pll_base); }
/* Now do the UART reset/clock enable */ #if defined(CONFIG_TEGRA2_ENABLE_UARTA) - /* Assert Reset to UART */ - reg = readl(&clkrst->crc_rst_dev_l); - reg |= SWR_UARTA_RST; /* SWR_UARTA_RST = 1 */ - writel(reg, &clkrst->crc_rst_dev_l); - - /* Enable clk to UART */ - reg = readl(&clkrst->crc_clk_out_enb_l); - reg |= CLK_ENB_UARTA; /* CLK_ENB_UARTA = 1 */ - writel(reg, &clkrst->crc_clk_out_enb_l); + /* Assert UART reset and enable clock */ + reset_set_enable(PERIPH_ID_UART1, 1); + clock_enable(PERIPH_ID_UART1);
/* Enable pllp_out0 to UART */ reg = readl(&clkrst->crc_clk_src_uarta); @@ -110,20 +106,12 @@ static void clock_init_uart(void) udelay(2);
/* De-assert reset to UART */ - reg = readl(&clkrst->crc_rst_dev_l); - reg &= ~SWR_UARTA_RST; /* SWR_UARTA_RST = 0 */ - writel(reg, &clkrst->crc_rst_dev_l); + reset_set_enable(PERIPH_ID_UART1, 0); #endif /* CONFIG_TEGRA2_ENABLE_UARTA */ #if defined(CONFIG_TEGRA2_ENABLE_UARTD) - /* Assert Reset to UART */ - reg = readl(&clkrst->crc_rst_dev_u); - reg |= SWR_UARTD_RST; /* SWR_UARTD_RST = 1 */ - writel(reg, &clkrst->crc_rst_dev_u); - - /* Enable clk to UART */ - reg = readl(&clkrst->crc_clk_out_enb_u); - reg |= CLK_ENB_UARTD; /* CLK_ENB_UARTD = 1 */ - writel(reg, &clkrst->crc_clk_out_enb_u); + /* Assert UART reset and enable clock */ + reset_set_enable(PERIPH_ID_UART4, 1); + clock_enable(PERIPH_ID_UART4);
/* Enable pllp_out0 to UART */ reg = readl(&clkrst->crc_clk_src_uartd); @@ -134,9 +122,7 @@ static void clock_init_uart(void) udelay(2);
/* De-assert reset to UART */ - reg = readl(&clkrst->crc_rst_dev_u); - reg &= ~SWR_UARTD_RST; /* SWR_UARTD_RST = 0 */ - writel(reg, &clkrst->crc_rst_dev_u); + reset_set_enable(PERIPH_ID_UART4, 0); #endif /* CONFIG_TEGRA2_ENABLE_UARTD */ }

This adds an enum for each pin and some functions for changing the pin muxing setup.
Changes for v2: - Removed use of bitfield access macros
Signed-off-by: Simon Glass sjg@chromium.org --- arch/arm/cpu/armv7/tegra2/Makefile | 2 +- arch/arm/cpu/armv7/tegra2/pinmux.c | 53 ++++++++++ arch/arm/include/asm/arch-tegra2/pinmux.h | 155 +++++++++++++++++++++++++++-- board/nvidia/common/board.c | 10 +-- 4 files changed, 205 insertions(+), 15 deletions(-) create mode 100644 arch/arm/cpu/armv7/tegra2/pinmux.c
diff --git a/arch/arm/cpu/armv7/tegra2/Makefile b/arch/arm/cpu/armv7/tegra2/Makefile index b35764c..f673f03 100644 --- a/arch/arm/cpu/armv7/tegra2/Makefile +++ b/arch/arm/cpu/armv7/tegra2/Makefile @@ -28,7 +28,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(SOC).o
SOBJS := lowlevel_init.o -COBJS := ap20.o board.o clock.o sys_info.o timer.o +COBJS := ap20.o board.o clock.o pinmux.o sys_info.o timer.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) diff --git a/arch/arm/cpu/armv7/tegra2/pinmux.c b/arch/arm/cpu/armv7/tegra2/pinmux.c new file mode 100644 index 0000000..4d35172 --- /dev/null +++ b/arch/arm/cpu/armv7/tegra2/pinmux.c @@ -0,0 +1,53 @@ +/* + * 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 pin multiplexing functions */ + +#include <asm/io.h> +#include <asm/arch/tegra2.h> +#include <asm/arch/pinmux.h> +#include <common.h> + + +void pinmux_set_tristate(enum pmux_pin pin, int enable) +{ + struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *tri = &pmt->pmt_tri[TRISTATE_REG(pin)]; + u32 reg; + + reg = readl(tri); + if (enable) + reg |= TRISTATE_MASK(pin); + else + reg &= ~TRISTATE_MASK(pin); + writel(reg, tri); +} + +void pinmux_tristate_enable(enum pmux_pin pin) +{ + pinmux_set_tristate(pin, 1); +} + +void pinmux_tristate_disable(enum pmux_pin pin) +{ + pinmux_set_tristate(pin, 0); +} + diff --git a/arch/arm/include/asm/arch-tegra2/pinmux.h b/arch/arm/include/asm/arch-tegra2/pinmux.h index 8b4bd8d..b8a4753 100644 --- a/arch/arm/include/asm/arch-tegra2/pinmux.h +++ b/arch/arm/include/asm/arch-tegra2/pinmux.h @@ -24,6 +24,142 @@ #ifndef _PINMUX_H_ #define _PINMUX_H_
+/* Pins which we can set to tristate or normal */ +enum pmux_pin { + /* APB_MISC_PP_TRISTATE_REG_A_0 */ + PIN_ATA, + PIN_ATB, + PIN_ATC, + PIN_ATD, + PIN_CDEV1, + PIN_CDEV2, + PIN_CSUS, + PIN_DAP1, + + PIN_DAP2, + PIN_DAP3, + PIN_DAP4, + PIN_DTA, + PIN_DTB, + PIN_DTC, + PIN_DTD, + PIN_DTE, + + PIN_GPU, + PIN_GPV, + PIN_I2CP, + PIN_IRTX, + PIN_IRRX, + PIN_KBCB, + PIN_KBCA, + PIN_PMC, + + PIN_PTA, + PIN_RM, + PIN_KBCE, + PIN_KBCF, + PIN_GMA, + PIN_GMC, + PIN_SDMMC1, + PIN_OWC, + + /* 32: APB_MISC_PP_TRISTATE_REG_B_0 */ + PIN_GME, + PIN_SDC, + PIN_SDD, + PIN_RESERVED0, + PIN_SLXA, + PIN_SLXC, + PIN_SLXD, + PIN_SLXK, + + PIN_SPDI, + PIN_SPDO, + PIN_SPIA, + PIN_SPIB, + PIN_SPIC, + PIN_SPID, + PIN_SPIE, + PIN_SPIF, + + PIN_SPIG, + PIN_SPIH, + PIN_UAA, + PIN_UAB, + PIN_UAC, + PIN_UAD, + PIN_UCA, + PIN_UCB, + + PIN_RESERVED1, + PIN_ATE, + PIN_KBCC, + PIN_RESERVED2, + PIN_RESERVED3, + PIN_GMB, + PIN_GMD, + PIN_DDC, + + /* 64: APB_MISC_PP_TRISTATE_REG_C_0 */ + PIN_LD0, + PIN_LD1, + PIN_LD2, + PIN_LD3, + PIN_LD4, + PIN_LD5, + PIN_LD6, + PIN_LD7, + + PIN_LD8, + PIN_LD9, + PIN_LD10, + PIN_LD11, + PIN_LD12, + PIN_LD13, + PIN_LD14, + PIN_LD15, + + PIN_LD16, + PIN_LD17, + PIN_LHP0, + PIN_LHP1, + PIN_LHP2, + PIN_LVP0, + PIN_LVP1, + PIN_HDINT, + + PIN_LM0, + PIN_LM1, + PIN_LVS, + PIN_LSC0, + PIN_LSC1, + PIN_LSCK, + PIN_LDC, + PIN_LCSN, + + /* 96: APB_MISC_PP_TRISTATE_REG_D_0 */ + PIN_LSPI, + PIN_LSDA, + PIN_LSDI, + PIN_LPW0, + PIN_LPW1, + PIN_LPW2, + PIN_LDI, + PIN_LHS, + + PIN_LPP, + PIN_RESERVED4, + PIN_KBCD, + PIN_GPU7, + PIN_DTF, + PIN_UDA, + PIN_CRTP, + PIN_SDB, +}; + + +#define TEGRA_TRISTATE_REGS 4 + /* APB MISC Pin Mux and Tristate (APB_MISC_PP_) registers */ struct pmux_tri_ctlr { uint pmt_reserved0; /* ABP_MISC_PP_ reserved offset 00 */ @@ -31,10 +167,7 @@ struct pmux_tri_ctlr { uint pmt_strap_opt_a; /* _STRAPPING_OPT_A_0, offset 08 */ uint pmt_reserved2; /* ABP_MISC_PP_ reserved offset 0C */ uint pmt_reserved3; /* ABP_MISC_PP_ reserved offset 10 */ - uint pmt_tri_a; /* _TRI_STATE_REG_A_0, offset 14 */ - uint pmt_tri_b; /* _TRI_STATE_REG_B_0, offset 18 */ - uint pmt_tri_c; /* _TRI_STATE_REG_C_0, offset 1C */ - uint pmt_tri_d; /* _TRI_STATE_REG_D_0, offset 20 */ + uint pmt_tri[TEGRA_TRISTATE_REGS]; /* _TRI_STATE_REG_A/B/C/D_0 14-20 */ uint pmt_cfg_ctl; /* _CONFIG_CTL_0, offset 24 */
uint pmt_reserved[22]; /* ABP_MISC_PP_ reserved offs 28-7C */ @@ -48,8 +181,16 @@ struct pmux_tri_ctlr { uint pmt_ctl_g; /* _PIN_MUX_CTL_G_0, offset 98 */ };
-#define Z_GMC (1 << 29) -#define Z_IRRX (1 << 20) -#define Z_IRTX (1 << 19) +/* Converts a pin number to a tristate register: 0=A, 1=B, 2=C, 3=D */ +#define TRISTATE_REG(id) ((id) >> 5) + +/* Mask value for a tristate (within TRISTATE_REG(id)) */ +#define TRISTATE_MASK(id) (1 << ((id) & 0x1f)) + +/* Set a pin to tristate */ +void pinmux_tristate_enable(enum pmux_pin pin); + +/* Set a pin to normal (non tristate) */ +void pinmux_tristate_disable(enum pmux_pin pin);
#endif /* PINMUX_H */ diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index fa8243f..480b11b 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -140,19 +140,15 @@ static void pin_mux_uart(void) reg &= 0xFFF0FFFF; /* IRRX_/IRTX_SEL [19:16] = 00 UARTA */ writel(reg, &pmt->pmt_ctl_c);
- reg = readl(&pmt->pmt_tri_a); - reg &= ~Z_IRRX; /* Z_IRRX = normal (0) */ - reg &= ~Z_IRTX; /* Z_IRTX = normal (0) */ - writel(reg, &pmt->pmt_tri_a); + pinmux_tristate_disable(PIN_IRRX); + pinmux_tristate_disable(PIN_IRTX); #endif /* CONFIG_TEGRA2_ENABLE_UARTA */ #if defined(CONFIG_TEGRA2_ENABLE_UARTD) reg = readl(&pmt->pmt_ctl_b); reg &= 0xFFFFFFF3; /* GMC_SEL [3:2] = 00, UARTD */ writel(reg, &pmt->pmt_ctl_b);
- reg = readl(&pmt->pmt_tri_a); - reg &= ~Z_GMC; /* Z_GMC = normal (0) */ - writel(reg, &pmt->pmt_tri_a); + pinmux_tristate_disable(PIN_GMC); #endif /* CONFIG_TEGRA2_ENABLE_UARTD */ }

Signed-off-by: Simon Glass sjg@chromium.org --- arch/arm/cpu/armv7/tegra2/ap20.c | 47 ++++++++------------------- arch/arm/include/asm/arch-tegra2/clk_rst.h | 37 ---------------------- board/nvidia/common/board.c | 12 +++--- 3 files changed, 20 insertions(+), 76 deletions(-)
diff --git a/arch/arm/cpu/armv7/tegra2/ap20.c b/arch/arm/cpu/armv7/tegra2/ap20.c index e3832e2..dc5f984 100644 --- a/arch/arm/cpu/armv7/tegra2/ap20.c +++ b/arch/arm/cpu/armv7/tegra2/ap20.c @@ -40,23 +40,21 @@ void init_pllx(void) u32 reg;
/* If PLLX is already enabled, just return */ - reg = readl(&pll->pll_base); - if (reg & PLL_ENABLE) + if (readl(&pll->pll_base) & PLL_ENABLE_MASK) return;
/* Set PLLX_MISC */ - reg = CPCON; /* CPCON[11:8] = 0001 */ - writel(reg, &pll->pll_misc); + writel(1 << PLL_CPCON_SHIFT, &pll->pll_misc);
/* Use 12MHz clock here */ - reg = (PLL_BYPASS | PLL_DIVM_VALUE); - reg |= (1000 << 8); /* DIVN = 0x3E8 */ + reg = PLL_BYPASS_MASK | (12 << PLL_DIVM_SHIFT); + reg |= 1000 << PLL_DIVN_SHIFT; writel(reg, &pll->pll_base);
- reg |= PLL_ENABLE; + reg |= PLL_ENABLE_MASK; writel(reg, &pll->pll_base);
- reg &= ~PLL_BYPASS; + reg &= ~PLL_BYPASS_MASK; writel(reg, &pll->pll_base); }
@@ -90,16 +88,11 @@ static void enable_cpu_clock(int enable) * always stop the clock to CPU 1. */ clk = readl(&clkrst->crc_clk_cpu_cmplx); - clk |= CPU1_CLK_STP; - - if (enable) { - /* Unstop the CPU clock */ - clk &= ~CPU0_CLK_STP; - } else { - /* Stop the CPU clock */ - clk |= CPU0_CLK_STP; - } + clk |= 1 << CPU1_CLK_STP_SHIFT;
+ /* Stop/Unstop the CPU clock */ + clk &= ~CPU0_CLK_STP_MASK; + clk |= !enable << CPU0_CLK_STP_SHIFT; writel(clk, &clkrst->crc_clk_cpu_cmplx);
clock_enable(PERIPH_ID_CPU); @@ -177,9 +170,6 @@ static void enable_cpu_power_rail(void)
static void reset_A9_cpu(int reset) { - struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - u32 cpu; - /* * 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 @@ -188,19 +178,10 @@ static void reset_A9_cpu(int reset) * are multiple processors in the CPU complex. */
- /* Hold CPU 1 in reset */ - cpu = SET_DBGRESET1 | SET_DERESET1 | SET_CPURESET1; - writel(cpu, &clkrst->crc_cpu_cmplx_set); - - if (reset) { - /* Now place CPU0 into reset */ - cpu |= SET_DBGRESET0 | SET_DERESET0 | SET_CPURESET0; - writel(cpu, &clkrst->crc_cpu_cmplx_set); - } else { - /* Take CPU0 out of reset */ - cpu = CLR_DBGRESET0 | CLR_DERESET0 | CLR_CPURESET0; - writel(cpu, &clkrst->crc_cpu_cmplx_clr); - } + /* 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); diff --git a/arch/arm/include/asm/arch-tegra2/clk_rst.h b/arch/arm/include/asm/arch-tegra2/clk_rst.h index 6c74410..e64fc93 100644 --- a/arch/arm/include/asm/arch-tegra2/clk_rst.h +++ b/arch/arm/include/asm/arch-tegra2/clk_rst.h @@ -142,43 +142,6 @@ struct clk_rst_ctlr { uint crc_cpu_cmplx_clr; /* _CPU_CMPLX_CLR_0, 0x344 */ };
-#define PLL_BYPASS (1 << 31) -#define PLL_ENABLE (1 << 30) -#define PLL_BASE_OVRRIDE (1 << 28) -#define PLL_DIVP_VALUE (1 << 20) /* post divider, b22:20 */ -#define PLL_DIVM_VALUE 0x0C /* input divider, b4:0 */ - -#define SWR_UARTD_RST (1 << 1) -#define CLK_ENB_UARTD (1 << 1) -#define SWR_UARTA_RST (1 << 6) -#define CLK_ENB_UARTA (1 << 6) - -#define SWR_CPU_RST (1 << 0) -#define CLK_ENB_CPU (1 << 0) -#define SWR_CSITE_RST (1 << 9) -#define CLK_ENB_CSITE (1 << 9) - -#define SET_CPURESET0 (1 << 0) -#define SET_DERESET0 (1 << 4) -#define SET_DBGRESET0 (1 << 12) - -#define SET_CPURESET1 (1 << 1) -#define SET_DERESET1 (1 << 5) -#define SET_DBGRESET1 (1 << 13) - -#define CLR_CPURESET0 (1 << 0) -#define CLR_DERESET0 (1 << 4) -#define CLR_DBGRESET0 (1 << 12) - -#define CLR_CPURESET1 (1 << 1) -#define CLR_DERESET1 (1 << 5) -#define CLR_DBGRESET1 (1 << 13) - -#define CPU0_CLK_STP (1 << 8) -#define CPU1_CLK_STP (1 << 9) - -#define CPCON (1 << 8) - /* CLK_RST_CONTROLLER_CLK_CPU_CMPLX_0 */ #define CPU1_CLK_STP_BITS 9 : 9 #define CPU1_CLK_STP_SHIFT bf_shift(CPU1_CLK_STP_BITS) diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index 480b11b..2007d13 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -78,20 +78,20 @@ static void clock_init_uart(void) u32 reg;
reg = readl(&pll->pll_base); - if (!(reg & PLL_BASE_OVRRIDE)) { + if (!(reg & PLL_BASE_OVRRIDE_MASK)) { /* Override pllp setup for 216MHz operation. */ - reg = (PLL_BYPASS | PLL_BASE_OVRRIDE | PLL_DIVP_VALUE); - reg |= (((NVRM_PLLP_FIXED_FREQ_KHZ/500) << 8) | PLL_DIVM_VALUE); + reg = PLL_BYPASS_MASK | PLL_BASE_OVRRIDE_MASK | + (1 << PLL_DIVP_SHIFT) | (0xc << PLL_DIVM_SHIFT); + reg |= (NVRM_PLLP_FIXED_FREQ_KHZ / 500) << PLL_DIVN_SHIFT; writel(reg, &pll->pll_base);
- reg |= PLL_ENABLE; + reg |= PLL_ENABLE_MASK; writel(reg, &pll->pll_base);
- reg &= ~PLL_BYPASS; + reg &= ~PLL_BYPASS_MASK; writel(reg, &pll->pll_base); }
- /* Now do the UART reset/clock enable */ #if defined(CONFIG_TEGRA2_ENABLE_UARTA) /* Assert UART reset and enable clock */ reset_set_enable(PERIPH_ID_UART1, 1);

Hi,
On Mon, Jun 13, 2011 at 4:38 PM, Simon Glass sjg@chromium.org wrote:
This patch series adds basic clock and pinmux functions to the Tegra2, and modifies the ap20 and board code to use them. It includes a few very simple required bitfield helper macros for ARM Tegra2 only.
Changes for v2:
- Removed use of bitfield macros in C code
- Now uses manual shifts and masks
Simon Glass (5): Tegra2: Add macros to calculate bitfield shifts and masks Tegra2: Add microsecond timer functions Tegra2: Add more clock support Tegra2: add additional pin multiplexing features Tegra2: Use clock and pinmux functions to simplify code
Is everyone OK with this patch set? Should I resend? Now that the GPIO code is in, this can go in also.
Regards, Simon
arch/arm/cpu/armv7/tegra2/Makefile | 2 +- arch/arm/cpu/armv7/tegra2/ap20.c | 91 +++------- arch/arm/cpu/armv7/tegra2/clock.c | 158 ++++++++++++++++ arch/arm/cpu/armv7/tegra2/pinmux.c | 53 ++++++ arch/arm/cpu/armv7/tegra2/timer.c | 27 ++- arch/arm/include/asm/arch-tegra2/bitfield.h | 96 ++++++++++ arch/arm/include/asm/arch-tegra2/clk_rst.h | 140 +++++++------- arch/arm/include/asm/arch-tegra2/clock.h | 264 +++++++++++++++++++++++++++ arch/arm/include/asm/arch-tegra2/pinmux.h | 155 +++++++++++++++- arch/arm/include/asm/arch-tegra2/timer.h | 34 ++++ board/nvidia/common/board.c | 64 +++---- 11 files changed, 893 insertions(+), 191 deletions(-) create mode 100644 arch/arm/cpu/armv7/tegra2/clock.c create mode 100644 arch/arm/cpu/armv7/tegra2/pinmux.c create mode 100644 arch/arm/include/asm/arch-tegra2/bitfield.h create mode 100644 arch/arm/include/asm/arch-tegra2/clock.h create mode 100644 arch/arm/include/asm/arch-tegra2/timer.h
-- 1.7.3.1
participants (1)
-
Simon Glass