u-boot/board/ti/am335x/board.c
Steve Kipisz c5c7a7c32d am335x_evm: Add support to boot from NOR.
NOR requires that s_init be within the first 4KiB of the image so that
we can perform the rest of the required pinmuxing to talk with the rest
of NOR that we are found on.  When NOR_BOOT is set we save our
environment in NOR at 512KiB and a redundant copy at 768KiB.  We avoid
using SPL for this case and u-boot.bin is written directly to the start
of NOR.

We enclose the DMM-related parts of arch/arm/cpu/armv7/am33xx/emif4.c
with TI81xx checks as at this time U-Boot does not discard unused
sections in the main build and this code relies on functions specific to
(and only provided in) ti81xx-related code.

Cc: Albert ARIBAUD <albert.u.boot@aribaud.net>
Signed-off-by: Steve Kipisz <s-kipisz2@ti.com>
Signed-off-by: Tom Rini <trini@ti.com>
2013-07-30 09:21:41 -04:00

539 lines
15 KiB
C

/*
* board.c
*
* Board functions for TI AM335X based boards
*
* Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <errno.h>
#include <spl.h>
#include <asm/arch/cpu.h>
#include <asm/arch/hardware.h>
#include <asm/arch/omap.h>
#include <asm/arch/ddr_defs.h>
#include <asm/arch/clock.h>
#include <asm/arch/gpio.h>
#include <asm/arch/mmc_host_def.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/mem.h>
#include <asm/io.h>
#include <asm/emif.h>
#include <asm/gpio.h>
#include <i2c.h>
#include <miiphy.h>
#include <cpsw.h>
#include "board.h"
DECLARE_GLOBAL_DATA_PTR;
static struct wd_timer *wdtimer = (struct wd_timer *)WDT_BASE;
/* MII mode defines */
#define MII_MODE_ENABLE 0x0
#define RGMII_MODE_ENABLE 0x3A
/* GPIO that controls power to DDR on EVM-SK */
#define GPIO_DDR_VTT_EN 7
static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE;
/*
* Read header information from EEPROM into global structure.
*/
static int read_eeprom(struct am335x_baseboard_id *header)
{
/* Check if baseboard eeprom is available */
if (i2c_probe(CONFIG_SYS_I2C_EEPROM_ADDR)) {
puts("Could not probe the EEPROM; something fundamentally "
"wrong on the I2C bus.\n");
return -ENODEV;
}
/* read the eeprom using i2c */
if (i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, 0, 2, (uchar *)header,
sizeof(struct am335x_baseboard_id))) {
puts("Could not read the EEPROM; something fundamentally"
" wrong on the I2C bus.\n");
return -EIO;
}
if (header->magic != 0xEE3355AA) {
/*
* read the eeprom using i2c again,
* but use only a 1 byte address
*/
if (i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, 0, 1, (uchar *)header,
sizeof(struct am335x_baseboard_id))) {
puts("Could not read the EEPROM; something "
"fundamentally wrong on the I2C bus.\n");
return -EIO;
}
if (header->magic != 0xEE3355AA) {
printf("Incorrect magic number (0x%x) in EEPROM\n",
header->magic);
return -EINVAL;
}
}
return 0;
}
#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_NOR_BOOT)
static const struct ddr_data ddr2_data = {
.datardsratio0 = ((MT47H128M16RT25E_RD_DQS<<30) |
(MT47H128M16RT25E_RD_DQS<<20) |
(MT47H128M16RT25E_RD_DQS<<10) |
(MT47H128M16RT25E_RD_DQS<<0)),
.datawdsratio0 = ((MT47H128M16RT25E_WR_DQS<<30) |
(MT47H128M16RT25E_WR_DQS<<20) |
(MT47H128M16RT25E_WR_DQS<<10) |
(MT47H128M16RT25E_WR_DQS<<0)),
.datawiratio0 = ((MT47H128M16RT25E_PHY_WRLVL<<30) |
(MT47H128M16RT25E_PHY_WRLVL<<20) |
(MT47H128M16RT25E_PHY_WRLVL<<10) |
(MT47H128M16RT25E_PHY_WRLVL<<0)),
.datagiratio0 = ((MT47H128M16RT25E_PHY_GATELVL<<30) |
(MT47H128M16RT25E_PHY_GATELVL<<20) |
(MT47H128M16RT25E_PHY_GATELVL<<10) |
(MT47H128M16RT25E_PHY_GATELVL<<0)),
.datafwsratio0 = ((MT47H128M16RT25E_PHY_FIFO_WE<<30) |
(MT47H128M16RT25E_PHY_FIFO_WE<<20) |
(MT47H128M16RT25E_PHY_FIFO_WE<<10) |
(MT47H128M16RT25E_PHY_FIFO_WE<<0)),
.datawrsratio0 = ((MT47H128M16RT25E_PHY_WR_DATA<<30) |
(MT47H128M16RT25E_PHY_WR_DATA<<20) |
(MT47H128M16RT25E_PHY_WR_DATA<<10) |
(MT47H128M16RT25E_PHY_WR_DATA<<0)),
.datauserank0delay = MT47H128M16RT25E_PHY_RANK0_DELAY,
.datadldiff0 = PHY_DLL_LOCK_DIFF,
};
static const struct cmd_control ddr2_cmd_ctrl_data = {
.cmd0csratio = MT47H128M16RT25E_RATIO,
.cmd0dldiff = MT47H128M16RT25E_DLL_LOCK_DIFF,
.cmd0iclkout = MT47H128M16RT25E_INVERT_CLKOUT,
.cmd1csratio = MT47H128M16RT25E_RATIO,
.cmd1dldiff = MT47H128M16RT25E_DLL_LOCK_DIFF,
.cmd1iclkout = MT47H128M16RT25E_INVERT_CLKOUT,
.cmd2csratio = MT47H128M16RT25E_RATIO,
.cmd2dldiff = MT47H128M16RT25E_DLL_LOCK_DIFF,
.cmd2iclkout = MT47H128M16RT25E_INVERT_CLKOUT,
};
static const struct emif_regs ddr2_emif_reg_data = {
.sdram_config = MT47H128M16RT25E_EMIF_SDCFG,
.ref_ctrl = MT47H128M16RT25E_EMIF_SDREF,
.sdram_tim1 = MT47H128M16RT25E_EMIF_TIM1,
.sdram_tim2 = MT47H128M16RT25E_EMIF_TIM2,
.sdram_tim3 = MT47H128M16RT25E_EMIF_TIM3,
.emif_ddr_phy_ctlr_1 = MT47H128M16RT25E_EMIF_READ_LATENCY,
};
static const struct ddr_data ddr3_data = {
.datardsratio0 = MT41J128MJT125_RD_DQS,
.datawdsratio0 = MT41J128MJT125_WR_DQS,
.datafwsratio0 = MT41J128MJT125_PHY_FIFO_WE,
.datawrsratio0 = MT41J128MJT125_PHY_WR_DATA,
.datadldiff0 = PHY_DLL_LOCK_DIFF,
};
static const struct ddr_data ddr3_beagleblack_data = {
.datardsratio0 = MT41K256M16HA125E_RD_DQS,
.datawdsratio0 = MT41K256M16HA125E_WR_DQS,
.datafwsratio0 = MT41K256M16HA125E_PHY_FIFO_WE,
.datawrsratio0 = MT41K256M16HA125E_PHY_WR_DATA,
.datadldiff0 = PHY_DLL_LOCK_DIFF,
};
static const struct ddr_data ddr3_evm_data = {
.datardsratio0 = MT41J512M8RH125_RD_DQS,
.datawdsratio0 = MT41J512M8RH125_WR_DQS,
.datafwsratio0 = MT41J512M8RH125_PHY_FIFO_WE,
.datawrsratio0 = MT41J512M8RH125_PHY_WR_DATA,
.datadldiff0 = PHY_DLL_LOCK_DIFF,
};
static const struct cmd_control ddr3_cmd_ctrl_data = {
.cmd0csratio = MT41J128MJT125_RATIO,
.cmd0dldiff = MT41J128MJT125_DLL_LOCK_DIFF,
.cmd0iclkout = MT41J128MJT125_INVERT_CLKOUT,
.cmd1csratio = MT41J128MJT125_RATIO,
.cmd1dldiff = MT41J128MJT125_DLL_LOCK_DIFF,
.cmd1iclkout = MT41J128MJT125_INVERT_CLKOUT,
.cmd2csratio = MT41J128MJT125_RATIO,
.cmd2dldiff = MT41J128MJT125_DLL_LOCK_DIFF,
.cmd2iclkout = MT41J128MJT125_INVERT_CLKOUT,
};
static const struct cmd_control ddr3_beagleblack_cmd_ctrl_data = {
.cmd0csratio = MT41K256M16HA125E_RATIO,
.cmd0dldiff = MT41K256M16HA125E_DLL_LOCK_DIFF,
.cmd0iclkout = MT41K256M16HA125E_INVERT_CLKOUT,
.cmd1csratio = MT41K256M16HA125E_RATIO,
.cmd1dldiff = MT41K256M16HA125E_DLL_LOCK_DIFF,
.cmd1iclkout = MT41K256M16HA125E_INVERT_CLKOUT,
.cmd2csratio = MT41K256M16HA125E_RATIO,
.cmd2dldiff = MT41K256M16HA125E_DLL_LOCK_DIFF,
.cmd2iclkout = MT41K256M16HA125E_INVERT_CLKOUT,
};
static const struct cmd_control ddr3_evm_cmd_ctrl_data = {
.cmd0csratio = MT41J512M8RH125_RATIO,
.cmd0dldiff = MT41J512M8RH125_DLL_LOCK_DIFF,
.cmd0iclkout = MT41J512M8RH125_INVERT_CLKOUT,
.cmd1csratio = MT41J512M8RH125_RATIO,
.cmd1dldiff = MT41J512M8RH125_DLL_LOCK_DIFF,
.cmd1iclkout = MT41J512M8RH125_INVERT_CLKOUT,
.cmd2csratio = MT41J512M8RH125_RATIO,
.cmd2dldiff = MT41J512M8RH125_DLL_LOCK_DIFF,
.cmd2iclkout = MT41J512M8RH125_INVERT_CLKOUT,
};
static struct emif_regs ddr3_emif_reg_data = {
.sdram_config = MT41J128MJT125_EMIF_SDCFG,
.ref_ctrl = MT41J128MJT125_EMIF_SDREF,
.sdram_tim1 = MT41J128MJT125_EMIF_TIM1,
.sdram_tim2 = MT41J128MJT125_EMIF_TIM2,
.sdram_tim3 = MT41J128MJT125_EMIF_TIM3,
.zq_config = MT41J128MJT125_ZQ_CFG,
.emif_ddr_phy_ctlr_1 = MT41J128MJT125_EMIF_READ_LATENCY |
PHY_EN_DYN_PWRDN,
};
static struct emif_regs ddr3_beagleblack_emif_reg_data = {
.sdram_config = MT41K256M16HA125E_EMIF_SDCFG,
.ref_ctrl = MT41K256M16HA125E_EMIF_SDREF,
.sdram_tim1 = MT41K256M16HA125E_EMIF_TIM1,
.sdram_tim2 = MT41K256M16HA125E_EMIF_TIM2,
.sdram_tim3 = MT41K256M16HA125E_EMIF_TIM3,
.zq_config = MT41K256M16HA125E_ZQ_CFG,
.emif_ddr_phy_ctlr_1 = MT41K256M16HA125E_EMIF_READ_LATENCY,
};
static struct emif_regs ddr3_evm_emif_reg_data = {
.sdram_config = MT41J512M8RH125_EMIF_SDCFG,
.ref_ctrl = MT41J512M8RH125_EMIF_SDREF,
.sdram_tim1 = MT41J512M8RH125_EMIF_TIM1,
.sdram_tim2 = MT41J512M8RH125_EMIF_TIM2,
.sdram_tim3 = MT41J512M8RH125_EMIF_TIM3,
.zq_config = MT41J512M8RH125_ZQ_CFG,
.emif_ddr_phy_ctlr_1 = MT41J512M8RH125_EMIF_READ_LATENCY |
PHY_EN_DYN_PWRDN,
};
#ifdef CONFIG_SPL_OS_BOOT
int spl_start_uboot(void)
{
/* break into full u-boot on 'c' */
return (serial_tstc() && serial_getc() == 'c');
}
#endif
#endif
/*
* early system init of muxing and clocks.
*/
void s_init(void)
{
__maybe_unused struct am335x_baseboard_id header;
/*
* The ROM will only have set up sufficient pinmux to allow for the
* first 4KiB NOR to be read, we must finish doing what we know of
* the NOR mux in this space in order to continue.
*/
#ifdef CONFIG_NOR_BOOT
asm("stmfd sp!, {r2 - r4}");
asm("movw r4, #0x8A4");
asm("movw r3, #0x44E1");
asm("orr r4, r4, r3, lsl #16");
asm("mov r2, #9");
asm("mov r3, #8");
asm("gpmc_mux: str r2, [r4], #4");
asm("subs r3, r3, #1");
asm("bne gpmc_mux");
asm("ldmfd sp!, {r2 - r4}");
#endif
#ifdef CONFIG_SPL_BUILD
/*
* Save the boot parameters passed from romcode.
* We cannot delay the saving further than this,
* to prevent overwrites.
*/
save_omap_boot_params();
#endif
/* 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)
;
#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_NOR_BOOT)
/* Setup the PLLs and the clocks for the peripherals */
pll_init();
/* Enable RTC32K clock */
rtc32k_enable();
#ifdef CONFIG_SERIAL1
enable_uart0_pin_mux();
#endif /* CONFIG_SERIAL1 */
#ifdef CONFIG_SERIAL2
enable_uart1_pin_mux();
#endif /* CONFIG_SERIAL2 */
#ifdef CONFIG_SERIAL3
enable_uart2_pin_mux();
#endif /* CONFIG_SERIAL3 */
#ifdef CONFIG_SERIAL4
enable_uart3_pin_mux();
#endif /* CONFIG_SERIAL4 */
#ifdef CONFIG_SERIAL5
enable_uart4_pin_mux();
#endif /* CONFIG_SERIAL5 */
#ifdef CONFIG_SERIAL6
enable_uart5_pin_mux();
#endif /* CONFIG_SERIAL6 */
uart_soft_reset();
#if defined(CONFIG_NOR_BOOT)
/* We want our console now. */
gd->baudrate = CONFIG_BAUDRATE;
serial_init();
gd->have_console = 1;
#else
gd = &gdata;
preloader_console_init();
#endif
/* Initalize the board header */
enable_i2c0_pin_mux();
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
if (read_eeprom(&header) < 0)
puts("Could not get board ID.\n");
enable_board_pin_mux(&header);
if (board_is_evm_sk(&header)) {
/*
* EVM SK 1.2A and later use gpio0_7 to enable DDR3.
* This is safe enough to do on older revs.
*/
gpio_request(GPIO_DDR_VTT_EN, "ddr_vtt_en");
gpio_direction_output(GPIO_DDR_VTT_EN, 1);
}
if (board_is_evm_sk(&header))
config_ddr(303, MT41J128MJT125_IOCTRL_VALUE, &ddr3_data,
&ddr3_cmd_ctrl_data, &ddr3_emif_reg_data, 0);
else if (board_is_bone_lt(&header))
config_ddr(400, MT41K256M16HA125E_IOCTRL_VALUE,
&ddr3_beagleblack_data,
&ddr3_beagleblack_cmd_ctrl_data,
&ddr3_beagleblack_emif_reg_data, 0);
else if (board_is_evm_15_or_later(&header))
config_ddr(303, MT41J512M8RH125_IOCTRL_VALUE, &ddr3_evm_data,
&ddr3_evm_cmd_ctrl_data, &ddr3_evm_emif_reg_data, 0);
else
config_ddr(266, MT47H128M16RT25E_IOCTRL_VALUE, &ddr2_data,
&ddr2_cmd_ctrl_data, &ddr2_emif_reg_data, 0);
#endif
}
/*
* Basic board specific setup. Pinmux has been handled already.
*/
int board_init(void)
{
#ifdef CONFIG_NOR
const u32 gpmc_nor[GPMC_MAX_REG] = { STNOR_GPMC_CONFIG1,
STNOR_GPMC_CONFIG2, STNOR_GPMC_CONFIG3, STNOR_GPMC_CONFIG4,
STNOR_GPMC_CONFIG5, STNOR_GPMC_CONFIG6, STNOR_GPMC_CONFIG7 };
#endif
gd->bd->bi_boot_params = PHYS_DRAM_1 + 0x100;
gpmc_init();
#ifdef CONFIG_NOR
/* Reconfigure CS0 for NOR instead of NAND. */
enable_gpmc_cs_config(gpmc_nor, &gpmc_cfg->cs[0],
CONFIG_SYS_FLASH_BASE, GPMC_SIZE_16M);
#endif
return 0;
}
#ifdef CONFIG_BOARD_LATE_INIT
int board_late_init(void)
{
#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
char safe_string[HDR_NAME_LEN + 1];
struct am335x_baseboard_id header;
if (read_eeprom(&header) < 0)
puts("Could not get board ID.\n");
/* Now set variables based on the header. */
strncpy(safe_string, (char *)header.name, sizeof(header.name));
safe_string[sizeof(header.name)] = 0;
setenv("board_name", safe_string);
strncpy(safe_string, (char *)header.version, sizeof(header.version));
safe_string[sizeof(header.version)] = 0;
setenv("board_rev", safe_string);
#endif
return 0;
}
#endif
#if (defined(CONFIG_DRIVER_TI_CPSW) && !defined(CONFIG_SPL_BUILD)) || \
(defined(CONFIG_SPL_ETH_SUPPORT) && defined(CONFIG_SPL_BUILD))
static void cpsw_control(int enabled)
{
/* VTP can be added here */
return;
}
static struct cpsw_slave_data cpsw_slaves[] = {
{
.slave_reg_ofs = 0x208,
.sliver_reg_ofs = 0xd80,
.phy_id = 0,
},
{
.slave_reg_ofs = 0x308,
.sliver_reg_ofs = 0xdc0,
.phy_id = 1,
},
};
static struct cpsw_platform_data cpsw_data = {
.mdio_base = CPSW_MDIO_BASE,
.cpsw_base = CPSW_BASE,
.mdio_div = 0xff,
.channels = 8,
.cpdma_reg_ofs = 0x800,
.slaves = 1,
.slave_data = cpsw_slaves,
.ale_reg_ofs = 0xd00,
.ale_entries = 1024,
.host_port_reg_ofs = 0x108,
.hw_stats_reg_ofs = 0x900,
.bd_ram_ofs = 0x2000,
.mac_control = (1 << 5),
.control = cpsw_control,
.host_port_num = 0,
.version = CPSW_CTRL_VERSION_2,
};
#endif
#if defined(CONFIG_DRIVER_TI_CPSW) || \
(defined(CONFIG_USB_ETHER) && defined(CONFIG_MUSB_GADGET))
int board_eth_init(bd_t *bis)
{
int rv, n = 0;
uint8_t mac_addr[6];
uint32_t mac_hi, mac_lo;
__maybe_unused struct am335x_baseboard_id header;
/* try reading mac address from efuse */
mac_lo = readl(&cdev->macid0l);
mac_hi = readl(&cdev->macid0h);
mac_addr[0] = mac_hi & 0xFF;
mac_addr[1] = (mac_hi & 0xFF00) >> 8;
mac_addr[2] = (mac_hi & 0xFF0000) >> 16;
mac_addr[3] = (mac_hi & 0xFF000000) >> 24;
mac_addr[4] = mac_lo & 0xFF;
mac_addr[5] = (mac_lo & 0xFF00) >> 8;
#if (defined(CONFIG_DRIVER_TI_CPSW) && !defined(CONFIG_SPL_BUILD)) || \
(defined(CONFIG_SPL_ETH_SUPPORT) && defined(CONFIG_SPL_BUILD))
if (!getenv("ethaddr")) {
printf("<ethaddr> not set. Validating first E-fuse MAC\n");
if (is_valid_ether_addr(mac_addr))
eth_setenv_enetaddr("ethaddr", mac_addr);
}
#ifdef CONFIG_DRIVER_TI_CPSW
if (read_eeprom(&header) < 0)
puts("Could not get board ID.\n");
if (board_is_bone(&header) || board_is_bone_lt(&header) ||
board_is_idk(&header)) {
writel(MII_MODE_ENABLE, &cdev->miisel);
cpsw_slaves[0].phy_if = cpsw_slaves[1].phy_if =
PHY_INTERFACE_MODE_MII;
} else {
writel(RGMII_MODE_ENABLE, &cdev->miisel);
cpsw_slaves[0].phy_if = cpsw_slaves[1].phy_if =
PHY_INTERFACE_MODE_RGMII;
}
rv = cpsw_register(&cpsw_data);
if (rv < 0)
printf("Error %d registering CPSW switch\n", rv);
else
n += rv;
#endif
/*
*
* CPSW RGMII Internal Delay Mode is not supported in all PVT
* operating points. So we must set the TX clock delay feature
* in the AR8051 PHY. Since we only support a single ethernet
* device in U-Boot, we only do this for the first instance.
*/
#define AR8051_PHY_DEBUG_ADDR_REG 0x1d
#define AR8051_PHY_DEBUG_DATA_REG 0x1e
#define AR8051_DEBUG_RGMII_CLK_DLY_REG 0x5
#define AR8051_RGMII_TX_CLK_DLY 0x100
if (board_is_evm_sk(&header) || board_is_gp_evm(&header)) {
const char *devname;
devname = miiphy_get_current_dev();
miiphy_write(devname, 0x0, AR8051_PHY_DEBUG_ADDR_REG,
AR8051_DEBUG_RGMII_CLK_DLY_REG);
miiphy_write(devname, 0x0, AR8051_PHY_DEBUG_DATA_REG,
AR8051_RGMII_TX_CLK_DLY);
}
#endif
#if defined(CONFIG_USB_ETHER) && \
(!defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_USBETH_SUPPORT))
if (is_valid_ether_addr(mac_addr))
eth_setenv_enetaddr("usbnet_devaddr", mac_addr);
rv = usb_eth_initialize(bis);
if (rv < 0)
printf("Error %d registering USB_ETHER\n", rv);
else
n += rv;
#endif
return n;
}
#endif