diff options
author | Wolfgang Denk <wd@denx.de> | 2011-10-28 00:15:19 +0200 |
---|---|---|
committer | Wolfgang Denk <wd@denx.de> | 2011-10-28 00:15:19 +0200 |
commit | 87a5d601031652293ec4b729fdb7ee01bbd940a8 (patch) | |
tree | 91ede3ee45b228736c1876a700024782d7bc2032 /arch/arm/cpu/armv7 | |
parent | 606a76f8ef479e42ae4d06f8f3ce87e9a1c72acf (diff) | |
parent | 37fc0ed268dc5acacd3a83adafa26eb1a84e90af (diff) | |
download | u-boot-imx-87a5d601031652293ec4b729fdb7ee01bbd940a8.zip u-boot-imx-87a5d601031652293ec4b729fdb7ee01bbd940a8.tar.gz u-boot-imx-87a5d601031652293ec4b729fdb7ee01bbd940a8.tar.bz2 |
Merge branch 'master' of git://git.denx.de/u-boot-arm
* 'master' of git://git.denx.de/u-boot-arm:
ARM: Add Calxeda Highbank platform
dkb: make mmc command as default enabled
Marvell: dkb: add mmc support
ARM: pantheon: add mmc definition
davinci: remove config.mk file from the sources
ARM:AM33XX: Add support for TI AM335X EVM
ARM:AM33XX: Added timer support
ARM:AM33XX: Add emif/ddr support
ARM:AM33XX: Add clock definitions
ARM:AM33XX: Added support for AM33xx
omap3/emif4: fix registers definition
davinci: remove obsolete macro CONFIG_EMAC_MDIO_PHY_NUM
davinci: emac: add support for more than 1 PHYs
davinci: emac: add new features to autonegotiate for EMAC
da850evm: Move LPSC configuration to board_early_init_f()
omap4_panda: Build in cmd_gpio support on panda
omap: Don't use gpio_free to change direction to input
mmc: omap: Allow OMAP_HSMMC[23]_BASE to be unset
OMAP3: overo : Add environment variable optargs to bootargs
OMAP3: overo: Move ethernet CS4 configuration to execute based on board id
OMAP3: overo : Use ttyO2 instead of ttyS2.
da830: add support for NAND boot mode
dm36x: revert cache disable patch
dm644X: revert cache disable patch
devkit8000: Add malloc space
omap: spl: fix build break due to changes in FAT
OMAP3 SPL: Provide weak omap_rev_string
omap: beagle: Use ubifs instead of jffs2 for nand boot
omap: overo: Disable pull-ups on camera PCLK, HS and VS signals
omap: overo: Configure mux for gpio10
SPL: Add DMA library
omap3: Add interface for omap3 DMA
omap3: Add DMA register accessors
omap3: Add Base register for DMA
arm, davinci: add missing LSPC define for MMC/SD1
U-Boot/SPL: omap4: Make ddr pre-calculated timings as default.
DaVinci: correct MDSTAT.STATE mask
omap4: splitting padconfs into common, 4430 and 4460
omap4: adding revision detection for 4460 ES1.1
omap4: replacing OMAP4_CONTROL with OMAP4430_CONTROL
gplug: fixed build error as a result of code cleanup patch
kirkwood_spi: add dummy spi_init()
gpio: mvmfp: reduce include platform file
ARM: orion5x: reduce dependence of including platform file
serial: reduce include platform file for marvell chip
ARM: kirkwood: reduce dependence of including platform file
ARM: armada100: reduce dependence of including platform file
ARM: pantheon: reduce dependence of including platform file
Armada100: Add env storage support for Marvell gplugD
Armada100: Add SPI flash support for Marvell gplugD
Armada100: Add SPI support for Marvell gplugD
SPI: Add SPI driver support for Marvell Armada100
dreamplug: initial board support.
imx: fix coding style
misc: pmic: drop old Freescale's pmic driver
MX31: mx31pdk: use new pmic driver
MX31: mx31ads: use new pmic driver
MX31: mx31_litekit: use new pmic driver
MX5: mx53evk: use new pmic driver
MX5: mx51evk: use new pmic driver
MX35: mx35pdk: use new pmic driver
misc: pmic: addI2C support to pmic_fsl driver
misc: pmic: use I2C_SET_BUS in pmic I2C
MX5: efikamx/efikasb: use new pmic driver
MX3: qong: use new pmic driver
RTC: Switch mc13783 to generic pmic code
MX5: vision2: use new pmic driver
misc: pmic: Freescale PMIC switches to generic PMIC driver
misc:pmic:samsung Enable PMIC driver at GONI target
misc:pmic:max8998 MAX8998 support at a new PMIC driver.
misc:pmic:core New generic PMIC driver
mx31pdk: Remove unneeded config
mx31: provide readable WEIM CS accessor
MX51: vision2: Set global macros
I2C: Add i2c_get/set_speed() to mxc_i2c.c
ARM: Update mach-types
devkit8000: Add config to enable SPL MMC boot
devkit8000: protect board_mmc_init
arm, post: add missing post_time_ms for arm
cosmetic, post: Codingstyle cleanup
arm, logbuffer: make it compileclean
tegra2: Enable MMC for Seaboard
tegra2: Add more pinmux functions
tegra2: Rename PIN_ to PINGRP_
tegra2: Add more clock functions
tegra2: Clean up board code a little
tegra2: Rename CLOCK_PLL_ID to CLOCK_ID
Diffstat (limited to 'arch/arm/cpu/armv7')
-rw-r--r-- | arch/arm/cpu/armv7/am33xx/Makefile | 48 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/am33xx/board.c | 66 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/am33xx/clock.c | 273 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/am33xx/ddr.c | 147 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/am33xx/emif4.c | 201 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/am33xx/lowlevel_init.S | 72 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/am33xx/sys_info.c | 130 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/highbank/Makefile | 46 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/highbank/timer.c | 123 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/mx5/soc.c | 10 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap-common/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap-common/gpio.c | 7 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap-common/spl.c | 12 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap3/board.c | 6 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap4/board.c | 24 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/omap4/omap4_mux_data.h | 7 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/tegra2/ap20.c | 5 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/tegra2/clock.c | 825 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/tegra2/pinmux.c | 528 |
19 files changed, 2491 insertions, 41 deletions
diff --git a/arch/arm/cpu/armv7/am33xx/Makefile b/arch/arm/cpu/armv7/am33xx/Makefile new file mode 100644 index 0000000..6beafbb --- /dev/null +++ b/arch/arm/cpu/armv7/am33xx/Makefile @@ -0,0 +1,48 @@ +# +# Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed "as is" WITHOUT ANY WARRANTY of any +# kind, whether express or implied; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).o + +SOBJS := lowlevel_init.o + +COBJS += clock.o +COBJS += sys_info.o +COBJS += ddr.o +COBJS += emif4.o +COBJS += board.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(COBJS-y) $(SOBJS)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak .depend + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/armv7/am33xx/board.c b/arch/arm/cpu/armv7/am33xx/board.c new file mode 100644 index 0000000..2d6d359 --- /dev/null +++ b/arch/arm/cpu/armv7/am33xx/board.c @@ -0,0 +1,66 @@ +/* + * board.c + * + * Common board functions for AM33XX based boards + * + * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/hardware.h> +#include <asm/arch/ddr_defs.h> +#include <asm/arch/clock.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct wd_timer *wdtimer = (struct wd_timer *)WDT_BASE; +struct timer_reg *timerreg = (struct timer_reg *)DM_TIMER2_BASE; + +/* + * early system init of muxing and clocks. + */ +void s_init(u32 in_ddr) +{ + /* WDT1 is already running when the bootloader gets control + * Disable it to avoid "random" resets + */ + writel(0xAAAA, &wdtimer->wdtwspr); + while (readl(&wdtimer->wdtwwps) != 0x0) + ; + writel(0x5555, &wdtimer->wdtwspr); + while (readl(&wdtimer->wdtwwps) != 0x0) + ; + + /* Setup the PLLs and the clocks for the peripherals */ +#ifdef CONFIG_SETUP_PLL + pll_init(); +#endif + if (!in_ddr) + config_ddr(); +} + +/* Initialize timer */ +void init_timer(void) +{ + /* Reset the Timer */ + writel(0x2, (&timerreg->tsicrreg)); + + /* Wait until the reset is done */ + while (readl(&timerreg->tiocpcfgreg) & 1) + ; + + /* Start the Timer */ + writel(0x1, (&timerreg->tclrreg)); +} diff --git a/arch/arm/cpu/armv7/am33xx/clock.c b/arch/arm/cpu/armv7/am33xx/clock.c new file mode 100644 index 0000000..4ca6c45 --- /dev/null +++ b/arch/arm/cpu/armv7/am33xx/clock.c @@ -0,0 +1,273 @@ +/* + * clock.c + * + * clocks for AM33XX based boards + * + * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clock.h> +#include <asm/arch/hardware.h> +#include <asm/io.h> + +#define PRCM_MOD_EN 0x2 +#define PRCM_FORCE_WAKEUP 0x2 + +#define PRCM_EMIF_CLK_ACTIVITY BIT(2) +#define PRCM_L3_GCLK_ACTIVITY BIT(4) + +#define PLL_BYPASS_MODE 0x4 +#define ST_MN_BYPASS 0x00000100 +#define ST_DPLL_CLK 0x00000001 +#define CLK_SEL_MASK 0x7ffff +#define CLK_DIV_MASK 0x1f +#define CLK_DIV2_MASK 0x7f +#define CLK_SEL_SHIFT 0x8 +#define CLK_MODE_SEL 0x7 +#define CLK_MODE_MASK 0xfffffff8 +#define CLK_DIV_SEL 0xFFFFFFE0 + + +const struct cm_perpll *cmper = (struct cm_perpll *)CM_PER; +const struct cm_wkuppll *cmwkup = (struct cm_wkuppll *)CM_WKUP; +const struct cm_dpll *cmdpll = (struct cm_dpll *)CM_DPLL; + +static void enable_interface_clocks(void) +{ + /* Enable all the Interconnect Modules */ + writel(PRCM_MOD_EN, &cmper->l3clkctrl); + while (readl(&cmper->l3clkctrl) != PRCM_MOD_EN) + ; + + writel(PRCM_MOD_EN, &cmper->l4lsclkctrl); + while (readl(&cmper->l4lsclkctrl) != PRCM_MOD_EN) + ; + + writel(PRCM_MOD_EN, &cmper->l4fwclkctrl); + while (readl(&cmper->l4fwclkctrl) != PRCM_MOD_EN) + ; + + writel(PRCM_MOD_EN, &cmwkup->wkl4wkclkctrl); + while (readl(&cmwkup->wkl4wkclkctrl) != PRCM_MOD_EN) + ; + + writel(PRCM_MOD_EN, &cmper->l3instrclkctrl); + while (readl(&cmper->l3instrclkctrl) != PRCM_MOD_EN) + ; + + writel(PRCM_MOD_EN, &cmper->l4hsclkctrl); + while (readl(&cmper->l4hsclkctrl) != PRCM_MOD_EN) + ; +} + +/* + * Force power domain wake up transition + * Ensure that the corresponding interface clock is active before + * using the peripheral + */ +static void power_domain_wkup_transition(void) +{ + writel(PRCM_FORCE_WAKEUP, &cmper->l3clkstctrl); + writel(PRCM_FORCE_WAKEUP, &cmper->l4lsclkstctrl); + writel(PRCM_FORCE_WAKEUP, &cmwkup->wkclkstctrl); + writel(PRCM_FORCE_WAKEUP, &cmper->l4fwclkstctrl); + writel(PRCM_FORCE_WAKEUP, &cmper->l3sclkstctrl); +} + +/* + * Enable the peripheral clock for required peripherals + */ +static void enable_per_clocks(void) +{ + /* Enable the control module though RBL would have done it*/ + writel(PRCM_MOD_EN, &cmwkup->wkctrlclkctrl); + while (readl(&cmwkup->wkctrlclkctrl) != PRCM_MOD_EN) + ; + + /* Enable the module clock */ + writel(PRCM_MOD_EN, &cmper->timer2clkctrl); + while (readl(&cmper->timer2clkctrl) != PRCM_MOD_EN) + ; + + /* UART0 */ + writel(PRCM_MOD_EN, &cmwkup->wkup_uart0ctrl); + while (readl(&cmwkup->wkup_uart0ctrl) != PRCM_MOD_EN) + ; +} + +static void mpu_pll_config(void) +{ + u32 clkmode, clksel, div_m2; + + clkmode = readl(&cmwkup->clkmoddpllmpu); + clksel = readl(&cmwkup->clkseldpllmpu); + div_m2 = readl(&cmwkup->divm2dpllmpu); + + /* Set the PLL to bypass Mode */ + writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllmpu); + while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS) + ; + + clksel = clksel & (~CLK_SEL_MASK); + clksel = clksel | ((MPUPLL_M << CLK_SEL_SHIFT) | MPUPLL_N); + writel(clksel, &cmwkup->clkseldpllmpu); + + div_m2 = div_m2 & ~CLK_DIV_MASK; + div_m2 = div_m2 | MPUPLL_M2; + writel(div_m2, &cmwkup->divm2dpllmpu); + + clkmode = clkmode | CLK_MODE_SEL; + writel(clkmode, &cmwkup->clkmoddpllmpu); + + while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK) + ; +} + +static void core_pll_config(void) +{ + u32 clkmode, clksel, div_m4, div_m5, div_m6; + + clkmode = readl(&cmwkup->clkmoddpllcore); + clksel = readl(&cmwkup->clkseldpllcore); + div_m4 = readl(&cmwkup->divm4dpllcore); + div_m5 = readl(&cmwkup->divm5dpllcore); + div_m6 = readl(&cmwkup->divm6dpllcore); + + /* Set the PLL to bypass Mode */ + writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllcore); + + while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS) + ; + + clksel = clksel & (~CLK_SEL_MASK); + clksel = clksel | ((COREPLL_M << CLK_SEL_SHIFT) | COREPLL_N); + writel(clksel, &cmwkup->clkseldpllcore); + + div_m4 = div_m4 & ~CLK_DIV_MASK; + div_m4 = div_m4 | COREPLL_M4; + writel(div_m4, &cmwkup->divm4dpllcore); + + div_m5 = div_m5 & ~CLK_DIV_MASK; + div_m5 = div_m5 | COREPLL_M5; + writel(div_m5, &cmwkup->divm5dpllcore); + + div_m6 = div_m6 & ~CLK_DIV_MASK; + div_m6 = div_m6 | COREPLL_M6; + writel(div_m6, &cmwkup->divm6dpllcore); + + clkmode = clkmode | CLK_MODE_SEL; + writel(clkmode, &cmwkup->clkmoddpllcore); + + while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK) + ; +} + +static void per_pll_config(void) +{ + u32 clkmode, clksel, div_m2; + + clkmode = readl(&cmwkup->clkmoddpllper); + clksel = readl(&cmwkup->clkseldpllper); + div_m2 = readl(&cmwkup->divm2dpllper); + + /* Set the PLL to bypass Mode */ + writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllper); + + while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS) + ; + + clksel = clksel & (~CLK_SEL_MASK); + clksel = clksel | ((PERPLL_M << CLK_SEL_SHIFT) | PERPLL_N); + writel(clksel, &cmwkup->clkseldpllper); + + div_m2 = div_m2 & ~CLK_DIV2_MASK; + div_m2 = div_m2 | PERPLL_M2; + writel(div_m2, &cmwkup->divm2dpllper); + + clkmode = clkmode | CLK_MODE_SEL; + writel(clkmode, &cmwkup->clkmoddpllper); + + while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK) + ; +} + +static void ddr_pll_config(void) +{ + u32 clkmode, clksel, div_m2; + + clkmode = readl(&cmwkup->clkmoddpllddr); + clksel = readl(&cmwkup->clkseldpllddr); + div_m2 = readl(&cmwkup->divm2dpllddr); + + /* Set the PLL to bypass Mode */ + clkmode = (clkmode & CLK_MODE_MASK) | PLL_BYPASS_MODE; + writel(clkmode, &cmwkup->clkmoddpllddr); + + /* Wait till bypass mode is enabled */ + while ((readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS) + != ST_MN_BYPASS) + ; + + clksel = clksel & (~CLK_SEL_MASK); + clksel = clksel | ((DDRPLL_M << CLK_SEL_SHIFT) | DDRPLL_N); + writel(clksel, &cmwkup->clkseldpllddr); + + div_m2 = div_m2 & CLK_DIV_SEL; + div_m2 = div_m2 | DDRPLL_M2; + writel(div_m2, &cmwkup->divm2dpllddr); + + clkmode = (clkmode & CLK_MODE_MASK) | CLK_MODE_SEL; + writel(clkmode, &cmwkup->clkmoddpllddr); + + /* Wait till dpll is locked */ + while ((readl(&cmwkup->idlestdpllddr) & ST_DPLL_CLK) != ST_DPLL_CLK) + ; +} + +void enable_emif_clocks(void) +{ + /* Enable the EMIF_FW Functional clock */ + writel(PRCM_MOD_EN, &cmper->emiffwclkctrl); + /* Enable EMIF0 Clock */ + writel(PRCM_MOD_EN, &cmper->emifclkctrl); + /* Poll for emif_gclk & L3_G clock are active */ + while ((readl(&cmper->l3clkstctrl) & (PRCM_EMIF_CLK_ACTIVITY | + PRCM_L3_GCLK_ACTIVITY)) != (PRCM_EMIF_CLK_ACTIVITY | + PRCM_L3_GCLK_ACTIVITY)) + ; + /* Poll if module is functional */ + while ((readl(&cmper->emifclkctrl)) != PRCM_MOD_EN) + ; +} + +/* + * Configure the PLL/PRCM for necessary peripherals + */ +void pll_init() +{ + mpu_pll_config(); + core_pll_config(); + per_pll_config(); + ddr_pll_config(); + + /* Enable the required interconnect clocks */ + enable_interface_clocks(); + + /* Power domain wake up transition */ + power_domain_wkup_transition(); + + /* Enable the required peripherals */ + enable_per_clocks(); +} diff --git a/arch/arm/cpu/armv7/am33xx/ddr.c b/arch/arm/cpu/armv7/am33xx/ddr.c new file mode 100644 index 0000000..ed982c1 --- /dev/null +++ b/arch/arm/cpu/armv7/am33xx/ddr.c @@ -0,0 +1,147 @@ +/* + * DDR Configuration for AM33xx devices. + * + * Copyright (C) 2011 Texas Instruments Incorporated - +http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <asm/arch/cpu.h> +#include <asm/arch/ddr_defs.h> +#include <asm/io.h> + +/** + * Base address for EMIF instances + */ +static struct emif_regs *emif_reg = { + (struct emif_regs *)EMIF4_0_CFG_BASE}; + +/** + * Base address for DDR instance + */ +static struct ddr_regs *ddr_reg[2] = { + (struct ddr_regs *)DDR_PHY_BASE_ADDR, + (struct ddr_regs *)DDR_PHY_BASE_ADDR2}; + +/** + * Base address for ddr io control instances + */ +static struct ddr_cmdtctrl *ioctrl_reg = { + (struct ddr_cmdtctrl *)DDR_CONTROL_BASE_ADDR}; + +/** + * As a convention, all functions here return 0 on success + * -1 on failure. + */ + +/** + * Configure SDRAM + */ +int config_sdram(struct sdram_config *cfg) +{ + writel(cfg->sdrcr, &emif_reg->sdrcr); + writel(cfg->sdrcr2, &emif_reg->sdrcr2); + writel(cfg->refresh, &emif_reg->sdrrcr); + writel(cfg->refresh_sh, &emif_reg->sdrrcsr); + + return 0; +} + +/** + * Set SDRAM timings + */ +int set_sdram_timings(struct sdram_timing *t) +{ + writel(t->time1, &emif_reg->sdrtim1); + writel(t->time1_sh, &emif_reg->sdrtim1sr); + writel(t->time2, &emif_reg->sdrtim2); + writel(t->time2_sh, &emif_reg->sdrtim2sr); + writel(t->time3, &emif_reg->sdrtim3); + writel(t->time3_sh, &emif_reg->sdrtim3sr); + + return 0; +} + +/** + * Configure DDR PHY + */ +int config_ddr_phy(struct ddr_phy_control *p) +{ + writel(p->reg, &emif_reg->ddrphycr); + writel(p->reg_sh, &emif_reg->ddrphycsr); + + return 0; +} + +/** + * Configure DDR CMD control registers + */ +int config_cmd_ctrl(struct cmd_control *cmd) +{ + writel(cmd->cmd0csratio, &ddr_reg[0]->cm0csratio); + writel(cmd->cmd0csforce, &ddr_reg[0]->cm0csforce); + writel(cmd->cmd0csdelay, &ddr_reg[0]->cm0csdelay); + writel(cmd->cmd0dldiff, &ddr_reg[0]->cm0dldiff); + writel(cmd->cmd0iclkout, &ddr_reg[0]->cm0iclkout); + + writel(cmd->cmd1csratio, &ddr_reg[0]->cm1csratio); + writel(cmd->cmd1csforce, &ddr_reg[0]->cm1csforce); + writel(cmd->cmd1csdelay, &ddr_reg[0]->cm1csdelay); + writel(cmd->cmd1dldiff, &ddr_reg[0]->cm1dldiff); + writel(cmd->cmd1iclkout, &ddr_reg[0]->cm1iclkout); + + writel(cmd->cmd2csratio, &ddr_reg[0]->cm2csratio); + writel(cmd->cmd2csforce, &ddr_reg[0]->cm2csforce); + writel(cmd->cmd2csdelay, &ddr_reg[0]->cm2csdelay); + writel(cmd->cmd2dldiff, &ddr_reg[0]->cm2dldiff); + writel(cmd->cmd2iclkout, &ddr_reg[0]->cm2iclkout); + + return 0; +} + +/** + * Configure DDR DATA registers + */ +int config_ddr_data(int macrono, struct ddr_data *data) +{ + writel(data->datardsratio0, &ddr_reg[macrono]->dt0rdsratio0); + writel(data->datardsratio1, &ddr_reg[macrono]->dt0rdsratio1); + + writel(data->datawdsratio0, &ddr_reg[macrono]->dt0wdsratio0); + writel(data->datawdsratio1, &ddr_reg[macrono]->dt0wdsratio1); + + writel(data->datawiratio0, &ddr_reg[macrono]->dt0wiratio0); + writel(data->datawiratio1, &ddr_reg[macrono]->dt0wiratio1); + writel(data->datagiratio0, &ddr_reg[macrono]->dt0giratio0); + writel(data->datagiratio1, &ddr_reg[macrono]->dt0giratio1); + + writel(data->datafwsratio0, &ddr_reg[macrono]->dt0fwsratio0); + writel(data->datafwsratio1, &ddr_reg[macrono]->dt0fwsratio1); + + writel(data->datawrsratio0, &ddr_reg[macrono]->dt0wrsratio0); + writel(data->datawrsratio1, &ddr_reg[macrono]->dt0wrsratio1); + + writel(data->datadldiff0, &ddr_reg[macrono]->dt0dldiff0); + + return 0; +} + +int config_io_ctrl(struct ddr_ioctrl *ioctrl) +{ + writel(ioctrl->cmd1ctl, &ioctrl_reg->cm0ioctl); + writel(ioctrl->cmd2ctl, &ioctrl_reg->cm1ioctl); + writel(ioctrl->cmd3ctl, &ioctrl_reg->cm2ioctl); + writel(ioctrl->data1ctl, &ioctrl_reg->dt0ioctl); + writel(ioctrl->data2ctl, &ioctrl_reg->dt1ioctl); + + return 0; +} diff --git a/arch/arm/cpu/armv7/am33xx/emif4.c b/arch/arm/cpu/armv7/am33xx/emif4.c new file mode 100644 index 0000000..1318365 --- /dev/null +++ b/arch/arm/cpu/armv7/am33xx/emif4.c @@ -0,0 +1,201 @@ +/* + * emif4.c + * + * AM33XX emif4 configuration file + * + * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/ddr_defs.h> +#include <asm/arch/hardware.h> +#include <asm/arch/clock.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct ddr_regs *ddrregs = (struct ddr_regs *)DDR_PHY_BASE_ADDR; +struct vtp_reg *vtpreg = (struct vtp_reg *)VTP0_CTRL_ADDR; +struct ddr_ctrl *ddrctrl = (struct ddr_ctrl *)DDR_CTRL_ADDR; + + +int dram_init(void) +{ + /* dram_init must store complete ramsize in gd->ram_size */ + gd->ram_size = get_ram_size( + (void *)CONFIG_SYS_SDRAM_BASE, + CONFIG_MAX_RAM_BANK_SIZE); + return 0; +} + +void dram_init_banksize(void) +{ + gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; + gd->bd->bi_dram[0].size = gd->ram_size; +} + + +#ifdef CONFIG_AM335X_CONFIG_DDR +static void data_macro_config(int dataMacroNum) +{ + struct ddr_data data; + + data.datardsratio0 = ((DDR2_RD_DQS<<30)|(DDR2_RD_DQS<<20) + |(DDR2_RD_DQS<<10)|(DDR2_RD_DQS<<0)); + data.datardsratio1 = DDR2_RD_DQS>>2; + data.datawdsratio0 = ((DDR2_WR_DQS<<30)|(DDR2_WR_DQS<<20) + |(DDR2_WR_DQS<<10)|(DDR2_WR_DQS<<0)); + data.datawdsratio1 = DDR2_WR_DQS>>2; + data.datawiratio0 = ((DDR2_PHY_WRLVL<<30)|(DDR2_PHY_WRLVL<<20) + |(DDR2_PHY_WRLVL<<10)|(DDR2_PHY_WRLVL<<0)); + data.datawiratio1 = DDR2_PHY_WRLVL>>2; + data.datagiratio0 = ((DDR2_PHY_GATELVL<<30)|(DDR2_PHY_GATELVL<<20) + |(DDR2_PHY_GATELVL<<10)|(DDR2_PHY_GATELVL<<0)); + data.datagiratio1 = DDR2_PHY_GATELVL>>2; + data.datafwsratio0 = ((DDR2_PHY_FIFO_WE<<30)|(DDR2_PHY_FIFO_WE<<20) + |(DDR2_PHY_FIFO_WE<<10)|(DDR2_PHY_FIFO_WE<<0)); + data.datafwsratio1 = DDR2_PHY_FIFO_WE>>2; + data.datawrsratio0 = ((DDR2_PHY_WR_DATA<<30)|(DDR2_PHY_WR_DATA<<20) + |(DDR2_PHY_WR_DATA<<10)|(DDR2_PHY_WR_DATA<<0)); + data.datawrsratio1 = DDR2_PHY_WR_DATA>>2; + data.datadldiff0 = PHY_DLL_LOCK_DIFF; + + config_ddr_data(dataMacroNum, &data); +} + +static void cmd_macro_config(void) +{ + struct cmd_control cmd; + + cmd.cmd0csratio = DDR2_RATIO; + cmd.cmd0csforce = CMD_FORCE; + cmd.cmd0csdelay = CMD_DELAY; + cmd.cmd0dldiff = DDR2_DLL_LOCK_DIFF; + cmd.cmd0iclkout = DDR2_INVERT_CLKOUT; + + cmd.cmd1csratio = DDR2_RATIO; + cmd.cmd1csforce = CMD_FORCE; + cmd.cmd1csdelay = CMD_DELAY; + cmd.cmd1dldiff = DDR2_DLL_LOCK_DIFF; + cmd.cmd1iclkout = DDR2_INVERT_CLKOUT; + + cmd.cmd2csratio = DDR2_RATIO; + cmd.cmd2csforce = CMD_FORCE; + cmd.cmd2csdelay = CMD_DELAY; + cmd.cmd2dldiff = DDR2_DLL_LOCK_DIFF; + cmd.cmd2iclkout = DDR2_INVERT_CLKOUT; + + config_cmd_ctrl(&cmd); + +} + +static void config_vtp(void) +{ + writel(readl(&vtpreg->vtp0ctrlreg) | VTP_CTRL_ENABLE, + &vtpreg->vtp0ctrlreg); + writel(readl(&vtpreg->vtp0ctrlreg) & (~VTP_CTRL_START_EN), + &vtpreg->vtp0ctrlreg); + writel(readl(&vtpreg->vtp0ctrlreg) | VTP_CTRL_START_EN, + &vtpreg->vtp0ctrlreg); + + /* Poll for READY */ + while ((readl(&vtpreg->vtp0ctrlreg) & VTP_CTRL_READY) != + VTP_CTRL_READY) + ; +} + +static void config_emif_ddr2(void) +{ + int i; + int ret; + struct sdram_config cfg; + struct sdram_timing tmg; + struct ddr_phy_control phyc; + + /*Program EMIF0 CFG Registers*/ + phyc.reg = EMIF_READ_LATENCY; + phyc.reg_sh = EMIF_READ_LATENCY; + phyc.reg2 = EMIF_READ_LATENCY; + + tmg.time1 = EMIF_TIM1; + tmg.time1_sh = EMIF_TIM1; + tmg.time2 = EMIF_TIM2; + tmg.time2_sh = EMIF_TIM2; + tmg.time3 = EMIF_TIM3; + tmg.time3_sh = EMIF_TIM3; + + cfg.sdrcr = EMIF_SDCFG; + cfg.sdrcr2 = EMIF_SDCFG; + cfg.refresh = 0x00004650; + cfg.refresh_sh = 0x00004650; + + /* Program EMIF instance */ + ret = config_ddr_phy(&phyc); + if (ret < 0) + printf("Couldn't configure phyc\n"); + + ret = config_sdram(&cfg); + if (ret < 0) + printf("Couldn't configure SDRAM\n"); + + ret = set_sdram_timings(&tmg); + if (ret < 0) + printf("Couldn't configure timings\n"); + + /* Delay */ + for (i = 0; i < 5000; i++) + ; + + cfg.refresh = EMIF_SDREF; + cfg.refresh_sh = EMIF_SDREF; + cfg.sdrcr = EMIF_SDCFG; + cfg.sdrcr2 = EMIF_SDCFG; + + ret = config_sdram(&cfg); + if (ret < 0) + printf("Couldn't configure SDRAM\n"); +} + +void config_ddr(void) +{ + int data_macro_0 = 0; + int data_macro_1 = 1; + struct ddr_ioctrl ioctrl; + + enable_emif_clocks(); + + config_vtp(); + + cmd_macro_config(); + + data_macro_config(data_macro_0); + data_macro_config(data_macro_1); + + writel(PHY_RANK0_DELAY, &ddrregs->dt0rdelays0); + writel(PHY_RANK0_DELAY, &ddrregs->dt1rdelays0); + + ioctrl.cmd1ctl = DDR_IOCTRL_VALUE; + ioctrl.cmd2ctl = DDR_IOCTRL_VALUE; + ioctrl.cmd3ctl = DDR_IOCTRL_VALUE; + ioctrl.data1ctl = DDR_IOCTRL_VALUE; + ioctrl.data2ctl = DDR_IOCTRL_VALUE; + + config_io_ctrl(&ioctrl); + + writel(readl(&ddrctrl->ddrioctrl) & 0xefffffff, &ddrctrl->ddrioctrl); + writel(readl(&ddrctrl->ddrckectrl) | 0x00000001, &ddrctrl->ddrckectrl); + + config_emif_ddr2(); +} +#endif diff --git a/arch/arm/cpu/armv7/am33xx/lowlevel_init.S b/arch/arm/cpu/armv7/am33xx/lowlevel_init.S new file mode 100644 index 0000000..17c962f --- /dev/null +++ b/arch/arm/cpu/armv7/am33xx/lowlevel_init.S @@ -0,0 +1,72 @@ +/* + * lowlevel_init.S + * + * AM33XX low level initialization. + * + * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/ + * + * Initial Code by: + * Mansoor Ahamed <mansoor.ahamed@ti.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <config.h> +#include <asm/arch/hardware.h> + +_mark1: + .word mark1 +_lowlevel_init1: + .word lowlevel_init +_s_init_start: + .word s_init_start + +_TEXT_BASE: + .word CONFIG_SYS_TEXT_BASE /* sdram load addr from config.mk */ + +/***************************************************************************** + * lowlevel_init: - Platform low level init. + ****************************************************************************/ +.globl lowlevel_init +lowlevel_init: + + /* The link register is saved in ip by start.S */ + mov r6, ip + /* check if we are already running from RAM */ + ldr r2, _lowlevel_init1 + ldr r3, _TEXT_BASE + sub r4, r2, r3 + sub r0, pc, r4 + ldr sp, SRAM_STACK +mark1: + ldr r5, _mark1 + sub r5, r5, r2 /* bytes between mark1 and lowlevel_init */ + sub r0, r0, r5 /* r0 <- _start w.r.t current place of execution */ + mov r10, #0x0 /* r10 has in_ddr used by s_init() */ + + ands r0, r0, #0xC0000000 + /* MSB 2 bits <> 0 then we are in ocmc or DDR */ + cmp r0, #0x80000000 + bne s_init_start + mov r10, #0x01 + b s_init_start + +s_init_start: + mov r0, r10 /* passing in_ddr in r0 */ + bl s_init + /* back to arch calling code */ + mov pc, r6 + /* the literal pools origin */ + .ltorg + +SRAM_STACK: + /* Place stack at the top */ + .word LOW_LEVEL_SRAM_STACK diff --git a/arch/arm/cpu/armv7/am33xx/sys_info.c b/arch/arm/cpu/armv7/am33xx/sys_info.c new file mode 100644 index 0000000..507b618 --- /dev/null +++ b/arch/arm/cpu/armv7/am33xx/sys_info.c @@ -0,0 +1,130 @@ +/* + * sys_info.c + * + * System information functions + * + * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/ + * + * Derived from Beagle Board and 3430 SDP code by + * Richard Woodruff <r-woodruff2@ti.com> + * Syed Mohammed Khasim <khasim@ti.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/sys_proto.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clock.h> + +struct ctrl_stat *cstat = (struct ctrl_stat *)CTRL_BASE; + +/** + * get_cpu_rev(void) - extract rev info + */ +u32 get_cpu_rev(void) +{ + u32 id; + u32 rev; + + id = readl(DEVICE_ID); + rev = (id >> 28) & 0xff; + + return rev; +} + +/** + * get_cpu_type(void) - extract cpu info + */ +u32 get_cpu_type(void) +{ + u32 id = 0; + u32 partnum; + + id = readl(DEVICE_ID); + partnum = (id >> 12) & 0xffff; + + return partnum; +} + +/** + * get_board_rev() - setup to pass kernel board revision information + * returns:(bit[0-3] sub version, higher bit[7-4] is higher version) + */ +u32 get_board_rev(void) +{ + return BOARD_REV_ID; +} + +/** + * get_device_type(): tell if GP/HS/EMU/TST + */ +u32 get_device_type(void) +{ + int mode; + mode = readl(&cstat->statusreg) & (DEVICE_MASK); + return mode >>= 8; +} + +/** + * get_sysboot_value(void) - return SYS_BOOT[4:0] + */ +u32 get_sysboot_value(void) +{ + int mode; + mode = readl(&cstat->statusreg) & (SYSBOOT_MASK); + return mode; +} + +#ifdef CONFIG_DISPLAY_CPUINFO +/** + * Print CPU information + */ +int print_cpuinfo(void) +{ + char *cpu_s, *sec_s; + int arm_freq, ddr_freq; + + switch (get_cpu_type()) { + case AM335X: + cpu_s = "AM335X"; + break; + default: + cpu_s = "Unknown cpu type"; + break; + } + + switch (get_device_type()) { + case TST_DEVICE: + sec_s = "TST"; + break; + case EMU_DEVICE: + sec_s = "EMU"; + break; + case HS_DEVICE: + sec_s = "HS"; + break; + case GP_DEVICE: + sec_s = "GP"; + break; + default: + sec_s = "?"; + } + + printf("AM%s-%s rev %d\n", + cpu_s, sec_s, get_cpu_rev()); + + /* TODO: Print ARM and DDR frequencies */ + + return 0; +} +#endif /* CONFIG_DISPLAY_CPUINFO */ diff --git a/arch/arm/cpu/armv7/highbank/Makefile b/arch/arm/cpu/armv7/highbank/Makefile new file mode 100644 index 0000000..76faeb0 --- /dev/null +++ b/arch/arm/cpu/armv7/highbank/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).o + +COBJS := timer.o +SOBJS := + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/armv7/highbank/timer.c b/arch/arm/cpu/armv7/highbank/timer.c new file mode 100644 index 0000000..d8a0288 --- /dev/null +++ b/arch/arm/cpu/armv7/highbank/timer.c @@ -0,0 +1,123 @@ +/* + * Copyright 2010-2011 Calxeda, Inc. + * + * Based on arm926ejs/mx27/timer.c + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <common.h> +#include <div64.h> +#include <linux/types.h> /* for size_t */ +#include <linux/stddef.h> /* for NULL */ +#include <asm/io.h> +#include <asm/arch-armv7/systimer.h> + +#undef SYSTIMER_BASE +#define SYSTIMER_BASE 0xFFF34000 /* Timer 0 and 1 base */ +#define SYSTIMER_RATE 150000000 + +static ulong timestamp; +static ulong lastinc; +static struct systimer *systimer_base = (struct systimer *)SYSTIMER_BASE; + +/* + * Start the timer + */ +int timer_init(void) +{ + /* + * Setup timer0 + */ + writel(SYSTIMER_RELOAD, &systimer_base->timer0load); + writel(SYSTIMER_RELOAD, &systimer_base->timer0value); + writel(SYSTIMER_EN | SYSTIMER_32BIT, &systimer_base->timer0control); + + reset_timer_masked(); + + return 0; + +} + +#define TICK_PER_TIME ((SYSTIMER_RATE + CONFIG_SYS_HZ / 2) / CONFIG_SYS_HZ) +#define NS_PER_TICK (1000000000 / SYSTIMER_RATE) + +static inline unsigned long long tick_to_time(unsigned long long tick) +{ + do_div(tick, TICK_PER_TIME); + return tick; +} + +static inline unsigned long long time_to_tick(unsigned long long time) +{ + return time * TICK_PER_TIME; +} + +static inline unsigned long long us_to_tick(unsigned long long us) +{ + unsigned long long tick = us << 16; + tick += NS_PER_TICK - 1; + do_div(tick, NS_PER_TICK); + return tick >> 16; +} + +unsigned long long get_ticks(void) +{ + ulong now = ~readl(&systimer_base->timer0value); + + if (now >= lastinc) /* normal mode (non roll) */ + /* move stamp forward with absolut diff ticks */ + timestamp += (now - lastinc); + else /* we have rollover of incrementer */ + timestamp += (0xFFFFFFFF - lastinc) + now; + lastinc = now; + return timestamp; +} + +/* + * Delay x useconds AND preserve advance timstamp value + * assumes timer is ticking at 1 msec + */ +void __udelay(ulong usec) +{ + unsigned long long tmp; + ulong tmo; + + tmo = us_to_tick(usec); + tmp = get_ticks() + tmo; /* get current timestamp */ + + while (get_ticks() < tmp) /* loop till event */ + /*NOP*/; +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +void reset_timer_masked(void) +{ + lastinc = ~readl(&systimer_base->timer0value); + timestamp = 0; +} + +void reset_timer(void) +{ + reset_timer_masked(); +} + +ulong get_timer_masked(void) +{ + return tick_to_time(get_ticks()); +} diff --git a/arch/arm/cpu/armv7/mx5/soc.c b/arch/arm/cpu/armv7/mx5/soc.c index c6106d5..cf12ba8 100644 --- a/arch/arm/cpu/armv7/mx5/soc.c +++ b/arch/arm/cpu/armv7/mx5/soc.c @@ -26,6 +26,8 @@ #include <common.h> #include <asm/arch/imx-regs.h> #include <asm/arch/clock.h> +#include <asm/arch/sys_proto.h> + #include <asm/errno.h> #include <asm/io.h> @@ -117,14 +119,6 @@ int print_cpuinfo(void) } #endif -/* - * Initializes on-chip ethernet controllers. - * to override, implement board_eth_init() - */ -#if defined(CONFIG_FEC_MXC) -extern int fecmxc_initialize(bd_t *bis); -#endif - int cpu_eth_init(bd_t *bis) { int rc = -ENODEV; diff --git a/arch/arm/cpu/armv7/omap-common/Makefile b/arch/arm/cpu/armv7/omap-common/Makefile index 0b96b47..1dee81f 100644 --- a/arch/arm/cpu/armv7/omap-common/Makefile +++ b/arch/arm/cpu/armv7/omap-common/Makefile @@ -29,7 +29,9 @@ SOBJS := reset.o COBJS := timer.o COBJS += utils.o +ifdef CONFIG_OMAP COBJS += gpio.o +endif ifdef CONFIG_SPL_BUILD COBJS += spl.o diff --git a/arch/arm/cpu/armv7/omap-common/gpio.c b/arch/arm/cpu/armv7/omap-common/gpio.c index e62c6f4..75a02da 100644 --- a/arch/arm/cpu/armv7/omap-common/gpio.c +++ b/arch/arm/cpu/armv7/omap-common/gpio.c @@ -237,11 +237,4 @@ int gpio_request(int gpio, const char *label) */ void gpio_free(unsigned gpio) { - const struct gpio_bank *bank; - - if (check_gpio(gpio) < 0) - return; - bank = get_gpio_bank(gpio); - - _set_gpio_direction(bank, get_gpio_index(gpio), 1); } diff --git a/arch/arm/cpu/armv7/omap-common/spl.c b/arch/arm/cpu/armv7/omap-common/spl.c index 01fd58a..d37ca0f 100644 --- a/arch/arm/cpu/armv7/omap-common/spl.c +++ b/arch/arm/cpu/armv7/omap-common/spl.c @@ -34,6 +34,7 @@ #include <asm/arch/mmc_host_def.h> #include <i2c.h> #include <image.h> +#include <malloc.h> DECLARE_GLOBAL_DATA_PTR; @@ -105,6 +106,9 @@ void board_init_r(gd_t *id, ulong dummy) u32 boot_device; debug(">>spl:board_init_r()\n"); + mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START, + CONFIG_SYS_SPL_MALLOC_SIZE); + timer_init(); i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); @@ -160,3 +164,11 @@ void preloader_console_init(void) omap_rev_string(rev_string_buffer); printf("Texas Instruments %s\n", rev_string_buffer); } + +void __omap_rev_string(char *str) +{ + sprintf(str, "Revision detection unimplemented"); +} + +void omap_rev_string(char *str) + __attribute__((weak, alias("__omap_rev_string"))); diff --git a/arch/arm/cpu/armv7/omap3/board.c b/arch/arm/cpu/armv7/omap3/board.c index 1b3ef69..a9fdb4f 100644 --- a/arch/arm/cpu/armv7/omap3/board.c +++ b/arch/arm/cpu/armv7/omap3/board.c @@ -450,9 +450,3 @@ void enable_caches(void) dcache_enable(); } #endif - -void omap_rev_string(char *omap_rev_string) -{ - sprintf(omap_rev_string, "OMAP3, sorry revision detection" \ - " unimplemented"); -} diff --git a/arch/arm/cpu/armv7/omap4/board.c b/arch/arm/cpu/armv7/omap4/board.c index 8584fdd..2497e3e 100644 --- a/arch/arm/cpu/armv7/omap4/board.c +++ b/arch/arm/cpu/armv7/omap4/board.c @@ -152,9 +152,11 @@ static void set_muxconf_regs_essential(void) sizeof(wkup_padconf_array_essential) / sizeof(struct pad_conf_entry)); - /* gpio_wk7 is used for controlling TPS on 4460 */ if (omap_revision() >= OMAP4460_ES1_0) - writew(M3, CONTROL_WKUP_PAD1_FREF_CLK4_REQ); + do_set_mux(CONTROL_PADCONF_WKUP, + wkup_padconf_array_essential_4460, + sizeof(wkup_padconf_array_essential_4460) / + sizeof(struct pad_conf_entry)); } static void set_mux_conf_regs(void) @@ -200,13 +202,13 @@ static void init_omap4_revision(void) break; case MIDR_CORTEX_A9_R1P2: switch (readl(CONTROL_ID_CODE)) { - case OMAP4_CONTROL_ID_CODE_ES2_0: + case OMAP4430_CONTROL_ID_CODE_ES2_0: *omap4_revision = OMAP4430_ES2_0; break; - case OMAP4_CONTROL_ID_CODE_ES2_1: + case OMAP4430_CONTROL_ID_CODE_ES2_1: *omap4_revision = OMAP4430_ES2_1; break; - case OMAP4_CONTROL_ID_CODE_ES2_2: + case OMAP4430_CONTROL_ID_CODE_ES2_2: *omap4_revision = OMAP4430_ES2_2; break; default: @@ -218,7 +220,17 @@ static void init_omap4_revision(void) *omap4_revision = OMAP4430_ES2_3; break; case MIDR_CORTEX_A9_R2P10: - *omap4_revision = OMAP4460_ES1_0; + switch (readl(CONTROL_ID_CODE)) { + case OMAP4460_CONTROL_ID_CODE_ES1_0: + *omap4_revision = OMAP4460_ES1_0; + break; + case OMAP4460_CONTROL_ID_CODE_ES1_1: + *omap4_revision = OMAP4460_ES1_1; + break; + default: + *omap4_revision = OMAP4460_ES1_0; + break; + } break; default: *omap4_revision = OMAP4430_SILICON_ID_INVALID; diff --git a/arch/arm/cpu/armv7/omap4/omap4_mux_data.h b/arch/arm/cpu/armv7/omap4/omap4_mux_data.h index 00c52f8..b940391 100644 --- a/arch/arm/cpu/armv7/omap4/omap4_mux_data.h +++ b/arch/arm/cpu/armv7/omap4/omap4_mux_data.h @@ -73,4 +73,11 @@ const struct pad_conf_entry wkup_padconf_array_essential[] = { }; +const struct pad_conf_entry wkup_padconf_array_essential_4460[] = { + +{PAD1_FREF_CLK4_REQ, (M3)}, /* gpio_wk7, TPS */ + +}; + + #endif /* _OMAP4_MUX_DATA_H_ */ diff --git a/arch/arm/cpu/armv7/tegra2/ap20.c b/arch/arm/cpu/armv7/tegra2/ap20.c index dc5f984..5cb4b1b 100644 --- a/arch/arm/cpu/armv7/tegra2/ap20.c +++ b/arch/arm/cpu/armv7/tegra2/ap20.c @@ -36,7 +36,7 @@ u32 s_first_boot = 1; void init_pllx(void) { struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - struct clk_pll *pll = &clkrst->crc_pll[CLOCK_PLL_ID_XCPU]; + struct clk_pll *pll = &clkrst->crc_pll[CLOCK_ID_XCPU]; u32 reg; /* If PLLX is already enabled, just return */ @@ -189,7 +189,6 @@ static void reset_A9_cpu(int reset) static void clock_enable_coresight(int enable) { - struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; u32 rst, src; clock_set_enable(PERIPH_ID_CORESIGHT, enable); @@ -203,7 +202,7 @@ static void clock_enable_coresight(int enable) * (bits 7:0), so 00000001b == 1.5 (n+1 + .5) */ src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000); - writel(src, &clkrst->crc_clk_src_csite); + clock_ll_set_source_divisor(PERIPH_ID_CSI, 0, src); /* Unlock the CPU CoreSight interfaces */ rst = 0xC5ACCE55; diff --git a/arch/arm/cpu/armv7/tegra2/clock.c b/arch/arm/cpu/armv7/tegra2/clock.c index 0aaed7d..03ac1e3 100644 --- a/arch/arm/cpu/armv7/tegra2/clock.c +++ b/arch/arm/cpu/armv7/tegra2/clock.c @@ -27,6 +27,371 @@ #include <asm/arch/timer.h> #include <asm/arch/tegra2.h> #include <common.h> +#include <div64.h> + +/* + * This is our record of the current clock rate of each clock. We don't + * fill all of these in since we are only really interested in clocks which + * we use as parents. + */ +static unsigned pll_rate[CLOCK_ID_COUNT]; + +/* + * The oscillator frequency is fixed to one of four set values. Based on this + * the other clocks are set up appropriately. + */ +static unsigned osc_freq[CLOCK_OSC_FREQ_COUNT] = { + 13000000, + 19200000, + 12000000, + 26000000, +}; + +/* + * Clock types that we can use as a source. The Tegra2 has muxes for the + * peripheral clocks, and in most cases there are four options for the clock + * source. This gives us a clock 'type' and exploits what commonality exists + * in the device. + * + * Letters are obvious, except for T which means CLK_M, and S which means the + * clock derived from 32KHz. Beware that CLK_M (also called OSC in the + * datasheet) and PLL_M are different things. The former is the basic + * clock supplied to the SOC from an external oscillator. The latter is the + * memory clock PLL. + * + * See definitions in clock_id in the header file. + */ +enum clock_type_id { + CLOCK_TYPE_AXPT, /* PLL_A, PLL_X, PLL_P, CLK_M */ + CLOCK_TYPE_MCPA, /* and so on */ + CLOCK_TYPE_MCPT, + CLOCK_TYPE_PCM, + CLOCK_TYPE_PCMT, + CLOCK_TYPE_PCXTS, + CLOCK_TYPE_PDCT, + + CLOCK_TYPE_COUNT, + CLOCK_TYPE_NONE = -1, /* invalid clock type */ +}; + +/* return 1 if a peripheral ID is in range */ +#define clock_type_id_isvalid(id) ((id) >= 0 && \ + (id) < CLOCK_TYPE_COUNT) + +char pllp_valid = 1; /* PLLP is set up correctly */ + +enum { + CLOCK_MAX_MUX = 4 /* number of source options for each clock */ +}; + +/* + * Clock source mux for each clock type. This just converts our enum into + * a list of mux sources for use by the code. Note that CLOCK_TYPE_PCXTS + * is special as it has 5 sources. Since it also has a different number of + * bits in its register for the source, we just handle it with a special + * case in the code. + */ +#define CLK(x) CLOCK_ID_ ## x +static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX] = { + { CLK(AUDIO), CLK(XCPU), CLK(PERIPH), CLK(OSC) }, + { CLK(MEMORY), CLK(CGENERAL), CLK(PERIPH), CLK(AUDIO) }, + { CLK(MEMORY), CLK(CGENERAL), CLK(PERIPH), CLK(OSC) }, + { CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY), CLK(NONE) }, + { CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY), CLK(OSC) }, + { CLK(PERIPH), CLK(CGENERAL), CLK(XCPU), CLK(OSC) }, + { CLK(PERIPH), CLK(DISPLAY), CLK(CGENERAL), CLK(OSC) }, +}; + +/* + * Clock peripheral IDs which sadly don't match up with PERIPH_ID. This is + * not in the header file since it is for purely internal use - we want + * callers to use the PERIPH_ID for all access to peripheral clocks to avoid + * confusion bewteen PERIPH_ID_... and PERIPHC_... + * + * We don't call this CLOCK_PERIPH_ID or PERIPH_CLOCK_ID as it would just be + * confusing. + * + * Note to SOC vendors: perhaps define a unified numbering for peripherals and + * use it for reset, clock enable, clock source/divider and even pinmuxing + * if you can. + */ +enum periphc_internal_id { + /* 0x00 */ + PERIPHC_I2S1, + PERIPHC_I2S2, + PERIPHC_SPDIF_OUT, + PERIPHC_SPDIF_IN, + PERIPHC_PWM, + PERIPHC_SPI1, + PERIPHC_SPI2, + PERIPHC_SPI3, + + /* 0x08 */ + PERIPHC_XIO, + PERIPHC_I2C1, + PERIPHC_DVC_I2C, + PERIPHC_TWC, + PERIPHC_0c, + PERIPHC_10, /* PERIPHC_SPI1, what is this really? */ + PERIPHC_DISP1, + PERIPHC_DISP2, + + /* 0x10 */ + PERIPHC_CVE, + PERIPHC_IDE0, + PERIPHC_VI, + PERIPHC_1c, + PERIPHC_SDMMC1, + PERIPHC_SDMMC2, + PERIPHC_G3D, + PERIPHC_G2D, + + /* 0x18 */ + PERIPHC_NDFLASH, + PERIPHC_SDMMC4, + PERIPHC_VFIR, + PERIPHC_EPP, + PERIPHC_MPE, + PERIPHC_MIPI, + PERIPHC_UART1, + PERIPHC_UART2, + + /* 0x20 */ + PERIPHC_HOST1X, + PERIPHC_21, + PERIPHC_TVO, + PERIPHC_HDMI, + PERIPHC_24, + PERIPHC_TVDAC, + PERIPHC_I2C2, + PERIPHC_EMC, + + /* 0x28 */ + PERIPHC_UART3, + PERIPHC_29, + PERIPHC_VI_SENSOR, + PERIPHC_2b, + PERIPHC_2c, + PERIPHC_SPI4, + PERIPHC_I2C3, + PERIPHC_SDMMC3, + + /* 0x30 */ + PERIPHC_UART4, + PERIPHC_UART5, + PERIPHC_VDE, + PERIPHC_OWR, + PERIPHC_NOR, + PERIPHC_CSITE, + + PERIPHC_COUNT, + + PERIPHC_NONE = -1, +}; + +/* return 1 if a periphc_internal_id is in range */ +#define periphc_internal_id_isvalid(id) ((id) >= 0 && \ + (id) < PERIPHC_COUNT) + +/* + * Clock type for each peripheral clock source. We put the name in each + * record just so it is easy to match things up + */ +#define TYPE(name, type) type +static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { + /* 0x00 */ + TYPE(PERIPHC_I2S1, CLOCK_TYPE_AXPT), + TYPE(PERIPHC_I2S2, CLOCK_TYPE_AXPT), + TYPE(PERIPHC_SPDIF_OUT, CLOCK_TYPE_AXPT), + TYPE(PERIPHC_SPDIF_IN, CLOCK_TYPE_PCM), + TYPE(PERIPHC_PWM, CLOCK_TYPE_PCXTS), + TYPE(PERIPHC_SPI1, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_SPI22, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_SPI3, CLOCK_TYPE_PCMT), + + /* 0x08 */ + TYPE(PERIPHC_XIO, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_I2C1, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_DVC_I2C, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_TWC, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), + TYPE(PERIPHC_SPI1, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_DISP1, CLOCK_TYPE_PDCT), + TYPE(PERIPHC_DISP2, CLOCK_TYPE_PDCT), + + /* 0x10 */ + TYPE(PERIPHC_CVE, CLOCK_TYPE_PDCT), + TYPE(PERIPHC_IDE0, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_VI, CLOCK_TYPE_MCPA), + TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), + TYPE(PERIPHC_SDMMC1, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_SDMMC2, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_G3D, CLOCK_TYPE_MCPA), + TYPE(PERIPHC_G2D, CLOCK_TYPE_MCPA), + + /* 0x18 */ + TYPE(PERIPHC_NDFLASH, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_SDMMC4, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_VFIR, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_EPP, CLOCK_TYPE_MCPA), + TYPE(PERIPHC_MPE, CLOCK_TYPE_MCPA), + TYPE(PERIPHC_MIPI, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_UART1, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_UART2, CLOCK_TYPE_PCMT), + + /* 0x20 */ + TYPE(PERIPHC_HOST1X, CLOCK_TYPE_MCPA), + TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), + TYPE(PERIPHC_TVO, CLOCK_TYPE_PDCT), + TYPE(PERIPHC_HDMI, CLOCK_TYPE_PDCT), + TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), + TYPE(PERIPHC_TVDAC, CLOCK_TYPE_PDCT), + TYPE(PERIPHC_I2C2, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_EMC, CLOCK_TYPE_MCPT), + + /* 0x28 */ + TYPE(PERIPHC_UART3, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), + TYPE(PERIPHC_VI, CLOCK_TYPE_MCPA), + TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), + TYPE(PERIPHC_NONE, CLOCK_TYPE_NONE), + TYPE(PERIPHC_SPI4, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_I2C3, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_SDMMC3, CLOCK_TYPE_PCMT), + + /* 0x30 */ + TYPE(PERIPHC_UART4, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_UART5, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_VDE, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_OWR, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_NOR, CLOCK_TYPE_PCMT), + TYPE(PERIPHC_CSITE, CLOCK_TYPE_PCMT), +}; + +/* + * This array translates a periph_id to a periphc_internal_id + * + * Not present/matched up: + * uint vi_sensor; _VI_SENSOR_0, 0x1A8 + * SPDIF - which is both 0x08 and 0x0c + * + */ +#define NONE(name) (-1) +#define OFFSET(name, value) PERIPHC_ ## name +static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = { + /* Low word: 31:0 */ + NONE(CPU), + NONE(RESERVED1), + NONE(RESERVED2), + NONE(AC97), + NONE(RTC), + NONE(TMR), + PERIPHC_UART1, + PERIPHC_UART2, /* and vfir 0x68 */ + + /* 0x08 */ + NONE(GPIO), + PERIPHC_SDMMC2, + NONE(SPDIF), /* 0x08 and 0x0c, unclear which to use */ + PERIPHC_I2S1, + PERIPHC_I2C1, + PERIPHC_NDFLASH, + PERIPHC_SDMMC1, + PERIPHC_SDMMC4, + + /* 0x10 */ + PERIPHC_TWC, + PERIPHC_PWM, + PERIPHC_I2S2, + PERIPHC_EPP, + PERIPHC_VI, + PERIPHC_G2D, + NONE(USBD), + NONE(ISP), + + /* 0x18 */ + PERIPHC_G3D, + PERIPHC_IDE0, + PERIPHC_DISP2, + PERIPHC_DISP1, + PERIPHC_HOST1X, + NONE(VCP), + NONE(RESERVED30), + NONE(CACHE2), + + /* Middle word: 63:32 */ + NONE(MEM), + NONE(AHBDMA), + NONE(APBDMA), + NONE(RESERVED35), + NONE(KBC), + NONE(STAT_MON), + NONE(PMC), + NONE(FUSE), + + /* 0x28 */ + NONE(KFUSE), + NONE(SBC1), /* SBC1, 0x34, is this SPI1? */ + PERIPHC_NOR, + PERIPHC_SPI1, + PERIPHC_SPI2, + PERIPHC_XIO, + PERIPHC_SPI3, + PERIPHC_DVC_I2C, + + /* 0x30 */ + NONE(DSI), + PERIPHC_TVO, /* also CVE 0x40 */ + PERIPHC_MIPI, + PERIPHC_HDMI, + PERIPHC_CSITE, + PERIPHC_TVDAC, + PERIPHC_I2C2, + PERIPHC_UART3, + + /* 0x38 */ + NONE(RESERVED56), + PERIPHC_EMC, + NONE(USB2), + NONE(USB3), + PERIPHC_MPE, + PERIPHC_VDE, + NONE(BSEA), + NONE(BSEV), + + /* Upper word 95:64 */ + NONE(SPEEDO), + PERIPHC_UART4, + PERIPHC_UART5, + PERIPHC_I2C3, + PERIPHC_SPI4, + PERIPHC_SDMMC3, + NONE(PCIE), + PERIPHC_OWR, + + /* 0x48 */ + NONE(AFI), + NONE(CORESIGHT), + NONE(RESERVED74), + NONE(AVPUCQ), + NONE(RESERVED76), + NONE(RESERVED77), + NONE(RESERVED78), + NONE(RESERVED79), + + /* 0x50 */ + NONE(RESERVED80), + NONE(RESERVED81), + NONE(RESERVED82), + NONE(RESERVED83), + NONE(IRAMA), + NONE(IRAMB), + NONE(IRAMC), + NONE(IRAMD), + + /* 0x58 */ + NONE(CRAM2), +}; /* * Get the oscillator frequency, from the corresponding hardware configuration @@ -42,16 +407,21 @@ enum clock_osc_freq clock_get_osc_freq(void) return (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT; } -unsigned long clock_start_pll(enum clock_pll_id clkid, u32 divm, u32 divn, - u32 divp, u32 cpcon, u32 lfcon) +/* Returns a pointer to the registers of the given pll */ +static struct clk_pll *get_pll(enum clock_id clkid) { struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - u32 data; - struct clk_pll *pll; - assert(clock_pll_id_isvalid(clkid)); - pll = &clkrst->crc_pll[clkid]; + assert(clock_id_isvalid(clkid)); + return &clkrst->crc_pll[clkid]; +} + +unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn, + u32 divp, u32 cpcon, u32 lfcon) +{ + struct clk_pll *pll = get_pll(clkid); + u32 data; /* * We cheat by treating all PLL (except PLLU) in the same fashion. @@ -66,7 +436,7 @@ unsigned long clock_start_pll(enum clock_pll_id clkid, u32 divm, u32 divn, data = (divm << PLL_DIVM_SHIFT) | (divn << PLL_DIVN_SHIFT) | (0 << PLL_BYPASS_SHIFT) | (1 << PLL_ENABLE_SHIFT); - if (clkid == CLOCK_PLL_ID_USB) + if (clkid == CLOCK_ID_USB) data |= divp << PLLU_VCO_FREQ_SHIFT; else data |= divp << PLL_DIVP_SHIFT; @@ -76,6 +446,294 @@ unsigned long clock_start_pll(enum clock_pll_id clkid, u32 divm, u32 divn, return timer_get_us() + CLOCK_PLL_STABLE_DELAY_US; } +/* return 1 if a peripheral ID is in range and valid */ +static int clock_periph_id_isvalid(enum periph_id id) +{ + if (id < PERIPH_ID_FIRST || id >= PERIPH_ID_COUNT) + printf("Peripheral id %d out of range\n", id); + else { + switch (id) { + case PERIPH_ID_RESERVED1: + case PERIPH_ID_RESERVED2: + case PERIPH_ID_RESERVED30: + case PERIPH_ID_RESERVED35: + case PERIPH_ID_RESERVED56: + case PERIPH_ID_RESERVED74: + case PERIPH_ID_RESERVED76: + case PERIPH_ID_RESERVED77: + case PERIPH_ID_RESERVED78: + case PERIPH_ID_RESERVED79: + case PERIPH_ID_RESERVED80: + case PERIPH_ID_RESERVED81: + case PERIPH_ID_RESERVED82: + case PERIPH_ID_RESERVED83: + printf("Peripheral id %d is reserved\n", id); + break; + default: + return 1; + } + } + return 0; +} + +/* Returns a pointer to the clock source register for a peripheral */ +static u32 *get_periph_source_reg(enum periph_id periph_id) +{ + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + enum periphc_internal_id internal_id; + + assert(clock_periph_id_isvalid(periph_id)); + internal_id = periph_id_to_internal_id[periph_id]; + assert(internal_id != -1); + return &clkrst->crc_clk_src[internal_id]; +} + +void clock_ll_set_source_divisor(enum periph_id periph_id, unsigned source, + unsigned divisor) +{ + u32 *reg = get_periph_source_reg(periph_id); + u32 value; + + value = readl(reg); + + value &= ~OUT_CLK_SOURCE_MASK; + value |= source << OUT_CLK_SOURCE_SHIFT; + + value &= ~OUT_CLK_DIVISOR_MASK; + value |= divisor << OUT_CLK_DIVISOR_SHIFT; + + writel(value, reg); +} + +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); +} + +/** + * Given the parent's rate and the required rate for the children, this works + * out the peripheral clock divider to use, in 7.1 binary format. + * + * @param parent_rate clock rate of parent clock in Hz + * @param rate required clock rate for this clock + * @return divider which should be used + */ +static int clk_div7_1_get_divider(unsigned long parent_rate, + unsigned long rate) +{ + u64 divider = parent_rate * 2; + + divider += rate - 1; + do_div(divider, rate); + + if ((s64)divider - 2 < 0) + return 0; + + if ((s64)divider - 2 > 255) + return -1; + + return divider - 2; +} + +/** + * Given the parent's rate and the divider in 7.1 format, this works out the + * resulting peripheral clock rate. + * + * @param parent_rate clock rate of parent clock in Hz + * @param divider which should be used in 7.1 format + * @return effective clock rate of peripheral + */ +static unsigned long get_rate_from_divider(unsigned long parent_rate, + int divider) +{ + u64 rate; + + rate = (u64)parent_rate * 2; + do_div(rate, divider + 2); + return rate; +} + +unsigned long clock_get_periph_rate(enum periph_id periph_id, + enum clock_id parent) +{ + u32 *reg = get_periph_source_reg(periph_id); + + return get_rate_from_divider(pll_rate[parent], + (readl(reg) & OUT_CLK_DIVISOR_MASK) >> OUT_CLK_DIVISOR_SHIFT); +} + +/** + * Find the best available 7.1 format divisor given a parent clock rate and + * required child clock rate. This function assumes that a second-stage + * divisor is available which can divide by powers of 2 from 1 to 256. + * + * @param parent_rate clock rate of parent clock in Hz + * @param rate required clock rate for this clock + * @param extra_div value for the second-stage divisor (not set if this + * function returns -1. + * @return divider which should be used, or -1 if nothing is valid + * + */ +static int find_best_divider(unsigned long parent_rate, unsigned long rate, + int *extra_div) +{ + int shift; + int best_divider = -1; + int best_error = rate; + + /* try dividers from 1 to 256 and find closest match */ + for (shift = 0; shift <= 8 && best_error > 0; shift++) { + unsigned divided_parent = parent_rate >> shift; + int divider = clk_div7_1_get_divider(divided_parent, rate); + unsigned effective_rate = get_rate_from_divider(divided_parent, + divider); + int error = rate - effective_rate; + + /* Given a valid divider, look for the lowest error */ + if (divider != -1 && error < best_error) { + best_error = error; + *extra_div = 1 << shift; + best_divider = divider; + } + } + + /* return what we found - *extra_div will already be set */ + return best_divider; +} + +/** + * Given a peripheral ID and the required source clock, this returns which + * value should be programmed into the source mux for that peripheral. + * + * There is special code here to handle the one source type with 5 sources. + * + * @param periph_id peripheral to start + * @param source PLL id of required parent clock + * @param mux_bits Set to number of bits in mux register: 2 or 4 + * @return mux value (0-4, or -1 if not found) + */ +static int get_periph_clock_source(enum periph_id periph_id, + enum clock_id parent, int *mux_bits) +{ + enum clock_type_id type; + enum periphc_internal_id internal_id; + int mux; + + assert(clock_periph_id_isvalid(periph_id)); + + internal_id = periph_id_to_internal_id[periph_id]; + assert(periphc_internal_id_isvalid(internal_id)); + + type = clock_periph_type[internal_id]; + assert(clock_type_id_isvalid(type)); + + /* Special case here for the clock with a 4-bit source mux */ + if (type == CLOCK_TYPE_PCXTS) + *mux_bits = 4; + else + *mux_bits = 2; + + for (mux = 0; mux < CLOCK_MAX_MUX; mux++) + if (clock_source[type][mux] == parent) + return mux; + + /* + * Not found: it might be looking for the 'S' in CLOCK_TYPE_PCXTS + * which is not in our table. If not, then they are asking for a + * source which this peripheral can't access through its mux. + */ + assert(type == CLOCK_TYPE_PCXTS); + assert(parent == CLOCK_ID_SFROM32KHZ); + if (type == CLOCK_TYPE_PCXTS && parent == CLOCK_ID_SFROM32KHZ) + return 4; /* mux value for this clock */ + + /* if we get here, either us or the caller has made a mistake */ + printf("Caller requested bad clock: periph=%d, parent=%d\n", periph_id, + parent); + return -1; +} + +/** + * Adjust peripheral PLL to use the given divider and source. + * + * @param periph_id peripheral to adjust + * @param parent Required parent clock (for source mux) + * @param divider Required divider in 7.1 format + * @return 0 if ok, -1 on error (requesting a parent clock which is not valid + * for this peripheral) + */ +static int adjust_periph_pll(enum periph_id periph_id, + enum clock_id parent, unsigned divider) +{ + u32 *reg = get_periph_source_reg(periph_id); + unsigned source; + int mux_bits; + + clrsetbits_le32(reg, OUT_CLK_DIVISOR_MASK, + divider << OUT_CLK_DIVISOR_SHIFT); + udelay(1); + + /* work out the source clock and set it */ + source = get_periph_clock_source(periph_id, parent, &mux_bits); + if (source < 0) + return -1; + if (mux_bits == 4) { + 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); + } + udelay(2); + return 0; +} + +unsigned clock_adjust_periph_pll_div(enum periph_id periph_id, + enum clock_id parent, unsigned rate, int *extra_div) +{ + unsigned effective_rate; + int divider; + + if (extra_div) + divider = find_best_divider(pll_rate[parent], rate, extra_div); + else + divider = clk_div7_1_get_divider(pll_rate[parent], rate); + assert(divider >= 0); + if (adjust_periph_pll(periph_id, parent, divider)) + return -1U; + debug("periph %d, rate=%d, reg=%p = %x\n", periph_id, rate, + get_periph_source_reg(periph_id), + readl(get_periph_source_reg(periph_id))); + + /* Check what we ended up with. This shouldn't matter though */ + effective_rate = clock_get_periph_rate(periph_id, parent); + if (extra_div) + effective_rate /= *extra_div; + if (rate != effective_rate) + debug("Requested clock rate %u not honored (got %u)\n", + rate, effective_rate); + return effective_rate; +} + +unsigned clock_start_periph_pll(enum periph_id periph_id, + enum clock_id parent, unsigned rate) +{ + unsigned effective_rate; + + reset_set_enable(periph_id, 1); + clock_enable(periph_id); + + effective_rate = clock_adjust_periph_pll_div(periph_id, parent, rate, + NULL); + + reset_set_enable(periph_id, 0); + return effective_rate; +} + void clock_set_enable(enum periph_id periph_id, int enable) { struct clk_rst_ctlr *clkrst = @@ -148,3 +806,156 @@ void reset_cmplx_set_enable(int cpu, int which, int reset) else writel(mask, &clkrst->crc_cpu_cmplx_clr); } + +unsigned clock_get_rate(enum clock_id clkid) +{ + struct clk_pll *pll; + u32 base; + u32 divm; + u64 parent_rate; + u64 rate; + + parent_rate = osc_freq[clock_get_osc_freq()]; + if (clkid == CLOCK_ID_OSC) + return parent_rate; + + pll = get_pll(clkid); + base = readl(&pll->pll_base); + + /* Oh for bf_unpack()... */ + rate = parent_rate * ((base & PLL_DIVN_MASK) >> PLL_DIVN_SHIFT); + divm = (base & PLL_DIVM_MASK) >> PLL_DIVM_SHIFT; + if (clkid == CLOCK_ID_USB) + divm <<= (base & PLLU_VCO_FREQ_MASK) >> PLLU_VCO_FREQ_SHIFT; + else + divm <<= (base & PLL_DIVP_MASK) >> PLL_DIVP_SHIFT; + do_div(rate, divm); + return rate; +} + +/** + * Set the output frequency you want for each PLL clock. + * PLL output frequencies are programmed by setting their N, M and P values. + * The governing equations are: + * VCO = (Fi / m) * n, Fo = VCO / (2^p) + * where Fo is the output frequency from the PLL. + * Example: Set the output frequency to 216Mhz(Fo) with 12Mhz OSC(Fi) + * 216Mhz = ((12Mhz / m) * n) / (2^p) so n=432,m=12,p=1 + * Please see Tegra TRM section 5.3 to get the detail for PLL Programming + * + * @param n PLL feedback divider(DIVN) + * @param m PLL input divider(DIVN) + * @param p post divider(DIVP) + * @param cpcon base PLL charge pump(CPCON) + * @return 0 if ok, -1 on error (the requested PLL is incorrect and cannot + * be overriden), 1 if PLL is already correct + */ +static int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon) +{ + u32 base_reg; + u32 misc_reg; + struct clk_pll *pll; + + pll = get_pll(clkid); + + base_reg = readl(&pll->pll_base); + + /* Set BYPASS, m, n and p to PLL_BASE */ + base_reg &= ~PLL_DIVM_MASK; + base_reg |= m << PLL_DIVM_SHIFT; + + base_reg &= ~PLL_DIVN_MASK; + base_reg |= n << PLL_DIVN_SHIFT; + + base_reg &= ~PLL_DIVP_MASK; + base_reg |= p << PLL_DIVP_SHIFT; + + if (clkid == CLOCK_ID_PERIPH) { + /* + * If the PLL is already set up, check that it is correct + * and record this info for clock_verify() to check. + */ + if (base_reg & PLL_BASE_OVRRIDE_MASK) { + base_reg |= PLL_ENABLE_MASK; + if (base_reg != readl(&pll->pll_base)) + pllp_valid = 0; + return pllp_valid ? 1 : -1; + } + base_reg |= PLL_BASE_OVRRIDE_MASK; + } + + base_reg |= PLL_BYPASS_MASK; + writel(base_reg, &pll->pll_base); + + /* Set cpcon to PLL_MISC */ + misc_reg = readl(&pll->pll_misc); + misc_reg &= ~PLL_CPCON_MASK; + misc_reg |= cpcon << PLL_CPCON_SHIFT; + writel(misc_reg, &pll->pll_misc); + + /* Enable PLL */ + base_reg |= PLL_ENABLE_MASK; + writel(base_reg, &pll->pll_base); + + /* Disable BYPASS */ + base_reg &= ~PLL_BYPASS_MASK; + writel(base_reg, &pll->pll_base); + + return 0; +} + +int clock_verify(void) +{ + struct clk_pll *pll = get_pll(CLOCK_ID_PERIPH); + u32 reg = readl(&pll->pll_base); + + if (!pllp_valid) { + printf("Warning: PLLP %x is not correct\n", reg); + return -1; + } + debug("PLLX %x is correct\n", reg); + return 0; +} + +void clock_early_init(void) +{ + /* + * PLLP output frequency set to 216MHz + * PLLC output frequency set to 600Mhz + * + * TODO: Can we calculate these values instead of hard-coding? + */ + switch (clock_get_osc_freq()) { + case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */ + clock_set_rate(CLOCK_ID_PERIPH, 432, 12, 1, 8); + clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8); + break; + + case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */ + clock_set_rate(CLOCK_ID_PERIPH, 432, 26, 1, 8); + clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8); + break; + + case CLOCK_OSC_FREQ_13_0: + case CLOCK_OSC_FREQ_19_2: + default: + /* + * These are not supported. It is too early to print a + * message and the UART likely won't work anyway due to the + * oscillator being wrong. + */ + break; + } +} + +void clock_init(void) +{ + pll_rate[CLOCK_ID_MEMORY] = clock_get_rate(CLOCK_ID_MEMORY); + pll_rate[CLOCK_ID_PERIPH] = clock_get_rate(CLOCK_ID_PERIPH); + pll_rate[CLOCK_ID_CGENERAL] = clock_get_rate(CLOCK_ID_CGENERAL); + pll_rate[CLOCK_ID_OSC] = clock_get_rate(CLOCK_ID_OSC); + pll_rate[CLOCK_ID_SFROM32KHZ] = 32768; + debug("Osc = %d\n", pll_rate[CLOCK_ID_OSC]); + debug("PLLM = %d\n", pll_rate[CLOCK_ID_MEMORY]); + debug("PLLP = %d\n", pll_rate[CLOCK_ID_PERIPH]); +} diff --git a/arch/arm/cpu/armv7/tegra2/pinmux.c b/arch/arm/cpu/armv7/tegra2/pinmux.c index 5594ab8..b053f90 100644 --- a/arch/arm/cpu/armv7/tegra2/pinmux.c +++ b/arch/arm/cpu/armv7/tegra2/pinmux.c @@ -27,9 +27,463 @@ #include <common.h> -void pinmux_set_tristate(enum pmux_pin pin, int enable) +/* + * This defines the order of the pin mux control bits in the registers. For + * some reason there is no correspendence between the tristate, pin mux and + * pullup/pulldown registers. + */ +enum pmux_ctlid { + /* 0: APB_MISC_PP_PIN_MUX_CTL_A_0 */ + MUXCTL_UAA, + MUXCTL_UAB, + MUXCTL_UAC, + MUXCTL_UAD, + MUXCTL_UDA, + MUXCTL_RESERVED5, + MUXCTL_ATE, + MUXCTL_RM, + + MUXCTL_ATB, + MUXCTL_RESERVED9, + MUXCTL_ATD, + MUXCTL_ATC, + MUXCTL_ATA, + MUXCTL_KBCF, + MUXCTL_KBCE, + MUXCTL_SDMMC1, + + /* 16: APB_MISC_PP_PIN_MUX_CTL_B_0 */ + MUXCTL_GMA, + MUXCTL_GMC, + MUXCTL_HDINT, + MUXCTL_SLXA, + MUXCTL_OWC, + MUXCTL_SLXC, + MUXCTL_SLXD, + MUXCTL_SLXK, + + MUXCTL_UCA, + MUXCTL_UCB, + MUXCTL_DTA, + MUXCTL_DTB, + MUXCTL_RESERVED28, + MUXCTL_DTC, + MUXCTL_DTD, + MUXCTL_DTE, + + /* 32: APB_MISC_PP_PIN_MUX_CTL_C_0 */ + MUXCTL_DDC, + MUXCTL_CDEV1, + MUXCTL_CDEV2, + MUXCTL_CSUS, + MUXCTL_I2CP, + MUXCTL_KBCA, + MUXCTL_KBCB, + MUXCTL_KBCC, + + MUXCTL_IRTX, + MUXCTL_IRRX, + MUXCTL_DAP1, + MUXCTL_DAP2, + MUXCTL_DAP3, + MUXCTL_DAP4, + MUXCTL_GMB, + MUXCTL_GMD, + + /* 48: APB_MISC_PP_PIN_MUX_CTL_D_0 */ + MUXCTL_GME, + MUXCTL_GPV, + MUXCTL_GPU, + MUXCTL_SPDO, + MUXCTL_SPDI, + MUXCTL_SDB, + MUXCTL_SDC, + MUXCTL_SDD, + + MUXCTL_SPIH, + MUXCTL_SPIG, + MUXCTL_SPIF, + MUXCTL_SPIE, + MUXCTL_SPID, + MUXCTL_SPIC, + MUXCTL_SPIB, + MUXCTL_SPIA, + + /* 64: APB_MISC_PP_PIN_MUX_CTL_E_0 */ + MUXCTL_LPW0, + MUXCTL_LPW1, + MUXCTL_LPW2, + MUXCTL_LSDI, + MUXCTL_LSDA, + MUXCTL_LSPI, + MUXCTL_LCSN, + MUXCTL_LDC, + + MUXCTL_LSCK, + MUXCTL_LSC0, + MUXCTL_LSC1, + MUXCTL_LHS, + MUXCTL_LVS, + MUXCTL_LM0, + MUXCTL_LM1, + MUXCTL_LVP0, + + /* 80: APB_MISC_PP_PIN_MUX_CTL_F_0 */ + MUXCTL_LD0, + MUXCTL_LD1, + MUXCTL_LD2, + MUXCTL_LD3, + MUXCTL_LD4, + MUXCTL_LD5, + MUXCTL_LD6, + MUXCTL_LD7, + + MUXCTL_LD8, + MUXCTL_LD9, + MUXCTL_LD10, + MUXCTL_LD11, + MUXCTL_LD12, + MUXCTL_LD13, + MUXCTL_LD14, + MUXCTL_LD15, + + /* 96: APB_MISC_PP_PIN_MUX_CTL_G_0 */ + MUXCTL_LD16, + MUXCTL_LD17, + MUXCTL_LHP1, + MUXCTL_LHP2, + MUXCTL_LVP1, + MUXCTL_LHP0, + MUXCTL_RESERVED102, + MUXCTL_LPP, + + MUXCTL_LDI, + MUXCTL_PMC, + MUXCTL_CRTP, + MUXCTL_PTA, + MUXCTL_RESERVED108, + MUXCTL_KBCD, + MUXCTL_GPU7, + MUXCTL_DTF, + + MUXCTL_NONE = -1, +}; + +/* + * And this defines the order of the pullup/pulldown controls which are again + * in a different order + */ +enum pmux_pullid { + /* 0: APB_MISC_PP_PULLUPDOWN_REG_A_0 */ + PUCTL_ATA, + PUCTL_ATB, + PUCTL_ATC, + PUCTL_ATD, + PUCTL_ATE, + PUCTL_DAP1, + PUCTL_DAP2, + PUCTL_DAP3, + + PUCTL_DAP4, + PUCTL_DTA, + PUCTL_DTB, + PUCTL_DTC, + PUCTL_DTD, + PUCTL_DTE, + PUCTL_DTF, + PUCTL_GPV, + + /* 16: APB_MISC_PP_PULLUPDOWN_REG_B_0 */ + PUCTL_RM, + PUCTL_I2CP, + PUCTL_PTA, + PUCTL_GPU7, + PUCTL_KBCA, + PUCTL_KBCB, + PUCTL_KBCC, + PUCTL_KBCD, + + PUCTL_SPDI, + PUCTL_SPDO, + PUCTL_GPSLXAU, + PUCTL_CRTP, + PUCTL_SLXC, + PUCTL_SLXD, + PUCTL_SLXK, + + /* 32: APB_MISC_PP_PULLUPDOWN_REG_C_0 */ + PUCTL_CDEV1, + PUCTL_CDEV2, + PUCTL_SPIA, + PUCTL_SPIB, + PUCTL_SPIC, + PUCTL_SPID, + PUCTL_SPIE, + PUCTL_SPIF, + + PUCTL_SPIG, + PUCTL_SPIH, + PUCTL_IRTX, + PUCTL_IRRX, + PUCTL_GME, + PUCTL_RESERVED45, + PUCTL_XM2D, + PUCTL_XM2C, + + /* 48: APB_MISC_PP_PULLUPDOWN_REG_D_0 */ + PUCTL_UAA, + PUCTL_UAB, + PUCTL_UAC, + PUCTL_UAD, + PUCTL_UCA, + PUCTL_UCB, + PUCTL_LD17, + PUCTL_LD19_18, + + PUCTL_LD21_20, + PUCTL_LD23_22, + PUCTL_LS, + PUCTL_LC, + PUCTL_CSUS, + PUCTL_DDRC, + PUCTL_SDC, + PUCTL_SDD, + + /* 64: APB_MISC_PP_PULLUPDOWN_REG_E_0 */ + PUCTL_KBCF, + PUCTL_KBCE, + PUCTL_PMCA, + PUCTL_PMCB, + PUCTL_PMCC, + PUCTL_PMCD, + PUCTL_PMCE, + PUCTL_CK32, + + PUCTL_UDA, + PUCTL_SDMMC1, + PUCTL_GMA, + PUCTL_GMB, + PUCTL_GMC, + PUCTL_GMD, + PUCTL_DDC, + PUCTL_OWC, + + PUCTL_NONE = -1 +}; + +struct tegra_pingroup_desc { + const char *name; + enum pmux_func funcs[4]; + enum pmux_func func_safe; + enum pmux_vddio vddio; + enum pmux_ctlid ctl_id; + enum pmux_pullid pull_id; +}; + + +/* Converts a pmux_pingrp number to a tristate register: 0=A, 1=B, 2=C, 3=D */ +#define TRISTATE_REG(pmux_pingrp) ((pmux_pingrp) >> 5) + +/* Mask value for a tristate (within TRISTATE_REG(id)) */ +#define TRISTATE_MASK(pmux_pingrp) (1 << ((pmux_pingrp) & 0x1f)) + +/* Converts a PUCTL id to a pull register: 0=A, 1=B...4=E */ +#define PULL_REG(pmux_pullid) ((pmux_pullid) >> 4) + +/* Converts a PUCTL id to a shift position */ +#define PULL_SHIFT(pmux_pullid) ((pmux_pullid << 1) & 0x1f) + +/* Converts a MUXCTL id to a ctl register: 0=A, 1=B...6=G */ +#define MUXCTL_REG(pmux_ctlid) ((pmux_ctlid) >> 4) + +/* Converts a MUXCTL id to a shift position */ +#define MUXCTL_SHIFT(pmux_ctlid) ((pmux_ctlid << 1) & 0x1f) + +/* Convenient macro for defining pin group properties */ +#define PINALL(pg_name, vdd, f0, f1, f2, f3, f_safe, mux, pupd) \ + { \ + .vddio = PMUX_VDDIO_ ## vdd, \ + .funcs = { \ + PMUX_FUNC_ ## f0, \ + PMUX_FUNC_ ## f1, \ + PMUX_FUNC_ ## f2, \ + PMUX_FUNC_ ## f3, \ + }, \ + .func_safe = PMUX_FUNC_ ## f_safe, \ + .ctl_id = mux, \ + .pull_id = pupd \ + } + +/* A normal pin group where the mux name and pull-up name match */ +#define PIN(pg_name, vdd, f0, f1, f2, f3, f_safe) \ + PINALL(pg_name, vdd, f0, f1, f2, f3, f_safe, \ + MUXCTL_ ## pg_name, PUCTL_ ## pg_name) + +/* A pin group where the pull-up name doesn't have a 1-1 mapping */ +#define PINP(pg_name, vdd, f0, f1, f2, f3, f_safe, pupd) \ + PINALL(pg_name, vdd, f0, f1, f2, f3, f_safe, \ + MUXCTL_ ## pg_name, PUCTL_ ## pupd) + +/* A pin group number which is not used */ +#define PIN_RESERVED \ + PIN(NONE, NONE, NONE, NONE, NONE, NONE, NONE) + +const struct tegra_pingroup_desc tegra_soc_pingroups[PINGRP_COUNT] = { + PIN(ATA, NAND, IDE, NAND, GMI, RSVD, IDE), + PIN(ATB, NAND, IDE, NAND, GMI, SDIO4, IDE), + PIN(ATC, NAND, IDE, NAND, GMI, SDIO4, IDE), + PIN(ATD, NAND, IDE, NAND, GMI, SDIO4, IDE), + PIN(CDEV1, AUDIO, OSC, PLLA_OUT, PLLM_OUT1, AUDIO_SYNC, OSC), + PIN(CDEV2, AUDIO, OSC, AHB_CLK, APB_CLK, PLLP_OUT4, OSC), + PIN(CSUS, VI, PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK, + PLLC_OUT1), + PIN(DAP1, AUDIO, DAP1, RSVD, GMI, SDIO2, DAP1), + + PIN(DAP2, AUDIO, DAP2, TWC, RSVD, GMI, DAP2), + PIN(DAP3, BB, DAP3, RSVD, RSVD, RSVD, DAP3), + PIN(DAP4, UART, DAP4, RSVD, GMI, RSVD, DAP4), + PIN(DTA, VI, RSVD, SDIO2, VI, RSVD, RSVD4), + PIN(DTB, VI, RSVD, RSVD, VI, SPI1, RSVD1), + PIN(DTC, VI, RSVD, RSVD, VI, RSVD, RSVD1), + PIN(DTD, VI, RSVD, SDIO2, VI, RSVD, RSVD1), + PIN(DTE, VI, RSVD, RSVD, VI, SPI1, RSVD1), + + PINP(GPU, UART, PWM, UARTA, GMI, RSVD, RSVD4, + GPSLXAU), + PIN(GPV, SD, PCIE, RSVD, RSVD, RSVD, PCIE), + PIN(I2CP, SYS, I2C, RSVD, RSVD, RSVD, RSVD4), + PIN(IRTX, UART, UARTA, UARTB, GMI, SPI4, UARTB), + PIN(IRRX, UART, UARTA, UARTB, GMI, SPI4, UARTB), + PIN(KBCB, SYS, KBC, NAND, SDIO2, MIO, KBC), + PIN(KBCA, SYS, KBC, NAND, SDIO2, EMC_TEST0_DLL, KBC), + PINP(PMC, SYS, PWR_ON, PWR_INTR, RSVD, RSVD, PWR_ON, NONE), + + PIN(PTA, NAND, I2C2, HDMI, GMI, RSVD, RSVD4), + PIN(RM, UART, I2C, RSVD, RSVD, RSVD, RSVD4), + PIN(KBCE, SYS, KBC, NAND, OWR, RSVD, KBC), + PIN(KBCF, SYS, KBC, NAND, TRACE, MIO, KBC), + PIN(GMA, NAND, UARTE, SPI3, GMI, SDIO4, SPI3), + PIN(GMC, NAND, UARTD, SPI4, GMI, SFLASH, SPI4), + PIN(SDMMC1, BB, SDIO1, RSVD, UARTE, UARTA, RSVD2), + PIN(OWC, SYS, OWR, RSVD, RSVD, RSVD, OWR), + + PIN(GME, NAND, RSVD, DAP5, GMI, SDIO4, GMI), + PIN(SDC, SD, PWM, TWC, SDIO3, SPI3, TWC), + PIN(SDD, SD, UARTA, PWM, SDIO3, SPI3, PWM), + PIN_RESERVED, + PINP(SLXA, SD, PCIE, SPI4, SDIO3, SPI2, PCIE, CRTP), + PIN(SLXC, SD, SPDIF, SPI4, SDIO3, SPI2, SPI4), + PIN(SLXD, SD, SPDIF, SPI4, SDIO3, SPI2, SPI4), + PIN(SLXK, SD, PCIE, SPI4, SDIO3, SPI2, PCIE), + + PIN(SPDI, AUDIO, SPDIF, RSVD, I2C, SDIO2, RSVD2), + PIN(SPDO, AUDIO, SPDIF, RSVD, I2C, SDIO2, RSVD2), + PIN(SPIA, AUDIO, SPI1, SPI2, SPI3, GMI, GMI), + PIN(SPIB, AUDIO, SPI1, SPI2, SPI3, GMI, GMI), + PIN(SPIC, AUDIO, SPI1, SPI2, SPI3, GMI, GMI), + PIN(SPID, AUDIO, SPI2, SPI1, SPI2_ALT, GMI, GMI), + PIN(SPIE, AUDIO, SPI2, SPI1, SPI2_ALT, GMI, GMI), + PIN(SPIF, AUDIO, SPI3, SPI1, SPI2, RSVD, RSVD4), + + PIN(SPIG, AUDIO, SPI3, SPI2, SPI2_ALT, I2C, SPI2_ALT), + PIN(SPIH, AUDIO, SPI3, SPI2, SPI2_ALT, I2C, SPI2_ALT), + PIN(UAA, BB, SPI3, MIPI_HS, UARTA, ULPI, MIPI_HS), + PIN(UAB, BB, SPI2, MIPI_HS, UARTA, ULPI, MIPI_HS), + PIN(UAC, BB, OWR, RSVD, RSVD, RSVD, RSVD4), + PIN(UAD, UART, IRDA, SPDIF, UARTA, SPI4, SPDIF), + PIN(UCA, UART, UARTC, RSVD, GMI, RSVD, RSVD4), + PIN(UCB, UART, UARTC, PWM, GMI, RSVD, RSVD4), + + PIN_RESERVED, + PIN(ATE, NAND, IDE, NAND, GMI, RSVD, IDE), + PIN(KBCC, SYS, KBC, NAND, TRACE, EMC_TEST1_DLL, KBC), + PIN_RESERVED, + PIN_RESERVED, + PIN(GMB, NAND, IDE, NAND, GMI, GMI_INT, GMI), + PIN(GMD, NAND, RSVD, NAND, GMI, SFLASH, GMI), + PIN(DDC, LCD, I2C2, RSVD, RSVD, RSVD, RSVD4), + + /* 64 */ + PINP(LD0, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD1, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD2, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD3, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD4, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD5, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD6, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD7, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + + PINP(LD8, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD9, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD10, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD11, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD12, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD13, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD14, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD15, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + + PINP(LD16, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LD17), + PINP(LD17, LCD, DISPA, DISPB, RSVD, RSVD, RSVD4, LD17), + PINP(LHP0, LCD, DISPA, DISPB, RSVD, RSVD, RSVD4, LD21_20), + PINP(LHP1, LCD, DISPA, DISPB, RSVD, RSVD, RSVD4, LD19_18), + PINP(LHP2, LCD, DISPA, DISPB, RSVD, RSVD, RSVD4, LD19_18), + PINP(LVP0, LCD, DISPA, DISPB, RSVD, RSVD, RSVD4, LC), + PINP(LVP1, LCD, DISPA, DISPB, RSVD, RSVD, RSVD4, LD21_20), + PINP(HDINT, LCD, HDMI, RSVD, RSVD, RSVD, HDMI , LC), + + PINP(LM0, LCD, DISPA, DISPB, SPI3, RSVD, RSVD4, LC), + PINP(LM1, LCD, DISPA, DISPB, RSVD, CRT, RSVD3, LC), + PINP(LVS, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LC), + PINP(LSC0, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LC), + PINP(LSC1, LCD, DISPA, DISPB, SPI3, HDMI, DISPA, LS), + PINP(LSCK, LCD, DISPA, DISPB, SPI3, HDMI, DISPA, LS), + PINP(LDC, LCD, DISPA, DISPB, RSVD, RSVD, RSVD4, LS), + PINP(LCSN, LCD, DISPA, DISPB, SPI3, RSVD, RSVD4, LS), + + /* 96 */ + PINP(LSPI, LCD, DISPA, DISPB, XIO, HDMI, DISPA, LC), + PINP(LSDA, LCD, DISPA, DISPB, SPI3, HDMI, DISPA, LS), + PINP(LSDI, LCD, DISPA, DISPB, SPI3, RSVD, DISPA, LS), + PINP(LPW0, LCD, DISPA, DISPB, SPI3, HDMI, DISPA, LS), + PINP(LPW1, LCD, DISPA, DISPB, RSVD, RSVD, RSVD4, LS), + PINP(LPW2, LCD, DISPA, DISPB, SPI3, HDMI, DISPA, LS), + PINP(LDI, LCD, DISPA, DISPB, RSVD, RSVD, RSVD4, LD23_22), + PINP(LHS, LCD, DISPA, DISPB, XIO, RSVD, RSVD4, LC), + + PINP(LPP, LCD, DISPA, DISPB, RSVD, RSVD, RSVD4, LD23_22), + PIN_RESERVED, + PIN(KBCD, SYS, KBC, NAND, SDIO2, MIO, KBC), + PIN(GPU7, SYS, RTCK, RSVD, RSVD, RSVD, RTCK), + PIN(DTF, VI, I2C3, RSVD, VI, RSVD, RSVD4), + PIN(UDA, BB, SPI1, RSVD, UARTD, ULPI, RSVD2), + PIN(CRTP, LCD, CRT, RSVD, RSVD, RSVD, RSVD), + PINP(SDB, SD, UARTA, PWM, SDIO3, SPI2, PWM, NONE), + + /* these pin groups only have pullup and pull down control */ + PINALL(CK32, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, MUXCTL_NONE, + PUCTL_NONE), + PINALL(DDRC, DDR, RSVD, RSVD, RSVD, RSVD, RSVD, MUXCTL_NONE, + PUCTL_NONE), + PINALL(PMCA, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, MUXCTL_NONE, + PUCTL_NONE), + PINALL(PMCB, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, MUXCTL_NONE, + PUCTL_NONE), + PINALL(PMCC, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, MUXCTL_NONE, + PUCTL_NONE), + PINALL(PMCD, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, MUXCTL_NONE, + PUCTL_NONE), + PINALL(PMCE, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, MUXCTL_NONE, + PUCTL_NONE), + PINALL(XM2C, DDR, RSVD, RSVD, RSVD, RSVD, RSVD, MUXCTL_NONE, + PUCTL_NONE), + PINALL(XM2D, DDR, RSVD, RSVD, RSVD, RSVD, RSVD, MUXCTL_NONE, + PUCTL_NONE), +}; + +void pinmux_set_tristate(enum pmux_pingrp pin, int enable) { - struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; u32 *tri = &pmt->pmt_tri[TRISTATE_REG(pin)]; u32 reg; @@ -41,12 +495,78 @@ void pinmux_set_tristate(enum pmux_pin pin, int enable) writel(reg, tri); } -void pinmux_tristate_enable(enum pmux_pin pin) +void pinmux_tristate_enable(enum pmux_pingrp pin) { pinmux_set_tristate(pin, 1); } -void pinmux_tristate_disable(enum pmux_pin pin) +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; + enum pmux_pullid pull_id = tegra_soc_pingroups[pin].pull_id; + u32 *pull = &pmt->pmt_pull[PULL_REG(pull_id)]; + u32 mask_bit; + u32 reg; + mask_bit = PULL_SHIFT(pull_id); + + reg = readl(pull); + reg &= ~(0x3 << mask_bit); + reg |= pupd << mask_bit; + 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; + enum pmux_ctlid mux_id = tegra_soc_pingroups[pin].ctl_id; + u32 *muxctl = &pmt->pmt_ctl[MUXCTL_REG(mux_id)]; + u32 mask_bit; + int i, mux = -1; + u32 reg; + + assert(pmux_func_isvalid(func)); + + /* Handle special values */ + if (func >= PMUX_FUNC_RSVD1) { + mux = (func - PMUX_FUNC_RSVD1) & 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); + + mask_bit = MUXCTL_SHIFT(mux_id); + reg = readl(muxctl); + reg &= ~(0x3 << mask_bit); + reg |= mux << mask_bit; + writel(reg, muxctl); +} + +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); +} + +void pinmux_config_table(struct pingroup_config *config, int len) +{ + int i; + + for (i = 0; i < len; i++) + pinmux_config_pingroup(&config[i]); +} |