blob: 19451f01b43a5e84efff387de5dd21a8b314a1f9 [file] [log] [blame]
/*
*
* Copyright (C) 2015 Amlogic, Inc. All rights reserved.
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <common.h>
#include <malloc.h>
#include <errno.h>
#include <environment.h>
#include <fdt_support.h>
#include <libfdt.h>
#ifdef CONFIG_SYS_I2C_AML
#include <aml_i2c.h>
#include <asm/arch/secure_apb.h>
#endif
#include <amlogic/canvas.h>
#ifdef CONFIG_AML_VPU
#include <vpu.h>
#endif
#include <vpp.h>
#ifdef CONFIG_AML_V2_FACTORY_BURN
#include <amlogic/aml_v2_burning.h>
#endif// #ifdef CONFIG_AML_V2_FACTORY_BURN
#ifdef CONFIG_AML_HDMITX20
#include <amlogic/hdmi.h>
#endif
#include <linux/mtd/partitions.h>
#include <linux/sizes.h>
#include <phy.h>
#include <asm/cpu_id.h>
#include <asm/arch/mailbox.h>
#ifdef DTB_BIND_KERNEL
#include "storage.h"
#endif
DECLARE_GLOBAL_DATA_PTR;
int serial_set_pin_port(unsigned long port_base)
{
//UART in "Always On Module"
//GPIOAO_0==tx,GPIOAO_1==rx
//setbits_le32(P_AO_RTI_PIN_MUX_REG,3<<11);
return 0;
}
int dram_init(void)
{
gd->ram_size = PHYS_SDRAM_1_SIZE;
return 0;
}
/* secondary_boot_func
* this function should be write with asm, here, is is only for compiling pass
* */
void secondary_boot_func(void)
{
}
#if CONFIG_AML_SD_EMMC
#include <mmc.h>
#include <asm/arch/sd_emmc.h>
static int sd_emmc_init(unsigned port)
{
switch (port)
{
case SDIO_PORT_A:
break;
case SDIO_PORT_B:
//todo add card detect
//setbits_le32(P_PREG_PAD_GPIO5_EN_N,1<<29);//CARD_6
break;
case SDIO_PORT_C:
//enable pull up
//clrbits_le32(P_PAD_PULL_UP_REG3, 0xff<<0);
break;
default:
break;
}
return cpu_sd_emmc_init(port);
}
extern unsigned sd_debug_board_1bit_flag;
static int sd_emmc_detect(unsigned port)
{
int ret;
switch (port) {
case SDIO_PORT_A:
break;
case SDIO_PORT_B:
setbits_le32(P_PREG_PAD_GPIO2_EN_N, 1 << 26);//CARD_6
ret = readl(P_PREG_PAD_GPIO2_I) & (1 << 26) ? 0 : 1;
printf("%s\n", ret ? "card in" : "card out");
if ((readl(P_PERIPHS_PIN_MUX_6) & (3 << 8))) { //if uart pinmux set, debug board in
if (!(readl(P_PREG_PAD_GPIO2_I) & (1 << 24))) {
printf("sdio debug board detected, sd card with 1bit mode\n");
sd_debug_board_1bit_flag = 1;
} else{
printf("sdio debug board detected, no sd card in\n");
sd_debug_board_1bit_flag = 0;
return 1;
}
}
break;
default:
break;
}
return 0;
}
static void sd_emmc_pwr_prepare(unsigned port)
{
cpu_sd_emmc_pwr_prepare(port);
}
static void sd_emmc_pwr_on(unsigned port)
{
switch (port)
{
case SDIO_PORT_A:
break;
case SDIO_PORT_B:
// clrbits_le32(P_PREG_PAD_GPIO5_O,(1<<31)); //CARD_8
// clrbits_le32(P_PREG_PAD_GPIO5_EN_N,(1<<31));
/// @todo NOT FINISH
break;
case SDIO_PORT_C:
break;
default:
break;
}
return;
}
static void sd_emmc_pwr_off(unsigned port)
{
/// @todo NOT FINISH
switch (port)
{
case SDIO_PORT_A:
break;
case SDIO_PORT_B:
// setbits_le32(P_PREG_PAD_GPIO5_O,(1<<31)); //CARD_8
// clrbits_le32(P_PREG_PAD_GPIO5_EN_N,(1<<31));
break;
case SDIO_PORT_C:
break;
default:
break;
}
return;
}
// #define CONFIG_TSD 1
static void board_mmc_register(unsigned port)
{
struct aml_card_sd_info *aml_priv=cpu_sd_emmc_get(port);
if (aml_priv == NULL)
return;
aml_priv->sd_emmc_init=sd_emmc_init;
aml_priv->sd_emmc_detect=sd_emmc_detect;
aml_priv->sd_emmc_pwr_off=sd_emmc_pwr_off;
aml_priv->sd_emmc_pwr_on=sd_emmc_pwr_on;
aml_priv->sd_emmc_pwr_prepare=sd_emmc_pwr_prepare;
aml_priv->desc_buf = malloc(NEWSD_MAX_DESC_MUN*(sizeof(struct sd_emmc_desc_info)));
if (NULL == aml_priv->desc_buf)
printf(" desc_buf Dma alloc Fail!\n");
else
printf("aml_priv->desc_buf = 0x%p\n",aml_priv->desc_buf);
sd_emmc_register(aml_priv);
}
int board_mmc_init(bd_t *bis)
{
__maybe_unused struct mmc *mmc;
#ifdef CONFIG_VLSI_EMULATOR
//board_mmc_register(SDIO_PORT_A);
#else
//board_mmc_register(SDIO_PORT_B);
#endif
board_mmc_register(SDIO_PORT_B);
board_mmc_register(SDIO_PORT_C);
// board_mmc_register(SDIO_PORT_B1);
#if defined(CONFIG_ENV_IS_NOWHERE) && !defined(CONFIG_AML_MTD)
/* try emmc here. */
mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
if (!mmc)
printf("%s() %d: No MMC found\n", __func__, __LINE__);
else if (mmc_init(mmc))
printf("%s() %d: MMC init failed\n", __func__, __LINE__);
#endif
return 0;
}
#ifdef CONFIG_SYS_I2C_AML
#if 0
static void board_i2c_set_pinmux(void){
/*********************************************/
/* | I2C_Master_AO |I2C_Slave | */
/*********************************************/
/* | I2C_SCK | I2C_SCK_SLAVE | */
/* GPIOAO_4 | [AO_PIN_MUX: 6] | [AO_PIN_MUX: 2] | */
/*********************************************/
/* | I2C_SDA | I2C_SDA_SLAVE | */
/* GPIOAO_5 | [AO_PIN_MUX: 5] | [AO_PIN_MUX: 1] | */
/*********************************************/
//disable all other pins which share with I2C_SDA_AO & I2C_SCK_AO
clrbits_le32(P_AO_RTI_PIN_MUX_REG, ((1<<2)|(1<<24)|(1<<1)|(1<<23)));
//enable I2C MASTER AO pins
setbits_le32(P_AO_RTI_PIN_MUX_REG,
(MESON_I2C_MASTER_AO_GPIOAO_4_BIT | MESON_I2C_MASTER_AO_GPIOAO_5_BIT));
udelay(10);
};
#endif
struct aml_i2c_platform g_aml_i2c_plat = {
.wait_count = 1000000,
.wait_ack_interval = 5,
.wait_read_interval = 5,
.wait_xfer_interval = 5,
.master_no = AML_I2C_MASTER_AO,
.use_pio = 0,
.master_i2c_speed = AML_I2C_SPPED_400K,
.master_ao_pinmux = {
.scl_reg = (unsigned long)MESON_I2C_MASTER_AO_GPIOAO_4_REG,
.scl_bit = MESON_I2C_MASTER_AO_GPIOAO_4_BIT,
.sda_reg = (unsigned long)MESON_I2C_MASTER_AO_GPIOAO_5_REG,
.sda_bit = MESON_I2C_MASTER_AO_GPIOAO_5_BIT,
}
};
#if 0
static void board_i2c_init(void)
{
//set I2C pinmux with PCB board layout
board_i2c_set_pinmux();
//Amlogic I2C controller initialized
//note: it must be call before any I2C operation
aml_i2c_init();
udelay(10);
}
#endif
#endif
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_F)
int board_early_init_f(void){
/*add board early init function here*/
return 0;
}
#endif
#ifdef CONFIG_USB_XHCI_AMLOGIC_GXL
#include <asm/arch/usb-new.h>
#include <asm/arch/gpio.h>
#define CONFIG_GXL_USB_U2_PORT_NUM 2
#define CONFIG_GXL_USB_U3_PORT_NUM 0
struct amlogic_usb_config g_usb_config_GXL_skt={
CONFIG_GXL_XHCI_BASE,
USB_ID_MODE_HARDWARE,
NULL,//gpio_set_vbus_power, //set_vbus_power
CONFIG_GXL_USB_PHY2_BASE,
CONFIG_GXL_USB_PHY3_BASE,
CONFIG_GXL_USB_U2_PORT_NUM,
CONFIG_GXL_USB_U3_PORT_NUM,
};
#endif /*CONFIG_USB_XHCI_AMLOGIC*/
#ifdef CONFIG_AML_HDMITX20
static void hdmi_tx_set_hdmi_5v(void)
{
/*Power on VCC_5V for HDMI_5V*/
clrbits_le32(P_PREG_PAD_GPIO1_EN_N, 1 << 23);
clrbits_le32(P_PREG_PAD_GPIO1_O, 1 << 23);
}
#endif
/*
* mtd nand partition table, only care the size!
* offset will be calculated by nand driver.
*/
#ifdef CONFIG_AML_MTD
static struct mtd_partition normal_partition_info[] = {
#ifdef CONFIG_DISCRETE_BOOTLOADER
/* MUST NOT CHANGE this part unless u know what you are doing!
* inherent parition for descrete bootloader to store fip
* size is determind by TPL_SIZE_PER_COPY*TPL_COPY_NUM
* name must be same with TPL_PART_NAME
*/
{
.name = "tpl",
.offset = 0,
.size = 0,
},
#endif
{
.name = "fts",
.offset = 0,
.size = 1*SZ_1M,
},
{
.name = "factory",
.offset = 0,
.size = 8*SZ_1M,
},
{
.name = "recovery",
.offset = 0,
.size = 16*SZ_1M,
},
{
.name = "boot",
.offset = 0,
.size = 12*SZ_1M,
},
{
.name = "system",
.offset = 0,
.size = 220*SZ_1M,
},
/* last partition get the rest capacity */
{
.name = "cache",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
},
};
struct mtd_partition *get_aml_mtd_partition(void)
{
return normal_partition_info;
}
int get_aml_partition_count(void)
{
return ARRAY_SIZE(normal_partition_info);
}
#endif /* CONFIG_AML_MTD */
int board_init(void)
{
//Please keep CONFIG_AML_V2_FACTORY_BURN at first place of board_init
#ifdef CONFIG_AML_V2_FACTORY_BURN
if ((0x1b8ec003 != readl(P_PREG_STICKY_REG2)) && (0x1b8ec004 != readl(P_PREG_STICKY_REG2))) {
aml_try_factory_usb_burning(0, gd->bd);
}
#endif// #ifdef CONFIG_AML_V2_FACTORY_BURN
/*for LED*/
//clear pinmux
clrbits_le32(AO_RTI_PIN_MUX_REG, ((1<<3)|(1<<4)));
clrbits_le32(AO_RTI_PIN_MUX_REG2, ((1<<1)|(1<<31)));
//set output mode
clrbits_le32(PREG_PAD_GPIO0_EN_N, (1 << 24));
//set output 1
setbits_le32(PREG_PAD_GPIO0_O, (1 << 24));
/*increase cpu core voltage to 1.15 V*/
//clear pinmux
clrbits_le32(P_PERIPHS_PIN_MUX_6, (1<<1)|(1<<7)|(1<<9)|(1<<11));
clrbits_le32(P_PERIPHS_PIN_MUX_6, (1<<0)|(1<<6)|(1<<8)|(1<<10));
//set output mode
clrbits_le32(P_PREG_PAD_GPIO2_EN_N, (1 << 24));
clrbits_le32(P_PREG_PAD_GPIO2_EN_N, (1 << 25));
//set output 1
setbits_le32(P_PREG_PAD_GPIO2_O, 1 << 24);
setbits_le32(P_PREG_PAD_GPIO2_O, 1 << 25);
/*Power on GPIOAO_2 for VCC_5V*/
clrbits_le32(P_AO_GPIO_O_EN_N, ((1<<2)|(1<<18)));
#ifdef CONFIG_USB_XHCI_AMLOGIC_GXL
board_usb_init(&g_usb_config_GXL_skt,BOARD_USB_MODE_HOST);
#endif /*CONFIG_USB_XHCI_AMLOGIC*/
canvas_init();
#ifndef CONFIG_AML_IRDETECT_EARLY
#ifdef CONFIG_AML_HDMITX20
hdmi_tx_set_hdmi_5v();
hdmi_tx_init();
#endif
#endif
#ifdef CONFIG_AML_NAND
extern int amlnf_init(unsigned char flag);
amlnf_init(0);
#endif
return 0;
}
#ifdef CONFIG_AML_IRDETECT_EARLY
#ifdef CONFIG_AML_HDMITX20
static int do_hdmi_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
hdmi_tx_set_hdmi_5v();
hdmi_tx_init();
return 0;
}
U_BOOT_CMD(hdmi_init, CONFIG_SYS_MAXARGS, 0, do_hdmi_init,
"HDMI_INIT sub-system",
"hdmit init\n")
#endif
#endif
#ifdef CONFIG_BOARD_LATE_INIT
#define SAMPLE_BIT_MASK 0xfff
#define NUM 50
#define BASE_CH7 1843
#define P_SAR_ADC_REG0 (volatile unsigned int *)0xc1108680
#define P_SAR_ADC_CHAN_LIST (volatile unsigned int *)0xc1108684
#define P_SAR_ADC_REG3 (volatile unsigned int *)0xc110868c
#define P_SAR_ADC_FIFO_RD (volatile unsigned int *)0xc1108698
#define P_SAR_ADC_DETECT_IDLE_SW (volatile unsigned int *)0xc11086a4
#define P_SAR_ADC_REG13 (volatile unsigned int *)0xc11086b4
#if 0
#define dbgv(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define dbgv(fmt, ...)
#endif
void quicksort1(unsigned int a[], int numsize)
{
int i = 0, j = numsize-1;
int val = a[0];
if (numsize > 1) {
while (i < j) {
for (; j > i; j--)
if (a[j] < val) {
a[i] = a[j];
break;
}
for (; i < j; i++)
if (a[i] > val) {
a[j] = a[i];
break;
}
}
a[i] = val;
quicksort1(a, i);
quicksort1(a+i+1, numsize-1-i);
}
}
int check_vref(void)
{
int i,count;
unsigned int value[50];
unsigned int value7=0;
unsigned int bak, bak_reg3;
unsigned int vref_efuse = (readl(SEC_AO_SEC_SD_CFG12)>>19)&(0x1f);
if (!vref_efuse) {
dbgv("This chip has no FT vref, no need to check, PASS\n");
return 0;
}
//run_command("md 0xc1108680 0x10", 0);
dbgv("SEC_AO_SEC_SD_CFG12: 0x%x\n",readl(SEC_AO_SEC_SD_CFG12));
dbgv("vref_efuse: %d\n",vref_efuse);
dbgv("P_SAR_ADC_REG13: 0x%x\n",readl(P_SAR_ADC_REG13));
bak = (readl(P_SAR_ADC_REG13)>>8)&0x3f; /*back up SAR_ADC_REG13[13:8]*/
writel((readl(P_SAR_ADC_REG13)&(~(0x3f<<8)))|(vref_efuse<<9), P_SAR_ADC_REG13);
dbgv("P_SAR_ADC_REG13: 0x%x\n",readl(P_SAR_ADC_REG13));
writel(0x00000007, P_SAR_ADC_CHAN_LIST);/*ch7*/
//writel(0xc000c|(0x7<<23)|(0x7<<7), P_SAR_ADC_DETECT_IDLE_SW);/*channel 7*/
bak_reg3 = readl(P_SAR_ADC_REG3);
writel((readl(P_SAR_ADC_REG3)&(~(0x7<<23)))|(0x2<<23), P_SAR_ADC_REG3);/*AVDD18/2*/
dbgv("P_SAR_ADC_REG13: 0x%x\n",readl(P_SAR_ADC_REG13));
//run_command("md 0xc1108680 0x10", 0);
for (i=0;i<NUM;i++) {
writel((readl(P_SAR_ADC_REG0)&(~(1<<0))), P_SAR_ADC_REG0);
writel((readl(P_SAR_ADC_REG0)|(1<<0)), P_SAR_ADC_REG0);
writel((readl(P_SAR_ADC_REG0)|(1<<2)), P_SAR_ADC_REG0);/*start sample*/
count = 0;
do {
udelay(20);
count++;
} while ((readl(P_SAR_ADC_REG0) & (0x7<<28))
&& (count < 100));/*finish sample?*/
if (count == 100) {
printf("%s : ch7 wait finish sample timeout!\n",__func__);
return -1;
}
value[i] = readl(P_SAR_ADC_FIFO_RD); /*read saradc*/
if (((value[i]>>12) & 0x7) == 0x7)
value[i] = value[i]&SAMPLE_BIT_MASK;
else {
printf("%s : not ch7! sample err!\n",__func__);
return -1;
}
}
quicksort1(value, NUM);
for (i = 0; i < NUM; i++)
dbgv("%d ", value[i]);
dbgv("\n");
for (i = 2; i < NUM-2; i++)
value7 += value[i];
value7 = value7/(NUM-4);
dbgv("the average ch7 adc=%d\n", value7);
dbgv("vref_efuse: %d\n",vref_efuse);
if ((value7 < (BASE_CH7*94/100)) || (value7 > (BASE_CH7*106/100))) { //1843
printf("the average ch7 : %d out of range: %d ~ %d\n",
value7, (BASE_CH7*94/100), (BASE_CH7*106/100));
printf("replace FT vref...\n");
thermal_calibration(4, bak>>1); /*[13:9]*/
}
/*write back SAR_ADC_REG13[13:8]*/
writel(((readl(P_SAR_ADC_REG13))&(~(0x3f<<8)))|
((bak & 0x3f)<<8),
P_SAR_ADC_REG13);
writel(bak_reg3, P_SAR_ADC_REG3);
dbgv("P_SAR_ADC_REG13: 0x%x\n",readl(P_SAR_ADC_REG13));
dbgv("SEC_AO_SEC_SD_CFG12: 0x%x\n",readl(SEC_AO_SEC_SD_CFG12));
//run_command("md 0xc1108680 0x10", 0);
return 0;
}
int board_late_init(void){
//update env before anyone using it
run_command("get_rebootmode; echo reboot_mode=${reboot_mode}; "\
"if test ${reboot_mode} = factory_reset; then "\
"defenv_reserv aml_dt;setenv upgrade_step 2;save; fi;", 0);
run_command("if itest ${upgrade_step} == 1; then "\
"defenv_reserv; setenv upgrade_step 2; saveenv; fi;", 0);
/*add board late init function here*/
#ifndef DTB_BIND_KERNEL
int ret;
ret = run_command("store dtb read $dtb_mem_addr", 1);
if (ret) {
printf("%s(): [store dtb read $dtb_mem_addr] fail\n", __func__);
#ifdef CONFIG_DTB_MEM_ADDR
char cmd[64];
printf("load dtb to %x\n", CONFIG_DTB_MEM_ADDR);
sprintf(cmd, "store dtb read %x", CONFIG_DTB_MEM_ADDR);
ret = run_command(cmd, 1);
if (ret) {
printf("%s(): %s fail\n", __func__, cmd);
}
#endif
}
#elif defined(CONFIG_DTB_MEM_ADDR)
{
char cmd[128];
int ret;
if (!getenv("dtb_mem_addr")) {
sprintf(cmd, "setenv dtb_mem_addr 0x%x", CONFIG_DTB_MEM_ADDR);
run_command(cmd, 0);
}
sprintf(cmd, "imgread dtb boot ${dtb_mem_addr}");
ret = run_command(cmd, 0);
if (ret) {
printf("%s(): cmd[%s] fail, ret=%d\n", __func__, cmd, ret);
}
}
#endif// #ifndef DTB_BIND_KERNEL
#ifdef CONFIG_AML_VPU
vpu_probe();
#endif
vpp_init();
#ifndef CONFIG_AML_IRDETECT_EARLY
/* after */
run_command("cvbs init;hdmitx hpd", 0);
run_command("vout output $outputmode", 0);
#endif
#ifdef CONFIG_AML_V2_FACTORY_BURN
if (0x1b8ec003 == readl(P_PREG_STICKY_REG2))
aml_try_factory_usb_burning(1, gd->bd);
aml_try_factory_sdcard_burning(0, gd->bd);
#endif// #ifdef CONFIG_AML_V2_FACTORY_BURN
ret = check_vref();
if (get_cpu_id().family_id == MESON_CPU_MAJOR_ID_GXL) {
setenv("maxcpus","4");
}
return 0;
}
#endif
phys_size_t get_effective_memsize(void)
{
// >>16 -> MB, <<20 -> real size, so >>16<<20 = <<4
#if defined(CONFIG_SYS_MEM_TOP_HIDE)
return (((readl(AO_SEC_GP_CFG0)) & 0xFFFF0000) << 4) - CONFIG_SYS_MEM_TOP_HIDE;
#else
return (((readl(AO_SEC_GP_CFG0)) & 0xFFFF0000) << 4);
#endif
}
#ifdef CONFIG_MULTI_DTB
int checkhw(char * name)
{
unsigned int ddr_size=0;
char loc_name[64] = {0};
int i;
for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {
ddr_size += gd->bd->bi_dram[i].size;
}
#if defined(CONFIG_SYS_MEM_TOP_HIDE)
ddr_size += CONFIG_SYS_MEM_TOP_HIDE;
#endif
switch (ddr_size) {
case 0x80000000:
strcpy(loc_name, "gxl_p212_2g\0");
break;
case 0x40000000:
strcpy(loc_name, "gxl_p212_1g\0");
break;
case 0x2000000:
strcpy(loc_name, "gxl_p212_512m\0");
break;
default:
//printf("DDR size: 0x%x, multi-dt doesn't support\n", ddr_size);
strcpy(loc_name, "gxl_p212_unsupport");
break;
}
strcpy(name, loc_name);
setenv("aml_dt", loc_name);
return 0;
}
#endif
const char * const _env_args_reserve_[] =
{
"aml_dt",
"firstboot",
NULL//Keep NULL be last to tell END
};