diff options
Diffstat (limited to 'arch/arm/cpu')
66 files changed, 3260 insertions, 1267 deletions
diff --git a/arch/arm/cpu/arm1136/config.mk b/arch/arm/cpu/arm1136/config.mk index f74228c..ab1fc4a 100644 --- a/arch/arm/cpu/arm1136/config.mk +++ b/arch/arm/cpu/arm1136/config.mk @@ -14,6 +14,6 @@ ifdef CONFIG_SPL_BUILD ALL-y += $(OBJTREE)/SPL endif else -ALL-y += $(obj)u-boot.imx +ALL-y += u-boot.imx endif endif diff --git a/arch/arm/cpu/arm1176/bcm2835/config.mk b/arch/arm/cpu/arm1176/bcm2835/config.mk deleted file mode 100644 index b87ce24..0000000 --- a/arch/arm/cpu/arm1176/bcm2835/config.mk +++ /dev/null @@ -1,19 +0,0 @@ -# -# (C) Copyright 2012 Stephen Warren -# -# 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 -# version 2 as published by the Free Software Foundation. -# -# 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. - -# Don't attempt to override the target CPU/ABI options; -# the Raspberry Pi toolchain does the right thing by default. -PLATFORM_RELFLAGS := $(filter-out -msoft-float,$(PLATFORM_RELFLAGS)) -PLATFORM_CPPFLAGS := $(filter-out -march=armv5t,$(PLATFORM_CPPFLAGS)) diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.c b/arch/arm/cpu/arm720t/tegra-common/cpu.c index 72c69b9..2c5cd63 100644 --- a/arch/arm/cpu/arm720t/tegra-common/cpu.c +++ b/arch/arm/cpu/arm720t/tegra-common/cpu.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -112,24 +112,38 @@ struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = { { .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz */ { .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz */ }, + + /* + * T124: 700 MHz + * + * Register Field Bits Width + * ------------------------------ + * PLLX_BASE p 23:20 4 + * PLLX_BASE n 15: 8 8 + * PLLX_BASE m 7: 0 8 + */ + { + { .n = 108, .m = 1, .p = 1 }, /* OSC: 13.0 MHz */ + { .n = 73, .m = 1, .p = 1 }, /* OSC: 19.2 MHz */ + { .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz */ + { .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz */ + }, }; -void adjust_pllp_out_freqs(void) +static inline void pllx_set_iddq(void) { +#if defined(CONFIG_TEGRA124) struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - struct clk_pll *pll = &clkrst->crc_pll[CLOCK_ID_PERIPH]; u32 reg; - /* Set T30 PLLP_OUT1, 2, 3 & 4 freqs to 9.6, 48, 102 & 204MHz */ - reg = readl(&pll->pll_out[0]); /* OUTA, contains OUT2 / OUT1 */ - reg |= (IN_408_OUT_48_DIVISOR << PLLP_OUT2_RATIO) | PLLP_OUT2_OVR - | (IN_408_OUT_9_6_DIVISOR << PLLP_OUT1_RATIO) | PLLP_OUT1_OVR; - writel(reg, &pll->pll_out[0]); - - reg = readl(&pll->pll_out[1]); /* OUTB, contains OUT4 / OUT3 */ - reg |= (IN_408_OUT_204_DIVISOR << PLLP_OUT4_RATIO) | PLLP_OUT4_OVR - | (IN_408_OUT_102_DIVISOR << PLLP_OUT3_RATIO) | PLLP_OUT3_OVR; - writel(reg, &pll->pll_out[1]); + /* Disable IDDQ */ + reg = readl(&clkrst->crc_pllx_misc3); + reg &= ~PLLX_IDDQ_MASK; + writel(reg, &clkrst->crc_pllx_misc3); + udelay(2); + debug("%s: IDDQ: PLLX IDDQ = 0x%08X\n", __func__, + readl(&clkrst->crc_pllx_misc3)); +#endif } int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm, @@ -146,6 +160,8 @@ int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm, debug(" pllx_set_rate entry\n"); + pllx_set_iddq(); + /* Set BYPASS, m, n and p to PLLX_BASE */ reg = PLL_BYPASS_MASK | (divm << PLL_DIVM_SHIFT); reg |= ((divn << PLL_DIVN_SHIFT) | (divp << PLL_DIVP_SHIFT)); @@ -162,18 +178,23 @@ int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm, reg |= (1 << PLL_DCCON_SHIFT); writel(reg, &pll->pll_misc); - /* Enable PLLX */ - reg = readl(&pll->pll_base); - reg |= PLL_ENABLE_MASK; - /* Disable BYPASS */ + reg = readl(&pll->pll_base); reg &= ~PLL_BYPASS_MASK; writel(reg, &pll->pll_base); + debug("pllx_set_rate: base = 0x%08X\n", reg); /* Set lock_enable to PLLX_MISC */ reg = readl(&pll->pll_misc); reg |= PLL_LOCK_ENABLE_MASK; writel(reg, &pll->pll_misc); + debug("pllx_set_rate: misc = 0x%08X\n", reg); + + /* Enable PLLX last, once it's all configured */ + reg = readl(&pll->pll_base); + reg |= PLL_ENABLE_MASK; + writel(reg, &pll->pll_base); + debug("pllx_set_rate: base final = 0x%08X\n", reg); return 0; } @@ -207,12 +228,6 @@ void init_pllx(void) /* set pllx */ sel = &tegra_pll_x_table[chip_sku][osc]; pllx_set_rate(pll, sel->n, sel->m, sel->p, sel->cpcon); - - /* adjust PLLP_out1-4 on T3x/T114 */ - if (soc_type >= CHIPID_TEGRA30) { - debug(" init_pllx: adjusting PLLP out freqs\n"); - adjust_pllp_out_freqs(); - } } void enable_cpu_clock(int enable) @@ -334,7 +349,6 @@ void reset_A9_cpu(int reset) void clock_enable_coresight(int enable) { u32 rst, src = 2; - int soc_type; debug("clock_enable_coresight entry\n"); clock_set_enable(PERIPH_ID_CORESIGHT, enable); @@ -343,20 +357,11 @@ void clock_enable_coresight(int enable) if (enable) { /* * Put CoreSight on PLLP_OUT0 and divide it down as per - * PLLP base frequency based on SoC type (T20/T30/T114). + * PLLP base frequency based on SoC type (T20/T30+). * Clock divider request would setup CSITE clock as 144MHz * for PLLP base 216MHz and 204MHz for PLLP base 408MHz */ - - soc_type = tegra_get_chip(); - if (soc_type == CHIPID_TEGRA30 || soc_type == CHIPID_TEGRA114) - src = CLK_DIVIDER(NVBL_PLLP_KHZ, 204000); - else if (soc_type == CHIPID_TEGRA20) - src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000); - else - printf("%s: Unknown SoC type %X!\n", - __func__, soc_type); - + src = CLK_DIVIDER(NVBL_PLLP_KHZ, CSITE_KHZ); clock_ll_set_source_divisor(PERIPH_ID_CSI, 0, src); /* Unlock the CPU CoreSight interfaces */ diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.h b/arch/arm/cpu/arm720t/tegra-common/cpu.h index 60412c7..b4ca44f 100644 --- a/arch/arm/cpu/arm720t/tegra-common/cpu.h +++ b/arch/arm/cpu/arm720t/tegra-common/cpu.h @@ -1,5 +1,5 @@ /* - * (C) Copyright 2010-2011 + * (C) Copyright 2010-2014 * NVIDIA Corporation <www.nvidia.com> * * SPDX-License-Identifier: GPL-2.0+ @@ -11,9 +11,12 @@ #define IO_STABILIZATION_DELAY (1000) #if defined(CONFIG_TEGRA20) -#define NVBL_PLLP_KHZ (216000) -#elif defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114) -#define NVBL_PLLP_KHZ (408000) +#define NVBL_PLLP_KHZ 216000 +#define CSITE_KHZ 144000 +#elif defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114) || \ + defined(CONFIG_TEGRA124) +#define NVBL_PLLP_KHZ 408000 +#define CSITE_KHZ 204000 #else #error "Unknown Tegra chip!" #endif @@ -68,3 +71,4 @@ int tegra_get_chip(void); int tegra_get_sku_info(void); int tegra_get_chip_sku(void); void adjust_pllp_out_freqs(void); +void pmic_enable_cpu_vdd(void); diff --git a/arch/arm/cpu/arm720t/tegra114/cpu.c b/arch/arm/cpu/arm720t/tegra114/cpu.c index 51ecff7..d10b96a 100644 --- a/arch/arm/cpu/arm720t/tegra114/cpu.c +++ b/arch/arm/cpu/arm720t/tegra114/cpu.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -68,7 +68,7 @@ static void enable_cpu_clocks(void) /* Wait for PLL-X to lock */ do { reg = readl(&clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base); - } while ((reg & (1 << 27)) == 0); + } while ((reg & PLL_LOCK_MASK) == 0); /* Wait until all clocks are stable */ udelay(PLL_STABILIZATION_DELAY); @@ -126,18 +126,6 @@ void t114_init_clocks(void) /* Set active CPU cluster to G */ clrbits_le32(&flow->cluster_control, 1); - /* - * Switch system clock to PLLP_OUT4 (108 MHz), AVP will now run - * at 108 MHz. This is glitch free as only the source is changed, no - * special precaution needed. - */ - val = (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_FIQ_SOURCE_SHIFT) | - (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IRQ_SOURCE_SHIFT) | - (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_RUN_SOURCE_SHIFT) | - (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IDLE_SOURCE_SHIFT) | - (SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT); - writel(val, &clkrst->crc_sclk_brst_pol); - writel(SUPER_SCLK_ENB_MASK, &clkrst->crc_super_sclk_div); debug("Setting up PLLX\n"); @@ -204,45 +192,43 @@ void t114_init_clocks(void) debug("t114_init_clocks exit\n"); } -static int is_partition_powered(u32 mask) +static bool is_partition_powered(u32 partid) { struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; u32 reg; /* Get power gate status */ reg = readl(&pmc->pmc_pwrgate_status); - return (reg & mask) == mask; + return !!(reg & (1 << partid)); } -static int is_clamp_enabled(u32 mask) +static bool is_clamp_enabled(u32 partid) { struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; u32 reg; - /* Get clamp status. TODO: Add pmc_clamp_status alias to pmc.h */ - reg = readl(&pmc->pmc_pwrgate_timer_on); - return (reg & mask) == mask; + /* Get clamp status. */ + reg = readl(&pmc->pmc_clamp_status); + return !!(reg & (1 << partid)); } -static void power_partition(u32 status, u32 partid) +static void power_partition(u32 partid) { struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; - debug("%s: status = %08X, part ID = %08X\n", __func__, status, partid); + debug("%s: part ID = %08X\n", __func__, partid); /* Is the partition already on? */ - if (!is_partition_powered(status)) { + if (!is_partition_powered(partid)) { /* No, toggle the partition power state (OFF -> ON) */ debug("power_partition, toggling state\n"); - clrbits_le32(&pmc->pmc_pwrgate_toggle, 0x1F); - setbits_le32(&pmc->pmc_pwrgate_toggle, partid); - setbits_le32(&pmc->pmc_pwrgate_toggle, START_CP); + writel(START_CP | partid, &pmc->pmc_pwrgate_toggle); /* Wait for the power to come up */ - while (!is_partition_powered(status)) + while (!is_partition_powered(partid)) ; /* Wait for the clamp status to be cleared */ - while (is_clamp_enabled(status)) + while (is_clamp_enabled(partid)) ; /* Give I/O signals time to stabilize */ @@ -257,13 +243,13 @@ void powerup_cpus(void) /* We boot to the fast cluster */ debug("powerup_cpus entry: G cluster\n"); /* Power up the fast cluster rail partition */ - power_partition(CRAIL, CRAILID); + power_partition(CRAIL); /* Power up the fast cluster non-CPU partition */ - power_partition(C0NC, C0NCID); + power_partition(C0NC); /* Power up the fast cluster CPU0 partition */ - power_partition(CE0, CE0ID); + power_partition(CE0); } void start_cpu(u32 reset_vector) diff --git a/arch/arm/cpu/arm720t/tegra124/Makefile b/arch/arm/cpu/arm720t/tegra124/Makefile new file mode 100644 index 0000000..61abf45 --- /dev/null +++ b/arch/arm/cpu/arm720t/tegra124/Makefile @@ -0,0 +1,8 @@ +# +# (C) Copyright 2013-2014 +# NVIDIA Corporation <www.nvidia.com> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += cpu.o diff --git a/arch/arm/cpu/arm720t/tegra124/config.mk b/arch/arm/cpu/arm720t/tegra124/config.mk new file mode 100644 index 0000000..5e10701 --- /dev/null +++ b/arch/arm/cpu/arm720t/tegra124/config.mk @@ -0,0 +1,7 @@ +# +# (C) Copyright 2010-2013 +# NVIDIA Corporation <www.nvidia.com> +# +# SPDX-License-Identifier: GPL-2.0+ +#/ +USE_PRIVATE_LIBGCC = yes diff --git a/arch/arm/cpu/arm720t/tegra124/cpu.c b/arch/arm/cpu/arm720t/tegra124/cpu.c new file mode 100644 index 0000000..c03aaf1 --- /dev/null +++ b/arch/arm/cpu/arm720t/tegra124/cpu.c @@ -0,0 +1,265 @@ +/* + * (C) Copyright 2013 + * NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/ahb.h> +#include <asm/arch/clock.h> +#include <asm/arch/flow.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/tegra.h> +#include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/pmc.h> +#include <asm/arch-tegra/ap.h> +#include "../tegra-common/cpu.h" + +/* Tegra124-specific CPU init code */ + +static void enable_cpu_power_rail(void) +{ + struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; + + debug("enable_cpu_power_rail entry\n"); + + /* un-tristate PWR_I2C SCL/SDA, rest of the defaults are correct */ + pinmux_tristate_disable(PINGRP_PWR_I2C_SCL); + pinmux_tristate_disable(PINGRP_PWR_I2C_SDA); + + pmic_enable_cpu_vdd(); + + /* + * Set CPUPWRGOOD_TIMER - APB clock is 1/2 of SCLK (102MHz), + * set it for 5ms as per SysEng (102MHz*5ms = 510000 (7C830h). + */ + writel(0x7C830, &pmc->pmc_cpupwrgood_timer); + + /* Set polarity to 0 (normal) and enable CPUPWRREQ_OE */ + clrbits_le32(&pmc->pmc_cntrl, CPUPWRREQ_POL); + setbits_le32(&pmc->pmc_cntrl, CPUPWRREQ_OE); +} + +static void enable_cpu_clocks(void) +{ + struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + u32 reg; + + debug("enable_cpu_clocks entry\n"); + + /* Wait for PLL-X to lock */ + do { + reg = readl(&clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base); + debug("%s: PLLX base = 0x%08X\n", __func__, reg); + } while ((reg & PLL_LOCK_MASK) == 0); + + debug("%s: PLLX locked, delay for stable clocks\n", __func__); + /* Wait until all clocks are stable */ + udelay(PLL_STABILIZATION_DELAY); + + debug("%s: Setting CCLK_BURST and DIVIDER\n", __func__); + writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol); + writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div); + + debug("%s: Enabling clock to all CPUs\n", __func__); + /* Enable the clock to all CPUs */ + reg = CLR_CPU3_CLK_STP | CLR_CPU2_CLK_STP | CLR_CPU1_CLK_STP | + CLR_CPU0_CLK_STP; + writel(reg, &clkrst->crc_clk_cpu_cmplx_clr); + + debug("%s: Enabling main CPU complex clocks\n", __func__); + /* Always enable the main CPU complex clocks */ + clock_enable(PERIPH_ID_CPU); + clock_enable(PERIPH_ID_CPULP); + clock_enable(PERIPH_ID_CPUG); + + debug("%s: Done\n", __func__); +} + +static void remove_cpu_resets(void) +{ + struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + u32 reg; + + debug("remove_cpu_resets entry\n"); + + /* Take the slow and fast partitions out of reset */ + reg = CLR_NONCPURESET; + writel(reg, &clkrst->crc_rst_cpulp_cmplx_clr); + writel(reg, &clkrst->crc_rst_cpug_cmplx_clr); + + /* Clear the SW-controlled reset of the slow cluster */ + reg = CLR_CPURESET0 | CLR_DBGRESET0 | CLR_CORERESET0 | CLR_CXRESET0 | + CLR_L2RESET | CLR_PRESETDBG; + writel(reg, &clkrst->crc_rst_cpulp_cmplx_clr); + + /* Clear the SW-controlled reset of the fast cluster */ + reg = CLR_CPURESET0 | CLR_DBGRESET0 | CLR_CORERESET0 | CLR_CXRESET0 | + CLR_CPURESET1 | CLR_DBGRESET1 | CLR_CORERESET1 | CLR_CXRESET1 | + CLR_CPURESET2 | CLR_DBGRESET2 | CLR_CORERESET2 | CLR_CXRESET2 | + CLR_CPURESET3 | CLR_DBGRESET3 | CLR_CORERESET3 | CLR_CXRESET3 | + CLR_L2RESET | CLR_PRESETDBG; + writel(reg, &clkrst->crc_rst_cpug_cmplx_clr); +} + +/** + * The Tegra124 requires some special clock initialization, including setting up + * the DVC I2C, turning on MSELECT and selecting the G CPU cluster + */ +void tegra124_init_clocks(void) +{ + struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE; + struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + u32 val; + + debug("tegra124_init_clocks entry\n"); + + /* Set active CPU cluster to G */ + clrbits_le32(&flow->cluster_control, 1); + + /* Change the oscillator drive strength */ + val = readl(&clkrst->crc_osc_ctrl); + val &= ~OSC_XOFS_MASK; + val |= (OSC_DRIVE_STRENGTH << OSC_XOFS_SHIFT); + writel(val, &clkrst->crc_osc_ctrl); + + /* Update same value in PMC_OSC_EDPD_OVER XOFS field for warmboot */ + val = readl(&pmc->pmc_osc_edpd_over); + val &= ~PMC_XOFS_MASK; + val |= (OSC_DRIVE_STRENGTH << PMC_XOFS_SHIFT); + writel(val, &pmc->pmc_osc_edpd_over); + + /* Set HOLD_CKE_LOW_EN to 1 */ + setbits_le32(&pmc->pmc_cntrl2, HOLD_CKE_LOW_EN); + + debug("Setting up PLLX\n"); + init_pllx(); + + val = (1 << CLK_SYS_RATE_AHB_RATE_SHIFT); + writel(val, &clkrst->crc_clk_sys_rate); + + /* Enable clocks to required peripherals. TBD - minimize this list */ + debug("Enabling clocks\n"); + + clock_set_enable(PERIPH_ID_CACHE2, 1); + clock_set_enable(PERIPH_ID_GPIO, 1); + clock_set_enable(PERIPH_ID_TMR, 1); + clock_set_enable(PERIPH_ID_CPU, 1); + clock_set_enable(PERIPH_ID_EMC, 1); + clock_set_enable(PERIPH_ID_I2C5, 1); + clock_set_enable(PERIPH_ID_APBDMA, 1); + clock_set_enable(PERIPH_ID_MEM, 1); + clock_set_enable(PERIPH_ID_CORESIGHT, 1); + clock_set_enable(PERIPH_ID_MSELECT, 1); + clock_set_enable(PERIPH_ID_DVFS, 1); + + /* + * Set MSELECT clock source as PLLP (00), and ask for a clock + * divider that would set the MSELECT clock at 102MHz for a + * PLLP base of 408MHz. + */ + clock_ll_set_source_divisor(PERIPH_ID_MSELECT, 0, + CLK_DIVIDER(NVBL_PLLP_KHZ, 102000)); + + /* Give clock time to stabilize */ + udelay(IO_STABILIZATION_DELAY); + + /* I2C5 (DVC) gets CLK_M and a divisor of 17 */ + clock_ll_set_source_divisor(PERIPH_ID_I2C5, 3, 16); + + /* Give clock time to stabilize */ + udelay(IO_STABILIZATION_DELAY); + + /* Take required peripherals out of reset */ + debug("Taking periphs out of reset\n"); + reset_set_enable(PERIPH_ID_CACHE2, 0); + reset_set_enable(PERIPH_ID_GPIO, 0); + reset_set_enable(PERIPH_ID_TMR, 0); + reset_set_enable(PERIPH_ID_COP, 0); + reset_set_enable(PERIPH_ID_EMC, 0); + reset_set_enable(PERIPH_ID_I2C5, 0); + reset_set_enable(PERIPH_ID_APBDMA, 0); + reset_set_enable(PERIPH_ID_MEM, 0); + reset_set_enable(PERIPH_ID_CORESIGHT, 0); + reset_set_enable(PERIPH_ID_MSELECT, 0); + reset_set_enable(PERIPH_ID_DVFS, 0); + + debug("tegra124_init_clocks exit\n"); +} + +static bool is_partition_powered(u32 partid) +{ + struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; + u32 reg; + + /* Get power gate status */ + reg = readl(&pmc->pmc_pwrgate_status); + return !!(reg & (1 << partid)); +} + +static void power_partition(u32 partid) +{ + struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; + + debug("%s: part ID = %08X\n", __func__, partid); + /* Is the partition already on? */ + if (!is_partition_powered(partid)) { + /* No, toggle the partition power state (OFF -> ON) */ + debug("power_partition, toggling state\n"); + writel(START_CP | partid, &pmc->pmc_pwrgate_toggle); + + /* Wait for the power to come up */ + while (!is_partition_powered(partid)) + ; + + /* Give I/O signals time to stabilize */ + udelay(IO_STABILIZATION_DELAY); + } +} + +void powerup_cpus(void) +{ + debug("powerup_cpus entry\n"); + + /* We boot to the fast cluster */ + debug("powerup_cpus entry: G cluster\n"); + + /* Power up the fast cluster rail partition */ + debug("powerup_cpus: CRAIL\n"); + power_partition(CRAIL); + + /* Power up the fast cluster non-CPU partition */ + debug("powerup_cpus: C0NC\n"); + power_partition(C0NC); + + /* Power up the fast cluster CPU0 partition */ + debug("powerup_cpus: CE0\n"); + power_partition(CE0); + + debug("powerup_cpus: done\n"); +} + +void start_cpu(u32 reset_vector) +{ + struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; + + debug("start_cpu entry, reset_vector = %x\n", reset_vector); + + tegra124_init_clocks(); + + /* Set power-gating timer multiplier */ + clrbits_le32(&pmc->pmc_pwrgate_timer_mult, TIMER_MULT_MASK); + setbits_le32(&pmc->pmc_pwrgate_timer_mult, MULT_8); + + enable_cpu_power_rail(); + enable_cpu_clocks(); + clock_enable_coresight(1); + remove_cpu_resets(); + writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR); + powerup_cpus(); + debug("start_cpu exit, should continue @ reset_vector\n"); +} diff --git a/arch/arm/cpu/arm720t/tegra30/cpu.c b/arch/arm/cpu/arm720t/tegra30/cpu.c index e162357..a806483 100644 --- a/arch/arm/cpu/arm720t/tegra30/cpu.c +++ b/arch/arm/cpu/arm720t/tegra30/cpu.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -84,18 +84,6 @@ void t30_init_clocks(void) /* Set active CPU cluster to G */ clrbits_le32(flow->cluster_control, 1 << 0); - /* - * Switch system clock to PLLP_OUT4 (108 MHz), AVP will now run - * at 108 MHz. This is glitch free as only the source is changed, no - * special precaution needed. - */ - val = (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_FIQ_SOURCE_SHIFT) | - (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IRQ_SOURCE_SHIFT) | - (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_RUN_SOURCE_SHIFT) | - (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IDLE_SOURCE_SHIFT) | - (SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT); - writel(val, &clkrst->crc_sclk_brst_pol); - writel(SUPER_SCLK_ENB_MASK, &clkrst->crc_super_sclk_div); val = (0 << CLK_SYS_RATE_HCLK_DISABLE_SHIFT) | diff --git a/arch/arm/cpu/arm926ejs/config.mk b/arch/arm/cpu/arm926ejs/config.mk index 4d9895f..f27ca15 100644 --- a/arch/arm/cpu/arm926ejs/config.mk +++ b/arch/arm/cpu/arm926ejs/config.mk @@ -13,6 +13,6 @@ ifdef CONFIG_SPL_BUILD ALL-y += $(OBJTREE)/SPL endif else -ALL-y += $(obj)u-boot.imx +ALL-y += u-boot.imx endif endif diff --git a/arch/arm/cpu/arm926ejs/davinci/config.mk b/arch/arm/cpu/arm926ejs/davinci/config.mk index d5c978b..69e9d5a 100644 --- a/arch/arm/cpu/arm926ejs/davinci/config.mk +++ b/arch/arm/cpu/arm926ejs/davinci/config.mk @@ -4,5 +4,5 @@ # SPDX-License-Identifier: GPL-2.0+ # ifndef CONFIG_SPL_BUILD -ALL-$(CONFIG_SPL_FRAMEWORK) += $(obj)u-boot.ais +ALL-$(CONFIG_SPL_FRAMEWORK) += u-boot.ais endif diff --git a/arch/arm/cpu/arm926ejs/omap/Makefile b/arch/arm/cpu/arm926ejs/omap/Makefile index bd0a2fb..add9232 100644 --- a/arch/arm/cpu/arm926ejs/omap/Makefile +++ b/arch/arm/cpu/arm926ejs/omap/Makefile @@ -5,5 +5,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y = timer.o cpuinfo.o +obj-y = timer.o +obj-$(CONFIG_DISPLAY_CPUINFO) += cpuinfo.o obj-y += reset.o diff --git a/arch/arm/cpu/arm926ejs/omap/cpuinfo.c b/arch/arm/cpu/arm926ejs/omap/cpuinfo.c index 02332ee..587d99a 100644 --- a/arch/arm/cpu/arm926ejs/omap/cpuinfo.c +++ b/arch/arm/cpu/arm926ejs/omap/cpuinfo.c @@ -13,7 +13,7 @@ #include <command.h> #include <linux/compiler.h> -#if defined(CONFIG_DISPLAY_CPUINFO) && defined(CONFIG_OMAP) +#if defined(CONFIG_OMAP) #define omap_readw(x) *(volatile unsigned short *)(x) #define omap_readl(x) *(volatile unsigned long *)(x) @@ -239,4 +239,4 @@ int print_cpuinfo (void) return 0; } -#endif /* #if defined(CONFIG_DISPLAY_CPUINFO) && defined(CONFIG_OMAP) */ +#endif /* #if defined(CONFIG_OMAP) */ diff --git a/arch/arm/cpu/armv7/am33xx/config.mk b/arch/arm/cpu/armv7/am33xx/config.mk index 8e3668f..1c06fb4 100644 --- a/arch/arm/cpu/armv7/am33xx/config.mk +++ b/arch/arm/cpu/armv7/am33xx/config.mk @@ -7,5 +7,5 @@ ifdef CONFIG_SPL_BUILD ALL-y += $(OBJTREE)/MLO ALL-$(CONFIG_SPL_SPI_SUPPORT) += $(OBJTREE)/MLO.byteswap else -ALL-y += $(obj)u-boot.img +ALL-y += u-boot.img endif diff --git a/arch/arm/cpu/armv7/config.mk b/arch/arm/cpu/armv7/config.mk index 38b7c40..d01f3d9 100644 --- a/arch/arm/cpu/armv7/config.mk +++ b/arch/arm/cpu/armv7/config.mk @@ -20,6 +20,6 @@ ifdef CONFIG_SPL_BUILD ALL-y += $(OBJTREE)/SPL endif else -ALL-y += $(obj)u-boot.imx +ALL-y += u-boot.imx endif endif diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 5bde9d1..1fea4d6 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -26,7 +26,7 @@ struct clk_bit_info { }; /* src_bit div_bit prediv_bit */ -static struct clk_bit_info clk_bit_info[PERIPH_ID_COUNT] = { +static struct clk_bit_info clk_bit_info[] = { {0, 0, -1}, {4, 4, -1}, {8, 8, -1}, @@ -870,7 +870,6 @@ static void exynos4_set_mmc_clk(int dev_index, unsigned int div) struct exynos4_clock *clk = (struct exynos4_clock *)samsung_get_base_clock(); unsigned int addr; - unsigned int val; /* * CLK_DIV_FSYS1 @@ -890,10 +889,8 @@ static void exynos4_set_mmc_clk(int dev_index, unsigned int div) dev_index -= 2; } - val = readl(addr); - val &= ~(0xff << ((dev_index << 4) + 8)); - val |= (div & 0xff) << ((dev_index << 4) + 8); - writel(val, addr); + clrsetbits_le32(addr, 0xff << ((dev_index << 4) + 8), + (div & 0xff) << ((dev_index << 4) + 8)); } /* exynos4x12: set the mmc clock */ @@ -902,7 +899,6 @@ static void exynos4x12_set_mmc_clk(int dev_index, unsigned int div) struct exynos4x12_clock *clk = (struct exynos4x12_clock *)samsung_get_base_clock(); unsigned int addr; - unsigned int val; /* * CLK_DIV_FSYS1 @@ -917,10 +913,8 @@ static void exynos4x12_set_mmc_clk(int dev_index, unsigned int div) dev_index -= 2; } - val = readl(addr); - val &= ~(0xff << ((dev_index << 4) + 8)); - val |= (div & 0xff) << ((dev_index << 4) + 8); - writel(val, addr); + clrsetbits_le32(addr, 0xff << ((dev_index << 4) + 8), + (div & 0xff) << ((dev_index << 4) + 8)); } /* exynos5: set the mmc clock */ @@ -929,7 +923,6 @@ static void exynos5_set_mmc_clk(int dev_index, unsigned int div) struct exynos5_clock *clk = (struct exynos5_clock *)samsung_get_base_clock(); unsigned int addr; - unsigned int val; /* * CLK_DIV_FSYS1 @@ -944,10 +937,8 @@ static void exynos5_set_mmc_clk(int dev_index, unsigned int div) dev_index -= 2; } - val = readl(addr); - val &= ~(0xff << ((dev_index << 4) + 8)); - val |= (div & 0xff) << ((dev_index << 4) + 8); - writel(val, addr); + clrsetbits_le32(addr, 0xff << ((dev_index << 4) + 8), + (div & 0xff) << ((dev_index << 4) + 8)); } /* exynos5: set the mmc clock */ @@ -956,7 +947,7 @@ static void exynos5420_set_mmc_clk(int dev_index, unsigned int div) struct exynos5420_clock *clk = (struct exynos5420_clock *)samsung_get_base_clock(); unsigned int addr; - unsigned int val, shift; + unsigned int shift; /* * CLK_DIV_FSYS1 @@ -967,10 +958,7 @@ static void exynos5420_set_mmc_clk(int dev_index, unsigned int div) addr = (unsigned int)&clk->div_fsys1; shift = dev_index * 10; - val = readl(addr); - val &= ~(0x3ff << shift); - val |= (div & 0x3ff) << shift; - writel(val, addr); + clrsetbits_le32(addr, 0x3ff << shift, (div & 0x3ff) << shift); } /* get_lcd_clk: return lcd clock frequency */ @@ -1061,7 +1049,6 @@ void exynos4_set_lcd_clk(void) { struct exynos4_clock *clk = (struct exynos4_clock *)samsung_get_base_clock(); - unsigned int cfg = 0; /* * CLK_GATE_BLOCK @@ -1073,9 +1060,7 @@ void exynos4_set_lcd_clk(void) * CLK_LCD1 [5] * CLK_GPS [7] */ - cfg = readl(&clk->gate_block); - cfg |= 1 << 4; - writel(cfg, &clk->gate_block); + setbits_le32(&clk->gate_block, 1 << 4); /* * CLK_SRC_LCD0 @@ -1085,10 +1070,7 @@ void exynos4_set_lcd_clk(void) * MIPI0_SEL [12:15] * set lcd0 src clock 0x6: SCLK_MPLL */ - cfg = readl(&clk->src_lcd0); - cfg &= ~(0xf); - cfg |= 0x6; - writel(cfg, &clk->src_lcd0); + clrsetbits_le32(&clk->src_lcd0, 0xf, 0x6); /* * CLK_GATE_IP_LCD0 @@ -1100,9 +1082,7 @@ void exynos4_set_lcd_clk(void) * CLK_PPMULCD0 [5] * Gating all clocks for FIMD0 */ - cfg = readl(&clk->gate_ip_lcd0); - cfg |= 1 << 0; - writel(cfg, &clk->gate_ip_lcd0); + setbits_le32(&clk->gate_ip_lcd0, 1 << 0); /* * CLK_DIV_LCD0 @@ -1114,16 +1094,13 @@ void exynos4_set_lcd_clk(void) * MIPI0_PRE_RATIO [23:20] * set fimd ratio */ - cfg &= ~(0xf); - cfg |= 0x1; - writel(cfg, &clk->div_lcd0); + clrsetbits_le32(&clk->div_lcd0, 0xf, 0x1); } void exynos5_set_lcd_clk(void) { struct exynos5_clock *clk = (struct exynos5_clock *)samsung_get_base_clock(); - unsigned int cfg = 0; /* * CLK_GATE_BLOCK @@ -1135,9 +1112,7 @@ void exynos5_set_lcd_clk(void) * CLK_LCD1 [5] * CLK_GPS [7] */ - cfg = readl(&clk->gate_block); - cfg |= 1 << 4; - writel(cfg, &clk->gate_block); + setbits_le32(&clk->gate_block, 1 << 4); /* * CLK_SRC_LCD0 @@ -1147,10 +1122,7 @@ void exynos5_set_lcd_clk(void) * MIPI0_SEL [12:15] * set lcd0 src clock 0x6: SCLK_MPLL */ - cfg = readl(&clk->src_disp1_0); - cfg &= ~(0xf); - cfg |= 0x6; - writel(cfg, &clk->src_disp1_0); + clrsetbits_le32(&clk->src_disp1_0, 0xf, 0x6); /* * CLK_GATE_IP_LCD0 @@ -1162,9 +1134,7 @@ void exynos5_set_lcd_clk(void) * CLK_PPMULCD0 [5] * Gating all clocks for FIMD0 */ - cfg = readl(&clk->gate_ip_disp1); - cfg |= 1 << 0; - writel(cfg, &clk->gate_ip_disp1); + setbits_le32(&clk->gate_ip_disp1, 1 << 0); /* * CLK_DIV_LCD0 @@ -1176,16 +1146,13 @@ void exynos5_set_lcd_clk(void) * MIPI0_PRE_RATIO [23:20] * set fimd ratio */ - cfg &= ~(0xf); - cfg |= 0x0; - writel(cfg, &clk->div_disp1_0); + clrsetbits_le32(&clk->div_disp1_0, 0xf, 0x0); } void exynos4_set_mipi_clk(void) { struct exynos4_clock *clk = (struct exynos4_clock *)samsung_get_base_clock(); - unsigned int cfg = 0; /* * CLK_SRC_LCD0 @@ -1195,10 +1162,7 @@ void exynos4_set_mipi_clk(void) * MIPI0_SEL [12:15] * set mipi0 src clock 0x6: SCLK_MPLL */ - cfg = readl(&clk->src_lcd0); - cfg &= ~(0xf << 12); - cfg |= (0x6 << 12); - writel(cfg, &clk->src_lcd0); + clrsetbits_le32(&clk->src_lcd0, 0xf << 12, 0x6 << 12); /* * CLK_SRC_MASK_LCD0 @@ -1208,9 +1172,7 @@ void exynos4_set_mipi_clk(void) * MIPI0_MASK [12] * set src mask mipi0 0x1: Unmask */ - cfg = readl(&clk->src_mask_lcd0); - cfg |= (0x1 << 12); - writel(cfg, &clk->src_mask_lcd0); + setbits_le32(&clk->src_mask_lcd0, 0x1 << 12); /* * CLK_GATE_IP_LCD0 @@ -1222,9 +1184,7 @@ void exynos4_set_mipi_clk(void) * CLK_PPMULCD0 [5] * Gating all clocks for MIPI0 */ - cfg = readl(&clk->gate_ip_lcd0); - cfg |= 1 << 3; - writel(cfg, &clk->gate_ip_lcd0); + setbits_le32(&clk->gate_ip_lcd0, 1 << 3); /* * CLK_DIV_LCD0 @@ -1236,9 +1196,7 @@ void exynos4_set_mipi_clk(void) * MIPI0_PRE_RATIO [23:20] * set mipi ratio */ - cfg &= ~(0xf << 16); - cfg |= (0x1 << 16); - writel(cfg, &clk->div_lcd0); + clrsetbits_le32(&clk->div_lcd0, 0xf << 16, 0x1 << 16); } /* diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c index 904177a..645c497 100644 --- a/arch/arm/cpu/armv7/exynos/pinmux.c +++ b/arch/arm/cpu/armv7/exynos/pinmux.c @@ -751,12 +751,7 @@ static int exynos5_pinmux_decode_periph_id(const void *blob, int node) if (err) return PERIPH_ID_NONE; - /* check for invalid peripheral id */ - if ((PERIPH_ID_SDMMC4 > cell[1]) || (cell[1] < PERIPH_ID_UART0)) - return cell[1]; - - debug(" invalid peripheral id\n"); - return PERIPH_ID_NONE; + return cell[1]; } int pinmux_decode_periph_id(const void *blob, int node) diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c index 5617a41..bd65a08 100644 --- a/arch/arm/cpu/armv7/mx6/clock.c +++ b/arch/arm/cpu/armv7/mx6/clock.c @@ -409,20 +409,15 @@ u32 imx_get_uartclk(void) u32 imx_get_fecclk(void) { - return decode_pll(PLL_ENET, MXC_HCLK); + return mxc_get_clock(MXC_IPG_CLK); } -int enable_sata_clock(void) +static int enable_enet_pll(uint32_t en) { - u32 reg = 0; - s32 timeout = 100000; struct mxc_ccm_reg *const imx_ccm = (struct mxc_ccm_reg *) CCM_BASE_ADDR; - - /* Enable sata clock */ - reg = readl(&imx_ccm->CCGR5); /* CCGR5 */ - reg |= MXC_CCM_CCGR5_SATA_MASK; - writel(reg, &imx_ccm->CCGR5); + s32 timeout = 100000; + u32 reg = 0; /* Enable PLLs */ reg = readl(&imx_ccm->analog_pll_enet); @@ -437,10 +432,70 @@ int enable_sata_clock(void) return -EIO; reg &= ~BM_ANADIG_PLL_SYS_BYPASS; writel(reg, &imx_ccm->analog_pll_enet); - reg |= BM_ANADIG_PLL_ENET_ENABLE_SATA; + reg |= en; writel(reg, &imx_ccm->analog_pll_enet); + return 0; +} - return 0 ; +static void ungate_sata_clock(void) +{ + struct mxc_ccm_reg *const imx_ccm = + (struct mxc_ccm_reg *)CCM_BASE_ADDR; + + /* Enable SATA clock. */ + setbits_le32(&imx_ccm->CCGR5, MXC_CCM_CCGR5_SATA_MASK); +} + +static void ungate_pcie_clock(void) +{ + struct mxc_ccm_reg *const imx_ccm = + (struct mxc_ccm_reg *)CCM_BASE_ADDR; + + /* Enable PCIe clock. */ + setbits_le32(&imx_ccm->CCGR4, MXC_CCM_CCGR4_PCIE_MASK); +} + +int enable_sata_clock(void) +{ + ungate_sata_clock(); + return enable_enet_pll(BM_ANADIG_PLL_ENET_ENABLE_SATA); +} + +int enable_pcie_clock(void) +{ + struct anatop_regs *anatop_regs = + (struct anatop_regs *)ANATOP_BASE_ADDR; + struct mxc_ccm_reg *ccm_regs = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + + /* + * Here be dragons! + * + * The register ANATOP_MISC1 is not documented in the Freescale + * MX6RM. The register that is mapped in the ANATOP space and + * marked as ANATOP_MISC1 is actually documented in the PMU section + * of the datasheet as PMU_MISC1. + * + * Switch LVDS clock source to SATA (0xb), disable clock INPUT and + * enable clock OUTPUT. This is important for PCI express link that + * is clocked from the i.MX6. + */ +#define ANADIG_ANA_MISC1_LVDSCLK1_IBEN (1 << 12) +#define ANADIG_ANA_MISC1_LVDSCLK1_OBEN (1 << 10) +#define ANADIG_ANA_MISC1_LVDS1_CLK_SEL_MASK 0x0000001F + clrsetbits_le32(&anatop_regs->ana_misc1, + ANADIG_ANA_MISC1_LVDSCLK1_IBEN | + ANADIG_ANA_MISC1_LVDS1_CLK_SEL_MASK, + ANADIG_ANA_MISC1_LVDSCLK1_OBEN | 0xb); + + /* PCIe reference clock sourced from AXI. */ + clrbits_le32(&ccm_regs->cbcmr, MXC_CCM_CBCMR_PCIE_AXI_CLK_SEL); + + /* Party time! Ungate the clock to the PCIe. */ + ungate_sata_clock(); + ungate_pcie_clock(); + + return enable_enet_pll(BM_ANADIG_PLL_ENET_ENABLE_SATA | + BM_ANADIG_PLL_ENET_ENABLE_PCIE); } unsigned int mxc_get_clock(enum mxc_clock clk) diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index 0208cba..1725279 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -8,6 +8,8 @@ */ #include <common.h> +#include <asm/armv7.h> +#include <asm/pl310.h> #include <asm/errno.h> #include <asm/io.h> #include <asm/arch/imx-regs.h> @@ -41,14 +43,19 @@ u32 get_cpu_rev(void) if (type != MXC_CPU_MX6SL) { reg = readl(&anatop->digprog); + struct scu_regs *scu = (struct scu_regs *)SCU_BASE_ADDR; + u32 cfg = readl(&scu->config) & 3; type = ((reg >> 16) & 0xff); if (type == MXC_CPU_MX6DL) { - struct scu_regs *scu = (struct scu_regs *)SCU_BASE_ADDR; - u32 cfg = readl(&scu->config) & 3; - if (!cfg) type = MXC_CPU_MX6SOLO; } + + if (type == MXC_CPU_MX6Q) { + if (cfg == 1) + type = MXC_CPU_MX6D; + } + } reg &= 0xff; /* mx6 silicon revision */ return (type << 12) | (reg + 0x10); @@ -62,6 +69,9 @@ u32 __weak get_board_rev(void) if (type == MXC_CPU_MX6SOLO) cpurev = (MXC_CPU_MX6DL) << 12 | (cpurev & 0xFFF); + if (type == MXC_CPU_MX6D) + cpurev = (MXC_CPU_MX6Q) << 12 | (cpurev & 0xFFF); + return cpurev; } #endif @@ -177,10 +187,41 @@ static void imx_set_wdog_powerdown(bool enable) writew(enable, &wdog2->wmcr); } +static void set_ahb_rate(u32 val) +{ + struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + u32 reg, div; + + div = get_periph_clk() / val - 1; + reg = readl(&mxc_ccm->cbcdr); + + writel((reg & (~MXC_CCM_CBCDR_AHB_PODF_MASK)) | + (div << MXC_CCM_CBCDR_AHB_PODF_OFFSET), &mxc_ccm->cbcdr); +} + +static void clear_mmdc_ch_mask(void) +{ + struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + + /* Clear MMDC channel mask */ + writel(0, &mxc_ccm->ccdr); +} + int arch_cpu_init(void) { init_aips(); + /* Need to clear MMDC_CHx_MASK to make warm reset work. */ + clear_mmdc_ch_mask(); + + /* + * When low freq boot is enabled, ROM will not set AHB + * freq, so we need to ensure AHB freq is 132MHz in such + * scenario. + */ + if (mxc_get_clock(MXC_ARM_CLK) == 396000000) + set_ahb_rate(132000000); + imx_set_wdog_powerdown(false); /* Disable PDE bit of WMCR register */ #ifdef CONFIG_APBH_DMA @@ -336,3 +377,59 @@ void imx_setup_hdmi(void) writel(reg, &mxc_ccm->chsccdr); } #endif + +#ifndef CONFIG_SYS_L2CACHE_OFF +#define IOMUXC_GPR11_L2CACHE_AS_OCRAM 0x00000002 +void v7_outer_cache_enable(void) +{ + struct pl310_regs *const pl310 = (struct pl310_regs *)L2_PL310_BASE; + unsigned int val; + +#if defined CONFIG_MX6SL + struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR; + val = readl(&iomux->gpr[11]); + if (val & IOMUXC_GPR11_L2CACHE_AS_OCRAM) { + /* L2 cache configured as OCRAM, reset it */ + val &= ~IOMUXC_GPR11_L2CACHE_AS_OCRAM; + writel(val, &iomux->gpr[11]); + } +#endif + + writel(0x132, &pl310->pl310_tag_latency_ctrl); + writel(0x132, &pl310->pl310_data_latency_ctrl); + + val = readl(&pl310->pl310_prefetch_ctrl); + + /* Turn on the L2 I/D prefetch */ + val |= 0x30000000; + + /* + * The L2 cache controller(PL310) version on the i.MX6D/Q is r3p1-50rel0 + * The L2 cache controller(PL310) version on the i.MX6DL/SOLO/SL is r3p2 + * But according to ARM PL310 errata: 752271 + * ID: 752271: Double linefill feature can cause data corruption + * Fault Status: Present in: r3p0, r3p1, r3p1-50rel0. Fixed in r3p2 + * Workaround: The only workaround to this erratum is to disable the + * double linefill feature. This is the default behavior. + */ + +#ifndef CONFIG_MX6Q + val |= 0x40800000; +#endif + writel(val, &pl310->pl310_prefetch_ctrl); + + val = readl(&pl310->pl310_power_ctrl); + val |= L2X0_DYNAMIC_CLK_GATING_EN; + val |= L2X0_STNDBY_MODE_EN; + writel(val, &pl310->pl310_power_ctrl); + + setbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN); +} + +void v7_outer_cache_disable(void) +{ + struct pl310_regs *const pl310 = (struct pl310_regs *)L2_PL310_BASE; + + clrbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN); +} +#endif /* !CONFIG_SYS_L2CACHE_OFF */ diff --git a/arch/arm/cpu/armv7/omap-common/boot-common.c b/arch/arm/cpu/armv7/omap-common/boot-common.c index 69fff32..52e0f4a 100644 --- a/arch/arm/cpu/armv7/omap-common/boot-common.c +++ b/arch/arm/cpu/armv7/omap-common/boot-common.c @@ -66,7 +66,18 @@ u32 spl_boot_device(void) u32 spl_boot_mode(void) { - return gd->arch.omap_boot_params.omap_bootmode; + u32 val = gd->arch.omap_boot_params.omap_bootmode; + + if (val == MMCSD_MODE_RAW) + return MMCSD_MODE_RAW; + else if (val == MMCSD_MODE_FAT) + return MMCSD_MODE_FAT; + else +#ifdef CONFIG_SUPPORT_EMMC_BOOT + return MMCSD_MODE_EMMCBOOT; +#else + return MMCSD_MODE_UNDEFINED; +#endif } void spl_board_init(void) diff --git a/arch/arm/cpu/armv7/omap-common/clocks-common.c b/arch/arm/cpu/armv7/omap-common/clocks-common.c index dfa3760..8e7411d 100644 --- a/arch/arm/cpu/armv7/omap-common/clocks-common.c +++ b/arch/arm/cpu/armv7/omap-common/clocks-common.c @@ -418,55 +418,6 @@ static void setup_dplls(void) #endif } -#ifdef CONFIG_SYS_CLOCKS_ENABLE_ALL -static void setup_non_essential_dplls(void) -{ - u32 abe_ref_clk; - const struct dpll_params *params; - - /* IVA */ - clrsetbits_le32((*prcm)->cm_bypclk_dpll_iva, - CM_BYPCLK_DPLL_IVA_CLKSEL_MASK, DPLL_IVA_CLKSEL_CORE_X2_DIV_2); - - params = get_iva_dpll_params(*dplls_data); - do_setup_dpll((*prcm)->cm_clkmode_dpll_iva, params, DPLL_LOCK, "iva"); - - /* Configure ABE dpll */ - params = get_abe_dpll_params(*dplls_data); -#ifdef CONFIG_SYS_OMAP_ABE_SYSCK - abe_ref_clk = CM_ABE_PLL_REF_CLKSEL_CLKSEL_SYSCLK; - - if (omap_revision() == DRA752_ES1_0) - /* Select the sys clk for dpll_abe */ - clrsetbits_le32((*prcm)->cm_abe_pll_sys_clksel, - CM_CLKSEL_ABE_PLL_SYS_CLKSEL_MASK, - CM_ABE_PLL_SYS_CLKSEL_SYSCLK2); -#else - abe_ref_clk = CM_ABE_PLL_REF_CLKSEL_CLKSEL_32KCLK; - /* - * We need to enable some additional options to achieve - * 196.608MHz from 32768 Hz - */ - setbits_le32((*prcm)->cm_clkmode_dpll_abe, - CM_CLKMODE_DPLL_DRIFTGUARD_EN_MASK| - CM_CLKMODE_DPLL_RELOCK_RAMP_EN_MASK| - CM_CLKMODE_DPLL_LPMODE_EN_MASK| - CM_CLKMODE_DPLL_REGM4XEN_MASK); - /* Spend 4 REFCLK cycles at each stage */ - clrsetbits_le32((*prcm)->cm_clkmode_dpll_abe, - CM_CLKMODE_DPLL_RAMP_RATE_MASK, - 1 << CM_CLKMODE_DPLL_RAMP_RATE_SHIFT); -#endif - - /* Select the right reference clk */ - clrsetbits_le32((*prcm)->cm_abe_pll_ref_clksel, - CM_ABE_PLL_REF_CLKSEL_CLKSEL_MASK, - abe_ref_clk << CM_ABE_PLL_REF_CLKSEL_CLKSEL_SHIFT); - /* Lock the dpll */ - do_setup_dpll((*prcm)->cm_clkmode_dpll_abe, params, DPLL_LOCK, "abe"); -} -#endif - u32 get_offset_code(u32 volt_offset, struct pmic_data *pmic) { u32 offset_code; @@ -760,10 +711,6 @@ void prcm_init(void) timer_init(); scale_vcores(*omap_vcores); setup_dplls(); -#ifdef CONFIG_SYS_CLOCKS_ENABLE_ALL - setup_non_essential_dplls(); - enable_non_essential_clocks(); -#endif setup_warmreset_time(); break; default: diff --git a/arch/arm/cpu/armv7/omap-common/emif-common.c b/arch/arm/cpu/armv7/omap-common/emif-common.c index cd6289b..429c4be 100644 --- a/arch/arm/cpu/armv7/omap-common/emif-common.c +++ b/arch/arm/cpu/armv7/omap-common/emif-common.c @@ -179,8 +179,7 @@ void emif_update_timings(u32 base, const struct emif_regs *regs) writel(regs->temp_alert_config, &emif->emif_temp_alert_config); writel(regs->emif_ddr_phy_ctlr_1, &emif->emif_ddr_phy_ctrl_1_shdw); - if ((omap_revision() >= OMAP5430_ES1_0) || - (omap_revision() == DRA752_ES1_0)) { + if ((omap_revision() >= OMAP5430_ES1_0) || is_dra7xx()) { writel(EMIF_L3_CONFIG_VAL_SYS_10_MPU_5_LL_0, &emif->emif_l3_config); } else if (omap_revision() >= OMAP4460_ES1_0) { @@ -309,7 +308,7 @@ static void ddr3_init(u32 base, const struct emif_regs *regs) * The same sequence should work on OMAP5432 as well. But strange that * it is not working */ - if (omap_revision() == DRA752_ES1_0) { + if (is_dra7xx()) { do_ext_phy_settings(base, regs); writel(regs->sdram_config2, &emif->emif_lpddr2_nvm_config); writel(regs->sdram_config_init, &emif->emif_sdram_config); diff --git a/arch/arm/cpu/armv7/omap-common/hwinit-common.c b/arch/arm/cpu/armv7/omap-common/hwinit-common.c index 85d3754..ade744e 100644 --- a/arch/arm/cpu/armv7/omap-common/hwinit-common.c +++ b/arch/arm/cpu/armv7/omap-common/hwinit-common.c @@ -43,16 +43,10 @@ static void set_mux_conf_regs(void) set_muxconf_regs_essential(); break; case OMAP_INIT_CONTEXT_UBOOT_AFTER_SPL: -#ifdef CONFIG_SYS_ENABLE_PADS_ALL - set_muxconf_regs_non_essential(); -#endif break; case OMAP_INIT_CONTEXT_UBOOT_FROM_NOR: case OMAP_INIT_CONTEXT_UBOOT_AFTER_CH: set_muxconf_regs_essential(); -#ifdef CONFIG_SYS_ENABLE_PADS_ALL - set_muxconf_regs_non_essential(); -#endif break; } } @@ -254,6 +248,7 @@ u32 get_device_type(void) (DEVICE_TYPE_MASK)) >> DEVICE_TYPE_SHIFT; } +#if defined(CONFIG_DISPLAY_CPUINFO) /* * Print CPU information */ @@ -264,6 +259,8 @@ int print_cpuinfo(void) return 0; } +#endif + #ifndef CONFIG_SYS_DCACHE_OFF void enable_caches(void) { diff --git a/arch/arm/cpu/armv7/omap-common/sata.c b/arch/arm/cpu/armv7/omap-common/sata.c index f5468c4..cad4fee 100644 --- a/arch/arm/cpu/armv7/omap-common/sata.c +++ b/arch/arm/cpu/armv7/omap-common/sata.c @@ -12,6 +12,7 @@ #include <scsi.h> #include <asm/arch/clock.h> #include <asm/arch/sata.h> +#include <sata.h> #include <asm/io.h> #include "pipe3-phy.h" @@ -31,7 +32,7 @@ struct omap_pipe3 sata_phy = { .dpll_map = dpll_map_sata, }; -int omap_sata_init(void) +int init_sata(int dev) { int ret; u32 val; diff --git a/arch/arm/cpu/armv7/omap3/config.mk b/arch/arm/cpu/armv7/omap3/config.mk index 1d6a57c..2a3d1c5 100644 --- a/arch/arm/cpu/armv7/omap3/config.mk +++ b/arch/arm/cpu/armv7/omap3/config.mk @@ -11,5 +11,5 @@ ifdef CONFIG_SPL_BUILD ALL-y += $(OBJTREE)/MLO else -ALL-y += $(obj)u-boot.img +ALL-y += u-boot.img endif diff --git a/arch/arm/cpu/armv7/omap4/config.mk b/arch/arm/cpu/armv7/omap4/config.mk index 1d6a57c..2a3d1c5 100644 --- a/arch/arm/cpu/armv7/omap4/config.mk +++ b/arch/arm/cpu/armv7/omap4/config.mk @@ -11,5 +11,5 @@ ifdef CONFIG_SPL_BUILD ALL-y += $(OBJTREE)/MLO else -ALL-y += $(obj)u-boot.img +ALL-y += u-boot.img endif diff --git a/arch/arm/cpu/armv7/omap4/hw_data.c b/arch/arm/cpu/armv7/omap4/hw_data.c index 1b2f439..4dec73e 100644 --- a/arch/arm/cpu/armv7/omap4/hw_data.c +++ b/arch/arm/cpu/armv7/omap4/hw_data.c @@ -399,91 +399,6 @@ void enable_basic_uboot_clocks(void) 1); } -/* - * Enable non-essential clock domains, modules and - * do some additional special settings needed - */ -void enable_non_essential_clocks(void) -{ - u32 const clk_domains_non_essential[] = { - (*prcm)->cm_mpu_m3_clkstctrl, - (*prcm)->cm_ivahd_clkstctrl, - (*prcm)->cm_dsp_clkstctrl, - (*prcm)->cm_dss_clkstctrl, - (*prcm)->cm_sgx_clkstctrl, - (*prcm)->cm1_abe_clkstctrl, - (*prcm)->cm_c2c_clkstctrl, - (*prcm)->cm_cam_clkstctrl, - (*prcm)->cm_dss_clkstctrl, - (*prcm)->cm_sdma_clkstctrl, - 0 - }; - - u32 const clk_modules_hw_auto_non_essential[] = { - (*prcm)->cm_l3instr_l3_3_clkctrl, - (*prcm)->cm_l3instr_l3_instr_clkctrl, - (*prcm)->cm_l3instr_intrconn_wp1_clkctrl, - (*prcm)->cm_l3init_hsi_clkctrl, - 0 - }; - - u32 const clk_modules_explicit_en_non_essential[] = { - (*prcm)->cm1_abe_aess_clkctrl, - (*prcm)->cm1_abe_pdm_clkctrl, - (*prcm)->cm1_abe_dmic_clkctrl, - (*prcm)->cm1_abe_mcasp_clkctrl, - (*prcm)->cm1_abe_mcbsp1_clkctrl, - (*prcm)->cm1_abe_mcbsp2_clkctrl, - (*prcm)->cm1_abe_mcbsp3_clkctrl, - (*prcm)->cm1_abe_slimbus_clkctrl, - (*prcm)->cm1_abe_timer5_clkctrl, - (*prcm)->cm1_abe_timer6_clkctrl, - (*prcm)->cm1_abe_timer7_clkctrl, - (*prcm)->cm1_abe_timer8_clkctrl, - (*prcm)->cm1_abe_wdt3_clkctrl, - (*prcm)->cm_l4per_gptimer9_clkctrl, - (*prcm)->cm_l4per_gptimer10_clkctrl, - (*prcm)->cm_l4per_gptimer11_clkctrl, - (*prcm)->cm_l4per_gptimer3_clkctrl, - (*prcm)->cm_l4per_gptimer4_clkctrl, - (*prcm)->cm_l4per_hdq1w_clkctrl, - (*prcm)->cm_l4per_mcbsp4_clkctrl, - (*prcm)->cm_l4per_mcspi2_clkctrl, - (*prcm)->cm_l4per_mcspi3_clkctrl, - (*prcm)->cm_l4per_mcspi4_clkctrl, - (*prcm)->cm_l4per_mmcsd3_clkctrl, - (*prcm)->cm_l4per_mmcsd4_clkctrl, - (*prcm)->cm_l4per_mmcsd5_clkctrl, - (*prcm)->cm_l4per_uart1_clkctrl, - (*prcm)->cm_l4per_uart2_clkctrl, - (*prcm)->cm_l4per_uart4_clkctrl, - (*prcm)->cm_wkup_keyboard_clkctrl, - (*prcm)->cm_wkup_wdtimer2_clkctrl, - (*prcm)->cm_cam_iss_clkctrl, - (*prcm)->cm_cam_fdif_clkctrl, - (*prcm)->cm_dss_dss_clkctrl, - (*prcm)->cm_sgx_sgx_clkctrl, - 0 - }; - - /* Enable optional functional clock for ISS */ - setbits_le32((*prcm)->cm_cam_iss_clkctrl, ISS_CLKCTRL_OPTFCLKEN_MASK); - - /* Enable all optional functional clocks of DSS */ - setbits_le32((*prcm)->cm_dss_dss_clkctrl, DSS_CLKCTRL_OPTFCLKEN_MASK); - - do_enable_clocks(clk_domains_non_essential, - clk_modules_hw_auto_non_essential, - clk_modules_explicit_en_non_essential, - 0); - - /* Put camera module in no sleep mode */ - clrsetbits_le32((*prcm)->cm_cam_clkstctrl, - MODULE_CLKCTRL_MODULEMODE_MASK, - CD_CLKCTRL_CLKTRCTRL_NO_SLEEP << - MODULE_CLKCTRL_MODULEMODE_SHIFT); -} - void hw_data_init(void) { u32 omap_rev = omap_revision(); diff --git a/arch/arm/cpu/armv7/omap5/abb.c b/arch/arm/cpu/armv7/omap5/abb.c index 31b6795..3bf8897 100644 --- a/arch/arm/cpu/armv7/omap5/abb.c +++ b/arch/arm/cpu/armv7/omap5/abb.c @@ -28,18 +28,25 @@ s8 abb_setup_ldovbb(u32 fuse, u32 ldovbb) { u32 vset; + u32 fuse_enable_mask = OMAP5_ABB_FUSE_ENABLE_MASK; + u32 fuse_vset_mask = OMAP5_ABB_FUSE_VSET_MASK; + if (!is_omap54xx()) { + /* DRA7 */ + fuse_enable_mask = DRA7_ABB_FUSE_ENABLE_MASK; + fuse_vset_mask = DRA7_ABB_FUSE_VSET_MASK; + } /* * ABB parameters must be properly fused * otherwise ABB should be disabled */ vset = readl(fuse); - if (!(vset & OMAP5_ABB_FUSE_ENABLE_MASK)) + if (!(vset & fuse_enable_mask)) return -1; /* prepare VSET value for LDOVBB mux register */ - vset &= OMAP5_ABB_FUSE_VSET_MASK; - vset >>= ffs(OMAP5_ABB_FUSE_VSET_MASK) - 1; + vset &= fuse_vset_mask; + vset >>= ffs(fuse_vset_mask) - 1; vset <<= ffs(OMAP5_ABB_LDOVBBMPU_VSET_OUT_MASK) - 1; vset |= OMAP5_ABB_LDOVBBMPU_MUX_CTRL_MASK; diff --git a/arch/arm/cpu/armv7/omap5/config.mk b/arch/arm/cpu/armv7/omap5/config.mk index 2673af9..261b272 100644 --- a/arch/arm/cpu/armv7/omap5/config.mk +++ b/arch/arm/cpu/armv7/omap5/config.mk @@ -9,5 +9,5 @@ ifdef CONFIG_SPL_BUILD ALL-y += $(OBJTREE)/MLO else -ALL-y += $(obj)u-boot.img +ALL-y += u-boot.img endif diff --git a/arch/arm/cpu/armv7/omap5/hw_data.c b/arch/arm/cpu/armv7/omap5/hw_data.c index 5268a1f..ad97132 100644 --- a/arch/arm/cpu/armv7/omap5/hw_data.c +++ b/arch/arm/cpu/armv7/omap5/hw_data.c @@ -486,94 +486,6 @@ void enable_basic_uboot_clocks(void) 1); } -/* - * Enable non-essential clock domains, modules and - * do some additional special settings needed - */ -void enable_non_essential_clocks(void) -{ - u32 const clk_domains_non_essential[] = { - (*prcm)->cm_mpu_m3_clkstctrl, - (*prcm)->cm_ivahd_clkstctrl, - (*prcm)->cm_dsp_clkstctrl, - (*prcm)->cm_dss_clkstctrl, - (*prcm)->cm_sgx_clkstctrl, - (*prcm)->cm1_abe_clkstctrl, - (*prcm)->cm_c2c_clkstctrl, - (*prcm)->cm_cam_clkstctrl, - (*prcm)->cm_dss_clkstctrl, - (*prcm)->cm_sdma_clkstctrl, - 0 - }; - - u32 const clk_modules_hw_auto_non_essential[] = { - (*prcm)->cm_mpu_m3_mpu_m3_clkctrl, - (*prcm)->cm_ivahd_ivahd_clkctrl, - (*prcm)->cm_ivahd_sl2_clkctrl, - (*prcm)->cm_dsp_dsp_clkctrl, - (*prcm)->cm_l3instr_l3_3_clkctrl, - (*prcm)->cm_l3instr_l3_instr_clkctrl, - (*prcm)->cm_l3instr_intrconn_wp1_clkctrl, - (*prcm)->cm_l3init_hsi_clkctrl, - (*prcm)->cm_l4per_hdq1w_clkctrl, - 0 - }; - - u32 const clk_modules_explicit_en_non_essential[] = { - (*prcm)->cm1_abe_aess_clkctrl, - (*prcm)->cm1_abe_pdm_clkctrl, - (*prcm)->cm1_abe_dmic_clkctrl, - (*prcm)->cm1_abe_mcasp_clkctrl, - (*prcm)->cm1_abe_mcbsp1_clkctrl, - (*prcm)->cm1_abe_mcbsp2_clkctrl, - (*prcm)->cm1_abe_mcbsp3_clkctrl, - (*prcm)->cm1_abe_slimbus_clkctrl, - (*prcm)->cm1_abe_timer5_clkctrl, - (*prcm)->cm1_abe_timer6_clkctrl, - (*prcm)->cm1_abe_timer7_clkctrl, - (*prcm)->cm1_abe_timer8_clkctrl, - (*prcm)->cm1_abe_wdt3_clkctrl, - (*prcm)->cm_l4per_gptimer9_clkctrl, - (*prcm)->cm_l4per_gptimer10_clkctrl, - (*prcm)->cm_l4per_gptimer11_clkctrl, - (*prcm)->cm_l4per_gptimer3_clkctrl, - (*prcm)->cm_l4per_gptimer4_clkctrl, - (*prcm)->cm_l4per_mcspi2_clkctrl, - (*prcm)->cm_l4per_mcspi3_clkctrl, - (*prcm)->cm_l4per_mcspi4_clkctrl, - (*prcm)->cm_l4per_mmcsd3_clkctrl, - (*prcm)->cm_l4per_mmcsd4_clkctrl, - (*prcm)->cm_l4per_mmcsd5_clkctrl, - (*prcm)->cm_l4per_uart1_clkctrl, - (*prcm)->cm_l4per_uart2_clkctrl, - (*prcm)->cm_l4per_uart4_clkctrl, - (*prcm)->cm_wkup_keyboard_clkctrl, - (*prcm)->cm_wkup_wdtimer2_clkctrl, - (*prcm)->cm_cam_iss_clkctrl, - (*prcm)->cm_cam_fdif_clkctrl, - (*prcm)->cm_dss_dss_clkctrl, - (*prcm)->cm_sgx_sgx_clkctrl, - 0 - }; - - /* Enable optional functional clock for ISS */ - setbits_le32((*prcm)->cm_cam_iss_clkctrl, ISS_CLKCTRL_OPTFCLKEN_MASK); - - /* Enable all optional functional clocks of DSS */ - setbits_le32((*prcm)->cm_dss_dss_clkctrl, DSS_CLKCTRL_OPTFCLKEN_MASK); - - do_enable_clocks(clk_domains_non_essential, - clk_modules_hw_auto_non_essential, - clk_modules_explicit_en_non_essential, - 0); - - /* Put camera module in no sleep mode */ - clrsetbits_le32((*prcm)->cm_cam_clkstctrl, - MODULE_CLKCTRL_MODULEMODE_MASK, - CD_CLKCTRL_CLKTRCTRL_NO_SLEEP << - MODULE_CLKCTRL_MODULEMODE_SHIFT); -} - const struct ctrl_ioregs ioregs_omap5430 = { .ctrl_ddrch = DDR_IO_I_34OHM_SR_FASTEST_WD_DQ_NO_PULL_DQS_PULL_DOWN, .ctrl_lpddr2ch = DDR_IO_I_34OHM_SR_FASTEST_WD_CK_CKE_NCS_CA_PULL_DOWN, @@ -639,6 +551,7 @@ void hw_data_init(void) break; case DRA752_ES1_0: + case DRA752_ES1_1: *prcm = &dra7xx_prcm; *dplls_data = &dra7xx_dplls; *omap_vcores = &dra752_volts; @@ -666,6 +579,7 @@ void get_ioregs(const struct ctrl_ioregs **regs) *regs = &ioregs_omap5432_es2; break; case DRA752_ES1_0: + case DRA752_ES1_1: *regs = &ioregs_dra7xx_es1; break; diff --git a/arch/arm/cpu/armv7/omap5/hwinit.c b/arch/arm/cpu/armv7/omap5/hwinit.c index 5386ae0..737d23c 100644 --- a/arch/arm/cpu/armv7/omap5/hwinit.c +++ b/arch/arm/cpu/armv7/omap5/hwinit.c @@ -333,6 +333,9 @@ void init_omap_revision(void) case DRA752_CONTROL_ID_CODE_ES1_0: *omap_si_rev = DRA752_ES1_0; break; + case DRA752_CONTROL_ID_CODE_ES1_1: + *omap_si_rev = DRA752_ES1_1; + break; default: *omap_si_rev = OMAP5430_SILICON_ID_INVALID; } diff --git a/arch/arm/cpu/armv7/omap5/prcm-regs.c b/arch/arm/cpu/armv7/omap5/prcm-regs.c index 77c428b..ff32807 100644 --- a/arch/arm/cpu/armv7/omap5/prcm-regs.c +++ b/arch/arm/cpu/armv7/omap5/prcm-regs.c @@ -432,11 +432,13 @@ struct omap_sys_ctrl_regs const dra7xx_ctrl = { .control_srcomp_code_latch = 0x4A002E84, .control_ddr_control_ext_0 = 0x4A002E88, .control_padconf_core_base = 0x4A003400, + .control_std_fuse_opp_vdd_mpu_2 = 0x4A003B24, .control_port_emif1_sdram_config = 0x4AE0C110, .control_port_emif1_lpddr2_nvm_config = 0x4AE0C114, .control_port_emif2_sdram_config = 0x4AE0C118, .control_emif1_sdram_config_ext = 0x4AE0C144, .control_emif2_sdram_config_ext = 0x4AE0C148, + .control_wkup_ldovbb_mpu_voltage_ctrl = 0x4AE0C158, .control_padconf_mode = 0x4AE0C5A0, .control_xtal_oscillator = 0x4AE0C5A4, .control_i2c_2 = 0x4AE0C5A8, @@ -807,6 +809,9 @@ struct prcm_regs const dra7xx_prcm = { .cm_dsp_clkstctrl = 0x4a005400, .cm_dsp_dsp_clkctrl = 0x4a005420, + /* prm irqstatus regs */ + .prm_irqstatus_mpu_2 = 0x4ae06014, + /* cm2.ckgen */ .cm_clksel_usb_60mhz = 0x4a008104, .cm_clkmode_dpll_per = 0x4a008140, @@ -967,4 +972,7 @@ struct prcm_regs const dra7xx_prcm = { .prm_vc_val_bypass = 0x4ae07da0, .prm_vc_cfg_i2c_mode = 0x4ae07db4, .prm_vc_cfg_i2c_clk = 0x4ae07db8, + + .prm_abbldo_mpu_setup = 0x4AE07DDC, + .prm_abbldo_mpu_ctrl = 0x4AE07DE0, }; diff --git a/arch/arm/cpu/armv7/omap5/sdram.c b/arch/arm/cpu/armv7/omap5/sdram.c index 2e18706..16a91f9 100644 --- a/arch/arm/cpu/armv7/omap5/sdram.c +++ b/arch/arm/cpu/armv7/omap5/sdram.c @@ -245,6 +245,7 @@ static void emif_get_reg_dump_sdp(u32 emif_nr, const struct emif_regs **regs) *regs = &emif_regs_ddr3_532_mhz_1cs_es2; break; case DRA752_ES1_0: + case DRA752_ES1_1: switch (emif_nr) { case 1: *regs = &emif_1_regs_ddr3_532_mhz_1cs_dra_es1; @@ -273,6 +274,7 @@ static void emif_get_dmm_regs_sdp(const struct dmm_lisa_map_regs *dmm_lisa_regs = &lisa_map_4G_x_2_x_2; break; case DRA752_ES1_0: + case DRA752_ES1_1: default: *dmm_lisa_regs = &lisa_map_2G_x_2_x_2_2G_x_1_x_2; } @@ -460,6 +462,7 @@ static void emif_get_ext_phy_ctrl_const_regs(u32 emif_nr, *size = ARRAY_SIZE(ddr3_ext_phy_ctrl_const_base_es2); break; case DRA752_ES1_0: + case DRA752_ES1_1: if (emif_nr == 1) { *regs = dra_ddr3_ext_phy_ctrl_const_base_es1_emif1; *size = @@ -626,6 +629,7 @@ const struct read_write_regs *get_bug_regs(u32 *iterations) sizeof(omap5_bug_00339_regs[0]); break; case DRA752_ES1_0: + case DRA752_ES1_1: bug_00339_regs_ptr = dra_bug_00339_regs; *iterations = sizeof(dra_bug_00339_regs)/ sizeof(dra_bug_00339_regs[0]); diff --git a/arch/arm/cpu/armv7/socfpga/config.mk b/arch/arm/cpu/armv7/socfpga/config.mk index d33ab7d..3d18491 100644 --- a/arch/arm/cpu/armv7/socfpga/config.mk +++ b/arch/arm/cpu/armv7/socfpga/config.mk @@ -4,5 +4,5 @@ # SPDX-License-Identifier: GPL-2.0+ # ifndef CONFIG_SPL_BUILD -ALL-y += $(obj)u-boot.img +ALL-y += u-boot.img endif diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S index 6c9b11a..5aac773 100644 --- a/arch/arm/cpu/armv7/start.S +++ b/arch/arm/cpu/armv7/start.S @@ -38,12 +38,19 @@ _irq: .word _irq _fiq: .word _fiq _pad: .word 0x12345678 /* now 16*4=64 */ #else +.globl _undefined_instruction _undefined_instruction: .word undefined_instruction +.globl _software_interrupt _software_interrupt: .word software_interrupt +.globl _prefetch_abort _prefetch_abort: .word prefetch_abort +.globl _data_abort _data_abort: .word data_abort +.globl _not_used _not_used: .word not_used +.globl _irq _irq: .word irq +.globl _fiq _fiq: .word fiq _pad: .word 0x12345678 /* now 16*4=64 */ #endif /* CONFIG_SPL_BUILD */ diff --git a/arch/arm/cpu/armv7/tegra114/Makefile b/arch/arm/cpu/armv7/tegra114/Makefile index 886b509..77e2319 100644 --- a/arch/arm/cpu/armv7/tegra114/Makefile +++ b/arch/arm/cpu/armv7/tegra114/Makefile @@ -17,4 +17,5 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -obj- := +# necessary to create built-in.o +obj- := __dummy__.o diff --git a/arch/arm/cpu/armv7/tegra124/Makefile b/arch/arm/cpu/armv7/tegra124/Makefile new file mode 100644 index 0000000..9478d44 --- /dev/null +++ b/arch/arm/cpu/armv7/tegra124/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2013-2014 +# NVIDIA Corporation <www.nvidia.com> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +# necessary to create built-in.o +obj- := __dummy__.o diff --git a/arch/arm/cpu/armv7/tegra124/config.mk b/arch/arm/cpu/armv7/tegra124/config.mk new file mode 100644 index 0000000..2f1c645 --- /dev/null +++ b/arch/arm/cpu/armv7/tegra124/config.mk @@ -0,0 +1,10 @@ +# +# (C) Copyright 2013 +# NVIDIA Corporation <www.nvidia.com> +# (C) Copyright 2002 +# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +CONFIG_ARCH_DEVICE_TREE := tegra124 diff --git a/arch/arm/cpu/armv7/tegra30/Makefile b/arch/arm/cpu/armv7/tegra30/Makefile index 518d6d1..413eba1 100644 --- a/arch/arm/cpu/armv7/tegra30/Makefile +++ b/arch/arm/cpu/armv7/tegra30/Makefile @@ -17,4 +17,5 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -obj- := +# necessary to create built-in.o +obj- := __dummy__.o diff --git a/arch/arm/cpu/armv7/zynq/Makefile b/arch/arm/cpu/armv7/zynq/Makefile index d382d49..3363a3c 100644 --- a/arch/arm/cpu/armv7/zynq/Makefile +++ b/arch/arm/cpu/armv7/zynq/Makefile @@ -12,3 +12,5 @@ obj-y := timer.o obj-y += cpu.o obj-y += ddrc.o obj-y += slcr.o +obj-y += clk.o +obj-$(CONFIG_SPL_BUILD) += spl.o diff --git a/arch/arm/cpu/armv7/zynq/clk.c b/arch/arm/cpu/armv7/zynq/clk.c new file mode 100644 index 0000000..d2885dc --- /dev/null +++ b/arch/arm/cpu/armv7/zynq/clk.c @@ -0,0 +1,664 @@ +/* + * Copyright (C) 2013 Soren Brinkmann <soren.brinkmann@xilinx.com> + * Copyright (C) 2013 Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <errno.h> +#include <clk.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/clk.h> + +/* Board oscillator frequency */ +#ifndef CONFIG_ZYNQ_PS_CLK_FREQ +# define CONFIG_ZYNQ_PS_CLK_FREQ 33333333UL +#endif + +/* Register bitfield defines */ +#define PLLCTRL_FBDIV_MASK 0x7f000 +#define PLLCTRL_FBDIV_SHIFT 12 +#define PLLCTRL_BPFORCE_MASK (1 << 4) +#define PLLCTRL_PWRDWN_MASK 2 +#define PLLCTRL_PWRDWN_SHIFT 1 +#define PLLCTRL_RESET_MASK 1 +#define PLLCTRL_RESET_SHIFT 0 + +#define ZYNQ_CLK_MAXDIV 0x3f +#define CLK_CTRL_DIV1_SHIFT 20 +#define CLK_CTRL_DIV1_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT) +#define CLK_CTRL_DIV0_SHIFT 8 +#define CLK_CTRL_DIV0_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) +#define CLK_CTRL_SRCSEL_SHIFT 4 +#define CLK_CTRL_SRCSEL_MASK (0x3 << CLK_CTRL_SRCSEL_SHIFT) + +#define CLK_CTRL_DIV2X_SHIFT 26 +#define CLK_CTRL_DIV2X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV2X_SHIFT) +#define CLK_CTRL_DIV3X_SHIFT 20 +#define CLK_CTRL_DIV3X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV3X_SHIFT) + +#define ZYNQ_CLKMUX_SEL_0 0 +#define ZYNQ_CLKMUX_SEL_1 1 +#define ZYNQ_CLKMUX_SEL_2 2 +#define ZYNQ_CLKMUX_SEL_3 3 + +DECLARE_GLOBAL_DATA_PTR; + +struct clk; + +/** + * struct clk_ops: + * @set_rate: Function pointer to set_rate() implementation + * @get_rate: Function pointer to get_rate() implementation + */ +struct clk_ops { + int (*set_rate)(struct clk *clk, unsigned long rate); + unsigned long (*get_rate)(struct clk *clk); +}; + +/** + * struct clk: + * @name: Clock name + * @frequency: Currenct frequency + * @parent: Parent clock + * @flags: Clock flags + * @reg: Clock control register + * @ops: Clock operations + */ +struct clk { + char *name; + unsigned long frequency; + enum zynq_clk parent; + unsigned int flags; + u32 *reg; + struct clk_ops ops; +}; +#define ZYNQ_CLK_FLAGS_HAS_2_DIVS 1 + +static struct clk clks[clk_max]; + +/** + * __zynq_clk_cpu_get_parent() - Decode clock multiplexer + * @srcsel: Mux select value + * Returns the clock identifier associated with the selected mux input. + */ +static int __zynq_clk_cpu_get_parent(unsigned int srcsel) +{ + unsigned int ret; + + switch (srcsel) { + case ZYNQ_CLKMUX_SEL_0: + case ZYNQ_CLKMUX_SEL_1: + ret = armpll_clk; + break; + case ZYNQ_CLKMUX_SEL_2: + ret = ddrpll_clk; + break; + case ZYNQ_CLKMUX_SEL_3: + ret = iopll_clk; + break; + default: + ret = armpll_clk; + break; + } + + return ret; +} + +/** + * ddr2x_get_rate() - Get clock rate of DDR2x clock + * @clk: Clock handle + * Returns the current clock rate of @clk. + */ +static unsigned long ddr2x_get_rate(struct clk *clk) +{ + u32 clk_ctrl = readl(clk->reg); + u32 div = (clk_ctrl & CLK_CTRL_DIV2X_MASK) >> CLK_CTRL_DIV2X_SHIFT; + + return DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div); +} + +/** + * ddr3x_get_rate() - Get clock rate of DDR3x clock + * @clk: Clock handle + * Returns the current clock rate of @clk. + */ +static unsigned long ddr3x_get_rate(struct clk *clk) +{ + u32 clk_ctrl = readl(clk->reg); + u32 div = (clk_ctrl & CLK_CTRL_DIV3X_MASK) >> CLK_CTRL_DIV3X_SHIFT; + + return DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div); +} + +static void init_ddr_clocks(void) +{ + u32 div0, div1; + unsigned long prate = zynq_clk_get_rate(ddrpll_clk); + u32 clk_ctrl = readl(&slcr_base->ddr_clk_ctrl); + + /* DDR2x */ + clks[ddr2x_clk].reg = &slcr_base->ddr_clk_ctrl; + clks[ddr2x_clk].parent = ddrpll_clk; + clks[ddr2x_clk].name = "ddr_2x"; + clks[ddr2x_clk].frequency = ddr2x_get_rate(&clks[ddr2x_clk]); + clks[ddr2x_clk].ops.get_rate = ddr2x_get_rate; + + /* DDR3x */ + clks[ddr3x_clk].reg = &slcr_base->ddr_clk_ctrl; + clks[ddr3x_clk].parent = ddrpll_clk; + clks[ddr3x_clk].name = "ddr_3x"; + clks[ddr3x_clk].frequency = ddr3x_get_rate(&clks[ddr3x_clk]); + clks[ddr3x_clk].ops.get_rate = ddr3x_get_rate; + + /* DCI */ + clk_ctrl = readl(&slcr_base->dci_clk_ctrl); + div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; + div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT; + clks[dci_clk].reg = &slcr_base->dci_clk_ctrl; + clks[dci_clk].parent = ddrpll_clk; + clks[dci_clk].frequency = DIV_ROUND_CLOSEST( + DIV_ROUND_CLOSEST(prate, div0), div1); + clks[dci_clk].name = "dci"; + + gd->bd->bi_ddr_freq = clks[ddr3x_clk].frequency / 1000000; +} + +static void init_cpu_clocks(void) +{ + int clk_621; + u32 reg, div, srcsel; + enum zynq_clk parent; + + reg = readl(&slcr_base->arm_clk_ctrl); + clk_621 = readl(&slcr_base->clk_621_true) & 1; + div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; + srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; + parent = __zynq_clk_cpu_get_parent(srcsel); + + /* cpu clocks */ + clks[cpu_6or4x_clk].reg = &slcr_base->arm_clk_ctrl; + clks[cpu_6or4x_clk].parent = parent; + clks[cpu_6or4x_clk].frequency = DIV_ROUND_CLOSEST( + zynq_clk_get_rate(parent), div); + clks[cpu_6or4x_clk].name = "cpu_6or4x"; + + clks[cpu_3or2x_clk].reg = &slcr_base->arm_clk_ctrl; + clks[cpu_3or2x_clk].parent = cpu_6or4x_clk; + clks[cpu_3or2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / 2; + clks[cpu_3or2x_clk].name = "cpu_3or2x"; + + clks[cpu_2x_clk].reg = &slcr_base->arm_clk_ctrl; + clks[cpu_2x_clk].parent = cpu_6or4x_clk; + clks[cpu_2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / + (2 + clk_621); + clks[cpu_2x_clk].name = "cpu_2x"; + + clks[cpu_1x_clk].reg = &slcr_base->arm_clk_ctrl; + clks[cpu_1x_clk].parent = cpu_6or4x_clk; + clks[cpu_1x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / + (4 + 2 * clk_621); + clks[cpu_1x_clk].name = "cpu_1x"; +} + +/** + * periph_calc_two_divs() - Calculate clock dividers + * @cur_rate: Current clock rate + * @tgt_rate: Target clock rate + * @prate: Parent clock rate + * @div0: First divider (output) + * @div1: Second divider (output) + * Returns the actual clock rate possible. + * + * Calculates clock dividers for clocks with two 6-bit dividers. + */ +static unsigned long periph_calc_two_divs(unsigned long cur_rate, + unsigned long tgt_rate, unsigned long prate, u32 *div0, + u32 *div1) +{ + long err, best_err = (long)(~0UL >> 1); + unsigned long rate, best_rate = 0; + u32 d0, d1; + + for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) { + for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) { + rate = DIV_ROUND_CLOSEST(DIV_ROUND_CLOSEST(prate, d0), + d1); + err = abs(rate - tgt_rate); + + if (err < best_err) { + *div0 = d0; + *div1 = d1; + best_err = err; + best_rate = rate; + } + } + } + + return best_rate; +} + +/** + * zynq_clk_periph_set_rate() - Set clock rate + * @clk: Handle of the peripheral clock + * @rate: New clock rate + * Sets the clock frequency of @clk to @rate. Returns zero on success. + */ +static int zynq_clk_periph_set_rate(struct clk *clk, + unsigned long rate) +{ + u32 ctrl, div0 = 0, div1 = 0; + unsigned long prate, new_rate, cur_rate = clk->frequency; + + ctrl = readl(clk->reg); + prate = zynq_clk_get_rate(clk->parent); + ctrl &= ~CLK_CTRL_DIV0_MASK; + + if (clk->flags & ZYNQ_CLK_FLAGS_HAS_2_DIVS) { + ctrl &= ~CLK_CTRL_DIV1_MASK; + new_rate = periph_calc_two_divs(cur_rate, rate, prate, &div0, + &div1); + ctrl |= div1 << CLK_CTRL_DIV1_SHIFT; + } else { + div0 = DIV_ROUND_CLOSEST(prate, rate); + div0 &= ZYNQ_CLK_MAXDIV; + new_rate = DIV_ROUND_CLOSEST(rate, div0); + } + + /* write new divs to hardware */ + ctrl |= div0 << CLK_CTRL_DIV0_SHIFT; + writel(ctrl, clk->reg); + + /* update frequency in clk framework */ + clk->frequency = new_rate; + + return 0; +} + +/** + * zynq_clk_periph_get_rate() - Get clock rate + * @clk: Handle of the peripheral clock + * Returns the current clock rate of @clk. + */ +static unsigned long zynq_clk_periph_get_rate(struct clk *clk) +{ + u32 clk_ctrl = readl(clk->reg); + u32 div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; + u32 div1 = 1; + + if (clk->flags & ZYNQ_CLK_FLAGS_HAS_2_DIVS) + div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT; + + /* a register value of zero == division by 1 */ + if (!div0) + div0 = 1; + if (!div1) + div1 = 1; + + return + DIV_ROUND_CLOSEST( + DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div0), + div1); +} + +/** + * __zynq_clk_periph_get_parent() - Decode clock multiplexer + * @srcsel: Mux select value + * Returns the clock identifier associated with the selected mux input. + */ +static enum zynq_clk __zynq_clk_periph_get_parent(u32 srcsel) +{ + switch (srcsel) { + case ZYNQ_CLKMUX_SEL_0: + case ZYNQ_CLKMUX_SEL_1: + return iopll_clk; + case ZYNQ_CLKMUX_SEL_2: + return armpll_clk; + case ZYNQ_CLKMUX_SEL_3: + return ddrpll_clk; + default: + return 0; + } +} + +/** + * zynq_clk_periph_get_parent() - Decode clock multiplexer + * @clk: Clock handle + * Returns the clock identifier associated with the selected mux input. + */ +static enum zynq_clk zynq_clk_periph_get_parent(struct clk *clk) +{ + u32 clk_ctrl = readl(clk->reg); + u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; + + return __zynq_clk_periph_get_parent(srcsel); +} + +/** + * zynq_clk_register_periph_clk() - Set up a peripheral clock with the framework + * @clk: Pointer to struct clk for the clock + * @ctrl: Clock control register + * @name: PLL name + * @two_divs: Indicates whether the clock features one or two dividers + */ +static int zynq_clk_register_periph_clk(struct clk *clk, u32 *ctrl, char *name, + bool two_divs) +{ + clk->name = name; + clk->reg = ctrl; + if (two_divs) + clk->flags = ZYNQ_CLK_FLAGS_HAS_2_DIVS; + clk->parent = zynq_clk_periph_get_parent(clk); + clk->frequency = zynq_clk_periph_get_rate(clk); + clk->ops.get_rate = zynq_clk_periph_get_rate; + clk->ops.set_rate = zynq_clk_periph_set_rate; + + return 0; +} + +static void init_periph_clocks(void) +{ + zynq_clk_register_periph_clk(&clks[gem0_clk], &slcr_base->gem0_clk_ctrl, + "gem0", 1); + zynq_clk_register_periph_clk(&clks[gem1_clk], &slcr_base->gem1_clk_ctrl, + "gem1", 1); + + zynq_clk_register_periph_clk(&clks[smc_clk], &slcr_base->smc_clk_ctrl, + "smc", 0); + + zynq_clk_register_periph_clk(&clks[lqspi_clk], + &slcr_base->lqspi_clk_ctrl, "lqspi", 0); + + zynq_clk_register_periph_clk(&clks[sdio0_clk], + &slcr_base->sdio_clk_ctrl, "sdio0", 0); + zynq_clk_register_periph_clk(&clks[sdio1_clk], + &slcr_base->sdio_clk_ctrl, "sdio1", 0); + + zynq_clk_register_periph_clk(&clks[spi0_clk], &slcr_base->spi_clk_ctrl, + "spi0", 0); + zynq_clk_register_periph_clk(&clks[spi1_clk], &slcr_base->spi_clk_ctrl, + "spi1", 0); + + zynq_clk_register_periph_clk(&clks[uart0_clk], + &slcr_base->uart_clk_ctrl, "uart0", 0); + zynq_clk_register_periph_clk(&clks[uart1_clk], + &slcr_base->uart_clk_ctrl, "uart1", 0); + + zynq_clk_register_periph_clk(&clks[dbg_trc_clk], + &slcr_base->dbg_clk_ctrl, "dbg_trc", 0); + zynq_clk_register_periph_clk(&clks[dbg_apb_clk], + &slcr_base->dbg_clk_ctrl, "dbg_apb", 0); + + zynq_clk_register_periph_clk(&clks[pcap_clk], + &slcr_base->pcap_clk_ctrl, "pcap", 0); + + zynq_clk_register_periph_clk(&clks[fclk0_clk], + &slcr_base->fpga0_clk_ctrl, "fclk0", 1); + zynq_clk_register_periph_clk(&clks[fclk1_clk], + &slcr_base->fpga1_clk_ctrl, "fclk1", 1); + zynq_clk_register_periph_clk(&clks[fclk2_clk], + &slcr_base->fpga2_clk_ctrl, "fclk2", 1); + zynq_clk_register_periph_clk(&clks[fclk3_clk], + &slcr_base->fpga3_clk_ctrl, "fclk3", 1); +} + +/** + * zynq_clk_register_aper_clk() - Set up a APER clock with the framework + * @clk: Pointer to struct clk for the clock + * @ctrl: Clock control register + * @name: PLL name + */ +static void zynq_clk_register_aper_clk(struct clk *clk, u32 *ctrl, char *name) +{ + clk->name = name; + clk->reg = ctrl; + clk->parent = cpu_1x_clk; + clk->frequency = zynq_clk_get_rate(clk->parent); +} + +static void init_aper_clocks(void) +{ + zynq_clk_register_aper_clk(&clks[usb0_aper_clk], + &slcr_base->aper_clk_ctrl, "usb0_aper"); + zynq_clk_register_aper_clk(&clks[usb1_aper_clk], + &slcr_base->aper_clk_ctrl, "usb1_aper"); + + zynq_clk_register_aper_clk(&clks[gem0_aper_clk], + &slcr_base->aper_clk_ctrl, "gem0_aper"); + zynq_clk_register_aper_clk(&clks[gem1_aper_clk], + &slcr_base->aper_clk_ctrl, "gem1_aper"); + + zynq_clk_register_aper_clk(&clks[sdio0_aper_clk], + &slcr_base->aper_clk_ctrl, "sdio0_aper"); + zynq_clk_register_aper_clk(&clks[sdio1_aper_clk], + &slcr_base->aper_clk_ctrl, "sdio1_aper"); + + zynq_clk_register_aper_clk(&clks[spi0_aper_clk], + &slcr_base->aper_clk_ctrl, "spi0_aper"); + zynq_clk_register_aper_clk(&clks[spi1_aper_clk], + &slcr_base->aper_clk_ctrl, "spi1_aper"); + + zynq_clk_register_aper_clk(&clks[can0_aper_clk], + &slcr_base->aper_clk_ctrl, "can0_aper"); + zynq_clk_register_aper_clk(&clks[can1_aper_clk], + &slcr_base->aper_clk_ctrl, "can1_aper"); + + zynq_clk_register_aper_clk(&clks[i2c0_aper_clk], + &slcr_base->aper_clk_ctrl, "i2c0_aper"); + zynq_clk_register_aper_clk(&clks[i2c1_aper_clk], + &slcr_base->aper_clk_ctrl, "i2c1_aper"); + + zynq_clk_register_aper_clk(&clks[uart0_aper_clk], + &slcr_base->aper_clk_ctrl, "uart0_aper"); + zynq_clk_register_aper_clk(&clks[uart1_aper_clk], + &slcr_base->aper_clk_ctrl, "uart1_aper"); + + zynq_clk_register_aper_clk(&clks[gpio_aper_clk], + &slcr_base->aper_clk_ctrl, "gpio_aper"); + + zynq_clk_register_aper_clk(&clks[lqspi_aper_clk], + &slcr_base->aper_clk_ctrl, "lqspi_aper"); + + zynq_clk_register_aper_clk(&clks[smc_aper_clk], + &slcr_base->aper_clk_ctrl, "smc_aper"); +} + +/** + * __zynq_clk_pll_get_rate() - Get PLL rate + * @addr: Address of the PLL's control register + * Returns the current PLL output rate. + */ +static unsigned long __zynq_clk_pll_get_rate(u32 *addr) +{ + u32 reg, mul, bypass; + + reg = readl(addr); + bypass = reg & PLLCTRL_BPFORCE_MASK; + if (bypass) + mul = 1; + else + mul = (reg & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT; + + return CONFIG_ZYNQ_PS_CLK_FREQ * mul; +} + +/** + * zynq_clk_pll_get_rate() - Get PLL rate + * @pll: Handle of the PLL + * Returns the current clock rate of @pll. + */ +static unsigned long zynq_clk_pll_get_rate(struct clk *pll) +{ + return __zynq_clk_pll_get_rate(pll->reg); +} + +/** + * zynq_clk_register_pll() - Set up a PLL with the framework + * @clk: Pointer to struct clk for the PLL + * @ctrl: PLL control register + * @name: PLL name + * @prate: PLL input clock rate + */ +static void zynq_clk_register_pll(struct clk *clk, u32 *ctrl, char *name, + unsigned long prate) +{ + clk->name = name; + clk->reg = ctrl; + clk->frequency = zynq_clk_pll_get_rate(clk); + clk->ops.get_rate = zynq_clk_pll_get_rate; +} + +/** + * clkid_2_register() - Get clock control register + * @id: Clock identifier of one of the PLLs + * Returns the address of the requested PLL's control register. + */ +static u32 *clkid_2_register(enum zynq_clk id) +{ + switch (id) { + case armpll_clk: + return &slcr_base->arm_pll_ctrl; + case ddrpll_clk: + return &slcr_base->ddr_pll_ctrl; + case iopll_clk: + return &slcr_base->io_pll_ctrl; + default: + return &slcr_base->io_pll_ctrl; + } +} + +/* API */ +/** + * zynq_clk_early_init() - Early init for the clock framework + * + * This function is called from before relocation and sets up the CPU clock + * frequency in the global data struct. + */ +void zynq_clk_early_init(void) +{ + u32 reg = readl(&slcr_base->arm_clk_ctrl); + u32 div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; + u32 srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; + enum zynq_clk parent = __zynq_clk_cpu_get_parent(srcsel); + u32 *pllreg = clkid_2_register(parent); + unsigned long prate = __zynq_clk_pll_get_rate(pllreg); + + if (!div) + div = 1; + + gd->cpu_clk = DIV_ROUND_CLOSEST(prate, div); +} + +/** + * get_uart_clk() - Get UART input frequency + * @dev_index: UART ID + * Returns UART input clock frequency in Hz. + * + * Compared to zynq_clk_get_rate() this function is designed to work before + * relocation and can be called when the serial UART is set up. + */ +unsigned long get_uart_clk(int dev_index) +{ + u32 reg = readl(&slcr_base->uart_clk_ctrl); + u32 div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; + u32 srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; + enum zynq_clk parent = __zynq_clk_periph_get_parent(srcsel); + u32 *pllreg = clkid_2_register(parent); + unsigned long prate = __zynq_clk_pll_get_rate(pllreg); + + if (!div) + div = 1; + + return DIV_ROUND_CLOSEST(prate, div); +} + +/** + * set_cpu_clk_info() - Initialize clock framework + * Always returns zero. + * + * This function is called from common code after relocation and sets up the + * clock framework. The framework must not be used before this function had been + * called. + */ +int set_cpu_clk_info(void) +{ + zynq_clk_register_pll(&clks[armpll_clk], &slcr_base->arm_pll_ctrl, + "armpll", CONFIG_ZYNQ_PS_CLK_FREQ); + zynq_clk_register_pll(&clks[ddrpll_clk], &slcr_base->ddr_pll_ctrl, + "ddrpll", CONFIG_ZYNQ_PS_CLK_FREQ); + zynq_clk_register_pll(&clks[iopll_clk], &slcr_base->io_pll_ctrl, + "iopll", CONFIG_ZYNQ_PS_CLK_FREQ); + + init_ddr_clocks(); + init_cpu_clocks(); + init_periph_clocks(); + init_aper_clocks(); + + gd->bd->bi_arm_freq = gd->cpu_clk / 1000000; + gd->bd->bi_dsp_freq = 0; + + return 0; +} + +/** + * zynq_clk_get_rate() - Get clock rate + * @clk: Clock identifier + * Returns the current clock rate of @clk on success or zero for an invalid + * clock id. + */ +unsigned long zynq_clk_get_rate(enum zynq_clk clk) +{ + if (clk < 0 || clk >= clk_max) + return 0; + + return clks[clk].frequency; +} + +/** + * zynq_clk_set_rate() - Set clock rate + * @clk: Clock identifier + * @rate: Requested clock rate + * Passes on the return value from the clock's set_rate() function or negative + * errno. + */ +int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate) +{ + if (clk < 0 || clk >= clk_max) + return -ENODEV; + + if (clks[clk].ops.set_rate) + return clks[clk].ops.set_rate(&clks[clk], rate); + + return -ENXIO; +} + +/** + * zynq_clk_get_name() - Get clock name + * @clk: Clock identifier + * Returns the name of @clk. + */ +const char *zynq_clk_get_name(enum zynq_clk clk) +{ + return clks[clk].name; +} + +/** + * soc_clk_dump() - Print clock frequencies + * Returns zero on success + * + * Implementation for the clk dump command. + */ +int soc_clk_dump(void) +{ + int i; + + printf("clk\t\tfrequency\n"); + for (i = 0; i < clk_max; i++) { + const char *name = zynq_clk_get_name(i); + if (name) + printf("%10s%20lu\n", name, zynq_clk_get_rate(i)); + } + + return 0; +} diff --git a/arch/arm/cpu/armv7/zynq/cpu.c b/arch/arm/cpu/armv7/zynq/cpu.c index 9af340e..7626b5c 100644 --- a/arch/arm/cpu/armv7/zynq/cpu.c +++ b/arch/arm/cpu/armv7/zynq/cpu.c @@ -6,6 +6,7 @@ */ #include <common.h> #include <asm/io.h> +#include <asm/arch/clk.h> #include <asm/arch/sys_proto.h> #include <asm/arch/hardware.h> @@ -16,7 +17,7 @@ void lowlevel_init(void) int arch_cpu_init(void) { zynq_slcr_unlock(); - +#ifndef CONFIG_SPL_BUILD /* Device config APB, unlock the PCAP */ writel(0x757BDF0D, &devcfg_base->unlock); writel(0xFFFFFFFF, &devcfg_base->rom_shadow); @@ -34,7 +35,8 @@ int arch_cpu_init(void) /* Urgent write, ports S2/S3 */ writel(0xC, &slcr_base->ddr_urgent); #endif - +#endif + zynq_clk_early_init(); zynq_slcr_lock(); return 0; @@ -46,3 +48,11 @@ void reset_cpu(ulong addr) while (1) ; } + +#ifndef CONFIG_SYS_DCACHE_OFF +void enable_caches(void) +{ + /* Enable D-cache. I-cache is already enabled in start.S */ + dcache_enable(); +} +#endif diff --git a/arch/arm/cpu/armv7/zynq/slcr.c b/arch/arm/cpu/armv7/zynq/slcr.c index b4c11c3..d7c1882 100644 --- a/arch/arm/cpu/armv7/zynq/slcr.c +++ b/arch/arm/cpu/armv7/zynq/slcr.c @@ -8,6 +8,7 @@ #include <asm/io.h> #include <malloc.h> #include <asm/arch/hardware.h> +#include <asm/arch/clk.h> #define SLCR_LOCK_MAGIC 0x767B #define SLCR_UNLOCK_MAGIC 0xDF0D @@ -50,8 +51,10 @@ void zynq_slcr_cpu_reset(void) } /* Setup clk for network */ -void zynq_slcr_gem_clk_setup(u32 gem_id, u32 rclk, u32 clk) +void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate) { + int ret; + zynq_slcr_unlock(); if (gem_id > 1) { @@ -59,16 +62,16 @@ void zynq_slcr_gem_clk_setup(u32 gem_id, u32 rclk, u32 clk) goto out; } + ret = zynq_clk_set_rate(gem0_clk + gem_id, clk_rate); + if (ret) + goto out; + if (gem_id) { - /* Set divisors for appropriate frequency in GEM_CLK_CTRL */ - writel(clk, &slcr_base->gem1_clk_ctrl); /* Configure GEM_RCLK_CTRL */ - writel(rclk, &slcr_base->gem1_rclk_ctrl); + writel(1, &slcr_base->gem1_rclk_ctrl); } else { - /* Set divisors for appropriate frequency in GEM_CLK_CTRL */ - writel(clk, &slcr_base->gem0_clk_ctrl); /* Configure GEM_RCLK_CTRL */ - writel(rclk, &slcr_base->gem0_rclk_ctrl); + writel(1, &slcr_base->gem0_rclk_ctrl); } udelay(100000); out: diff --git a/arch/arm/cpu/armv7/zynq/spl.c b/arch/arm/cpu/armv7/zynq/spl.c new file mode 100644 index 0000000..fcad762 --- /dev/null +++ b/arch/arm/cpu/armv7/zynq/spl.c @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2014 Xilinx, Inc. Michal Simek + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <spl.h> + +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/spl.h> +#include <asm/arch/sys_proto.h> + +DECLARE_GLOBAL_DATA_PTR; + +void board_init_f(ulong dummy) +{ + ps7_init(); + + /* Clear the BSS. */ + memset(__bss_start, 0, __bss_end - __bss_start); + + /* Set global data pointer. */ + gd = &gdata; + + preloader_console_init(); + arch_cpu_init(); + board_init_r(NULL, 0); +} + +u32 spl_boot_device(void) +{ + u32 mode; + + switch ((zynq_slcr_get_boot_mode()) & ZYNQ_BM_MASK) { +#ifdef CONFIG_SPL_SPI_SUPPORT + case ZYNQ_BM_QSPI: + puts("qspi boot\n"); + mode = BOOT_DEVICE_SPI; + break; +#endif +#ifdef CONFIG_SPL_MMC_SUPPORT + case ZYNQ_BM_SD: + puts("mmc boot\n"); + mode = BOOT_DEVICE_MMC1; + break; +#endif + default: + puts("Unsupported boot mode selected\n"); + hang(); + } + + return mode; +} + +#ifdef CONFIG_SPL_MMC_SUPPORT +u32 spl_boot_mode(void) +{ + return MMCSD_MODE_FAT; +} +#endif + +#ifdef CONFIG_SPL_OS_BOOT +int spl_start_uboot(void) +{ + /* boot linux */ + return 0; +} +#endif diff --git a/arch/arm/cpu/armv7/zynq/timer.c b/arch/arm/cpu/armv7/zynq/timer.c index 2be253c..303dbcf 100644 --- a/arch/arm/cpu/armv7/zynq/timer.c +++ b/arch/arm/cpu/armv7/zynq/timer.c @@ -29,6 +29,7 @@ #include <div64.h> #include <asm/io.h> #include <asm/arch/hardware.h> +#include <asm/arch/clk.h> DECLARE_GLOBAL_DATA_PTR; @@ -48,7 +49,6 @@ static struct scu_timer *timer_base = #define TIMER_LOAD_VAL 0xFFFFFFFF #define TIMER_PRESCALE 255 -#define TIMER_TICK_HZ (CONFIG_CPU_FREQ_HZ / 2 / TIMER_PRESCALE) int timer_init(void) { @@ -56,6 +56,8 @@ int timer_init(void) (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) | SCUTIMER_CONTROL_ENABLE_MASK; + gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1); + /* Load the timer counter register */ writel(0xFFFFFFFF, &timer_base->load); @@ -69,7 +71,7 @@ int timer_init(void) /* Reset time */ gd->arch.lastinc = readl(&timer_base->counter) / - (TIMER_TICK_HZ / CONFIG_SYS_HZ); + (gd->arch.timer_rate_hz / CONFIG_SYS_HZ); gd->arch.tbl = 0; return 0; @@ -83,14 +85,15 @@ ulong get_timer_masked(void) { ulong now; - now = readl(&timer_base->counter) / (TIMER_TICK_HZ / CONFIG_SYS_HZ); + now = readl(&timer_base->counter) / + (gd->arch.timer_rate_hz / CONFIG_SYS_HZ); if (gd->arch.lastinc >= now) { /* Normal mode */ gd->arch.tbl += gd->arch.lastinc - now; } else { /* We have an overflow ... */ - gd->arch.tbl += gd->arch.lastinc + TIMER_LOAD_VAL - now; + gd->arch.tbl += gd->arch.lastinc + TIMER_LOAD_VAL - now + 1; } gd->arch.lastinc = now; @@ -107,7 +110,8 @@ void __udelay(unsigned long usec) if (usec == 0) return; - countticks = lldiv(TIMER_TICK_HZ * usec, 1000000); + countticks = lldiv(((unsigned long long)gd->arch.timer_rate_hz * usec), + 1000000); /* decrementing timer */ timeend = readl(&timer_base->counter) - countticks; diff --git a/arch/arm/cpu/armv7/zynq/u-boot-spl.lds b/arch/arm/cpu/armv7/zynq/u-boot-spl.lds new file mode 100644 index 0000000..0c4501e --- /dev/null +++ b/arch/arm/cpu/armv7/zynq/u-boot-spl.lds @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014 Xilinx, Inc. Michal Simek + * Copyright (c) 2004-2008 Texas Instruments + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\ + LENGTH = CONFIG_SPL_MAX_SIZE } +MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \ + LENGTH = CONFIG_SPL_BSS_MAX_SIZE } + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = ALIGN(4); + .text : + { + __image_copy_start = .; + CPUDIR/start.o (.text*) + *(.text*) + } > .sram + + . = ALIGN(4); + .rodata : { + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) + } > .sram + + . = ALIGN(4); + .data : { + *(.data*) + } > .sram + + . = ALIGN(4); + + . = .; + + __image_copy_end = .; + + _end = .; + + /* Move BSS section to RAM because of FAT */ + .bss (NOLOAD) : { + __bss_start = .; + *(.bss*) + . = ALIGN(4); + __bss_end = .; + } > .sdram + + /DISCARD/ : { *(.dynsym) } + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } +} diff --git a/arch/arm/cpu/ixp/u-boot.lds b/arch/arm/cpu/armv7/zynq/u-boot.lds index 676ae2c..a68b050 100644 --- a/arch/arm/cpu/ixp/u-boot.lds +++ b/arch/arm/cpu/armv7/zynq/u-boot.lds @@ -1,11 +1,13 @@ /* - * (C) Copyright 2000-2006 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Copyright (c) 2004-2008 Texas Instruments + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> * * SPDX-License-Identifier: GPL-2.0+ */ -OUTPUT_FORMAT("elf32-bigarm", "elf32-bigarm", "elf32-bigarm") +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS @@ -16,7 +18,7 @@ SECTIONS .text : { *(.__image_copy_start) - arch/arm/cpu/ixp/start.o(.text*) + CPUDIR/start.o (.text*) *(.text*) } @@ -75,17 +77,23 @@ SECTIONS . = ALIGN(4); __bss_limit = .; } + .bss_end __bss_limit (OVERLAY) : { KEEP(*(.__bss_end)); } - .dynsym _end : { *(.dynsym) } - .dynbss : { *(.dynbss) } - .dynstr : { *(.dynstr*) } - .dynamic : { *(.dynamic*) } - .hash : { *(.hash*) } - .plt : { *(.plt*) } - .interp : { *(.interp*) } - .gnu : { *(.gnu*) } - .ARM.exidx : { *(.ARM.exidx*) } + /* + * Zynq needs to discard more sections because the user + * is expected to pass this image on to tools for boot.bin + * generation that require them to be dropped. + */ + /DISCARD/ : { *(.dynsym) } + /DISCARD/ : { *(.dynbss*) } + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } + /DISCARD/ : { *(.ARM.exidx*) } + /DISCARD/ : { *(.gnu.linkonce.armexidx.*) } } diff --git a/arch/arm/cpu/ixp/Makefile b/arch/arm/cpu/ixp/Makefile deleted file mode 100644 index 4e66523..0000000 --- a/arch/arm/cpu/ixp/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# -# (C) Copyright 2000-2006 -# Wolfgang Denk, DENX Software Engineering, wd@denx.de. -# -# SPDX-License-Identifier: GPL-2.0+ -# - -extra-y = start.o - -obj-y += cpu.o -obj-$(CONFIG_USE_IRQ) += interrupts.o -obj-y += timer.o diff --git a/arch/arm/cpu/ixp/config.mk b/arch/arm/cpu/ixp/config.mk deleted file mode 100644 index 894861f..0000000 --- a/arch/arm/cpu/ixp/config.mk +++ /dev/null @@ -1,16 +0,0 @@ -# -# (C) Copyright 2002 -# Sysgo Real-Time Solutions, GmbH <www.elinos.com> -# Marius Groeger <mgroeger@sysgo.de> -# -# SPDX-License-Identifier: GPL-2.0+ -# - -BIG_ENDIAN = y - -PLATFORM_RELFLAGS += -mbig-endian - -PLATFORM_CPPFLAGS += -mbig-endian -march=armv5te -mtune=strongarm1100 - -PLATFORM_LDFLAGS += -EB -USE_PRIVATE_LIBGCC = yes diff --git a/arch/arm/cpu/ixp/cpu.c b/arch/arm/cpu/ixp/cpu.c deleted file mode 100644 index 4387c18..0000000 --- a/arch/arm/cpu/ixp/cpu.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Marius Groeger <mgroeger@sysgo.de> - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Alex Zuepke <azu@sysgo.de> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -/* - * CPU specific code - */ - -#include <common.h> -#include <command.h> -#include <netdev.h> -#include <asm/arch/ixp425.h> -#include <asm/system.h> - -static void cache_flush(void); - -#if defined(CONFIG_DISPLAY_CPUINFO) -int print_cpuinfo (void) -{ - unsigned long id; - int speed = 0; - - asm ("mrc p15, 0, %0, c0, c0, 0":"=r" (id)); - - puts("CPU: Intel IXP425 at "); - switch ((id & 0x000003f0) >> 4) { - case 0x1c: - speed = 533; - break; - - case 0x1d: - speed = 400; - break; - - case 0x1f: - speed = 266; - break; - } - - if (speed) - printf("%d MHz\n", speed); - else - puts("unknown revision\n"); - - return 0; -} -#endif /* CONFIG_DISPLAY_CPUINFO */ - -int cleanup_before_linux (void) -{ - /* - * this function is called just before we call linux - * it prepares the processor for linux - * - * just disable everything that can disturb booting linux - */ - - disable_interrupts (); - - /* turn off I-cache */ - icache_disable(); - dcache_disable(); - - /* flush I-cache */ - cache_flush(); - - return 0; -} - -/* flush I/D-cache */ -static void cache_flush (void) -{ - unsigned long i = 0; - - asm ("mcr p15, 0, %0, c7, c5, 0": :"r" (i)); -} - -/* FIXME */ -/* -void pci_init(void) -{ - return; -} -*/ - -int cpu_eth_init(bd_t *bis) -{ -#ifdef CONFIG_IXP4XX_NPE - npe_initialize(bis); -#endif - return 0; -} diff --git a/arch/arm/cpu/ixp/interrupts.c b/arch/arm/cpu/ixp/interrupts.c deleted file mode 100644 index 7694c6a..0000000 --- a/arch/arm/cpu/ixp/interrupts.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * (C) Copyright 2006 - * Stefan Roese, DENX Software Engineering, sr@denx.de. - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Marius Groeger <mgroeger@sysgo.de> - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Alex Zuepke <azu@sysgo.de> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/arch/ixp425.h> -#include <asm/proc-armv/ptrace.h> - -struct _irq_handler { - void *m_data; - void (*m_func)( void *data); -}; - -static struct _irq_handler IRQ_HANDLER[N_IRQS]; - -static void default_isr(void *data) -{ - printf("default_isr(): called for IRQ %d, Interrupt Status=%x PR=%x\n", - (int)data, *IXP425_ICIP, *IXP425_ICIH); -} - -static int next_irq(void) -{ - return (((*IXP425_ICIH & 0x000000fc) >> 2) - 1); -} - -void do_irq (struct pt_regs *pt_regs) -{ - int irq = next_irq(); - - IRQ_HANDLER[irq].m_func(IRQ_HANDLER[irq].m_data); -} - -void irq_install_handler (int irq, interrupt_handler_t handle_irq, void *data) -{ - if (irq >= N_IRQS || !handle_irq) - return; - - IRQ_HANDLER[irq].m_data = data; - IRQ_HANDLER[irq].m_func = handle_irq; -} - -int arch_interrupt_init (void) -{ - int i; - - /* install default interrupt handlers */ - for (i = 0; i < N_IRQS; i++) - irq_install_handler(i, default_isr, (void *)i); - - /* configure interrupts for IRQ mode */ - *IXP425_ICLR = 0x00000000; - - return (0); -} diff --git a/arch/arm/cpu/ixp/start.S b/arch/arm/cpu/ixp/start.S deleted file mode 100644 index 82c868a..0000000 --- a/arch/arm/cpu/ixp/start.S +++ /dev/null @@ -1,430 +0,0 @@ -/* vi: set ts=8 sw=8 noet: */ -/* - * u-boot - Startup Code for XScale IXP - * - * Copyright (C) 2003 Kyle Harris <kharris@nexus-tech.net> - * - * Based on startup code example contained in the - * Intel IXP4xx Programmer's Guide and past u-boot Start.S - * samples. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <asm-offsets.h> -#include <config.h> -#include <version.h> -#include <asm/arch/ixp425.h> - -#define MMU_Control_M 0x001 /* Enable MMU */ -#define MMU_Control_A 0x002 /* Enable address alignment faults */ -#define MMU_Control_C 0x004 /* Enable cache */ -#define MMU_Control_W 0x008 /* Enable write-buffer */ -#define MMU_Control_P 0x010 /* Compatability: 32 bit code */ -#define MMU_Control_D 0x020 /* Compatability: 32 bit data */ -#define MMU_Control_L 0x040 /* Compatability: */ -#define MMU_Control_B 0x080 /* Enable Big-Endian */ -#define MMU_Control_S 0x100 /* Enable system protection */ -#define MMU_Control_R 0x200 /* Enable ROM protection */ -#define MMU_Control_I 0x1000 /* Enable Instruction cache */ -#define MMU_Control_X 0x2000 /* Set interrupt vectors at 0xFFFF0000 */ -#define MMU_Control_Init (MMU_Control_P|MMU_Control_D|MMU_Control_L) - - -/* - * Macro definitions - */ - /* Delay a bit */ - .macro DELAY_FOR cycles, reg0 - ldr \reg0, =\cycles - subs \reg0, \reg0, #1 - subne pc, pc, #0xc - .endm - - /* wait for coprocessor write complete */ - .macro CPWAIT reg - mrc p15,0,\reg,c2,c0,0 - mov \reg,\reg - sub pc,pc,#4 - .endm - -.globl _start -_start: - ldr pc, _reset - ldr pc, _undefined_instruction - ldr pc, _software_interrupt - ldr pc, _prefetch_abort - ldr pc, _data_abort - ldr pc, _not_used - ldr pc, _irq - ldr pc, _fiq - -_reset: .word reset -_undefined_instruction: .word undefined_instruction -_software_interrupt: .word software_interrupt -_prefetch_abort: .word prefetch_abort -_data_abort: .word data_abort -_not_used: .word not_used -_irq: .word irq -_fiq: .word fiq - - .balignl 16,0xdeadbeef - - -/* - * Startup Code (reset vector) - * - * do important init only if we don't start from memory! - * - relocate armboot to ram - * - setup stack - * - jump to second stage - */ - -.globl _TEXT_BASE -_TEXT_BASE: -#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE) - .word CONFIG_SPL_TEXT_BASE -#else - .word CONFIG_SYS_TEXT_BASE -#endif - -/* - * These are defined in the board-specific linker script. - * Subtracting _start from them lets the linker put their - * relative position in the executable instead of leaving - * them null. - */ -.globl _bss_start_ofs -_bss_start_ofs: - .word __bss_start - _start - -.globl _bss_end_ofs -_bss_end_ofs: - .word __bss_end - _start - -.globl _end_ofs -_end_ofs: - .word _end - _start - -#ifdef CONFIG_USE_IRQ -/* IRQ stack memory (calculated at run-time) */ -.globl IRQ_STACK_START -IRQ_STACK_START: - .word 0x0badc0de - -/* IRQ stack memory (calculated at run-time) */ -.globl FIQ_STACK_START -FIQ_STACK_START: - .word 0x0badc0de -#endif - -/* IRQ stack memory (calculated at run-time) + 8 bytes */ -.globl IRQ_STACK_START_IN -IRQ_STACK_START_IN: - .word 0x0badc0de - -/* - * the actual reset code - */ - -reset: - /* disable mmu, set big-endian */ - mov r0, #0xf8 - mcr p15, 0, r0, c1, c0, 0 - CPWAIT r0 - - /* invalidate I & D caches & BTB */ - mcr p15, 0, r0, c7, c7, 0 - CPWAIT r0 - - /* invalidate I & Data TLB */ - mcr p15, 0, r0, c8, c7, 0 - CPWAIT r0 - - /* drain write and fill buffers */ - mcr p15, 0, r0, c7, c10, 4 - CPWAIT r0 - - /* disable write buffer coalescing */ - mrc p15, 0, r0, c1, c0, 1 - orr r0, r0, #1 - mcr p15, 0, r0, c1, c0, 1 - CPWAIT r0 - - /* set EXP CS0 to the optimum timing */ - ldr r1, =CONFIG_SYS_EXP_CS0 - ldr r2, =IXP425_EXP_CS0 - str r1, [r2] - - /* make sure flash is visible at 0 */ - mov r1, #CONFIG_SYS_SDR_CONFIG - ldr r2, =IXP425_SDR_CONFIG - str r1, [r2] - - /* disable refresh cycles */ - mov r1, #0 - ldr r3, =IXP425_SDR_REFRESH - str r1, [r3] - - /* send nop command */ - mov r1, #3 - ldr r4, =IXP425_SDR_IR - str r1, [r4] - DELAY_FOR 0x4000, r0 - - /* set SDRAM internal refresh val */ - ldr r1, =CONFIG_SYS_SDRAM_REFRESH_CNT - str r1, [r3] - DELAY_FOR 0x4000, r0 - - /* send precharge-all command to close all open banks */ - mov r1, #2 - str r1, [r4] - DELAY_FOR 0x4000, r0 - - /* provide 8 auto-refresh cycles */ - mov r1, #4 - mov r5, #8 -111: str r1, [r4] - DELAY_FOR 0x100, r0 - subs r5, r5, #1 - bne 111b - - /* set mode register in sdram */ - mov r1, #CONFIG_SYS_SDR_MODE_CONFIG - str r1, [r4] - DELAY_FOR 0x4000, r0 - - /* send normal operation command */ - mov r1, #6 - str r1, [r4] - DELAY_FOR 0x4000, r0 - - /* invalidate I & D caches & BTB */ - mcr p15, 0, r0, c7, c7, 0 - CPWAIT r0 - - /* invalidate I & Data TLB */ - mcr p15, 0, r0, c8, c7, 0 - CPWAIT r0 - - /* drain write and fill buffers */ - mcr p15, 0, r0, c7, c10, 4 - CPWAIT r0 - - /* remove flash mirror at 0x00000000 */ - ldr r2, =IXP425_EXP_CFG0 - ldr r1, [r2] - bic r1, r1, #0x80000000 - str r1, [r2] - - /* invalidate I & Data TLB */ - mcr p15, 0, r0, c8, c7, 0 - CPWAIT r0 - - /* enable I cache */ - mrc p15, 0, r0, c1, c0, 0 - orr r0, r0, #MMU_Control_I - mcr p15, 0, r0, c1, c0, 0 - CPWAIT r0 - - mrs r0,cpsr /* set the cpu to SVC32 mode */ - bic r0,r0,#0x1f /* (superviser mode, M=10011) */ - orr r0,r0,#0x13 - msr cpsr,r0 - - bl _main - -/*------------------------------------------------------------------------------*/ - - .globl c_runtime_cpu_setup -c_runtime_cpu_setup: - - bx lr - -/****************************************************************************/ -/* */ -/* Interrupt handling */ -/* */ -/****************************************************************************/ - -/* IRQ stack frame */ - -#define S_FRAME_SIZE 72 - -#define S_OLD_R0 68 -#define S_PSR 64 -#define S_PC 60 -#define S_LR 56 -#define S_SP 52 - -#define S_IP 48 -#define S_FP 44 -#define S_R10 40 -#define S_R9 36 -#define S_R8 32 -#define S_R7 28 -#define S_R6 24 -#define S_R5 20 -#define S_R4 16 -#define S_R3 12 -#define S_R2 8 -#define S_R1 4 -#define S_R0 0 - -#define MODE_SVC 0x13 - - /* use bad_save_user_regs for abort/prefetch/undef/swi ... */ - - .macro bad_save_user_regs - sub sp, sp, #S_FRAME_SIZE - stmia sp, {r0 - r12} /* Calling r0-r12 */ - add r8, sp, #S_PC - - ldr r2, IRQ_STACK_START_IN - ldmia r2, {r2 - r4} /* get pc, cpsr, old_r0 */ - add r0, sp, #S_FRAME_SIZE /* restore sp_SVC */ - - add r5, sp, #S_SP - mov r1, lr - stmia r5, {r0 - r4} /* save sp_SVC, lr_SVC, pc, cpsr, old_r */ - mov r0, sp - .endm - - - /* use irq_save_user_regs / irq_restore_user_regs for */ - /* IRQ/FIQ handling */ - - .macro irq_save_user_regs - sub sp, sp, #S_FRAME_SIZE - stmia sp, {r0 - r12} /* Calling r0-r12 */ - add r8, sp, #S_PC - stmdb r8, {sp, lr}^ /* Calling SP, LR */ - str lr, [r8, #0] /* Save calling PC */ - mrs r6, spsr - str r6, [r8, #4] /* Save CPSR */ - str r0, [r8, #8] /* Save OLD_R0 */ - mov r0, sp - .endm - - .macro irq_restore_user_regs - ldmia sp, {r0 - lr}^ @ Calling r0 - lr - mov r0, r0 - ldr lr, [sp, #S_PC] @ Get PC - add sp, sp, #S_FRAME_SIZE - subs pc, lr, #4 @ return & move spsr_svc into cpsr - .endm - - .macro get_bad_stack - ldr r13, IRQ_STACK_START_IN @ setup our mode stack - - str lr, [r13] @ save caller lr / spsr - mrs lr, spsr - str lr, [r13, #4] - - mov r13, #MODE_SVC @ prepare SVC-Mode - msr spsr_c, r13 - mov lr, pc - movs pc, lr - .endm - - .macro get_irq_stack @ setup IRQ stack - ldr sp, IRQ_STACK_START - .endm - - .macro get_fiq_stack @ setup FIQ stack - ldr sp, FIQ_STACK_START - .endm - - -/****************************************************************************/ -/* */ -/* exception handlers */ -/* */ -/****************************************************************************/ - - .align 5 -undefined_instruction: - get_bad_stack - bad_save_user_regs - bl do_undefined_instruction - - .align 5 -software_interrupt: - get_bad_stack - bad_save_user_regs - bl do_software_interrupt - - .align 5 -prefetch_abort: - get_bad_stack - bad_save_user_regs - bl do_prefetch_abort - - .align 5 -data_abort: - get_bad_stack - bad_save_user_regs - bl do_data_abort - - .align 5 -not_used: - get_bad_stack - bad_save_user_regs - bl do_not_used - -#ifdef CONFIG_USE_IRQ - - .align 5 -irq: - get_irq_stack - irq_save_user_regs - bl do_irq - irq_restore_user_regs - - .align 5 -fiq: - get_fiq_stack - irq_save_user_regs /* someone ought to write a more */ - bl do_fiq /* effiction fiq_save_user_regs */ - irq_restore_user_regs - -#else - - .align 5 -irq: - get_bad_stack - bad_save_user_regs - bl do_irq - - .align 5 -fiq: - get_bad_stack - bad_save_user_regs - bl do_fiq - -#endif - -/****************************************************************************/ -/* */ -/* Reset function: Use Watchdog to reset */ -/* */ -/****************************************************************************/ - - .align 5 -.globl reset_cpu - -reset_cpu: - ldr r1, =0x482e - ldr r2, =IXP425_OSWK - str r1, [r2] - ldr r1, =0x0fff - ldr r2, =IXP425_OSWT - str r1, [r2] - ldr r1, =0x5 - ldr r2, =IXP425_OSWE - str r1, [r2] - b reset_endless - -reset_endless: - b reset_endless diff --git a/arch/arm/cpu/ixp/timer.c b/arch/arm/cpu/ixp/timer.c deleted file mode 100644 index 38e2e28..0000000 --- a/arch/arm/cpu/ixp/timer.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * (C) Copyright 2010 - * Michael Schwingen, michael@schwingen.org - * - * (C) Copyright 2006 - * Stefan Roese, DENX Software Engineering, sr@denx.de. - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Marius Groeger <mgroeger@sysgo.de> - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Alex Zuepke <azu@sysgo.de> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/arch/ixp425.h> -#include <asm/io.h> -#include <div64.h> - -DECLARE_GLOBAL_DATA_PTR; - -/* - * The IXP42x time-stamp timer runs at 2*OSC_IN (66.666MHz when using a - * 33.333MHz crystal). - */ -static inline unsigned long long tick_to_time(unsigned long long tick) -{ - tick *= CONFIG_SYS_HZ; - do_div(tick, CONFIG_IXP425_TIMER_CLK); - return tick; -} - -static inline unsigned long long time_to_tick(unsigned long long time) -{ - time *= CONFIG_IXP425_TIMER_CLK; - do_div(time, CONFIG_SYS_HZ); - return time; -} - -static inline unsigned long long us_to_tick(unsigned long long us) -{ - us = us * CONFIG_IXP425_TIMER_CLK + 999999; - do_div(us, 1000000); - return us; -} - -unsigned long long get_ticks(void) -{ - ulong now = readl(IXP425_OSTS_B); - - if (readl(IXP425_OSST) & IXP425_OSST_TIMER_TS_PEND) { - /* rollover of timestamp timer register */ - gd->arch.timestamp += (0xFFFFFFFF - gd->arch.lastinc) + now + 1; - writel(IXP425_OSST_TIMER_TS_PEND, IXP425_OSST); - } else { - /* move stamp forward with absolut diff ticks */ - gd->arch.timestamp += (now - gd->arch.lastinc); - } - gd->arch.lastinc = now; - return gd->arch.timestamp; -} - - -void reset_timer_masked(void) -{ - /* capture current timestamp counter */ - gd->arch.lastinc = readl(IXP425_OSTS_B); - /* start "advancing" time stamp from 0 */ - gd->arch.timestamp = 0; -} - -ulong get_timer_masked(void) -{ - return tick_to_time(get_ticks()); -} - -ulong get_timer(ulong base) -{ - return get_timer_masked() - base; -} - -/* delay x useconds AND preserve advance timestamp value */ -void __udelay(unsigned long usec) -{ - unsigned long long tmp; - - tmp = get_ticks() + us_to_tick(usec); - - while (get_ticks() < tmp) - ; -} - -int timer_init(void) -{ - writel(IXP425_OSST_TIMER_TS_PEND, IXP425_OSST); - return 0; -} diff --git a/arch/arm/cpu/tegra-common/Makefile b/arch/arm/cpu/tegra-common/Makefile index edfc1a8..34d5734 100644 --- a/arch/arm/cpu/tegra-common/Makefile +++ b/arch/arm/cpu/tegra-common/Makefile @@ -8,4 +8,5 @@ # obj-y += lowlevel_init.o -obj-y += ap.o board.o sys_info.o clock.o cache.o +obj-y += ap.o board.o clock.o cache.o +obj-$(CONFIG_DISPLAY_CPUINFO) += sys_info.o diff --git a/arch/arm/cpu/tegra-common/ap.c b/arch/arm/cpu/tegra-common/ap.c index 60d71a6..91d70da 100644 --- a/arch/arm/cpu/tegra-common/ap.c +++ b/arch/arm/cpu/tegra-common/ap.c @@ -1,5 +1,5 @@ /* -* (C) Copyright 2010-2011 +* (C) Copyright 2010-2014 * NVIDIA Corporation <www.nvidia.com> * * SPDX-License-Identifier: GPL-2.0+ @@ -27,7 +27,7 @@ int tegra_get_chip(void) /* * This is undocumented, Chip ID is bits 15:8 of the register * APB_MISC + 0x804, and has value 0x20 for Tegra20, 0x30 for - * Tegra30, and 0x35 for T114. + * Tegra30, 0x35 for T114, and 0x40 for Tegra124. */ rev = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >> HIDREV_CHIPID_SHIFT; debug("%s: CHIPID is 0x%02X\n", __func__, rev); @@ -72,6 +72,7 @@ int tegra_get_chip_sku(void) case SKU_ID_T33: case SKU_ID_T30: case SKU_ID_TM30MQS_P_A3: + default: return TEGRA_SOC_T30; } break; @@ -79,10 +80,19 @@ int tegra_get_chip_sku(void) switch (sku_id) { case SKU_ID_T114_ENG: case SKU_ID_T114_1: + default: return TEGRA_SOC_T114; } break; + case CHIPID_TEGRA124: + switch (sku_id) { + case SKU_ID_T124_ENG: + default: + return TEGRA_SOC_T124; + } + break; } + /* unknown chip/sku id */ printf("%s: ERROR: UNKNOWN CHIP/SKU ID COMBO (0x%02X/0x%02X)\n", __func__, chip_id, sku_id); @@ -117,8 +127,8 @@ static u32 get_odmdata(void) * ODMDATA is stored in the BCT in IRAM by the BootROM. * The BCT start and size are stored in the BIT in IRAM. * Read the data @ bct_start + (bct_size - 12). This works - * on T20 and T30 BCTs, which are locked down. If this changes - * in new chips (T114, etc.), we can revisit this algorithm. + * on BCTs for currently supported SoCs, which are locked down. + * If this changes in new chips, we can revisit this algorithm. */ u32 bct_start, odmdata; diff --git a/arch/arm/cpu/tegra-common/board.c b/arch/arm/cpu/tegra-common/board.c index d9cbda8..6a6faf4 100644 --- a/arch/arm/cpu/tegra-common/board.c +++ b/arch/arm/cpu/tegra-common/board.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2010,2011 + * (C) Copyright 2010-2014 * NVIDIA Corporation <www.nvidia.com> * * SPDX-License-Identifier: GPL-2.0+ @@ -109,12 +109,18 @@ static int uart_configs[] = { -1, -1, -1, -#else /* Tegra114 */ +#elif defined(CONFIG_TEGRA114) -1, -1, -1, FUNCMUX_UART4_GMI, /* UARTD */ -1, +#else /* Tegra124 */ + FUNCMUX_UART1_KBC, /* UARTA */ + -1, + -1, + FUNCMUX_UART4_GPIO, /* UARTD */ + -1, #endif }; diff --git a/arch/arm/cpu/tegra-common/cache.c b/arch/arm/cpu/tegra-common/cache.c index 48e9319..94f5bce 100644 --- a/arch/arm/cpu/tegra-common/cache.c +++ b/arch/arm/cpu/tegra-common/cache.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -23,8 +23,6 @@ void config_cache(void) { - struct apb_misc_gp_ctlr *gp = - (struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE; u32 reg = 0; /* enable SMP mode and FW for CPU0, by writing to Auxiliary Ctl reg */ @@ -33,10 +31,10 @@ void config_cache(void) "orr r0, r0, #0x41\n" "mcr p15, 0, r0, c1, c0, 1\n"); - /* Currently, only T114 needs this L2 cache change to boot Linux */ - reg = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK); - if (reg != (CHIPID_TEGRA114 << HIDREV_CHIPID_SHIFT)) + /* Currently, only Tegra114+ needs this L2 cache change to boot Linux */ + if (tegra_get_chip() < CHIPID_TEGRA114) return; + /* * Systems with an architectural L2 cache must not use the PL310. * Config L2CTLR here for a data RAM latency of 3 cycles. diff --git a/arch/arm/cpu/tegra-common/clock.c b/arch/arm/cpu/tegra-common/clock.c index 268fb91..11c7435 100644 --- a/arch/arm/cpu/tegra-common/clock.c +++ b/arch/arm/cpu/tegra-common/clock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -142,8 +142,8 @@ void clock_ll_set_source_divisor(enum periph_id periph_id, unsigned source, value = readl(reg); - value &= ~OUT_CLK_SOURCE_MASK; - value |= source << OUT_CLK_SOURCE_SHIFT; + value &= ~OUT_CLK_SOURCE_31_30_MASK; + value |= source << OUT_CLK_SOURCE_31_30_SHIFT; value &= ~OUT_CLK_DIVISOR_MASK; value |= divisor << OUT_CLK_DIVISOR_SHIFT; @@ -155,8 +155,8 @@ void clock_ll_set_source(enum periph_id periph_id, unsigned source) { u32 *reg = get_periph_source_reg(periph_id); - clrsetbits_le32(reg, OUT_CLK_SOURCE_MASK, - source << OUT_CLK_SOURCE_SHIFT); + clrsetbits_le32(reg, OUT_CLK_SOURCE_31_30_MASK, + source << OUT_CLK_SOURCE_31_30_SHIFT); } /** @@ -304,13 +304,27 @@ static int adjust_periph_pll(enum periph_id periph_id, int source, /* work out the source clock and set it */ if (source < 0) return -1; - if (mux_bits == 4) { - clrsetbits_le32(reg, OUT_CLK_SOURCE4_MASK, - source << OUT_CLK_SOURCE4_SHIFT); - } else { - clrsetbits_le32(reg, OUT_CLK_SOURCE_MASK, - source << OUT_CLK_SOURCE_SHIFT); + + switch (mux_bits) { + case MASK_BITS_31_30: + clrsetbits_le32(reg, OUT_CLK_SOURCE_31_30_MASK, + source << OUT_CLK_SOURCE_31_30_SHIFT); + break; + + case MASK_BITS_31_29: + clrsetbits_le32(reg, OUT_CLK_SOURCE_31_29_MASK, + source << OUT_CLK_SOURCE_31_29_SHIFT); + break; + + case MASK_BITS_31_28: + clrsetbits_le32(reg, OUT_CLK_SOURCE_31_28_MASK, + source << OUT_CLK_SOURCE_31_28_SHIFT); + break; + + default: + return -1; } + udelay(2); return 0; } @@ -561,3 +575,95 @@ void clock_init(void) /* Do any special system timer/TSC setup */ arch_timer_init(); } + +static void set_avp_clock_source(u32 src) +{ + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + u32 val; + + val = (src << SCLK_SWAKEUP_FIQ_SOURCE_SHIFT) | + (src << SCLK_SWAKEUP_IRQ_SOURCE_SHIFT) | + (src << SCLK_SWAKEUP_RUN_SOURCE_SHIFT) | + (src << SCLK_SWAKEUP_IDLE_SOURCE_SHIFT) | + (SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT); + writel(val, &clkrst->crc_sclk_brst_pol); + udelay(3); +} + +/* + * This function is useful on Tegra30, and any later SoCs that have compatible + * PLLP configuration registers. + */ +void tegra30_set_up_pllp(void) +{ + struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + u32 reg; + + /* + * Based on the Tegra TRM, the system clock (which is the AVP clock) can + * run up to 275MHz. On power on, the default sytem clock source is set + * to PLLP_OUT0. This function sets PLLP's (hence PLLP_OUT0's) rate to + * 408MHz which is beyond system clock's upper limit. + * + * The fix is to set the system clock to CLK_M before initializing PLLP, + * and then switch back to PLLP_OUT4, which has an appropriate divider + * configured, after PLLP has been configured + */ + set_avp_clock_source(SCLK_SOURCE_CLKM); + + /* + * PLLP output frequency set to 408Mhz + * PLLC output frequency set to 228Mhz + */ + switch (clock_get_osc_freq()) { + case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */ + clock_set_rate(CLOCK_ID_PERIPH, 408, 12, 0, 8); + clock_set_rate(CLOCK_ID_CGENERAL, 456, 12, 1, 8); + break; + + case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */ + clock_set_rate(CLOCK_ID_PERIPH, 408, 26, 0, 8); + clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8); + break; + + case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */ + clock_set_rate(CLOCK_ID_PERIPH, 408, 13, 0, 8); + clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8); + break; + 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; + } + + /* Set PLLP_OUT1, 2, 3 & 4 freqs to 9.6, 48, 102 & 204MHz */ + + /* OUT1, 2 */ + /* Assert RSTN before enable */ + reg = PLLP_OUT2_RSTN_EN | PLLP_OUT1_RSTN_EN; + writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[0]); + /* Set divisor and reenable */ + reg = (IN_408_OUT_48_DIVISOR << PLLP_OUT2_RATIO) + | PLLP_OUT2_OVR | PLLP_OUT2_CLKEN | PLLP_OUT2_RSTN_DIS + | (IN_408_OUT_9_6_DIVISOR << PLLP_OUT1_RATIO) + | PLLP_OUT1_OVR | PLLP_OUT1_CLKEN | PLLP_OUT1_RSTN_DIS; + writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[0]); + + /* OUT3, 4 */ + /* Assert RSTN before enable */ + reg = PLLP_OUT4_RSTN_EN | PLLP_OUT3_RSTN_EN; + writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[1]); + /* Set divisor and reenable */ + reg = (IN_408_OUT_204_DIVISOR << PLLP_OUT4_RATIO) + | PLLP_OUT4_OVR | PLLP_OUT4_CLKEN | PLLP_OUT4_RSTN_DIS + | (IN_408_OUT_102_DIVISOR << PLLP_OUT3_RATIO) + | PLLP_OUT3_OVR | PLLP_OUT3_CLKEN | PLLP_OUT3_RSTN_DIS; + writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[1]); + + set_avp_clock_source(SCLK_SOURCE_PLLP_OUT4); +} diff --git a/arch/arm/cpu/tegra-common/sys_info.c b/arch/arm/cpu/tegra-common/sys_info.c index dc8a2e4..de20325 100644 --- a/arch/arm/cpu/tegra-common/sys_info.c +++ b/arch/arm/cpu/tegra-common/sys_info.c @@ -8,7 +8,6 @@ #include <common.h> #include <linux/ctype.h> -#ifdef CONFIG_DISPLAY_CPUINFO void upstring(char *s) { while (*s) { @@ -30,4 +29,3 @@ int print_cpuinfo(void) /* TBD: Add printf of major/minor rev info, stepping, etc. */ return 0; } -#endif /* CONFIG_DISPLAY_CPUINFO */ diff --git a/arch/arm/cpu/tegra114-common/clock.c b/arch/arm/cpu/tegra114-common/clock.c index 5c4305a..d5194e1 100644 --- a/arch/arm/cpu/tegra114-common/clock.c +++ b/arch/arm/cpu/tegra114-common/clock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -61,12 +61,6 @@ enum { CLOCK_MAX_MUX = 8 /* number of source options for each clock */ }; -enum { - MASK_BITS_31_30 = 2, /* num of bits used to specify clock source */ - MASK_BITS_31_29, - MASK_BITS_29_28, -}; - /* * Clock source mux for each clock type. This just converts our enum into * a list of mux sources for use by the code. @@ -109,7 +103,7 @@ static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX+1] = { MASK_BITS_31_29}, { CLK(PERIPH), CLK(CGENERAL), CLK(SFROM32KHZ), CLK(OSC), CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), - MASK_BITS_29_28} + MASK_BITS_31_28} }; /* @@ -610,26 +604,24 @@ void clock_early_init(void) struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + tegra30_set_up_pllp(); + /* - * PLLP output frequency set to 408Mhz * PLLC output frequency set to 600Mhz * PLLD output frequency set to 925Mhz */ switch (clock_get_osc_freq()) { case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */ - clock_set_rate(CLOCK_ID_PERIPH, 408, 12, 0, 8); clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8); clock_set_rate(CLOCK_ID_DISPLAY, 925, 12, 0, 12); break; case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */ - clock_set_rate(CLOCK_ID_PERIPH, 408, 26, 0, 8); clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8); clock_set_rate(CLOCK_ID_DISPLAY, 925, 26, 0, 12); break; case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */ - clock_set_rate(CLOCK_ID_PERIPH, 408, 13, 0, 8); clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8); clock_set_rate(CLOCK_ID_DISPLAY, 925, 13, 0, 12); break; diff --git a/arch/arm/cpu/tegra124-common/Makefile b/arch/arm/cpu/tegra124-common/Makefile new file mode 100644 index 0000000..ff77992 --- /dev/null +++ b/arch/arm/cpu/tegra124-common/Makefile @@ -0,0 +1,10 @@ +# +# (C) Copyright 2013-2014 +# NVIDIA Corporation <www.nvidia.com> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += clock.o +obj-y += funcmux.o +obj-y += pinmux.o diff --git a/arch/arm/cpu/tegra124-common/clock.c b/arch/arm/cpu/tegra124-common/clock.c new file mode 100644 index 0000000..7394363 --- /dev/null +++ b/arch/arm/cpu/tegra124-common/clock.c @@ -0,0 +1,826 @@ +/* + * (C) Copyright 2013 + * NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* Tegra124 Clock control functions */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/sysctr.h> +#include <asm/arch/tegra.h> +#include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/timer.h> +#include <div64.h> +#include <fdtdec.h> + +/* + * Clock types that we can use as a source. The Tegra124 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_PDCT, + CLOCK_TYPE_ACPT, + CLOCK_TYPE_ASPTE, + CLOCK_TYPE_PMDACD2T, + CLOCK_TYPE_PCST, + + CLOCK_TYPE_PC2CC3M, + CLOCK_TYPE_PC2CC3S_T, + CLOCK_TYPE_PC2CC3M_T, + CLOCK_TYPE_PC2CC3M_T16, /* PC2CC3M_T, but w/16-bit divisor (I2C) */ + CLOCK_TYPE_MC2CC3P_A, + CLOCK_TYPE_M, + CLOCK_TYPE_MCPTM2C2C3, + CLOCK_TYPE_PC2CC3T_S, + CLOCK_TYPE_AC2CC3P_TS2, + + CLOCK_TYPE_COUNT, + CLOCK_TYPE_NONE = -1, /* invalid clock type */ +}; + +enum { + CLOCK_MAX_MUX = 8 /* 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: + * The extra column in each clock source array is used to store the mask + * bits in its register for the source. + */ +#define CLK(x) CLOCK_ID_ ## x +static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX+1] = { + { CLK(AUDIO), CLK(XCPU), CLK(PERIPH), CLK(OSC), + CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), + MASK_BITS_31_30}, + { CLK(MEMORY), CLK(CGENERAL), CLK(PERIPH), CLK(AUDIO), + CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), + MASK_BITS_31_30}, + { CLK(MEMORY), CLK(CGENERAL), CLK(PERIPH), CLK(OSC), + CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), + MASK_BITS_31_30}, + { CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY), CLK(NONE), + CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), + MASK_BITS_31_30}, + { CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY), CLK(OSC), + CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), + MASK_BITS_31_30}, + { CLK(PERIPH), CLK(DISPLAY), CLK(CGENERAL), CLK(OSC), + CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), + MASK_BITS_31_30}, + { CLK(AUDIO), CLK(CGENERAL), CLK(PERIPH), CLK(OSC), + CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), + MASK_BITS_31_30}, + { CLK(AUDIO), CLK(SFROM32KHZ), CLK(PERIPH), CLK(OSC), + CLK(EPCI), CLK(NONE), CLK(NONE), CLK(NONE), + MASK_BITS_31_29}, + { CLK(PERIPH), CLK(MEMORY), CLK(DISPLAY), CLK(AUDIO), + CLK(CGENERAL), CLK(DISPLAY2), CLK(OSC), CLK(NONE), + MASK_BITS_31_29}, + { CLK(PERIPH), CLK(CGENERAL), CLK(SFROM32KHZ), CLK(OSC), + CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), + MASK_BITS_31_28}, + + /* Additional clock types on Tegra114+ */ + /* CLOCK_TYPE_PC2CC3M */ + { CLK(PERIPH), CLK(CGENERAL2), CLK(CGENERAL), CLK(CGENERAL3), + CLK(MEMORY), CLK(NONE), CLK(NONE), CLK(NONE), + MASK_BITS_31_29}, + /* CLOCK_TYPE_PC2CC3S_T */ + { CLK(PERIPH), CLK(CGENERAL2), CLK(CGENERAL), CLK(CGENERAL3), + CLK(SFROM32KHZ), CLK(NONE), CLK(OSC), CLK(NONE), + MASK_BITS_31_29}, + /* CLOCK_TYPE_PC2CC3M_T */ + { CLK(PERIPH), CLK(CGENERAL2), CLK(CGENERAL), CLK(CGENERAL3), + CLK(MEMORY), CLK(NONE), CLK(OSC), CLK(NONE), + MASK_BITS_31_29}, + /* CLOCK_TYPE_PC2CC3M_T, w/16-bit divisor (I2C) */ + { CLK(PERIPH), CLK(CGENERAL2), CLK(CGENERAL), CLK(CGENERAL3), + CLK(MEMORY), CLK(NONE), CLK(OSC), CLK(NONE), + MASK_BITS_31_29}, + /* CLOCK_TYPE_MC2CC3P_A */ + { CLK(MEMORY), CLK(CGENERAL2), CLK(CGENERAL), CLK(CGENERAL3), + CLK(PERIPH), CLK(NONE), CLK(AUDIO), CLK(NONE), + MASK_BITS_31_29}, + /* CLOCK_TYPE_M */ + { CLK(MEMORY), CLK(NONE), CLK(NONE), CLK(NONE), + CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), + MASK_BITS_31_30}, + /* CLOCK_TYPE_MCPTM2C2C3 */ + { CLK(MEMORY), CLK(CGENERAL), CLK(PERIPH), CLK(OSC), + CLK(MEMORY2), CLK(CGENERAL2), CLK(CGENERAL3), CLK(NONE), + MASK_BITS_31_29}, + /* CLOCK_TYPE_PC2CC3T_S */ + { CLK(PERIPH), CLK(CGENERAL2), CLK(CGENERAL), CLK(CGENERAL3), + CLK(OSC), CLK(NONE), CLK(SFROM32KHZ), CLK(NONE), + MASK_BITS_31_29}, + /* CLOCK_TYPE_AC2CC3P_TS2 */ + { CLK(AUDIO), CLK(CGENERAL2), CLK(CGENERAL), CLK(CGENERAL3), + CLK(PERIPH), CLK(NONE), CLK(OSC), CLK(SRC2), + MASK_BITS_31_29}, +}; + +/* + * 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_PC2CC3M), + TYPE(PERIPHC_PWM, CLOCK_TYPE_PC2CC3S_T), + TYPE(PERIPHC_05h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_SBC2, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_SBC3, CLOCK_TYPE_PC2CC3M_T), + + /* 0x08 */ + TYPE(PERIPHC_08h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_I2C1, CLOCK_TYPE_PC2CC3M_T16), + TYPE(PERIPHC_I2C5, CLOCK_TYPE_PC2CC3M_T16), + TYPE(PERIPHC_0bh, CLOCK_TYPE_NONE), + TYPE(PERIPHC_0ch, CLOCK_TYPE_NONE), + TYPE(PERIPHC_SBC1, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_DISP1, CLOCK_TYPE_PMDACD2T), + TYPE(PERIPHC_DISP2, CLOCK_TYPE_PMDACD2T), + + /* 0x10 */ + TYPE(PERIPHC_10h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_11h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_VI, CLOCK_TYPE_MC2CC3P_A), + TYPE(PERIPHC_13h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_SDMMC1, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_SDMMC2, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_16h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_17h, CLOCK_TYPE_NONE), + + /* 0x18 */ + TYPE(PERIPHC_18h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_SDMMC4, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_VFIR, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_1Bh, CLOCK_TYPE_NONE), + TYPE(PERIPHC_1Ch, CLOCK_TYPE_NONE), + TYPE(PERIPHC_HSI, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_UART1, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_UART2, CLOCK_TYPE_PC2CC3M_T), + + /* 0x20 */ + TYPE(PERIPHC_HOST1X, CLOCK_TYPE_MC2CC3P_A), + TYPE(PERIPHC_21h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_22h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_HDMI, CLOCK_TYPE_PMDACD2T), + TYPE(PERIPHC_24h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_25h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_I2C2, CLOCK_TYPE_PC2CC3M_T16), + TYPE(PERIPHC_EMC, CLOCK_TYPE_MCPTM2C2C3), + + /* 0x28 */ + TYPE(PERIPHC_UART3, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_29h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_VI_SENSOR, CLOCK_TYPE_MC2CC3P_A), + TYPE(PERIPHC_2bh, CLOCK_TYPE_NONE), + TYPE(PERIPHC_2ch, CLOCK_TYPE_NONE), + TYPE(PERIPHC_SBC4, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_I2C3, CLOCK_TYPE_PC2CC3M_T16), + TYPE(PERIPHC_SDMMC3, CLOCK_TYPE_PC2CC3M_T), + + /* 0x30 */ + TYPE(PERIPHC_UART4, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_UART5, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_VDE, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_OWR, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_NOR, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_CSITE, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_I2S0, CLOCK_TYPE_AXPT), + TYPE(PERIPHC_DTV, CLOCK_TYPE_NONE), + + /* 0x38 */ + TYPE(PERIPHC_38h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_39h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_3ah, CLOCK_TYPE_NONE), + TYPE(PERIPHC_3bh, CLOCK_TYPE_NONE), + TYPE(PERIPHC_MSENC, CLOCK_TYPE_MC2CC3P_A), + TYPE(PERIPHC_TSEC, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_3eh, CLOCK_TYPE_NONE), + TYPE(PERIPHC_OSC, CLOCK_TYPE_NONE), + + /* 0x40 */ + TYPE(PERIPHC_40h, CLOCK_TYPE_NONE), /* start with 0x3b0 */ + TYPE(PERIPHC_MSELECT, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_TSENSOR, CLOCK_TYPE_PC2CC3T_S), + TYPE(PERIPHC_I2S3, CLOCK_TYPE_AXPT), + TYPE(PERIPHC_I2S4, CLOCK_TYPE_AXPT), + TYPE(PERIPHC_I2C4, CLOCK_TYPE_PC2CC3M_T16), + TYPE(PERIPHC_SBC5, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_SBC6, CLOCK_TYPE_PC2CC3M_T), + + /* 0x48 */ + TYPE(PERIPHC_AUDIO, CLOCK_TYPE_AC2CC3P_TS2), + TYPE(PERIPHC_49h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_DAM0, CLOCK_TYPE_AC2CC3P_TS2), + TYPE(PERIPHC_DAM1, CLOCK_TYPE_AC2CC3P_TS2), + TYPE(PERIPHC_DAM2, CLOCK_TYPE_AC2CC3P_TS2), + TYPE(PERIPHC_HDA2CODEC2X, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_ACTMON, CLOCK_TYPE_PC2CC3S_T), + TYPE(PERIPHC_EXTPERIPH1, CLOCK_TYPE_ASPTE), + + /* 0x50 */ + TYPE(PERIPHC_EXTPERIPH2, CLOCK_TYPE_ASPTE), + TYPE(PERIPHC_EXTPERIPH3, CLOCK_TYPE_ASPTE), + TYPE(PERIPHC_52h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_I2CSLOW, CLOCK_TYPE_PC2CC3S_T), + TYPE(PERIPHC_SYS, CLOCK_TYPE_NONE), + TYPE(PERIPHC_55h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_56h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_57h, CLOCK_TYPE_NONE), + + /* 0x58 */ + TYPE(PERIPHC_58h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_59h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_5ah, CLOCK_TYPE_NONE), + TYPE(PERIPHC_5bh, CLOCK_TYPE_NONE), + TYPE(PERIPHC_SATAOOB, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_SATA, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_HDA, CLOCK_TYPE_PC2CC3M_T), + TYPE(PERIPHC_5fh, CLOCK_TYPE_NONE), + + /* 0x60 */ + TYPE(PERIPHC_XUSB_CORE_HOST, CLOCK_TYPE_NONE), + TYPE(PERIPHC_XUSB_FALCON, CLOCK_TYPE_NONE), + TYPE(PERIPHC_XUSB_FS, CLOCK_TYPE_NONE), + TYPE(PERIPHC_XUSB_CORE_DEV, CLOCK_TYPE_NONE), + TYPE(PERIPHC_XUSB_SS, CLOCK_TYPE_NONE), + TYPE(PERIPHC_CILAB, CLOCK_TYPE_NONE), + TYPE(PERIPHC_CILCD, CLOCK_TYPE_NONE), + TYPE(PERIPHC_CILE, CLOCK_TYPE_NONE), + + /* 0x68 */ + TYPE(PERIPHC_DSIA_LP, CLOCK_TYPE_NONE), + TYPE(PERIPHC_DSIB_LP, CLOCK_TYPE_NONE), + TYPE(PERIPHC_ENTROPY, CLOCK_TYPE_NONE), + TYPE(PERIPHC_DVFS_REF, CLOCK_TYPE_NONE), + TYPE(PERIPHC_DVFS_SOC, CLOCK_TYPE_NONE), + TYPE(PERIPHC_TRACECLKIN, CLOCK_TYPE_NONE), + TYPE(PERIPHC_ADX0, CLOCK_TYPE_NONE), + TYPE(PERIPHC_AMX0, CLOCK_TYPE_NONE), + + /* 0x70 */ + TYPE(PERIPHC_EMC_LATENCY, CLOCK_TYPE_NONE), + TYPE(PERIPHC_SOC_THERM, CLOCK_TYPE_NONE), + TYPE(PERIPHC_72h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_73h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_74h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_75h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_VI_SENSOR2, CLOCK_TYPE_NONE), + TYPE(PERIPHC_I2C6, CLOCK_TYPE_PC2CC3M_T16), + + /* 0x78 */ + TYPE(PERIPHC_78h, CLOCK_TYPE_NONE), + TYPE(PERIPHC_EMC_DLL, CLOCK_TYPE_MCPTM2C2C3), + TYPE(PERIPHC_HDMI_AUDIO, CLOCK_TYPE_NONE), + TYPE(PERIPHC_CLK72MHZ, CLOCK_TYPE_NONE), + TYPE(PERIPHC_ADX1, CLOCK_TYPE_AC2CC3P_TS2), + TYPE(PERIPHC_AMX1, CLOCK_TYPE_AC2CC3P_TS2), + TYPE(PERIPHC_VIC, CLOCK_TYPE_NONE), + TYPE(PERIPHC_7Fh, CLOCK_TYPE_NONE), +}; + +/* + * 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(COP), + NONE(TRIGSYS), + NONE(ISPB), + NONE(RESERVED4), + NONE(TMR), + PERIPHC_UART1, + PERIPHC_UART2, /* and vfir 0x68 */ + + /* 8 */ + NONE(GPIO), + PERIPHC_SDMMC2, + PERIPHC_SPDIF_IN, + PERIPHC_I2S1, + PERIPHC_I2C1, + NONE(RESERVED13), + PERIPHC_SDMMC1, + PERIPHC_SDMMC4, + + /* 16 */ + NONE(TCW), + PERIPHC_PWM, + PERIPHC_I2S2, + NONE(RESERVED19), + PERIPHC_VI, + NONE(RESERVED21), + NONE(USBD), + NONE(ISP), + + /* 24 */ + NONE(RESERVED24), + NONE(RESERVED25), + PERIPHC_DISP2, + PERIPHC_DISP1, + PERIPHC_HOST1X, + NONE(VCP), + PERIPHC_I2S0, + NONE(CACHE2), + + /* Middle word: 63:32 */ + NONE(MEM), + NONE(AHBDMA), + NONE(APBDMA), + NONE(RESERVED35), + NONE(RESERVED36), + NONE(STAT_MON), + NONE(RESERVED38), + NONE(FUSE), + + /* 40 */ + NONE(KFUSE), + PERIPHC_SBC1, /* SBCx = SPIx */ + PERIPHC_NOR, + NONE(RESERVED43), + PERIPHC_SBC2, + NONE(XIO), + PERIPHC_SBC3, + PERIPHC_I2C5, + + /* 48 */ + NONE(DSI), + NONE(RESERVED49), + PERIPHC_HSI, + PERIPHC_HDMI, + NONE(CSI), + NONE(RESERVED53), + PERIPHC_I2C2, + PERIPHC_UART3, + + /* 56 */ + NONE(MIPI_CAL), + PERIPHC_EMC, + NONE(USB2), + NONE(USB3), + NONE(RESERVED60), + PERIPHC_VDE, + NONE(BSEA), + NONE(BSEV), + + /* Upper word 95:64 */ + NONE(RESERVED64), + PERIPHC_UART4, + PERIPHC_UART5, + PERIPHC_I2C3, + PERIPHC_SBC4, + PERIPHC_SDMMC3, + NONE(PCIE), + PERIPHC_OWR, + + /* 72 */ + NONE(AFI), + PERIPHC_CSITE, + NONE(PCIEXCLK), + NONE(AVPUCQ), + NONE(LA), + NONE(TRACECLKIN), + NONE(SOC_THERM), + NONE(DTV), + + /* 80 */ + NONE(RESERVED80), + PERIPHC_I2CSLOW, + NONE(DSIB), + PERIPHC_TSEC, + NONE(RESERVED84), + NONE(RESERVED85), + NONE(RESERVED86), + NONE(EMUCIF), + + /* 88 */ + NONE(RESERVED88), + NONE(XUSB_HOST), + NONE(RESERVED90), + PERIPHC_MSENC, + NONE(RESERVED92), + NONE(RESERVED93), + NONE(RESERVED94), + NONE(XUSB_DEV), + + /* V word: 31:0 */ + NONE(CPUG), + NONE(CPULP), + NONE(V_RESERVED2), + PERIPHC_MSELECT, + NONE(V_RESERVED4), + PERIPHC_I2S3, + PERIPHC_I2S4, + PERIPHC_I2C4, + + /* 104 */ + PERIPHC_SBC5, + PERIPHC_SBC6, + PERIPHC_AUDIO, + NONE(APBIF), + PERIPHC_DAM0, + PERIPHC_DAM1, + PERIPHC_DAM2, + PERIPHC_HDA2CODEC2X, + + /* 112 */ + NONE(ATOMICS), + NONE(V_RESERVED17), + NONE(V_RESERVED18), + NONE(V_RESERVED19), + NONE(V_RESERVED20), + NONE(V_RESERVED21), + NONE(V_RESERVED22), + PERIPHC_ACTMON, + + /* 120 */ + NONE(EXTPERIPH1), + NONE(EXTPERIPH2), + NONE(EXTPERIPH3), + NONE(OOB), + PERIPHC_SATA, + PERIPHC_HDA, + NONE(TZRAM), + NONE(SE), + + /* W word: 31:0 */ + NONE(HDA2HDMICODEC), + NONE(SATACOLD), + NONE(W_RESERVED2), + NONE(W_RESERVED3), + NONE(W_RESERVED4), + NONE(W_RESERVED5), + NONE(W_RESERVED6), + NONE(W_RESERVED7), + + /* 136 */ + NONE(CEC), + NONE(W_RESERVED9), + NONE(W_RESERVED10), + NONE(W_RESERVED11), + NONE(W_RESERVED12), + NONE(W_RESERVED13), + NONE(XUSB_PADCTL), + NONE(W_RESERVED15), + + /* 144 */ + NONE(W_RESERVED16), + NONE(W_RESERVED17), + NONE(W_RESERVED18), + NONE(W_RESERVED19), + NONE(W_RESERVED20), + NONE(ENTROPY), + NONE(DDS), + NONE(W_RESERVED23), + + /* 152 */ + NONE(DP2), + NONE(AMX0), + NONE(ADX0), + NONE(DVFS), + NONE(XUSB_SS), + NONE(W_RESERVED29), + NONE(W_RESERVED30), + NONE(W_RESERVED31), + + /* X word: 31:0 */ + NONE(SPARE), + NONE(X_RESERVED1), + NONE(X_RESERVED2), + NONE(X_RESERVED3), + NONE(CAM_MCLK), + NONE(CAM_MCLK2), + PERIPHC_I2C6, + NONE(X_RESERVED7), + + /* 168 */ + NONE(X_RESERVED8), + NONE(X_RESERVED9), + NONE(X_RESERVED10), + NONE(VIM2_CLK), + NONE(X_RESERVED12), + NONE(X_RESERVED13), + NONE(EMC_DLL), + NONE(X_RESERVED15), + + /* 176 */ + NONE(HDMI_AUDIO), + NONE(CLK72MHZ), + NONE(VIC), + NONE(X_RESERVED19), + NONE(ADX1), + NONE(DPAUX), + NONE(SOR0), + NONE(X_RESERVED23), + + /* 184 */ + NONE(GPU), + NONE(AMX1), + NONE(X_RESERVED26), + NONE(X_RESERVED27), + NONE(X_RESERVED28), + NONE(X_RESERVED29), + NONE(X_RESERVED30), + NONE(X_RESERVED31), +}; + +/* + * Get the oscillator frequency, from the corresponding hardware configuration + * field. Note that Tegra30+ support 3 new higher freqs, but we map back + * to the old T20 freqs. Support for the higher oscillators is TBD. + */ +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); + reg = (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT; + + if (reg & 1) /* one of the newer freqs */ + printf("Warning: OSC_FREQ is unsupported! (%d)\n", reg); + + return reg >> 2; /* Map to most common (T20) freqs */ +} + +/* Returns a pointer to the clock source register for a peripheral */ +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; + + /* Coresight is a special case */ + if (periph_id == PERIPH_ID_CSI) + return &clkrst->crc_clk_src[PERIPH_ID_CSI+1]; + + assert(periph_id >= PERIPH_ID_FIRST && periph_id < PERIPH_ID_COUNT); + internal_id = periph_id_to_internal_id[periph_id]; + assert(internal_id != -1); + if (internal_id >= PERIPHC_VW_FIRST) { + internal_id -= PERIPHC_VW_FIRST; + return &clkrst->crc_clk_src_vw[internal_id]; + } else { + return &clkrst->crc_clk_src[internal_id]; + } +} + +/** + * 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 + * @param divider_bits Set to number of divider bits (8 or 16) + * @return mux value (0-4, or -1 if not found) + */ +int get_periph_clock_source(enum periph_id periph_id, + enum clock_id parent, int *mux_bits, int *divider_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)); + + *mux_bits = clock_source[type][CLOCK_MAX_MUX]; + + if (type == CLOCK_TYPE_PC2CC3M_T16) + *divider_bits = 16; + else + *divider_bits = 8; + + for (mux = 0; mux < CLOCK_MAX_MUX; mux++) + if (clock_source[type][mux] == parent) + return mux; + + /* 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; +} + +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; + u32 reg; + + /* Enable/disable the clock to this peripheral */ + assert(clock_periph_id_isvalid(periph_id)); + if ((int)periph_id < (int)PERIPH_ID_VW_FIRST) + clk = &clkrst->crc_clk_out_enb[PERIPH_REG(periph_id)]; + else + clk = &clkrst->crc_clk_out_enb_vw[PERIPH_REG(periph_id)]; + reg = readl(clk); + if (enable) + reg |= PERIPH_MASK(periph_id); + else + reg &= ~PERIPH_MASK(periph_id); + writel(reg, clk); +} + +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; + u32 reg; + + /* Enable/disable reset to the peripheral */ + assert(clock_periph_id_isvalid(periph_id)); + if (periph_id < PERIPH_ID_VW_FIRST) + reset = &clkrst->crc_rst_dev[PERIPH_REG(periph_id)]; + else + reset = &clkrst->crc_rst_dev_vw[PERIPH_REG(periph_id)]; + reg = readl(reset); + if (enable) + reg |= PERIPH_MASK(periph_id); + else + reg &= ~PERIPH_MASK(periph_id); + writel(reg, reset); +} + +#ifdef CONFIG_OF_CONTROL +/* + * Convert a device tree clock ID to our peripheral ID. They are mostly + * the same but we are very cautious so we check that a valid clock ID is + * provided. + * + * @param clk_id Clock ID according to tegra124 device tree binding + * @return peripheral ID, or PERIPH_ID_NONE if the clock ID is invalid + */ +enum periph_id clk_id_to_periph_id(int clk_id) +{ + if (clk_id > PERIPH_ID_COUNT) + return PERIPH_ID_NONE; + + switch (clk_id) { + case PERIPH_ID_RESERVED4: + case PERIPH_ID_RESERVED25: + case PERIPH_ID_RESERVED35: + case PERIPH_ID_RESERVED36: + case PERIPH_ID_RESERVED38: + case PERIPH_ID_RESERVED43: + case PERIPH_ID_RESERVED49: + case PERIPH_ID_RESERVED53: + case PERIPH_ID_RESERVED64: + case PERIPH_ID_RESERVED84: + case PERIPH_ID_RESERVED85: + case PERIPH_ID_RESERVED86: + case PERIPH_ID_RESERVED88: + case PERIPH_ID_RESERVED90: + case PERIPH_ID_RESERVED92: + case PERIPH_ID_RESERVED93: + case PERIPH_ID_RESERVED94: + case PERIPH_ID_V_RESERVED2: + case PERIPH_ID_V_RESERVED4: + case PERIPH_ID_V_RESERVED17: + case PERIPH_ID_V_RESERVED18: + case PERIPH_ID_V_RESERVED19: + case PERIPH_ID_V_RESERVED20: + case PERIPH_ID_V_RESERVED21: + case PERIPH_ID_V_RESERVED22: + case PERIPH_ID_W_RESERVED2: + case PERIPH_ID_W_RESERVED3: + case PERIPH_ID_W_RESERVED4: + case PERIPH_ID_W_RESERVED5: + case PERIPH_ID_W_RESERVED6: + case PERIPH_ID_W_RESERVED7: + case PERIPH_ID_W_RESERVED9: + case PERIPH_ID_W_RESERVED10: + case PERIPH_ID_W_RESERVED11: + case PERIPH_ID_W_RESERVED12: + case PERIPH_ID_W_RESERVED13: + case PERIPH_ID_W_RESERVED15: + case PERIPH_ID_W_RESERVED16: + case PERIPH_ID_W_RESERVED17: + case PERIPH_ID_W_RESERVED18: + case PERIPH_ID_W_RESERVED19: + case PERIPH_ID_W_RESERVED20: + case PERIPH_ID_W_RESERVED23: + case PERIPH_ID_W_RESERVED29: + case PERIPH_ID_W_RESERVED30: + case PERIPH_ID_W_RESERVED31: + return PERIPH_ID_NONE; + default: + return clk_id; + } +} +#endif /* CONFIG_OF_CONTROL */ + +void clock_early_init(void) +{ + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + + tegra30_set_up_pllp(); + + /* + * PLLC output frequency set to 600Mhz + * PLLD output frequency set to 925Mhz + */ + switch (clock_get_osc_freq()) { + case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */ + clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8); + clock_set_rate(CLOCK_ID_DISPLAY, 925, 12, 0, 12); + break; + + case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */ + clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8); + clock_set_rate(CLOCK_ID_DISPLAY, 925, 26, 0, 12); + break; + + case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */ + clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8); + clock_set_rate(CLOCK_ID_DISPLAY, 925, 13, 0, 12); + break; + 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; + } + + /* PLLC_MISC2: Set dynramp_stepA/B. MISC2 maps to pll_out[1] */ + writel(0x00561600, &clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_out[1]); + + /* PLLC_MISC: Set LOCK_ENABLE */ + writel(0x01000000, &clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_misc); + udelay(2); + + /* PLLD_MISC: Set CLKENABLE, CPCON 12, LFCON 1 */ + writel(0x40000C10, &clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_misc); + udelay(2); +} + +void arch_timer_init(void) +{ + struct sysctr_ctlr *sysctr = (struct sysctr_ctlr *)NV_PA_TSC_BASE; + u32 freq, val; + + freq = clock_get_rate(CLOCK_ID_OSC); + debug("%s: osc freq is %dHz [0x%08X]\n", __func__, freq, freq); + + /* ARM CNTFRQ */ + asm("mcr p15, 0, %0, c14, c0, 0\n" : : "r" (freq)); + + /* Only Tegra114+ has the System Counter regs */ + debug("%s: setting CNTFID0 to 0x%08X\n", __func__, freq); + writel(freq, &sysctr->cntfid0); + + val = readl(&sysctr->cntcr); + val |= TSC_CNTCR_ENABLE | TSC_CNTCR_HDBG; + writel(val, &sysctr->cntcr); + debug("%s: TSC CNTCR = 0x%08X\n", __func__, val); +} diff --git a/arch/arm/cpu/tegra124-common/funcmux.c b/arch/arm/cpu/tegra124-common/funcmux.c new file mode 100644 index 0000000..d19fda0 --- /dev/null +++ b/arch/arm/cpu/tegra124-common/funcmux.c @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2013 + * NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* Tegra124 high-level function multiplexing */ + +#include <common.h> +#include <asm/arch/clock.h> +#include <asm/arch/funcmux.h> +#include <asm/arch/pinmux.h> + +int funcmux_select(enum periph_id id, int config) +{ + int bad_config = config != FUNCMUX_DEFAULT; + + switch (id) { + case PERIPH_ID_UART4: + switch (config) { + case FUNCMUX_UART4_GPIO: /* TXD,RXD,CTS,RTS */ + pinmux_set_func(PINGRP_GPIO_PJ7, PMUX_FUNC_UARTD); + pinmux_set_func(PINGRP_GPIO_PB0, PMUX_FUNC_UARTD); + pinmux_set_func(PINGRP_GPIO_PB1, PMUX_FUNC_UARTD); + pinmux_set_func(PINGRP_GPIO_PK7, PMUX_FUNC_UARTD); + + pinmux_set_io(PINGRP_GPIO_PJ7, PMUX_PIN_OUTPUT); + pinmux_set_io(PINGRP_GPIO_PB0, PMUX_PIN_INPUT); + pinmux_set_io(PINGRP_GPIO_PB1, PMUX_PIN_INPUT); + pinmux_set_io(PINGRP_GPIO_PK7, PMUX_PIN_OUTPUT); + + pinmux_tristate_disable(PINGRP_GPIO_PJ7); + pinmux_tristate_disable(PINGRP_GPIO_PB0); + pinmux_tristate_disable(PINGRP_GPIO_PB1); + pinmux_tristate_disable(PINGRP_GPIO_PK7); + break; + } + break; + + case PERIPH_ID_UART1: + switch (config) { + case FUNCMUX_UART1_KBC: + pinmux_set_func(PINGRP_KB_ROW9, PMUX_FUNC_UARTA); + pinmux_set_func(PINGRP_KB_ROW10, PMUX_FUNC_UARTA); + + pinmux_set_io(PINGRP_KB_ROW9, PMUX_PIN_OUTPUT); + pinmux_set_io(PINGRP_KB_ROW10, PMUX_PIN_INPUT); + + pinmux_tristate_disable(PINGRP_KB_ROW9); + pinmux_tristate_disable(PINGRP_KB_ROW10); + break; + } + break; + + /* Add other periph IDs here as needed */ + + default: + debug("%s: invalid periph_id %d", __func__, id); + return -1; + } + + if (bad_config) { + debug("%s: invalid config %d for periph_id %d", __func__, + config, id); + return -1; + } + return 0; +} diff --git a/arch/arm/cpu/tegra124-common/pinmux.c b/arch/arm/cpu/tegra124-common/pinmux.c new file mode 100644 index 0000000..a4ab4ea --- /dev/null +++ b/arch/arm/cpu/tegra124-common/pinmux.c @@ -0,0 +1,730 @@ +/* + * (C) Copyright 2013 + * NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* Tegra124 pin multiplexing functions */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/tegra.h> +#include <asm/arch/pinmux.h> + +struct tegra_pingroup_desc { + const char *name; + enum pmux_func funcs[4]; + enum pmux_func func_safe; + enum pmux_vddio vddio; + enum pmux_pin_io io; +}; + +#define PMUX_MUXCTL_SHIFT 0 +#define PMUX_PULL_SHIFT 2 +#define PMUX_TRISTATE_SHIFT 4 +#define PMUX_TRISTATE_MASK (1 << PMUX_TRISTATE_SHIFT) +#define PMUX_IO_SHIFT 5 +#define PMUX_OD_SHIFT 6 +#define PMUX_LOCK_SHIFT 7 +#define PMUX_IO_RESET_SHIFT 8 +#define PMUX_RCV_SEL_SHIFT 9 + +#define PGRP_HSM_SHIFT 2 +#define PGRP_SCHMT_SHIFT 3 +#define PGRP_LPMD_SHIFT 4 +#define PGRP_LPMD_MASK (3 << PGRP_LPMD_SHIFT) +#define PGRP_DRVDN_SHIFT 12 +#define PGRP_DRVDN_MASK (0x7F << PGRP_DRVDN_SHIFT) +#define PGRP_DRVUP_SHIFT 20 +#define PGRP_DRVUP_MASK (0x7F << PGRP_DRVUP_SHIFT) +#define PGRP_SLWR_SHIFT 28 +#define PGRP_SLWR_MASK (3 << PGRP_SLWR_SHIFT) +#define PGRP_SLWF_SHIFT 30 +#define PGRP_SLWF_MASK (3 << PGRP_SLWF_SHIFT) + +/* Convenient macro for defining pin group properties */ +#define PIN(pg_name, vdd, f0, f1, f2, f3, iod) \ + { \ + .vddio = PMUX_VDDIO_ ## vdd, \ + .funcs = { \ + PMUX_FUNC_ ## f0, \ + PMUX_FUNC_ ## f1, \ + PMUX_FUNC_ ## f2, \ + PMUX_FUNC_ ## f3, \ + }, \ + .func_safe = PMUX_FUNC_RSVD1, \ + .io = PMUX_PIN_ ## iod, \ + } + +/* Input and output pins */ +#define PINI(pg_name, vdd, f0, f1, f2, f3) \ + PIN(pg_name, vdd, f0, f1, f2, f3, INPUT) +#define PINO(pg_name, vdd, f0, f1, f2, f3) \ + PIN(pg_name, vdd, f0, f1, f2, f3, OUTPUT) + +/* A pin group number which is not used */ +#define PIN_RESERVED \ + PIN(NONE, NONE, INVALID, INVALID, INVALID, INVALID, NONE) + +const struct tegra_pingroup_desc tegra_soc_pingroups[PINGRP_COUNT] = { + /* NAME VDD f0 f1 f2 f3 */ + PINI(ULPI_DATA0, BB, SPI3, HSI, UARTA, ULPI), + PINI(ULPI_DATA1, BB, SPI3, HSI, UARTA, ULPI), + PINI(ULPI_DATA2, BB, SPI3, HSI, UARTA, ULPI), + PINI(ULPI_DATA3, BB, SPI3, HSI, UARTA, ULPI), + PINI(ULPI_DATA4, BB, SPI2, HSI, UARTA, ULPI), + PINI(ULPI_DATA5, BB, SPI2, HSI, UARTA, ULPI), + PINI(ULPI_DATA6, BB, SPI2, HSI, UARTA, ULPI), + PINI(ULPI_DATA7, BB, SPI2, HSI, UARTA, ULPI), + PINI(ULPI_CLK, BB, SPI1, SPI5, UARTD, ULPI), + PINI(ULPI_DIR, BB, SPI1, SPI5, UARTD, ULPI), + PINI(ULPI_NXT, BB, SPI1, SPI5, UARTD, ULPI), + PINI(ULPI_STP, BB, SPI1, SPI5, UARTD, ULPI), + PINI(DAP3_FS, BB, I2S2, SPI5, DISPA, DISPB), + PINI(DAP3_DIN, BB, I2S2, SPI5, DISPA, DISPB), + PINI(DAP3_DOUT, BB, I2S2, SPI5, DISPA, DISPB), + PINI(DAP3_SCLK, BB, I2S2, SPI5, DISPA, DISPB), + PINI(GPIO_PV0, BB, USB, RSVD2, RSVD3, RSVD4), + PINI(GPIO_PV1, BB, RSVD1, RSVD2, RSVD3, RSVD4), + PINI(SDMMC1_CLK, SDMMC1, SDMMC1, CLK12, RSVD3, RSVD4), + PINI(SDMMC1_CMD, SDMMC1, SDMMC1, SPDIF, SPI4, UARTA), + PINI(SDMMC1_DAT3, SDMMC1, SDMMC1, SPDIF, SPI4, UARTA), + PINI(SDMMC1_DAT2, SDMMC1, SDMMC1, PWM0, SPI4, UARTA), + PINI(SDMMC1_DAT1, SDMMC1, SDMMC1, PWM1, SPI4, UARTA), + PINI(SDMMC1_DAT0, SDMMC1, SDMMC1, RSVD2, SPI4, UARTA), + PIN_RESERVED, /* Reserved: 0x3060 - 0x3064 */ + PIN_RESERVED, + PINI(CLK2_OUT, SDMMC1, EXTPERIPH2, RSVD2, RSVD3, RSVD4), + PINI(CLK2_REQ, SDMMC1, DAP, RSVD2, RSVD3, RSVD4), + PIN_RESERVED, /* Reserved: 0x3070 - 0x310c */ + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PINI(HDMI_INT, LCD, RSVD1, RSVD2, RSVD3, RSVD4), + PINI(DDC_SCL, LCD, I2C4, RSVD2, RSVD3, RSVD4), + PINI(DDC_SDA, LCD, I2C4, RSVD2, RSVD3, RSVD4), + PIN_RESERVED, /* Reserved: 0x311c - 0x3160 */ + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PINI(UART2_RXD, UART, UARTB, SPDIF, UARTA, SPI4), + PINI(UART2_TXD, UART, UARTB, SPDIF, UARTA, SPI4), + PINI(UART2_RTS_N, UART, UARTA, UARTB, RSVD3, SPI4), + PINI(UART2_CTS_N, UART, UARTA, UARTB, RSVD3, SPI4), + PINI(UART3_TXD, UART, UARTC, RSVD2, RSVD3, SPI4), + PINI(UART3_RXD, UART, UARTC, RSVD2, RSVD3, SPI4), + PINI(UART3_CTS_N, UART, UARTC, SDMMC1, DTV, SPI4), + PINI(UART3_RTS_N, UART, UARTC, PWM0, DTV, DISPA), + PINI(GPIO_PU0, UART, OWR, UARTA, RSVD3, RSVD4), + PINI(GPIO_PU1, UART, RSVD1, UARTA, RSVD3, RSVD4), + PINI(GPIO_PU2, UART, RSVD1, UARTA, RSVD3, RSVD4), + PINI(GPIO_PU3, UART, PWM0, UARTA, DISPA, DISPB), + PINI(GPIO_PU4, UART, PWM1, UARTA, DISPA, DISPB), + PINI(GPIO_PU5, UART, PWM2, UARTA, DISPA, DISPB), + PINI(GPIO_PU6, UART, PWM3, UARTA, USB, DISPB), + PINI(GEN1_I2C_SDA, UART, I2C1, RSVD2, RSVD3, RSVD4), + PINI(GEN1_I2C_SCL, UART, I2C1, RSVD2, RSVD3, RSVD4), + PINI(DAP4_FS, UART, I2S3, RSVD2, DTV, RSVD4), + PINI(DAP4_DIN, UART, I2S3, RSVD2, RSVD3, RSVD4), + PINI(DAP4_DOUT, UART, I2S3, RSVD2, DTV, RSVD4), + PINI(DAP4_SCLK, UART, I2S3, RSVD2, RSVD3, RSVD4), + PINI(CLK3_OUT, UART, EXTPERIPH3, RSVD2, RSVD3, RSVD4), + PINI(CLK3_REQ, UART, DEV3, RSVD2, RSVD3, RSVD4), + PINI(GMI_WP_N, GMI, RSVD1, NAND, GMI, GMI_ALT), + PINI(GMI_IORDY, GMI, SDMMC2, RSVD2, GMI, TRACE), + PINI(GMI_WAIT, GMI, SPI4, NAND, GMI, DTV), + PINI(GMI_ADV_N, GMI, RSVD1, NAND, GMI, TRACE), + PINI(GMI_CLK, GMI, SDMMC2, NAND, GMI, TRACE), + PINI(GMI_CS0_N, GMI, RSVD1, NAND, GMI, USB), + PINI(GMI_CS1_N, GMI, RSVD1, NAND, GMI, SOC), + PINI(GMI_CS2_N, GMI, SDMMC2, NAND, GMI, TRACE), + PINI(GMI_CS3_N, GMI, SDMMC2, NAND, GMI, GMI_ALT), + PINI(GMI_CS4_N, GMI, USB, NAND, GMI, TRACE), + PINI(GMI_CS6_N, GMI, NAND, NAND_ALT, GMI, SPI4), + PINI(GMI_CS7_N, GMI, NAND, NAND_ALT, GMI, SDMMC2), + PINI(GMI_AD0, GMI, RSVD1, NAND, GMI, RSVD4), + PINI(GMI_AD1, GMI, RSVD1, NAND, GMI, RSVD4), + PINI(GMI_AD2, GMI, RSVD1, NAND, GMI, RSVD4), + PINI(GMI_AD3, GMI, RSVD1, NAND, GMI, RSVD4), + PINI(GMI_AD4, GMI, RSVD1, NAND, GMI, RSVD4), + PINI(GMI_AD5, GMI, RSVD1, NAND, GMI, SPI4), + PINI(GMI_AD6, GMI, RSVD1, NAND, GMI, SPI4), + PINI(GMI_AD7, GMI, RSVD1, NAND, GMI, SPI4), + PINI(GMI_AD8, GMI, PWM0, NAND, GMI, DTV), + PINI(GMI_AD9, GMI, PWM1, NAND, GMI, CLDVFS), + PINI(GMI_AD10, GMI, PWM2, NAND, GMI, CLDVFS), + PINI(GMI_AD11, GMI, PWM3, NAND, GMI, USB), + PINI(GMI_AD12, GMI, SDMMC2, NAND, GMI, RSVD4), + PINI(GMI_AD13, GMI, SDMMC2, NAND, GMI, RSVD4), + PINI(GMI_AD14, GMI, SDMMC2, NAND, GMI, DTV), + PINI(GMI_AD15, GMI, SDMMC2, NAND, GMI, DTV), + PINI(GMI_A16, GMI, UARTD, TRACE, GMI, GMI_ALT), + PINI(GMI_A17, GMI, UARTD, RSVD2, GMI, TRACE), + PINI(GMI_A18, GMI, UARTD, RSVD2, GMI, TRACE), + PINI(GMI_A19, GMI, UARTD, SPI4, GMI, TRACE), + PINI(GMI_WR_N, GMI, RSVD1, NAND, GMI, SPI4), + PINI(GMI_OE_N, GMI, RSVD1, NAND, GMI, SOC), + PINI(GMI_DQS, GMI, SDMMC2, NAND, GMI, TRACE), + PINI(GMI_RST_N, GMI, NAND, NAND_ALT, GMI, RSVD4), + PINI(GEN2_I2C_SCL, GMI, I2C2, RSVD2, GMI, RSVD4), + PINI(GEN2_I2C_SDA, GMI, I2C2, RSVD2, GMI, RSVD4), + PINI(SDMMC4_CLK, SDMMC4, SDMMC4, RSVD2, GMI, RSVD4), + PINI(SDMMC4_CMD, SDMMC4, SDMMC4, RSVD2, GMI, RSVD4), + PINI(SDMMC4_DAT0, SDMMC4, SDMMC4, SPI3, GMI, RSVD4), + PINI(SDMMC4_DAT1, SDMMC4, SDMMC4, SPI3, GMI, RSVD4), + PINI(SDMMC4_DAT2, SDMMC4, SDMMC4, SPI3, GMI, RSVD4), + PINI(SDMMC4_DAT3, SDMMC4, SDMMC4, SPI3, GMI, RSVD4), + PINI(SDMMC4_DAT4, SDMMC4, SDMMC4, SPI3, GMI, RSVD4), + PINI(SDMMC4_DAT5, SDMMC4, SDMMC4, SPI3, GMI, RSVD4), + PINI(SDMMC4_DAT6, SDMMC4, SDMMC4, SPI3, GMI, RSVD4), + PINI(SDMMC4_DAT7, SDMMC4, SDMMC4, RSVD2, GMI, RSVD4), + PIN_RESERVED, /* Reserved: 0x3280 */ + PINI(CAM_MCLK, CAM, VI, VI_ALT1, VI_ALT3, RSVD4), + PINI(GPIO_PCC1, CAM, I2S4, RSVD2, RSVD3, RSVD4), + PINI(GPIO_PBB0, CAM, I2S4, VI, VI_ALT1, VI_ALT3), + PINI(CAM_I2C_SCL, CAM, VGP1, I2C3, RSVD3, RSVD4), + PINI(CAM_I2C_SDA, CAM, VGP2, I2C3, RSVD3, RSVD4), + PINI(GPIO_PBB3, CAM, VGP3, DISPA, DISPB, RSVD4), + PINI(GPIO_PBB4, CAM, VGP4, DISPA, DISPB, RSVD4), + PINI(GPIO_PBB5, CAM, VGP5, DISPA, DISPB, RSVD4), + PINI(GPIO_PBB6, CAM, VGP6, DISPA, DISPB, RSVD4), + PINI(GPIO_PBB7, CAM, I2S4, RSVD2, RSVD3, RSVD4), + PINI(GPIO_PCC2, CAM, I2S4, RSVD2, RSVD3, RSVD4), + PINI(JTAG_RTCK, SYS, RTCK, RSVD2, RSVD3, RSVD4), + PINI(PWR_I2C_SCL, SYS, I2CPWR, RSVD2, RSVD3, RSVD4), + PINI(PWR_I2C_SDA, SYS, I2CPWR, RSVD2, RSVD3, RSVD4), + PINI(KB_ROW0, SYS, KBC, RSVD2, DTV, RSVD4), + PINI(KB_ROW1, SYS, KBC, RSVD2, DTV, RSVD4), + PINI(KB_ROW2, SYS, KBC, RSVD2, DTV, SOC), + PINI(KB_ROW3, SYS, KBC, DISPA, RSVD3, DISPB), + PINI(KB_ROW4, SYS, KBC, DISPA, SPI2, DISPB), + PINI(KB_ROW5, SYS, KBC, DISPA, SPI2, DISPB), + PINI(KB_ROW6, SYS, KBC, DISPA, RSVD3, DISPB), + PINI(KB_ROW7, SYS, KBC, RSVD2, CLDVFS, UARTA), + PINI(KB_ROW8, SYS, KBC, RSVD2, RSVD3, UARTA), + PINI(KB_ROW9, SYS, KBC, RSVD2, RSVD3, UARTA), + PINI(KB_ROW10, SYS, KBC, RSVD2, RSVD3, UARTA), + PIN_RESERVED, /* Reserved: 0x32e8 - 0x32f8 */ + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PINI(KB_COL0, SYS, KBC, USB, SPI2, EMC_DLL), + PINI(KB_COL1, SYS, KBC, RSVD2, SPI2, EMC_DLL), + PINI(KB_COL2, SYS, KBC, RSVD2, SPI2, RSVD4), + PINI(KB_COL3, SYS, KBC, DISPA, PWM2, UARTA), + PINI(KB_COL4, SYS, KBC, OWR, SDMMC3, UARTA), + PINI(KB_COL5, SYS, KBC, RSVD2, SDMMC1, RSVD4), + PINI(KB_COL6, SYS, KBC, RSVD2, SPI2, RSVD4), + PINI(KB_COL7, SYS, KBC, RSVD2, SPI2, RSVD4), + PINI(CLK_32K_OUT, SYS, BLINK, SOC, RSVD3, RSVD4), + PINI(SYS_CLK_REQ, SYS, SYSCLK, RSVD2, RSVD3, RSVD4), + PINI(CORE_PWR_REQ, SYS, PWRON, RSVD2, RSVD3, RSVD4), + PINI(CPU_PWR_REQ, SYS, CPU, RSVD2, RSVD3, RSVD4), + PINI(PWR_INT_N, SYS, PMI, RSVD2, RSVD3, RSVD4), + PINI(CLK_32K_IN, SYS, CLK, RSVD2, RSVD3, RSVD4), + PINI(OWR, SYS, OWR, RSVD2, RSVD3, RSVD4), + PINI(DAP1_FS, AUDIO, I2S0, HDA, GMI, RSVD4), + PINI(DAP1_DIN, AUDIO, I2S0, HDA, GMI, RSVD4), + PINI(DAP1_DOUT, AUDIO, I2S0, HDA, GMI, RSVD4), + PINI(DAP1_SCLK, AUDIO, I2S0, HDA, GMI, RSVD4), + PINI(CLK1_REQ, AUDIO, DAP, DAP1, RSVD3, RSVD4), + PINI(CLK1_OUT, AUDIO, EXTPERIPH1, DAP2, RSVD3, RSVD4), + PINI(SPDIF_IN, AUDIO, SPDIF, USB, RSVD3, RSVD4), + PINI(SPDIF_OUT, AUDIO, SPDIF, RSVD2, RSVD3, RSVD4), + PINI(DAP2_FS, AUDIO, I2S1, HDA, RSVD3, RSVD4), + PINI(DAP2_DIN, AUDIO, I2S1, HDA, RSVD3, RSVD4), + PINI(DAP2_DOUT, AUDIO, I2S1, HDA, RSVD3, RSVD4), + PINI(DAP2_SCLK, AUDIO, I2S1, HDA, RSVD3, RSVD4), + PINI(DVFS_PWM, AUDIO, SPI6, CLDVFS, RSVD3, RSVD4), + PINI(GPIO_X1_AUD, AUDIO, SPI6, RSVD2, RSVD3, RSVD4), + PINI(GPIO_X3_AUD, AUDIO, SPI6, SPI1, RSVD3, RSVD4), + PINI(DVFS_CLK, AUDIO, SPI6, CLDVFS, RSVD3, RSVD4), + PINI(GPIO_X4_AUD, AUDIO, RSVD1, SPI1, SPI2, DAP2), + PINI(GPIO_X5_AUD, AUDIO, RSVD1, SPI1, SPI2, RSVD4), + PINI(GPIO_X6_AUD, AUDIO, SPI6, SPI1, SPI2, RSVD4), + PINI(GPIO_X7_AUD, AUDIO, RSVD1, SPI1, SPI2, RSVD4), + PIN_RESERVED, /* Reserved: 0x3388 - 0x338c */ + PIN_RESERVED, + PINI(SDMMC3_CLK, SDMMC3, SDMMC3, RSVD2, RSVD3, SPI3), + PINI(SDMMC3_CMD, SDMMC3, SDMMC3, PWM3, UARTA, SPI3), + PINI(SDMMC3_DAT0, SDMMC3, SDMMC3, RSVD2, RSVD3, SPI3), + PINI(SDMMC3_DAT1, SDMMC3, SDMMC3, PWM2, UARTA, SPI3), + PINI(SDMMC3_DAT2, SDMMC3, SDMMC3, PWM1, DISPA, SPI3), + PINI(SDMMC3_DAT3, SDMMC3, SDMMC3, PWM0, DISPB, SPI3), + PIN_RESERVED, /* Reserved: 0x33a8 - 0x33dc */ + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PINI(HDMI_CEC, SYS, CEC, SDMMC3, RSVD3, SOC), + PINI(SDMMC1_WP_N, SDMMC1, SDMMC1, CLK12, SPI4, UARTA), + PINI(SDMMC3_CD_N, SYS, SDMMC3, OWR, RSVD3, RSVD4), + PINI(GPIO_W2_AUD, AUDIO, SPI6, RSVD2, SPI2, I2C1), + PINI(GPIO_W3_AUD, AUDIO, SPI6, SPI1, SPI2, I2C1), + PINI(USB_VBUS_EN0, LCD, USB, RSVD2, RSVD3, RSVD4), + PINI(USB_VBUS_EN1, LCD, USB, RSVD2, RSVD3, RSVD4), + PINI(SDMMC3_CLK_LB_IN, SDMMC3, SDMMC3, RSVD2, RSVD3, RSVD4), + PINI(SDMMC3_CLK_LB_OUT, SDMMC3, SDMMC3, RSVD2, RSVD3, RSVD4), + PIN_RESERVED, /* Reserved: 0x3404 */ + PINO(RESET_OUT_N, SYS, RSVD1, RSVD2, RSVD3, RESET_OUT_N), +}; + +void pinmux_set_tristate(enum pmux_pingrp pin, int enable) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *tri = &pmt->pmt_ctl[pin]; + u32 reg; + + /* Error check on pin */ + assert(pmux_pingrp_isvalid(pin)); + + reg = readl(tri); + if (enable) + reg |= PMUX_TRISTATE_MASK; + else + reg &= ~PMUX_TRISTATE_MASK; + writel(reg, tri); +} + +void pinmux_tristate_enable(enum pmux_pingrp pin) +{ + pinmux_set_tristate(pin, 1); +} + +void pinmux_tristate_disable(enum pmux_pingrp pin) +{ + pinmux_set_tristate(pin, 0); +} + +void pinmux_set_pullupdown(enum pmux_pingrp pin, enum pmux_pull pupd) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pull = &pmt->pmt_ctl[pin]; + u32 reg; + + /* Error check on pin and pupd */ + assert(pmux_pingrp_isvalid(pin)); + assert(pmux_pin_pupd_isvalid(pupd)); + + reg = readl(pull); + reg &= ~(0x3 << PMUX_PULL_SHIFT); + reg |= (pupd << PMUX_PULL_SHIFT); + writel(reg, pull); +} + +void pinmux_set_func(enum pmux_pingrp pin, enum pmux_func func) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *muxctl = &pmt->pmt_ctl[pin]; + int i, mux = -1; + u32 reg; + + /* Error check on pin and func */ + assert(pmux_pingrp_isvalid(pin)); + assert(pmux_func_isvalid(func)); + + /* Handle special values */ + if (func == PMUX_FUNC_SAFE) + func = tegra_soc_pingroups[pin].func_safe; + + if (func & PMUX_FUNC_RSVD1) { + mux = func & 0x3; + } else { + /* Search for the appropriate function */ + for (i = 0; i < 4; i++) { + if (tegra_soc_pingroups[pin].funcs[i] == func) { + mux = i; + break; + } + } + } + assert(mux != -1); + + reg = readl(muxctl); + reg &= ~(0x3 << PMUX_MUXCTL_SHIFT); + reg |= (mux << PMUX_MUXCTL_SHIFT); + writel(reg, muxctl); +} + +void pinmux_set_io(enum pmux_pingrp pin, enum pmux_pin_io io) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pin_io = &pmt->pmt_ctl[pin]; + u32 reg; + + /* Error check on pin and io */ + assert(pmux_pingrp_isvalid(pin)); + assert(pmux_pin_io_isvalid(io)); + + reg = readl(pin_io); + reg &= ~(0x1 << PMUX_IO_SHIFT); + reg |= (io & 0x1) << PMUX_IO_SHIFT; + writel(reg, pin_io); +} + +static int pinmux_set_lock(enum pmux_pingrp pin, enum pmux_pin_lock lock) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pin_lock = &pmt->pmt_ctl[pin]; + u32 reg; + + /* Error check on pin and lock */ + assert(pmux_pingrp_isvalid(pin)); + assert(pmux_pin_lock_isvalid(lock)); + + if (lock == PMUX_PIN_LOCK_DEFAULT) + return 0; + + reg = readl(pin_lock); + reg &= ~(0x1 << PMUX_LOCK_SHIFT); + if (lock == PMUX_PIN_LOCK_ENABLE) { + reg |= (0x1 << PMUX_LOCK_SHIFT); + } else { + /* lock == DISABLE, which isn't possible */ + printf("%s: Warning: lock == %d, DISABLE is not allowed!\n", + __func__, lock); + } + writel(reg, pin_lock); + + return 0; +} + +static int pinmux_set_od(enum pmux_pingrp pin, enum pmux_pin_od od) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pin_od = &pmt->pmt_ctl[pin]; + u32 reg; + + /* Error check on pin and od */ + assert(pmux_pingrp_isvalid(pin)); + assert(pmux_pin_od_isvalid(od)); + + if (od == PMUX_PIN_OD_DEFAULT) + return 0; + + reg = readl(pin_od); + reg &= ~(0x1 << PMUX_OD_SHIFT); + if (od == PMUX_PIN_OD_ENABLE) + reg |= (0x1 << PMUX_OD_SHIFT); + writel(reg, pin_od); + + return 0; +} + +static int pinmux_set_ioreset(enum pmux_pingrp pin, + enum pmux_pin_ioreset ioreset) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pin_ioreset = &pmt->pmt_ctl[pin]; + u32 reg; + + /* Error check on pin and ioreset */ + assert(pmux_pingrp_isvalid(pin)); + assert(pmux_pin_ioreset_isvalid(ioreset)); + + if (ioreset == PMUX_PIN_IO_RESET_DEFAULT) + return 0; + + reg = readl(pin_ioreset); + reg &= ~(0x1 << PMUX_IO_RESET_SHIFT); + if (ioreset == PMUX_PIN_IO_RESET_ENABLE) + reg |= (0x1 << PMUX_IO_RESET_SHIFT); + writel(reg, pin_ioreset); + + return 0; +} + +static int pinmux_set_rcv_sel(enum pmux_pingrp pin, + enum pmux_pin_rcv_sel rcv_sel) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pin_rcv_sel = &pmt->pmt_ctl[pin]; + u32 reg; + + /* Error check on pin and rcv_sel */ + assert(pmux_pingrp_isvalid(pin)); + assert(pmux_pin_rcv_sel_isvalid(rcv_sel)); + + if (rcv_sel == PMUX_PIN_RCV_SEL_DEFAULT) + return 0; + + reg = readl(pin_rcv_sel); + reg &= ~(0x1 << PMUX_RCV_SEL_SHIFT); + if (rcv_sel == PMUX_PIN_RCV_SEL_HIGH) + reg |= (0x1 << PMUX_RCV_SEL_SHIFT); + writel(reg, pin_rcv_sel); + + return 0; +} + +void pinmux_config_pingroup(struct pingroup_config *config) +{ + enum pmux_pingrp pin = config->pingroup; + + pinmux_set_func(pin, config->func); + pinmux_set_pullupdown(pin, config->pull); + pinmux_set_tristate(pin, config->tristate); + pinmux_set_io(pin, config->io); + pinmux_set_lock(pin, config->lock); + pinmux_set_od(pin, config->od); + pinmux_set_ioreset(pin, config->ioreset); + pinmux_set_rcv_sel(pin, config->rcv_sel); +} + +void pinmux_config_table(struct pingroup_config *config, int len) +{ + int i; + + for (i = 0; i < len; i++) + pinmux_config_pingroup(&config[i]); +} + +static int padgrp_set_drvup_slwf(enum pdrive_pingrp pad, int slwf) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_slwf = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check on pad and slwf */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_slw_isvalid(slwf)); + + /* NONE means unspecified/do not change/use POR value */ + if (slwf == PGRP_SLWF_NONE) + return 0; + + reg = readl(pad_slwf); + reg &= ~PGRP_SLWF_MASK; + reg |= (slwf << PGRP_SLWF_SHIFT); + writel(reg, pad_slwf); + + return 0; +} + +static int padgrp_set_drvdn_slwr(enum pdrive_pingrp pad, int slwr) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_slwr = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check on pad and slwr */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_slw_isvalid(slwr)); + + /* NONE means unspecified/do not change/use POR value */ + if (slwr == PGRP_SLWR_NONE) + return 0; + + reg = readl(pad_slwr); + reg &= ~PGRP_SLWR_MASK; + reg |= (slwr << PGRP_SLWR_SHIFT); + writel(reg, pad_slwr); + + return 0; +} + +static int padgrp_set_drvup(enum pdrive_pingrp pad, int drvup) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_drvup = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check on pad and drvup */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_drv_isvalid(drvup)); + + /* NONE means unspecified/do not change/use POR value */ + if (drvup == PGRP_DRVUP_NONE) + return 0; + + reg = readl(pad_drvup); + reg &= ~PGRP_DRVUP_MASK; + reg |= (drvup << PGRP_DRVUP_SHIFT); + writel(reg, pad_drvup); + + return 0; +} + +static int padgrp_set_drvdn(enum pdrive_pingrp pad, int drvdn) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_drvdn = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check on pad and drvdn */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_drv_isvalid(drvdn)); + + /* NONE means unspecified/do not change/use POR value */ + if (drvdn == PGRP_DRVDN_NONE) + return 0; + + reg = readl(pad_drvdn); + reg &= ~PGRP_DRVDN_MASK; + reg |= (drvdn << PGRP_DRVDN_SHIFT); + writel(reg, pad_drvdn); + + return 0; +} + +static int padgrp_set_lpmd(enum pdrive_pingrp pad, enum pgrp_lpmd lpmd) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_lpmd = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check pad and lpmd value */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_lpmd_isvalid(lpmd)); + + /* NONE means unspecified/do not change/use POR value */ + if (lpmd == PGRP_LPMD_NONE) + return 0; + + reg = readl(pad_lpmd); + reg &= ~PGRP_LPMD_MASK; + reg |= (lpmd << PGRP_LPMD_SHIFT); + writel(reg, pad_lpmd); + + return 0; +} + +static int padgrp_set_schmt(enum pdrive_pingrp pad, enum pgrp_schmt schmt) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_schmt = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check pad */ + assert(pmux_padgrp_isvalid(pad)); + + /* NONE means unspecified/do not change/use POR value */ + if (schmt == PGRP_SCHMT_NONE) + return 0; + + reg = readl(pad_schmt); + reg &= ~(1 << PGRP_SCHMT_SHIFT); + if (schmt == PGRP_SCHMT_ENABLE) + reg |= (0x1 << PGRP_SCHMT_SHIFT); + writel(reg, pad_schmt); + + return 0; +} +static int padgrp_set_hsm(enum pdrive_pingrp pad, enum pgrp_hsm hsm) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_hsm = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check pad */ + assert(pmux_padgrp_isvalid(pad)); + + /* NONE means unspecified/do not change/use POR value */ + if (hsm == PGRP_HSM_NONE) + return 0; + + reg = readl(pad_hsm); + reg &= ~(1 << PGRP_HSM_SHIFT); + if (hsm == PGRP_HSM_ENABLE) + reg |= (0x1 << PGRP_HSM_SHIFT); + writel(reg, pad_hsm); + + return 0; +} + +void padctrl_config_pingroup(struct padctrl_config *config) +{ + enum pdrive_pingrp pad = config->padgrp; + + padgrp_set_drvup_slwf(pad, config->slwf); + padgrp_set_drvdn_slwr(pad, config->slwr); + padgrp_set_drvup(pad, config->drvup); + padgrp_set_drvdn(pad, config->drvdn); + padgrp_set_lpmd(pad, config->lpmd); + padgrp_set_schmt(pad, config->schmt); + padgrp_set_hsm(pad, config->hsm); +} + +void padgrp_config_table(struct padctrl_config *config, int len) +{ + int i; + + for (i = 0; i < len; i++) + padctrl_config_pingroup(&config[i]); +} diff --git a/arch/arm/cpu/tegra20-common/clock.c b/arch/arm/cpu/tegra20-common/clock.c index 34124f9..0c4f5fb 100644 --- a/arch/arm/cpu/tegra20-common/clock.c +++ b/arch/arm/cpu/tegra20-common/clock.c @@ -412,9 +412,9 @@ int get_periph_clock_source(enum periph_id periph_id, * with its 16-bit divisor */ if (type == CLOCK_TYPE_PCXTS) - *mux_bits = 4; + *mux_bits = MASK_BITS_31_28; else - *mux_bits = 2; + *mux_bits = MASK_BITS_31_30; if (type == CLOCK_TYPE_PCMT16) *divider_bits = 16; else diff --git a/arch/arm/cpu/tegra30-common/clock.c b/arch/arm/cpu/tegra30-common/clock.c index 74bd22b..80ba2d8 100644 --- a/arch/arm/cpu/tegra30-common/clock.c +++ b/arch/arm/cpu/tegra30-common/clock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -60,12 +60,6 @@ enum { CLOCK_MAX_MUX = 8 /* number of source options for each clock */ }; -enum { - MASK_BITS_31_30 = 2, /* num of bits used to specify clock source */ - MASK_BITS_31_29, - MASK_BITS_29_28, -}; - /* * Clock source mux for each clock type. This just converts our enum into * a list of mux sources for use by the code. @@ -108,7 +102,7 @@ static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX+1] = { MASK_BITS_31_29}, { CLK(PERIPH), CLK(CGENERAL), CLK(SFROM32KHZ), CLK(OSC), CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE), - MASK_BITS_29_28} + MASK_BITS_31_28} }; /* @@ -587,34 +581,7 @@ enum periph_id clk_id_to_periph_id(int clk_id) void clock_early_init(void) { - /* - * PLLP output frequency set to 408Mhz - * PLLC output frequency set to 228Mhz - */ - switch (clock_get_osc_freq()) { - case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */ - clock_set_rate(CLOCK_ID_PERIPH, 408, 12, 0, 8); - clock_set_rate(CLOCK_ID_CGENERAL, 456, 12, 1, 8); - break; - - case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */ - clock_set_rate(CLOCK_ID_PERIPH, 408, 26, 0, 8); - clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8); - break; - - case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */ - clock_set_rate(CLOCK_ID_PERIPH, 408, 13, 0, 8); - clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8); - break; - 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; - } + tegra30_set_up_pllp(); } void arch_timer_init(void) |