blob: ee014c24ff4b1b151f4059a54bbd454698819b89 [file] [log] [blame]
/*
* (C) Copyright 2010 Quantenna Communications Inc.
*
* 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 "ruby.h"
#include "malloc.h"
#include "ddr.h"
#include <shared_defs_common.h>
#include "ruby_board_cfg.h"
#include "ruby_board_db.h"
#include "board_cfg.h"
#include "pcie.h"
#include "ruby_spi_api.h"
#include "spi_api.h"
extern int board_hw_config_read(void);
extern int mdc_clk_divisor;
#ifndef TOPAZ_EP_MINI_UBOOT
void qtn_mini_hw_init(int board_id);
int board_cfg_init(int *p_board_id);
void board_pmu_init(void);
/* use spare register for saving gd pointer - used for EXPORT_FUNC() */
static void board_global_data_init(void)
{
DECLARE_GLOBAL_DATA_PTR;
gd->cpu_clk = RUBY_FIXED_CPU_CLK;
gd->bus_clk = RUBY_FIXED_DEV_CLK;
gd->baudrate = RUBY_SERIAL_BAUD;
gd->bd->bi_memsize = RUBY_MIN_DRAM_SIZE;
gd->bd->bi_boot_params = 0x0;
writel((int)gd,0xe00000bc);
}
int board_init(void)
{
dcache_enable();
board_pmu_init();
board_global_data_init();
board_serial_init();
board_check_build();
board_intr_init();
board_timer_init();
board_spi_flash_init();
return 0;
}
static void dump_muc_stack(const struct ruby_crumbs *crumbs)
{
uint32_t sp_muc;
const uint32_t *sp_virt;
const uint32_t * const sp_virt_end = (void*)CONFIG_ARC_MUC_STACK_INIT_UBOOT;
printf("\tMuC stack candidates:\n");
printf("\t\tdram text: 0x%08lx - 0x%08lx\n",
crumbs->muc_dram.start,
crumbs->muc_dram.end);
printf("\t\tsram text: 0x%08lx - 0x%08lx\n",
crumbs->muc_sram.start,
crumbs->muc_sram.end);
sp_muc = crumbs->muc.sp;
if (!sp_muc) {
/*
* if the MuC isn't recording prolog crumbs,
* use the lowest part of the MuC stack
*/
sp_muc = virt_to_bus((void*)CONFIG_ARC_STACK_BEGIN);
}
sp_virt = (void*)bus_to_virt(sp_muc);
if (sp_virt == RUBY_BAD_VIRT_ADDR) {
printf("%s: could not get sp_virt, sp_muc = 0x%08x\n", __FUNCTION__, sp_muc);
return;
}
if (sp_muc % 4 != 0 || ((uint32_t)sp_virt) % 4 != 0) {
printf("%s: misaligned stack pointer muc 0x%08x\n", __FUNCTION__, sp_muc);
return;
}
while (sp_virt <= sp_virt_end) {
/*
* read muc stack contents at *sp, compare value with muc text sections
*/
uint32_t val = *sp_virt;
int in_sram = val >= crumbs->muc_sram.start && val <= crumbs->muc_sram.end;
int in_dram = val >= crumbs->muc_dram.start && val <= crumbs->muc_dram.end;
if (val && (in_sram || in_dram)) {
printf("\t\tsp 0x%08x\tfn 0x%08x\n", sp_muc, val);
}
sp_muc += 4;
sp_virt++;
}
}
static void dump_core_crumbs(const char* core, const struct ruby_crumbs_percore *core_crumbs)
{
printf("\t%s:\tblink 0x%lx status32 0x%lx sp 0x%lx\n",
core,
core_crumbs->blink,
core_crumbs->status32,
core_crumbs->sp);
}
static void dump_ruby_crumbs(const struct ruby_crumbs *crumbs)
{
dump_core_crumbs("lhost", &crumbs->lhost);
dump_core_crumbs("DSP", &crumbs->dsp);
dump_core_crumbs("MuC", &crumbs->muc);
}
static void init_ruby_crumbs(void)
{
struct ruby_crumbs *crumbs = (struct ruby_crumbs*)RUBY_CRUMBS_ADDR_UBOOT;
char *crumb_env;
int show_crumbs = 0;
int magic_valid = crumbs->magic == RUBY_CRUMBS_MAGIC;
crumb_env = getenv("dump_crumbs");
if (crumb_env != NULL) {
show_crumbs = simple_strtoul(crumb_env, NULL, 10);
}
if (show_crumbs) {
printf("Info: last core activity: \n");
if (magic_valid) {
dump_ruby_crumbs(crumbs);
dump_muc_stack(crumbs);
} else {
printf("***Crumbs magic token is incorrect, values are probably invalid\n");
dump_ruby_crumbs(crumbs);
}
printf("\n");
}
/* clear the crumbs structure */
memset(crumbs, 0, sizeof(*crumbs));
}
int board_late_init(void)
{
DECLARE_GLOBAL_DATA_PTR;
u32 ddr_size = DEFAULT_DDR_SIZE;
int board_id;
char *p;
init_ruby_crumbs();
if (board_cfg_init(&board_id) != 0) {
printf("error: board configuration not found\n");
return -1;
}
p = getenv("mdc_clk_div");
if (p != NULL)
mdc_clk_divisor = 3 & simple_strtoul(p, NULL, 10);
gd->bd->bi_board_id = board_id;
ddr_size = board_config(board_id,BOARD_CFG_DDR_SIZE);
gd->bd->bi_memsize = ddr_size;
if (read_new_aux_reg(SCRATCH_DATA0)) {
printf("Warm boot\n");
} else {
printf("Cold boot\n");
qtn_mini_hw_init(board_id);
}
board_setup_bda((void *) CONFIG_ARC_CONF_BASE, board_id);
qtn_parse_early_flash_config(0);
/* Here we check the env to see if user want to Enable SPI Flash Protect
* Mode
*/
if ((p = getenv(SPI_PROTECT_MODE)) != NULL) {
if (strcmp (p, SPI_PROTECT_MODE_ENABLE) == 0){
spi_protect_mode_on();
} else {
spi_protect_mode_off();
}
}
#ifdef CONFIG_CMD_HNVRAM
RUN("hnvram load");
#endif
#ifdef GFRG240
char cmd[320];
sprintf(cmd, "if test xx$HNV_ACTIVATED_KERNEL_NAME = xxkernel1; "
"then gfkernel=0x%08x otherkernel=0x%08x; "
"else gfkernel=0x%08x otherkernel=0x%08x; fi; "
"loadaddr=0x%08x; kernelsize=0x%08x; ",
UBOOT_PARTITION_OFFSET_KERNEL1, UBOOT_PARTITION_OFFSET_KERNEL0,
UBOOT_PARTITION_OFFSET_KERNEL0, UBOOT_PARTITION_OFFSET_KERNEL1,
RUBY_KERNEL_LOAD_DRAM_BEGIN,
UBOOT_KERNEL_PARTITION_SIZE);
setenv("gfparams", cmd);
const char *gfboot = "run gfparams; "
"spi_flash read $gfkernel $loadaddr $kernelsize; "
"bootm $loadaddr; ";
char *env = getenv("gfboot");
if (env && strcmp(env, gfboot)) {
printf("WARNING: Overriding previously defined 'gfboot'\n");
}
setenv("gfboot", gfboot);
env = getenv("bootcmd");
if (!env) {
setenv("bootcmd", "run gfboot");
}
setenv("otherboot",
"run gfparams; "
"spi_flash read $otherkernel $loadaddr $kernelsize; "
"bootm $loadaddr; ");
#endif
return 0;
}
int protect_env_get(void)
{
char *p;
if ((p = getenv(SPI_PROTECT_MODE)) != NULL) {
if (strcmp (p, SPI_PROTECT_MODE_ENABLE) == 0){
return 0;
}
}
return -1;
}
#endif /* TOPAZ_EP_MINI_UBOOT */
void board_pmu_init(void)
{
#define TOPAZ_PMU_CONFIG_1 0xe00000f0
#define TOPAZ_PMU_CONFIG_2 0xe00000f4
u32 rdata;
rdata = 0xc00002f0;
REG_WRITE(TOPAZ_PMU_CONFIG_1,rdata);
rdata = 0xb7000027;
REG_WRITE(TOPAZ_PMU_CONFIG_2,rdata);
}
/*
* Figure out our board type from
* env and configure properly
*/
int board_cfg_init(int *p_board_id)
{
int board_id = DEFAULT_BOARD_ID;
#ifndef RUBY_MINI
int uart1 = 0;
#endif
int retval = 0;
char *s;
s = getenv("hw_config_id");
if (s == NULL)
printf("\"hw_config_id\" not set, using default value of %d\n", board_id);
else
board_id = simple_strtoul(s, NULL, 10);
if (board_id == QTN_RUBY_AUTOCONFIG_ID)
board_parse_custom_cfg();
if (board_id == QTN_RUBY_UNIVERSAL_BOARD_ID) {
retval = board_hw_config_read();
if (retval < 0)
return -1;
}
if (board_config(board_id, BOARD_CFG_ID) != board_id)
return -1;
s = (char *) board_config(board_id, BOARD_CFG_NAME);
if (s != NULL)
printf("hw_config_id %u: '%s'\n", board_id, s);
*p_board_id = board_id;
#ifndef RUBY_MINI
/* Setup UART1 */
s = getenv("uart1");
if (s)
uart1 = simple_strtoul(s, NULL, 1);
/* Check for u-boot env. or board configuration */
if (uart1 || (board_config(board_id, BOARD_CFG_UART1) == UART1_IN_USE)) {
printf("UART1 enabled: GPIO_PIN1 (input) Rx, GPIO_PIN9 (output) Tx\n");
gpio_config(GPIO_PIN(1), RUBY_GPIO_ALT_INPUT);
gpio_config(GPIO_PIN(9), RUBY_GPIO_ALT_OUTPUT);
}
#endif
return 0;
}
/*
* Quantenna minimal hardware initailization, which depends on board config.
* Include DDR and PCIe.
*/
void qtn_mini_hw_init(int board_id)
{
u32 ddr_speed = DEFAULT_DDR_SPEED;
u32 ddr_size = DEFAULT_DDR_SIZE;
u32 ddr_type = DEFAULT_DDR_CFG;
int pcie_flags;
printf("Reset status: 0x%08x\n",
arc_read_uncached_32(RUBY_SYS_CTL_RESET_CAUSE));
pcie_flags = board_config(board_id, BOARD_CFG_PCIE);
if (pcie_flags & PCIE_IN_USE) {
uint32_t time;
pcie_ep_early_init(pcie_flags);
time = read_new_aux_reg(ARC_REG_TIMER1_CNT);
time /= (RUBY_FIXED_CPU_CLK / 1000);
printf("PCIe early init, done@%dms\n", time);
}
#ifndef TOPAZ_EP_MINI_UBOOT
board_info_init();
spi_flash_info();
#endif
ddr_type = board_config(board_id, BOARD_CFG_DDR_TYPE);
ddr_speed = board_config(board_id, BOARD_CFG_DDR_SPEED);
ddr_size = board_config(board_id,BOARD_CFG_DDR_SIZE);
ddr_init(ddr_type, ddr_speed, ddr_size);
if (pcie_flags & PCIE_IN_USE) {
board_pcie_init(ddr_size, pcie_flags);
}
}