blob: 5f95b6b9016b9efbb460433bac5decf406712adb [file] [log] [blame]
/*
* (C) Copyright Marvell Semiconductors, Inc 2008 All rightes reserved
*/
#include "common.h"
#include "chipctrl_const.h"
#ifdef CONFIG_SM
#include "sm_const.h"
#include "SysMgr.h"
#endif // CONFIG_SM
#include "figo.h"
#include "config.h"
#include "nand_priv.h"
#include "util.h"
#include "cold_linuxparam.h"
#include "SystemManager.h"
#include "SysMgr.h"
#include "system_config.h"
#include "global.h"
#include "gpio.h"
#include "init_clock.h"
#include "led_pwm.h"
#include "apb_perf_base.h"
#include "apb_gpio.h"
#include "galois_speed.h"
#include "pin_settings.h"
#include "wol.h"
#include "berlin_bootinfo.h"
#include "mv_nand.h"
#include "drmdmx.h"
#include "basic_inc.h"
#include "timer.h"
#if 0 // BOOTLOADER_FASTLOGO
#include "thinvpp_api.h"
#include "avpll.h"
#include "api_avio_dhub.h"
#endif
#include "fastlogo.h"
#include "nand_block0_layout_A0.h"
#include "image2_header_A0.h"
#include "image3_header.h"
#include "version_table.h"
#if BG2CDP
#include "MctrlSS.h"
#include "cpu_ca7.h"
#include "block1_layout.h"
#include "bcmREG.h"
#include "bcm_mailbox.h"
#define BCM_MAILBOX MEMMAP_BCM_REG_BASE //0xF7930000
#define BCM_PI_IMAGE_VERIFY 0x004E
#define BCM_IMG_KERNEL_TYPE 4
#define BCM_IMG_USBIMG_TYPE 5
#define SYSPLL_CTRL_BASE (MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_sysPll)
#define CPUPLL_CTRL_BASE (MEMMAP_CA7_REG_BASE + RA_CA7PllReg_PllReg)
#define MEMPLL_CTRL_BASE (MEMMAP_MCTRLSS_REG_BASE + RA_MctrlSS_memPll)
#define VCORE_MASTER_ID (0x00)
#define LED_MASTER_ID (0x00)
#define VCORE_VOLT_INDEX (0x0A) // set to 1.15v
#endif
#define PMIC_TYPE_UNKNOWN 0
#define PMIC_TYPE_PG86X 1
#define PMIC_TYPE_SY20212B 2
#define PMIC_TYPE_MAX 3
static int PMIC_type = PMIC_TYPE_UNKNOWN;
#if ANDROID_BOOT
#include "android/bootimg.h"
#include "android/flash_ts.h"
#include "board_config.h"
#endif
#include "nflash_drv.h"
#include "linux_param.h"
#include "bootloader_customize.h"
#ifdef CONFIG_USB
#include "usb_storage.h"
#include "usb_key.h"
#endif
#include "cec.h"
#if (CFG_BOARD_NAME == BOARD_CHIRP_B1) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B3) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B4) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B1) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B3) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B4)
#undef DISABLE_CRASH_COUNTER
#else
// disable crash counter. b/10478589.
#define DISABLE_CRASH_COUNTER 1
#endif
//#define CONFIG_FORCE_ENCRYPTION
#define BOOT_SRC_NAND 1
#define BOOT_SRC_USB 2
/* on a USB storage device, leave first 4KB for MBR/part table
* and start boot image at a 4KB offset.
*/
#define USB_BOOTIMG_START (4 * 1024)
#define USB_BLOCK_SIZ 512
#define CPU_IMG_OFFS_MAGIC 4
#define CPU_IMG_OFFS_USRDATA 10
#define CPU_IMG_OFFS_IMGSIZ 40
#define CPU_IMG_OFFS_IMGSTA 332
#define CPU_IMG_USB_USRDATA 0xA33A
#define CPU_IMG_NAND_USRDATA 0x0
#define CPU_IMG_CODE_MAGIC 0xC0DE
#define MAX_ANDROID_IMG_SIZE (32 * 1024 * 1024)
#define MIN_ANDROID_IMG_SIZE (1 * 1024 * 1024)
#define MAX_LOGO_FRM_SIZE (4 * 1024 * 1024)
// The bootloader needs some temporary memory for loading the android image
// (during verification) and for the fast logo frame buffer. This memory is
// is not needed once we boot the kernel, but it should not conflict with the
// bootloader or where we relocate the kernel and ramdisk. Furthermore,
// the very top of memory is off limits (protected by the trust zone).
//
// Memory maps, starting at address 0:
//
// At kernel load time:
// [ TZ resident memory ] - size 17MB
// [ Bootloader + data (including bcm console) ] - starting at 22MB
// [ Unused memory ]
// Fast logo frame buffer - max size 4MB
// Android image buffer - max size 32MB
// [ secure memory ] - starts at MEMTOP - 8MB, size 8MB
//
// At kernel launch time:
// [ TZ resident memory ] - size 17MB
// [ Linux memory ] - total size ~302MB
// Kernel copied to 17MB, (note: *must* be < 5MB)
// Bootloader image is at 22MB
// Ramdisk copied to 96MB
// [ cache memory ] - size 168MB
// [ secure memory ] - starts at (BOARD_MEM_SIZE - 8MB), size 8MB
// Define an arbitrary maximum secure memory size which should be
// more than enough to avoid problems in case of expansion. The
// actual size is determined by the TZ and the kernel.
#define MAX_SECURE_MEMORY (32 * 1024 * 1024)
// Define the start of bootloader temporary memory.
#define BOOTLOADER_TEMP_MEMORY (BOARD_MEM_SIZE - MAX_SECURE_MEMORY - \
(MAX_LOGO_FRM_SIZE + MAX_ANDROID_IMG_SIZE))
// Logo is at the start of temporary memory.
#define LOGO_FRM_BUF (BOOTLOADER_TEMP_MEMORY)
// Android image buffer begins right after the frame buffer.
#define ANDROID_IMG_BUF (BOOTLOADER_TEMP_MEMORY + MAX_LOGO_FRM_SIZE)
#define CHIP_VERSION "BG2CDP"
#if !CDP_A0
#define MV88DE3100_CHIPID_REG1 (0xF7CFF030)
#define MV88DE3100_CHIPID_REG2 (0xF7CFF034)
#else
#define MV88DE3100_CHIPID_REG1 (0xF7CFF060)
#define MV88DE3100_CHIPID_REG2 (0xF7CFF064)
#endif
#define PRODUCT_CHIP_EXT_ID (MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_ProductId_ext)
#define MV88DE3XXX_OTP_STS_REG 0xF7CC08C8
#define MV88DE3XXX_OTP_LKG_ID 0XF7CC07DD
#define MV88DE3XXX_SOC_REV_REG 0XF7CC07D4
#define MV88DE3XXX_SOC_REV_MASK 0x3
#define MV88DE3XXX_SOC_REV_SHIFT 29
#define MAX_RAMDISK_IMPLICT_SIZE (0x2000000)
#define PRNG_DATA_SIZE 64
#define BERLIN_BOOTINFO_ADDR 0x01010000
/*
* Macro to remove unused variable warning for function args not used for
* specific platform.
*/
#define UNUSED(var) do { (void)(var); } while(0)
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
enum sm_ldo_ctrl_vout_sel_e {
SM_LDO_CTRL_VOUT_0_900V = 0,
SM_LDO_CTRL_VOUT_0_789V,
SM_LDO_CTRL_VOUT_0_826V,
SM_LDO_CTRL_VOUT_0_863V,
SM_LDO_CTRL_VOUT_0_937V,
SM_LDO_CTRL_VOUT_0_974V,
SM_LDO_CTRL_VOUT_1_011V,
SM_LDO_CTRL_VOUT_1_048V,
SM_LDO_CTRL_VOUT_MAX
};
extern int __bss_start;
extern int __bss_end;
#define BSS_START ((unsigned int)(&__bss_start))
#define BSS_END ((unsigned int)(&__bss_end))
#if ANDROID_BOOT
#define FTS_NAME "fts"
#define KERNEL_NAME "kernel"
#define RECOVERY_NAME "recovery"
#define FTS_KEY_MACADDR "macaddr"
#define FTS_KEY_COLOR "color"
#define FTS_WIFI_MFG_MODE "wifi_mfg_mode"
#define FTS_DEVICE_CFGED "device_configured"
#define BOOTLOADER_COMMAND_KEY "bootloader.command"
#define ANDROID_CRASH_COUNTER_KEY "crashcounter.android"
#define MAX_CRASH_COUNT 10
#define BOOTMODE_NORMAL 0
#define BOOTMODE_RECOVERY 1
#define BOOTMODE_BOOTUSB 2
#define BOOTMODE_BACKUPSYS 3
const char kBootcmdRecovery[] = "recovery";
const char kFtsBootcmdRecovery[] = "boot-recovery";
const char kFtsBootcmdBackupsys[] = "boot-backupsys";
#endif /* #if ANDROID_BOOT */
#define STR(x) #x
#define XSTR(x) STR(x)
//#if defined(DEBUG)
//#define debug_printf(a...) lgpl_printf(a)
//#else
//#define debug_printf(a...)
//#endif
//#define debug_printf(a...) lgpl_printf(a)
extern struct mv_nand_data nand_data ;
block0_t block0;
ver_table_entry_t vt_img3;
//ver_table_entry_t vt_sysconf;
//ver_table_entry_t vt_flashless;
#if ANDROID_BOOT
static const ver_table_entry_t vt_fts = {
.part1_start_blkind = FTS_BLK_START,
.part1_blks = FTS_BLK_CNT,
};
static const ver_table_entry_t vt_recovery = {
.part1_start_blkind = RECOVERY_BLK_START,
.part1_blks = RECOVERY_BLK_CNT,
};
static const ver_table_entry_t vt_kernel = {
.part1_start_blkind = KERNEL_BLK_START,
.part1_blks = KERNEL_BLK_CNT,
};
static const ver_table_entry_t vt_backupsys = {
.part1_start_blkind = BACKUPSYS_BLK_START,
.part1_blks = BACKUPSYS_BLK_CNT,
};
static unsigned int fts_dev_id = 0;
static boot_img_hdr Mkbootimg_hdr;
void (*TheKernel)(int zero, int arch, unsigned int params);
static int Bootmode = BOOTMODE_NORMAL;
#endif /* #if ANDROID_BOOT */
Image3_Attr img3_hdr;
sm_image_attr *sm_hdr;
cpu0_image_attr *cpu0_hdr;
cpu1_image_attr *cpu1_hdr;
recovery_ou_attr *recou_hdr;
Encryption_Header en_hdr;
gen_header_t sysconf_hdr;
Mem_Layout *sMem_Layout ;
#define REBOOT_MSG_EXTRA_BUF_ADDR 0xa00000 // TODO: need a buffer address
#define REBOOT_MSG_EXTRA_BUF_SIZE 512
char reset_msg_extra_buf[REBOOT_MSG_EXTRA_BUF_SIZE];
unsigned int uiWarmDown_2_Linux_Addr = 0;
void setup_linux_bootparam(u32 mem_start, u32 mem_size, char *cmdline,
u8 chip_rev, u8 board_rev);
extern void Jump(unsigned int, unsigned int, unsigned int, unsigned int);
extern void Copy_Code_To_Figo_Sram();
extern int MV_SM_Send_Msg(int, void *, int);
extern void APB_UART_init(unsigned int , unsigned int , unsigned int ) ;
extern char gp_cust_figo_image[];
extern int MV_DRMLIB_Load_Customer_Key( unsigned char *, int);
extern int lgpl_printf(const char *format, ...);
extern void AVPLL_Enable(void);
inline char itoc(char i);
HRESULT MV_SM_Dev_Init(UCHAR * pucData_Buffer,UINT32 uiData_Size);
void abort(){printf("Abort\n"); while(1);}
int IS_Z1() { return 0; return (readl(PRODUCT_CHIP_EXT_ID) & 0xFF) == 0; }
int IS_Z2() { return 0; return (readl(PRODUCT_CHIP_EXT_ID) & 0xFF) == 2; }
int IS_B0() { return 1; return (readl(PRODUCT_CHIP_EXT_ID) & 0xFF) >= 0xB0; }
#ifdef ENABLE_CONNECT_BTN
extern int is_EnterRecovery;
extern void Check_connectbtnGPIO();
#endif
#if BG2CDP
int bcm_image_verify(unsigned int type, unsigned int src, unsigned int dst);
#define VT_OFFSET_CDP (nand_data.szofblk - 4096) // CDP: version table at last 4KiB of the block
#define SZ_MV_BOOT_IMAGE_HEAD 1024
#define SZW_MV_BOOT_IMAGE_HEAD (SZ_MV_BOOT_IMAGE_HEAD/sizeof(int))
#define SZ_MV_KEY_STORE_TYPE_AESK 64
#define SZ_MV_KEY_STORE_TYPE_RSAK (1024 - 2*SZ_MV_KEY_STORE_TYPE_AESK)
#define MV_KEY_STORE_TYPE_MASK 0x0000ffff
#define MV_KEY_STORE_TYPE_RSAK 0x0000a2e1
#define MV_KEY_STORE_TYPE_AESK 0x0000c237
#define MV_KEY_STORE_TYPE_ENDK 0x0f01c0de
typedef struct _MV_KEY_STORE_HEAD
{
unsigned int version;
unsigned int type;
} MV_KEY_STORE_HEAD;
typedef struct _MV_LASTK_STORE
{
union
{
MV_KEY_STORE_HEAD custk;
unsigned char custk_bytes[SZ_MV_KEY_STORE_TYPE_AESK];
};
union
{
MV_KEY_STORE_HEAD custk_kernel;
unsigned char custk_kernel_bytes[SZ_MV_KEY_STORE_TYPE_AESK];
};
union
{
MV_KEY_STORE_HEAD extrsak;
unsigned char extrsak_bytes[SZ_MV_KEY_STORE_TYPE_RSAK];
};
} MV_LASTK_STORE;
typedef struct _MV_BOOT_IMAGE_HEAD
{
union
{
MV_KEY_STORE_HEAD head;
unsigned char bytes[SZ_MV_BOOT_IMAGE_HEAD];
unsigned int words[SZW_MV_BOOT_IMAGE_HEAD];
};
} MV_BOOT_IMAGE_HEAD;
typedef struct _MV_LASTK_IMAGE
{
union
{
struct
{
MV_BOOT_IMAGE_HEAD image;
} h1;
struct
{
MV_BOOT_IMAGE_HEAD custk;
MV_BOOT_IMAGE_HEAD image;
} h2;
struct
{
MV_BOOT_IMAGE_HEAD extrsak;
MV_BOOT_IMAGE_HEAD image;
} h2a;
struct
{
MV_BOOT_IMAGE_HEAD custk;
MV_BOOT_IMAGE_HEAD extrsak;
MV_BOOT_IMAGE_HEAD image;
} h3;
};
} MV_LASTK_IMAGE;
int load_lastk(void *key_store)
{
MV_LASTK_STORE *lastk = (MV_LASTK_STORE *) key_store;
int err = 0;
if ((lastk->custk_kernel.type& MV_KEY_STORE_TYPE_MASK) == MV_KEY_STORE_TYPE_AESK)
{
// there is an custk for kernel image; let's load it
MV_LASTK_IMAGE *header = (MV_LASTK_IMAGE *) &lastk->custk_kernel;
MV_KEY_STORE_HEAD *bi;
if (lastk->extrsak.type != MV_KEY_STORE_TYPE_RSAK)
{
// there is no extrsak for kernel image; use h2 format
bi = &header->h2.image.head;
}
else
{
// there is also a extrsak for kernel image; use h3 format
UtilMemCpy(header->h3.extrsak.bytes, lastk->extrsak_bytes, sizeof(lastk->extrsak_bytes));
bi = &header->h3.image.head;
}
bi->version = 1; // only version 1 is supported
bi->type = MV_KEY_STORE_TYPE_ENDK;
err = bcm_image_verify(0, (unsigned int) header, 0);
if (err == (int)0xe0000301) // we are expecting this return code
err = 0;
}
else
{
lgpl_printf("\tno need to load kernel keys\n");
}
return err;
}
#endif
void pad_init(void)
{
#if !BG2CD
int val;
T32Gbl_PadSelect reg;
GA_REG_WORD32_READ(MEMMAP_CHIP_CTRL_REG_BASE+ RA_Gbl_PadSelect, &(reg.u32));
reg.uPadSelect_DVIO_OEN = Gbl_PadSelect_DVIO_OEN_Enable;
#if 0 //def CYPRESS_EMI // default always disable
reg.uPadSelect_DVIO0_V18EN = 1; //BG_FIX for EMI issue
#else
reg.uPadSelect_DVIO0_V18EN = 0;
#endif
reg.uPadSelect_CLK0_ZN = 7;
reg.uPadSelect_CLK0_ZP = 7;
reg.uPadSelect_DVIO0_ZN = 7;
#if (BERLIN_CHIP_VERSION < BERLIN_BG2)
reg.uPadSelect_DVIO0_ZP = 7;
#endif
GA_REG_WORD32_WRITE(MEMMAP_CHIP_CTRL_REG_BASE+ RA_Gbl_PadSelect, (reg.u32));
#if (BERLIN_CHIP_VERSION >= BERLIN_BG2)
T32Gbl_PadSelect1 reg1;
GA_REG_WORD32_READ(MEMMAP_CHIP_CTRL_REG_BASE+ RA_Gbl_PadSelect1, &(reg1.u32));
reg1.uPadSelect_DVIO0_ZP = 7;
GA_REG_WORD32_WRITE(MEMMAP_CHIP_CTRL_REG_BASE+ RA_Gbl_PadSelect1, (reg1.u32));
#endif
#endif
}
#if CDP_A0==1
#define SOC_SM_CEC_BASE 0xF7FE1000
static int detect_reset_state(void)
{
unsigned int value, warm_boot = 0;
GA_REG_WORD32_READ(SOC_SM_CEC_BASE + RA_Cec_CHIP_RESET_TRACKER, &value);
if (value == 0) {
lgpl_printf("chip is cold boot.\n");
} else {
lgpl_printf("chip is warm boot.\n");
warm_boot = 1;
}
return warm_boot;
}
// Call this to make subsequent calls to detect_reset_state "warm"
// Lasts until power cycle.
static void set_reset_state_warm(void)
{
GA_REG_WORD32_WRITE(SOC_SM_CEC_BASE + RA_Cec_CHIP_RESET_TRACKER, 0x01);
}
#else
static int detect_reset_state(void) {
return 0; /* cold boot */
}
#endif //CDP_A0==1
/* Initiailize GPIOs used by bootloader.
*/
static void board_gpio_init(void)
{
int ret = 0;
if ((ret = GPIO_PortSetInOut(BUTTON_GPIO, 1)) != 0) {
lgpl_printf("ERROR: failed to set button GPIO: %d \n",
BUTTON_GPIO);
}
#if (CFG_BOARD_NAME == BOARD_CHIRP_B1) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B3) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B4) \
|| (CFG_BOARD_NAME == BOARD_COCO_P1) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B1) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B3) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B4)
if ((ret = GPIO_PortSetInOut(TOPBOARD_INTR_GPIO, 1)) != 0) {
lgpl_printf("ERROR: failed to set top board intr GPIO: %d \n",
TOPBOARD_INTR_GPIO);
}
#elif (CFG_BOARD_NAME == BOARD_COCO_P2)
if ((ret = GPIO_PortSetInOut(LAMP_BUTTON_GPIO, 1)) != 0) {
lgpl_printf("ERROR: failed to set lamp button GPIO: %d \n",
LAMP_BUTTON_GPIO);
}
if ((ret = GPIO_PortSetInOut(VOL_UP_BUTTON_GPIO, 1)) != 0) {
lgpl_printf("ERROR: failed to set volume up button GPIO: %d \n",
VOL_UP_BUTTON_GPIO);
}
if ((ret = GPIO_PortSetInOut(VOL_DOWN_BUTTON_GPIO, 1)) != 0) {
lgpl_printf("ERROR: failed to set volume down button GPIO: %d \n",
VOL_DOWN_BUTTON_GPIO);
}
#endif
}
static void prng_init(char *kernel_param, size_t kernel_param_size)
{
UINT8 rand_buf[PRNG_DATA_SIZE];
UINT32 rand_size = sizeof(rand_buf);
int ret = bcm_generate_random_number(rand_buf,rand_size);
if (ret != 0) {
debug_printf("ERROR: failed to generate random data. ret = %d\n",ret);
return;
}
// Append 64 bytes (128-bytes in hex) to kernel command line "prng_data=".
strlcat(kernel_param, " prng_data=", kernel_param_size);
size_t i;
for (i = 0; i < sizeof(rand_buf); ++i) {
char tmp[3] = {0};
snprintf(tmp, sizeof(tmp), "%02x", rand_buf[i]);
strlcat(kernel_param, tmp, kernel_param_size);
}
// Display random bits.
debug_printf("PRNG bytes\n");
for (i = 0; i < sizeof(rand_buf); i += 16) {
int j = 0;
debug_printf("\t");
for (j = 0; j < 16; ++j) {
debug_printf("%02x", rand_buf[i + j]);
}
debug_printf("\n");
}
}
/* get button status
* !0 - pressed
* 0 - not pressed
*/
static int get_button_status(void)
{
/* For CDp, read the status of bootstrap bit at start of boot process
* rather than reading current status of button. This will capture
* user's intent to boot in to USB early in boot process, even if
* the button was released in between IROM boot -> USB timeout
* -> sys_init -> bootloader transition.
*/
int button = readl(CHIP_CTRL_REG_BASE + RA_Gbl_bootStrap) & 0x1;
return (button == 0);
}
/* Get SOC revision information */
static unsigned char get_soc_rev(void)
{
/* Bits 30:29 are marked by Marvell to flag SoC revision.
* 0x0 - A0
* 0x1 - A1 (LVT + Metal fix)
* 0x2 - A2 (Metal fix only)
*/
/*unsigned int rev = readl(MV88DE3XXX_SOC_REV_REG);
rev &= (MV88DE3XXX_SOC_REV_MASK << MV88DE3XXX_SOC_REV_SHIFT);
rev >>= MV88DE3XXX_SOC_REV_SHIFT;
return (unsigned char)rev;*/
return 0;
}
#if ANDROID_BOOT
//typedef unsigned int u32;
void setup_linux_bootparam_with_ramdisk(u32 mem_start, u32 mem_size, char *cmdline,
u32 initrd_start, u32 initrd_size,
u8 chip_rev, u8 board_rev);
static long long nand_read_generic(unsigned int start, unsigned int end, unsigned char* data_buff,
unsigned int data_size);
inline unsigned get_aligned(unsigned address, unsigned page_size) {
return (address + page_size - 1) / page_size * page_size;
}
int bootimg_print_image_hdr (boot_img_hdr *hdr)
{
int i;
UNUSED(hdr);
debug_printf (" Image magic: %s\n", hdr->magic);
debug_printf (" kernel_size: 0x%x\n", hdr->kernel_size);
debug_printf (" kernel_addr: 0x%x\n", hdr->kernel_addr);
debug_printf (" rdisk_size: 0x%x\n", hdr->ramdisk_size);
debug_printf (" rdisk_addr: 0x%x\n", hdr->ramdisk_addr);
debug_printf (" second_size: 0x%x\n", hdr->second_size);
debug_printf (" second_addr: 0x%x\n", hdr->second_addr);
debug_printf (" tags_addr: 0x%x\n", hdr->tags_addr);
debug_printf (" page_size: 0x%x\n", hdr->page_size);
debug_printf (" name: %s\n", hdr->name);
debug_printf (" cmdline: %s\n", hdr->cmdline);
for (i=0;i<8;i++)
debug_printf (" id[%d]: 0x%x\n", i, hdr->id[i]);
return 0;
}
static int write_android_bootloader_message(const char *command,
const char *status,
const char *recovery)
{
int res = flash_ts_set("bootloader.command", command);
if (!res)
res = flash_ts_set("bootloader.status", status);
if (!res)
res = flash_ts_set("bootloader.recovery", recovery);
else {
debug_printf("Failed to set bootloader command\n");
}
return res;
}
static unsigned long checked_usb_read(int device, unsigned long blknr,
unsigned long blkcnt, void *buffer) {
block_dev_desc_t desc;
if (get_usb_storage_desc(device, &desc) != 0) {
debug_printf("Failed to get device descriptor for usb storage "
"device %d\n", device);
return 0;
}
if (desc.blksz != USB_BLOCK_SIZ) {
debug_printf("Invalid USB block size. Expected :%zu. Got: %zu",
(size_t)USB_BLOCK_SIZ, (size_t)desc.blksz);
return 0;
}
return usb_stor_read(device, blknr, blkcnt, buffer);
}
#ifndef DISABLE_CRASH_COUNTER
void set_android_crash_counter(int cnt)
{
char value[4] = {0};
if (cnt < 0) cnt = 0;
if (cnt > 99) cnt = 99;
if (cnt >= 10) {
value[0] = '0' + (cnt / 10);
value[1] = '0' + (cnt % 10);
} else {
value[0] = '0' + cnt;
}
flash_ts_set(ANDROID_CRASH_COUNTER_KEY, value);
lgpl_printf("set crashcounter to %d\n", cnt);
}
void increase_android_crash_counter(void)
{
int crash_counter = flash_ts_get_int(ANDROID_CRASH_COUNTER_KEY, 0);
if (crash_counter <= MAX_CRASH_COUNT) {
set_android_crash_counter(crash_counter + 1);
}
}
#endif // !DISABLE_CRASH_COUNTER
int check_android_recovery_mode(void)
{
char boot_command[256] = {0};
int button_status;
#ifndef DISABLE_CRASH_COUNTER
int crash_counter = flash_ts_get_int(ANDROID_CRASH_COUNTER_KEY, 0);
debug_printf ("fts: %s: %d\n", ANDROID_CRASH_COUNTER_KEY, crash_counter);
#endif // !DISABLE_CRASH_COUNTER
flash_ts_get(BOOTLOADER_COMMAND_KEY, boot_command, sizeof(boot_command));
debug_printf ("fts: %s: %s\n", BOOTLOADER_COMMAND_KEY, boot_command);
if (strncmp(boot_command, kFtsBootcmdRecovery, sizeof(kFtsBootcmdRecovery)) == 0) {
return BOOTMODE_RECOVERY;
}
if (strncmp(boot_command, kFtsBootcmdBackupsys,
sizeof(kFtsBootcmdBackupsys)) == 0) {
return BOOTMODE_BACKUPSYS;
}
/* Boot in to USB on button press only if no other
* conditions for booting in to recovery are being met. Since
* button press is also used for factory reset, request to
* boot in to recovery in fts overrides button press.
*/
button_status = get_button_status();
if (button_status){
lgpl_printf("Detected button press -- booting from USB\n");
return BOOTMODE_BOOTUSB;
}
#ifndef DISABLE_CRASH_COUNTER
if (crash_counter > MAX_CRASH_COUNT) {
if (!flash_ts_get_int("crashcounter-disable", 0)) {
lgpl_printf("force FDR due to crashcounter: %d\n", crash_counter);
write_android_bootloader_message("boot-recovery",
"", "recovery\n--wipe_data\n");
/* set_android_crash_counter(0) is called at start_android_kernel */
return BOOTMODE_RECOVERY;
}
}
lgpl_printf("boot normally (crashcounter: %d)\n", crash_counter);
#endif // !DISABLE_CRASH_COUNTER
return BOOTMODE_NORMAL;
}
#include "sha1.h"
static unsigned int swap32(unsigned int x)
{
unsigned y;
y = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0x00FF00FF);
y = (y >> 16) | (y << 16);
return y;
}
int verify_android_image(const unsigned char *img_start, unsigned int len)
{
int i;
SHA1Context sha; /* SHA-1 context */
const boot_img_hdr *hdr = (const boot_img_hdr *)img_start;
const unsigned char *kernel_data = img_start + hdr->page_size;
const unsigned char *ramdisk_data = kernel_data + get_aligned(hdr->kernel_size, hdr->page_size);
const unsigned char *second_data = ramdisk_data + get_aligned(hdr->ramdisk_size, hdr->page_size);
SHA1Reset(&sha);
SHA1Input(&sha, kernel_data, hdr->kernel_size);
SHA1Input(&sha, (const unsigned char *)&hdr->kernel_size, sizeof(hdr->kernel_size));
SHA1Input(&sha, ramdisk_data, hdr->ramdisk_size);
SHA1Input(&sha, (const unsigned char *)&hdr->ramdisk_size, sizeof(hdr->ramdisk_size));
SHA1Input(&sha, second_data, hdr->second_size);
SHA1Input(&sha, (const unsigned char *)&hdr->second_size, sizeof(hdr->second_size));
if (!SHA1Result(&sha))
printf("bootimg SHA: could not compute message digest\n");
else {
/* convert it into mkbootimg header's byte sequence */
for (i = 0; i < 5; i++)
sha.Message_Digest[i] = swap32(sha.Message_Digest[i]);
for (i = 0; i < 5; i++)
if (sha.Message_Digest[i] != hdr->id[i]) {
printf("bootimg SHA1 verify fail: start 0x%08x, size %d\n"
"\tOrig %08X %08X %08X %08X %08X\n"
"\tCalc %08X %08X %08X %08X %08X\n",
(unsigned int)img_start, len,
hdr->id[0],
hdr->id[1],
hdr->id[2],
hdr->id[3],
hdr->id[4],
sha.Message_Digest[0],
sha.Message_Digest[1],
sha.Message_Digest[2],
sha.Message_Digest[3],
sha.Message_Digest[4]);
return -1;
}
return 0;
}
return -1;
}
static int bootimg_hdr_verify(unsigned char *img, int boot_src)
{
UNUSED(img);
UNUSED(boot_src);
#if (CFG_BOARD_NAME == BOARD_LEXX_B4) \
|| (CFG_BOARD_NAME == BOARD_EARTH_B4) \
|| (CFG_BOARD_NAME == BOARD_HENDRIX_B4) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B4) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B4) \
|| (CFG_BOARD_NAME == BOARD_CAPRICA_B4)
unsigned short img_magic = *(short *)(img + CPU_IMG_OFFS_MAGIC);
unsigned char code_type = img[7];
unsigned short img_udata = *(short *)(img + CPU_IMG_OFFS_USRDATA);
if (boot_src == BOOT_SRC_USB){
/* TODO(kolla): Enable checks for ver, mkt_id etc.*/
if (img_magic != CPU_IMG_CODE_MAGIC)
return -1;
if (code_type != BCM_IMG_USBIMG_TYPE)
return -1;
if (img_udata != CPU_IMG_USB_USRDATA)
return -1;
} else {
/* TODO(kolla): Enable robust header checks for NAND image.*/
if (img_magic != CPU_IMG_CODE_MAGIC)
return -1;
if (code_type != BCM_IMG_KERNEL_TYPE)
return -1;
if (img_udata != CPU_IMG_NAND_USRDATA)
return -1;
}
#endif // BOARD_{LEXX,EARTH,HENDRIX,CHIRP,JOPLIN,CAPRICA}_B4
return 0;
}
static int load_android_image(int bootmode, int boot_src)
{
ver_table_entry_t *vt_android;
int iPageSize;
int iBlockSize;
unsigned int android_start, android_end;
int ret;
unsigned mkbootimg_page;
unsigned char* k_buff;
unsigned int k_buff_size;
unsigned int k_buff_offset;
unsigned int cpu_img_siz = 0;
int usb_stor_cnt;
unsigned char* k_buff_img;
unsigned int bcm_img_type = BCM_IMG_KERNEL_TYPE;
unsigned long hdr_blk_cnt = get_aligned(CPU_IMG_OFFS_IMGSTA,
USB_BLOCK_SIZ)/USB_BLOCK_SIZ;
UNUSED(iPageSize);
/* Use memory near the end of DDR for loading
* Android image for verification. Bootloader has
* configured MMU for flat memory map, i.e. VA == PA.
*/
k_buff = (unsigned char *)ANDROID_IMG_BUF;
/* Actual image may start with an offset in k_buff */
k_buff_img = k_buff;
/* Wipe the scratch memory first to make sure nothing */
/* is present from the last boot attempt. */
memset(k_buff, 0, MAX_ANDROID_IMG_SIZE);
if (boot_src == BOOT_SRC_USB){
#ifdef CONFIG_USB
android_start = USB_BOOTIMG_START/USB_BLOCK_SIZ;
ret = usb_init();
if (ret < 0){
lgpl_printf("ERROR: Failed to usb_init ret %d\n", ret);
return -1;
}
/* recognize storage devices */
usb_stor_cnt = usb_stor_scan();
if (!usb_stor_cnt){
lgpl_printf("ERROR: No USB storage device detected\n");
return -1;
}
#if (CFG_BOARD_NAME == BOARD_LEXX_B4) \
|| (CFG_BOARD_NAME == BOARD_EARTH_B4) \
|| (CFG_BOARD_NAME == BOARD_HENDRIX_B4) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B4) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B4) \
|| (CFG_BOARD_NAME == BOARD_CAPRICA_B4)
/* Prepend keystores used for sign verification and decryption
* to the image being read.
*/
/* TODO(kolla): Fix CUSTK, encryption of RSAK */
memcpy(k_buff_img, usb_extrsak_store, sizeof(usb_extrsak_store));
k_buff_img += USB_EXT_RSAKSTORE_LEN;
#endif // BOARD_{LEXX,EARTH,HENDRIX,CHIRP,JOPLIN,CAPRICA}_B4
lgpl_printf("Reading %d blocks from USB device \n", hdr_blk_cnt);
/* Read from first USB device */
if(checked_usb_read(0, android_start, hdr_blk_cnt, k_buff_img) != hdr_blk_cnt) {
lgpl_printf("ERROR: Failed to read CPU image header from USB \n");
return -1;
}
lgpl_printf("Read %d blocks from USB device \n", hdr_blk_cnt);
#else
debug_printf("ERROR: USB boot is not supported\n");
return -1;
#endif // CONFIG_USB
}else{
if (bootmode == BOOTMODE_RECOVERY)
vt_android = (ver_table_entry_t *)&vt_recovery;
else if (bootmode == BOOTMODE_BACKUPSYS)
vt_android = (ver_table_entry_t *)&vt_backupsys;
else
vt_android = (ver_table_entry_t *)&vt_kernel;
iPageSize = nand_data.szofpg ;
iBlockSize = nand_data.szofblk;
android_start = vt_android->part1_start_blkind;
android_end = android_start + vt_android->part1_blks;
android_start *= iBlockSize;
android_end *= iBlockSize;
debug_printf("NAND: Start to read CPU image header!\n");
/* Read CPU image header to determing length of the image */
ret = nand_read_generic(android_start ,
android_end,
k_buff_img, USB_BLOCK_SIZ);
if (ret < 0){
debug_printf("NAND: Failed to read CPU image header!\n");
return -1;
}
}
cpu_img_siz = *((unsigned int *)(k_buff_img + CPU_IMG_OFFS_IMGSIZ));
cpu_img_siz = get_aligned(cpu_img_siz, 16);
cpu_img_siz += CPU_IMG_OFFS_IMGSTA;
/* Add min size check to be safe */
int reqd_buf_siz = cpu_img_siz + k_buff_img - k_buff;
if (reqd_buf_siz > MAX_ANDROID_IMG_SIZE || reqd_buf_siz < MIN_ANDROID_IMG_SIZE) {
debug_printf("ERROR: aligned CPU img_siz %u is invalid\n",
reqd_buf_siz);
return -1;
}
if (boot_src == BOOT_SRC_USB){
#ifdef CONFIG_USB
int blk_cnt;
int ret;
blk_cnt = get_aligned(cpu_img_siz, USB_BLOCK_SIZ)/USB_BLOCK_SIZ;
/* Always read from first USB storage device */
lgpl_printf("Reading %d blocks from USB device \n", blk_cnt);
ret = checked_usb_read(0,
(android_start + hdr_blk_cnt),
(blk_cnt - hdr_blk_cnt),
(k_buff_img + hdr_blk_cnt * USB_BLOCK_SIZ));
if (ret != (int)(blk_cnt - hdr_blk_cnt)){
lgpl_printf("ERROR: Failed to read CPU image blk_cnt %d ret %d\n",
(blk_cnt - hdr_blk_cnt), ret);
return -1;
}
lgpl_printf("Read %d blocks from USB device \n", blk_cnt);
/* There can be trailing bytes beyond the end of the image */
/* due to rounding up to USB_BLOCK_SIZ (and which would */
/* otherwise be unverified). Might as well zero all remaining */
/* memory to be safer. */
int trailing_bytes = MAX_ANDROID_IMG_SIZE - reqd_buf_siz;
if (trailing_bytes > 0) {
lgpl_printf("NOTE: %x trailing bytes zeroed\n", trailing_bytes);
memset(k_buff_img + cpu_img_siz, 0, trailing_bytes);
}
bcm_img_type = BCM_IMG_USBIMG_TYPE;
#endif // CONFIG_USB
}else{
ret = nand_read_generic(android_start,
android_end,
k_buff_img,
cpu_img_siz);
if (ret < 0){
lgpl_printf("ERROR: Failed to read CPU image ret %d\n",
ret);
return -1;
}
}
/* Verify image header */
ret = bootimg_hdr_verify(k_buff_img, boot_src);
if (ret) {
lgpl_printf("ERROR: Boot image verify header failed!ret=0x%x\n", ret);
return -1;
}
ret = bcm_image_verify(bcm_img_type, (unsigned) k_buff, (unsigned) k_buff);
if (ret) {
lgpl_printf("ERROR: Verify k_buff image failed!ret=0x%x\n", ret);
return -1;
}
memcpy(&Mkbootimg_hdr, k_buff, sizeof(Mkbootimg_hdr));
if (strncmp((const char *)Mkbootimg_hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
printf("ERROR: Invalid mkbootimg header!\n");
return -1;
}
/* force to use predefined kernel addr (CPU0_START_ADDR) in config.
* We don't use the kernel_addr from kernel partition for scurity
* consideration.
*/
Mkbootimg_hdr.kernel_addr = CPU0_START_ADDR;
TheKernel = (void (*)(int, int, unsigned int))(Mkbootimg_hdr.kernel_addr);
mkbootimg_page = Mkbootimg_hdr.page_size;
// align by page_size and add one page for skipping header.
k_buff_size = mkbootimg_page +
get_aligned(Mkbootimg_hdr.kernel_size, mkbootimg_page) +
get_aligned(Mkbootimg_hdr.ramdisk_size, mkbootimg_page) +
get_aligned(Mkbootimg_hdr.second_size, mkbootimg_page);
/* Check bootloader has enough memory to be able to
* read the firmware image for verification.
*/
if (k_buff_size > MAX_ANDROID_IMG_SIZE){
debug_printf("BOOTLOADER: Firmware image is too big %d for "
"verification\n",
k_buff_size);
return -1;
}
UtilMemCpy((void *)Mkbootimg_hdr.kernel_addr, k_buff + mkbootimg_page, Mkbootimg_hdr.kernel_size);
if (Mkbootimg_hdr.ramdisk_size) {
k_buff_offset = get_aligned(Mkbootimg_hdr.kernel_size + mkbootimg_page, mkbootimg_page);
UtilMemCpy((void *)Mkbootimg_hdr.ramdisk_addr, k_buff + k_buff_offset, Mkbootimg_hdr.ramdisk_size);
}
bootimg_print_image_hdr(&Mkbootimg_hdr);
return 0;
}
// Set mac address for 8801.
static void make_wifi_macaddr(char *wifi_mac_addr_buf)
{
long chipid_reg1;
char *p;
int i;
// Use lowest 24 bit from chip ID.
chipid_reg1 = readl(MV88DE3100_CHIPID_REG1) ;
strcpy(wifi_mac_addr_buf, "F8:8F:CA");
p = wifi_mac_addr_buf + strlen(wifi_mac_addr_buf);
for(i = 0;i < 3; ++i) {
char hex;
hex = chipid_reg1 >> (16 - 8 * i);
*p++ = ':';
*p++ = itoc(hex>>4);
*p++ = itoc(hex);
}
*p = '\0';
}
void setup_android_kernel_param(int boot_mode)
{
char kernel_param[1024];
char wifi_mac_addr[64] = {0};
char tmp_buf[256];
//add flash_ts dev_id info
snprintf(tmp_buf, sizeof(tmp_buf),
" flash_ts.dev_id=%d flash_ts.size=%d flash_ts.erasesize=%d flash_ts.writesize=%d",
fts_dev_id, vt_fts.part1_blks * nand_data.szofblk, nand_data.szofblk, nand_data.szofpg);
lgpl_printf("mkbootimg bootargs: %s\n", Mkbootimg_hdr.cmdline);
strlcpy(kernel_param, (CHAR *)Mkbootimg_hdr.cmdline,
sizeof(kernel_param));
/* Append mac address and fts command line params to kernel
* command line.
*/
strlcat(kernel_param, " ", sizeof(kernel_param));
strlcat(kernel_param, tmp_buf, sizeof(kernel_param));
#if CDP_A0==1
if (PMIC_type > PMIC_TYPE_UNKNOWN && PMIC_type < PMIC_TYPE_MAX) {
int pmic_pg86x = 0, sy20212b = 0;
if (PMIC_type == PMIC_TYPE_PG86X) {
pmic_pg86x = 1;
} else if (PMIC_type == PMIC_TYPE_SY20212B) {
sy20212b = 1;
}
// Append PMIC kernel params
snprintf(tmp_buf, sizeof(tmp_buf), " sy8824x.enable=%d 88pg86x.enable=%d", sy20212b, pmic_pg86x);
strlcat(kernel_param, tmp_buf, sizeof(kernel_param));
} else { /* for debugging purpose. export the i2cget value to kernel command line */
extern int pg86x_val, sy21202_val;
snprintf(tmp_buf, sizeof(tmp_buf), " sy21202_val=0x%x pg86x_val=0x%x", sy21202_val, pg86x_val);
strlcat(kernel_param, tmp_buf, sizeof(kernel_param));
}
#endif
if (Mkbootimg_hdr.ramdisk_size) {
memset(tmp_buf, 0, sizeof(tmp_buf));
strlcat(kernel_param, tmp_buf, sizeof(kernel_param));
}
lgpl_printf("Generated bootargs: %s\n", kernel_param);
/* Setup androidboot.hardware and androidboot.bootmode
* params needed by kernel. Allow boot from USB to gain all
* permissions a recovery image would have.
*/
strlcat(kernel_param, " androidboot.hardware="XSTR(BOARD_NAME),
sizeof(kernel_param));
if (boot_mode == BOOTMODE_NORMAL)
strlcat(kernel_param, " androidboot.mode=normal",
sizeof(kernel_param));
else if ((boot_mode == BOOTMODE_RECOVERY) ||
(boot_mode == BOOTMODE_BOOTUSB))
strlcat(kernel_param, " androidboot.mode=recovery",
sizeof(kernel_param));
else if (boot_mode == BOOTMODE_BACKUPSYS)
strlcat(kernel_param, " androidboot.mode=backupsys",
sizeof(kernel_param));
else
lgpl_printf("ERROR: unknown boot mode %d \n", boot_mode);
/* Pass bootloader version info to kernel */
strlcat(kernel_param, " androidboot.bootloader="BOOTLOADER_VERSION,
sizeof(kernel_param));
/* Pass NAND boot path source info to kernel */
{
const volatile BERLIN_BOOTINFO *pinfo = (BERLIN_BOOTINFO *)BERLIN_BOOTINFO_ADDR;
snprintf(tmp_buf, sizeof(tmp_buf),
" nandboot.src_block_num=0x%08x%08x",
pinfo->nand_src_blk_num[1], pinfo->nand_src_blk_num[0]);
strlcat(kernel_param, tmp_buf, sizeof(kernel_param));
}
/* If the fts param for wifi mfg mode is set, pass module
* params to enable wifi mfg mode.
*/
flash_ts_get(FTS_WIFI_MFG_MODE, tmp_buf, sizeof(tmp_buf));
if ((boot_mode == BOOTMODE_NORMAL) && !strcmp("1", tmp_buf)) {
#if (CFG_BOARD_NAME == BOARD_EARTH_B1) \
|| (CFG_BOARD_NAME == BOARD_EARTH_B2) \
|| (CFG_BOARD_NAME == BOARD_EARTH_B3) \
|| (CFG_BOARD_NAME == BOARD_EARTH_B4) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B1) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B3) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B4) \
|| (CFG_BOARD_NAME == BOARD_COCO_P1) \
|| (CFG_BOARD_NAME == BOARD_COCO_P2) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B1) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B3) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B4) \
|| (CFG_BOARD_NAME == BOARD_HENDRIX_B1) \
|| (CFG_BOARD_NAME == BOARD_HENDRIX_B3) \
|| (CFG_BOARD_NAME == BOARD_HENDRIX_B4) \
|| (CFG_BOARD_NAME == BOARD_CAPRICA_B1) \
|| (CFG_BOARD_NAME == BOARD_CAPRICA_B3) \
|| (CFG_BOARD_NAME == BOARD_CAPRICA_B4)
strlcat(kernel_param, " sd8887.mfg_mode=1 sd8887.drv_mode=1",
sizeof(kernel_param));
strlcat(kernel_param, " sd8887.fw_name=mrvl/sd8887_mfg_wlan.bin",
sizeof(kernel_param));
strlcat(kernel_param, " bt8xxx.fw_name=mrvl/sd8887_mfg_bt.bin",
sizeof(kernel_param));
strlcat(kernel_param, " sd8887.cal_data_cfg=mrvl/WlanCalData_sd8887-b1.conf",
sizeof(kernel_param));
strlcat(kernel_param, " sd8887.cfg80211_drcs=0",
sizeof(kernel_param));
strlcat(kernel_param, " sd8887.ps_mode=2",
sizeof(kernel_param));
strlcat(kernel_param, " sd8887.uap_oper_ctrl=0x20001",
sizeof(kernel_param));
#else
strlcat(kernel_param, " sd8801.mfg_mode=1 sd8801.drv_mode=1",
sizeof(kernel_param));
strlcat(kernel_param, " sd8801.fw_name=mrvl/sd8801_mfg.bin",
sizeof(kernel_param));
strlcat(kernel_param, " sd8801.cfg80211_drcs=0",
sizeof(kernel_param));
strlcat(kernel_param, " sd8801.ps_mode=2",
sizeof(kernel_param));
strlcat(kernel_param, " sd8801.hw_test=1",
sizeof(kernel_param));
#endif
} else {
// Set MAC address only in non-MFG mode.
make_wifi_macaddr(wifi_mac_addr);
// Set calibration config file.
#if (CFG_BOARD_NAME == BOARD_LEXX_B3) \
|| (CFG_BOARD_NAME == BOARD_LEXX_B4)
strlcat(kernel_param, " sd8801.cal_data_cfg=mrvl/WlanCalData_sd8801-b2.conf",
sizeof(kernel_param));
strlcat(kernel_param, " sd8801.mac_addr=", sizeof(kernel_param));
strlcat(kernel_param, wifi_mac_addr, sizeof(kernel_param));
strlcat(kernel_param, " sd8801.txpwrlimit_cfg=mrvl/txpwr",
sizeof(kernel_param));
strlcat(kernel_param, " sd8801.cfg80211_drcs=0",
sizeof(kernel_param));
strlcat(kernel_param, " sd8801.ps_mode=2", sizeof(kernel_param));
strlcat(kernel_param, " sd8801.hw_test=1", sizeof(kernel_param));
#elif (CFG_BOARD_NAME == BOARD_EARTH_B1) \
|| (CFG_BOARD_NAME == BOARD_EARTH_B2) \
|| (CFG_BOARD_NAME == BOARD_EARTH_B3) \
|| (CFG_BOARD_NAME == BOARD_EARTH_B4) \
|| (CFG_BOARD_NAME == BOARD_HENDRIX_B1) \
|| (CFG_BOARD_NAME == BOARD_HENDRIX_B3) \
|| (CFG_BOARD_NAME == BOARD_HENDRIX_B4) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B1) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B3) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B4) \
|| (CFG_BOARD_NAME == BOARD_COCO_P1) \
|| (CFG_BOARD_NAME == BOARD_COCO_P2) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B1) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B3) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B4) \
|| (CFG_BOARD_NAME == BOARD_CAPRICA_B1) \
|| (CFG_BOARD_NAME == BOARD_CAPRICA_B3) \
|| (CFG_BOARD_NAME == BOARD_CAPRICA_B4)
strlcat(kernel_param, " sd8887.cal_data_cfg=mrvl/WlanCalData_sd8887-b1.conf", sizeof(kernel_param));
strlcat(kernel_param, " sd8887.fw_name=mrvl/sd8887_wlan_a2.bin",
sizeof(kernel_param));
strlcat(kernel_param, " sd8887.auto_ds=2",
sizeof(kernel_param));
strlcat(kernel_param, " sd8887.mac_addr=",
sizeof(kernel_param));
strlcat(kernel_param, wifi_mac_addr, sizeof(kernel_param));
strlcat(kernel_param, " sd8887.txpwrlimit_cfg=mrvl/txpwr",
sizeof(kernel_param));
strlcat(kernel_param, " sd8887.cfg80211_drcs=0",
sizeof(kernel_param));
strlcat(kernel_param, " sd8887.ps_mode=2",
sizeof(kernel_param));
strlcat(kernel_param, " sd8887.uap_oper_ctrl=0x20001",
sizeof(kernel_param));
strlcat(kernel_param, " bt8xxx.fw_name=mrvl/sd8887_bt_a2.bin",
sizeof(kernel_param));
strlcat(kernel_param, " bt8xxx.bt_fw_serial=0",
sizeof(kernel_param));
#endif
}
#if CDP_A0==1
int rv = detect_reset_state();
snprintf(tmp_buf, sizeof(tmp_buf), " warm_boot=%d", rv);
strlcat(kernel_param, tmp_buf, sizeof(kernel_param));
#endif // CDP_A0==1
prng_init(kernel_param, sizeof(kernel_param));
setup_linux_bootparam_with_ramdisk(Mkbootimg_hdr.kernel_addr - 0x8000,
MEMORY_SIZE - Mkbootimg_hdr.kernel_addr,
kernel_param,
Mkbootimg_hdr.ramdisk_addr,
Mkbootimg_hdr.ramdisk_size,
get_soc_rev(), BOARD_REV);
}
#if (CFG_BOARD_NAME == BOARD_CHIRP_B1) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B3) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B4) \
|| (CFG_BOARD_NAME == BOARD_COCO_P1) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B1) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B3) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B4)
static void set_topboard_leds(unsigned char led_slave_addr,
unsigned char* led_frame,
size_t led_frame_size,
enum led_chip_model_t model) {
if (detect_reset_state() == 1) {
// This is a warm boot, do not show LEDs
return;
}
// Boot is cold. Show LEDs.
// See mapping at
// Chirp:
// https://docs.google.com/document/d/1L_DVMgrjZeU3MMt8VjrJeZIAtCuu-HxV1DrQcBH0fTg
// Joplin:
// https://docs.google.com/document/d/1DpCafQJHLSdMjOAKXNlkX9_osCplYxzsBgVyqlK8_yo
diag_i2c_led_set_frame(LED_MASTER_ID, led_slave_addr, led_frame,
led_frame_size, model);
}
#endif // BOARD_CHIRP_B{1,3,4} BOARD_JOPLIN_B{1,3,4}
#if (CFG_BOARD_NAME == BOARD_COCO_P1) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B1) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B3) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B4)
static void get_device_color(char color[], size_t n) {
flash_ts_get(FTS_KEY_COLOR, color, n);
}
#endif // BOARD_COCO_P1, BOARD_JOPLIN_B{1,3,4}
void start_android_kernel(void)
{
// TODO: Set appropriate arch parameter.
unsigned arch = 0;
unsigned params = Mkbootimg_hdr.kernel_addr - 0x8000 + 0x100;
if (Bootmode == BOOTMODE_NORMAL) {
lgpl_printf("Boot normal GTV image\n");
// crash counter will be cleared after completing GTV boot (by CrashCounter app)
#ifndef DISABLE_CRASH_COUNTER
if (!detect_reset_state()) {
lgpl_printf("cold boot\n");
increase_android_crash_counter(); /* cold boot only */
} else {
lgpl_printf("warm boot\n");
}
#endif // !DISABLE_CRASH_COUNTER
} else {
lgpl_printf("Boot recovery image\n");
#ifndef DISABLE_CRASH_COUNTER
set_android_crash_counter(0);
#endif // !DISABLE_CRASH_COUNTER
}
#if (CFG_BOARD_NAME == BOARD_CHIRP_B1) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B3) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B4)
unsigned char led_frame_15[18] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF};
unsigned char led_frame_17[18] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00};
set_topboard_leds(0x15, led_frame_15, ARRAY_SIZE(led_frame_15),
LED_MODEL_PCA9956B);
set_topboard_leds(0x17, led_frame_17, ARRAY_SIZE(led_frame_17),
LED_MODEL_PCA9956B);
#elif (CFG_BOARD_NAME == BOARD_COCO_P1) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B1) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B3) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B4)
char color[64] = {0};
get_device_color(color, sizeof(color));
// Reduce Red by 50% on campari color devices
if (!strcmp("campari", color)) {
unsigned char led_frame_17[16] = {0x00, 0xFF, 0x80, 0x64,
0x00, 0xFF, 0x80, 0x64,
0x00, 0x64, 0x80, 0xFF,
0x00, 0x64, 0x80, 0xFF};
set_topboard_leds(0x17, led_frame_17, ARRAY_SIZE(led_frame_17),
LED_MODEL_PCA9955B);
} else {
unsigned char led_frame_17[16] = {0x00, 0xFF, 0xFF, 0x64,
0x00, 0xFF, 0xFF, 0x64,
0x00, 0x64, 0xFF, 0xFF,
0x00, 0x64, 0xFF, 0xFF};
set_topboard_leds(0x17, led_frame_17, ARRAY_SIZE(led_frame_17),
LED_MODEL_PCA9955B);
}
#endif // BOARD_CHIRP_B{1,3,4} BOARD_COCO_P1 BOARD_JOPLIN_B{1,3,4}
#if CDP_A0==1
set_reset_state_warm();
#endif //CDP_A0==1
lgpl_printf("Start kernel at 0x%08x\n", Mkbootimg_hdr.kernel_addr);
__reset_cpu((int)TheKernel , 1330, params) ;
TheKernel (0, arch, params);
}
#endif // ANDROID_BOOT
/*
* return: the block address after the last block of the image
*/
static long long nand_read_generic(unsigned int start, unsigned int end, unsigned char* data_buff,
unsigned int data_size)
{
unsigned int i,j,k;
unsigned int block_size, page_size;
int page_buff[8448/4];
unsigned int residual, br;
block_size = nand_data.szofblk;
page_size = nand_data.szofpg;
if((start & (block_size - 1)) || (end & (block_size - 1)))
return -1;
if( (end < start) || (end - start < data_size))
return -1;
j=0;
for(i=start;i<end;i+=block_size) {
residual = data_size - j;
br = residual < block_size ? residual : block_size;
if(j >= data_size)
break;
if(is_block_bad((loff_t)i)) {
debug_printf("Bad block found @0x%08x.\n", i);
continue;
}
for(k=0;k<br;k+=page_size) {
unsigned int resd = br - k;
unsigned int cp_size = resd < page_size ? resd : page_size;
//get_nand_partition_type((loff_t)i + k);
//if(NFlash_PageRead((loff_t)i + k, page_buff))
//int mv_nand_read_large_page(loff_t srcx , char *buf, int oob)
if (page_size != (UINT32)mv_nand_read_block( (loff_t)i+k, (CHAR *)page_buff, page_size))
{
lgpl_printf("Read failed @ 0x%08x\n", i + k);
return -1;
}
UtilMemCpy(data_buff + j + k, page_buff, cp_size);
}
j+=block_size;
}
if(j < data_size)
return -1;
return i;
}
#define NW_START 0x01000000
/*
* ECC strength parameter is for A0
* fix addr_cycle to 5
*/
int init_nfc(int block_size, int page_size, int ecc_strength)
{
// int ret=0;
// configure device
unsigned int nand_param_buff[4];
nand_data.szofpg = page_size;
nand_data.szofblk = block_size;
nand_data.t = ecc_strength;
if((nand_data.szofpg != 512) && (nand_data.szofpg != 2048) &&
(nand_data.szofpg != 4096) && (nand_data.szofpg != 8192)) {
UtilMemCpy((char*)nand_param_buff, (char *)(NW_START + 16), 16);
nand_data.szofpg = nand_param_buff[0];
nand_data.t = nand_param_buff[1];
nand_data.szofblk = nand_param_buff[2];
printf("[%s:%d] get nand parameters from tz_loder (block_size=%d, page_size=%d, ecc=%d)\n",
__func__, __LINE__, nand_data.szofblk, nand_data.szofpg, nand_data.t);
}
if((nand_data.szofpg != 512) && (nand_data.szofpg != 2048) &&
(nand_data.szofpg != 4096) && (nand_data.szofpg != 8192)) {
#if 1
nand_data.szofpg = 0x1000;
nand_data.szofblk = 0x100000;
nand_data.t = 48;
printf("[%s:%d] force nand parameters(block_size=%d, page_size=%d, ecc=%d)\n",
__func__, __LINE__, nand_data.szofblk, nand_data.szofpg, nand_data.t);
#else
printf("[%s:%d] error nand parameters(block_size=%d, page_size=%d, ecc=%d)\n",
__func__, __LINE__, block_size, page_size, ecc_strength);
return -1;
#endif
}
debug_printf("NAND block size %d, page size %d, ecc_strength %d\n",
nand_data.szofblk, nand_data.szofpg, nand_data.t);
NFlash_Init();
#if 0
if(NFlash_ResetDevice()){
lgpl_printf("Reset NAND error!\n");;
// while(1);
}
if( (ret = NAND_ReadData( (unsigned char *)0,
(unsigned char *)(&block0), sizeof(block0_t) )) != 0 ) {
lgpl_printf("Read NAND block0 error, ret = %u!\n", ret);;
// while(1);
return ret;
}
nand_data.ndtr0cs0 = block0.ndtr0cs0;
nand_data.ndtr1cs0 = block0.ndtr1cs0;
nand_data.ndredel = block0.ndredel;
NFlash_Init();
if(NFlash_ResetDevice()){
lgpl_printf("reinit NAND error!\n");;
while(1);
}
#endif
return 0;
}
void DisableInterrupt(void)
{
// int my_cpsr ;
__asm__ __volatile__(
"MRS r0, CPSR" "\n\t" //get CRPR
"BIC r0, #0xC0" "\n\t" // disable IRQ and FIQ
"MSR CPSR, r0" "\n\t"
:
:
:"r0"
);
}
inline int ctoi(char c)
{
if((c>='0')&&(c<='9'))
return c-'0';
else if((c>='a')&&(c<='f'))
return c-'a' + 10;
else if((c>='A')&&(c<='F'))
return c-'A' + 10;
else
return -1;
}
inline char itoc(char i)
{
int j = i&0xf;
if(j<10)
return j+'0';
else
return j-10+'A';
}
#define SOC_WOL_BASE 0xf7fe0000
void set_wol_macaddr(char* mac)
{
int i=0;
int value[2];
char *p=(char*)value;
printf("WOL MAC address: %s\n", mac);
for(i=0;i<6;i++){
p[i]=(ctoi(mac[3*i])<<4) + ctoi(mac[3*i+1]);
}
#if !CDP_A0
writel(value[0], (SOC_WOL_BASE + RA_WOL_MAC_ADDR_LO));
writel(value[1], (SOC_WOL_BASE + RA_WOL_MAC_ADDR_HI));
#endif /* FIXME: A0 bring up */
}
#if !ANDROID_BOOT
/*
* Get MAC address from NAND
*/
static int get_mac_addr(char* macaddr)
{
int i;
#define NAND_UBOOT_ENV_BLOCK_START (12)
int uboot_env_start = NAND_UBOOT_ENV_BLOCK_START * nand_data.szofblk;
int uboot_env_end = 0x4000000;
int uboot_env_size = 0x1000;
char *env_buff = UtilMemAlloc(uboot_env_size);
int blk_size = nand_data.szofblk;
char *tmp_buf;
for(i=0;i<4;i++) {
if(nand_read_generic(uboot_env_start + i*blk_size,
uboot_env_end, (unsigned char *)env_buff,
uboot_env_size) >= 0) {
break;
}
}
if(i==4) {
UtilMemCpy(macaddr, "macaddr=00:11:22:33:44:55", 25);
macaddr[25]='\0';
return -1;
}
i=0;
while(i<uboot_env_size) {
tmp_buf = strstr(env_buff, "ethaddr=");
if(tmp_buf)
break;
i += strlen(env_buff);
env_buff += strlen(env_buff);
i++;
env_buff++;
}
// lgpl_printf("uboot env: %s\n", env_buff);
if(i>=uboot_env_size) {
UtilMemCpy(macaddr, "macaddr=00:11:22:33:44:55", 25);
macaddr[25]='\0';
return -1;
}
strcpy(macaddr, "macaddr=");
UtilMemCpy(macaddr+8, tmp_buf+8, 17);
macaddr[25]='\0';
return 0;
}
#endif // !ANDROID_BOOT
#if !ANDROID_BOOT
static void init_mac_address(long long chipid, const char* old_param, char* new_param)
{
int len;
char *new = new_param;
debug_printf("cpu id:%08x %08x\n", (int)(chipid>>32), (int)(chipid));
len = strlen(old_param);
UtilMemCpy(new, old_param, len);
new+=len;
*new = ' ';
new++;
make_mac_from_chipid(chipid, new);
set_wol_macaddr(new+8);
/*
UtilMemCpy(new, " macaddr=",sizeof(" macaddr=")-1);
new+=sizeof(" macaddr=")-1;
*new++='0';
*new++='0';
for(i=0;i<5;i++) {
char hex;
hex = chipid >> (32-8*i);
*new++=':';
*new++=itoc(hex>>4);
*new++=itoc(hex);
}
*new='\0';
*/
}
static long long get_next_img_addr(unsigned int start, unsigned int end, unsigned int data_size)
{
unsigned int i,j;
unsigned int block_size;
block_size = nand_data.szofblk;
j = (data_size + block_size - 1) & ~(block_size - 1);
for(i=start;i<end;i+=block_size) {
if(j==0)
break;
if(is_block_bad((loff_t)i)) {
debug_printf("Bad block found @0x%08x.\n", i);
continue;
}
j-=block_size;
}
if(i >= end)
return -1;
return i;
}
#endif // !ANDROID_BOOT
#if BG2CDP
typedef struct BTLD_CTX {
//unsigned char * gp_vt_buf; // VT_BUF_ADDR
//unsigned char *gp_figo_buf; // FIGO_BUF_ADDR;
//unsigned char *gp_key_buf; // KEY_BUF_ADDR;
//unsigned char * gp_loader_buf; // Loader_BUF_ADDR;
//int iVT_OFFSET;
//int iLoader_OFFSET;
unsigned blk_addr;
//unsigned has_lastk;
unsigned char lastk[1024*3];
char partition_info_buff[4096];
} BTLD_CTX;
BTLD_CTX g;
unsigned berlin_delay(unsigned int tick)
{
volatile unsigned int itick = tick * 250;
while (itick--);
return itick;
}
#define BCM_STATUS_BCM_FAULT (1<<10)
#define BCM_STATUS_BOOTSTRAP_IN_PROGRESS (1<<9)
#define BCM_STATUS_BCM_READY (1<<8)
#define BCM_STATUS_BCM_CMD_FLIP (1<<7)
int bcm_image_verify(unsigned int type, unsigned int src, unsigned int dst)
{
unsigned status;
unsigned waitCount;
unsigned i, *p32;
volatile NOT_MAILBOX volatile *mb = (NOT_MAILBOX *) BCM_MAILBOX;
p32 = (unsigned *) src;
lgpl_printf("\tverify 0k:0x%x, 1k:0x%x, 2k:0x%x\n", p32[1], p32[1+1024/4], p32[1+2048/4]);
status = mb->command_fifo_status;
// lgpl_printf("bcm fifo staus = 0x%x\n", status);
// older erom will have BCM_STATUS_BOOTSTRAP_IN_PROGRESS set
if (0 == (status & BCM_STATUS_BOOTSTRAP_IN_PROGRESS))
{
// wait for bcm ready
// lgpl_printf("wait for bcm ready...\n");
// for (waitCount=~255; waitCount; waitCount--)
while (0 == (status & BCM_STATUS_BCM_READY))
{
if (status != mb->command_fifo_status)
{
status = mb->command_fifo_status;
// lgpl_printf("bcm fifo staus = 0x%x\n", status);
}
}
}
//lgpl_printf("send BCM cmd: 0x%x 0x%x 0x%x 0x%x: 0x%x\n", BCM_PI_IMAGE_VERIFY, type, src, dst, mb-> host_interrupt_register);
mb->primitive_command_parameter0 = type;
mb->primitive_command_parameter1 = src;
mb->primitive_command_parameter2 = dst;
mb->secure_processor_command = BCM_PI_IMAGE_VERIFY;
//for (waitCount=0; waitCount<~255; waitCount++) // Wait_For_WTM_Complete( 0x10000, pCtrl );
for (waitCount=0; ; waitCount++) // Wait_For_WTM_Complete( 0x10000, pCtrl );
{
//if ((mb->command_fifo_status & BCM_STATUS_BCM_CMD_FLIP) != status)
//break;
// wait for "command complete" or timeout
if( mb-> host_interrupt_register & 0x1 )
break;
berlin_delay(100);
}
mb-> host_interrupt_register = 0x70001; // Clear_WTM_Interrupts( 0xffffffff, pCtrl );
status = mb->command_return_status;
i = mb->command_status_0;
lgpl_printf("\tverify image %x, size=%d, waitcount=%d\n", status, i, waitCount);
return status;
}
#endif // BG2CDP
#if ANDROID_BOOT
/*
* For Android not need to load SM from bootimgs.
* Currently, we use this solution. Because it can save the space of flash
* memory of bootimgs & bootimgs-B. And currently, there is a bug in recoery
* scripts, it doesn't update bootimgs-B.
*/
int Image_Load_And_Start(void)
{
int ret= 0;
#ifdef ENABLE_CONNECT_BTN
/* the second time to check connect btn */
#ifndef BG2CDP
Check_connectbtnGPIO();
#endif
#endif
#ifdef ENABLE_CONNECT_BTN
/* the third time to check connect btn */
#ifndef BG2CDP
Check_connectbtnGPIO();
#endif
#endif
lgpl_printf("**************************************************************** \n");
lgpl_printf(" Read and setup kernel Image \n");
lgpl_printf("**************************************************************** \n");
Bootmode = check_android_recovery_mode();
if (Bootmode == BOOTMODE_BOOTUSB)
ret = load_android_image(Bootmode, BOOT_SRC_USB);
else
ret = load_android_image(Bootmode, BOOT_SRC_NAND);
if (ret != 0 && Bootmode == BOOTMODE_NORMAL) {
lgpl_printf("Invalid normal boot image! Boot recovery image...\n");
write_android_bootloader_message("boot-recovery", "", "recovery\n--show_text\n");
Bootmode = BOOTMODE_RECOVERY;
ret = load_android_image(Bootmode, BOOT_SRC_NAND);
} else if (ret != 0 && Bootmode == BOOTMODE_RECOVERY) {
lgpl_printf("Invalid recovery boot image! Boot normal image...\n");
/* Note: we don't clear the recovery flags, we just let device
* to enter recovery mode if recovery mode is avaliable.
* write_android_bootloader_message("", "", "");
*/
Bootmode = BOOTMODE_NORMAL;
ret = load_android_image(BOOTMODE_NORMAL, BOOT_SRC_NAND);
}
if (ret != 0) {
/* Booting from NAND failed, try boot from USB */
lgpl_printf("Booting from NAND failed, booting from USB....!\n");
Bootmode = BOOTMODE_BOOTUSB;
ret = load_android_image(Bootmode, BOOT_SRC_USB);
}
if (ret != 0){
lgpl_printf("FATAL ERROR! There is no bootable image on this machine!\n");
return -1;
}
#ifdef LED_RED_PWM
/* Turn on Red LED indicating booting */
set_led_backlight(LED_RED_PWM, 100);
#endif
#if CDP_A0==1
if (!diag_i2c_check_pg86x(VCORE_MASTER_ID)) {
lgpl_printf("Detected pg86x regulator\n");
PMIC_type = PMIC_TYPE_PG86X;
} else if (!diag_i2c_check_sy21202(VCORE_MASTER_ID)) {
lgpl_printf("Detected sy21202 regulator\n");
PMIC_type = PMIC_TYPE_SY20212B;
} else {
lgpl_printf("Did NOT detect PMIC\n");
}
#endif
/*
* setup linux boot parameter
*/
setup_android_kernel_param(Bootmode);
return 0;
}
#else /* !#if ANDROID_BOOT */
/* For
* - Linux
* - Android needs to load SM from bootimgs
*/
int Image_Load_And_Start()
{
int iPageSize = 0;
int iBlockSize ;
int ret= 0;
unsigned int img3_start, img3_end;
unsigned int en_size;
char *sm_buff, *cpu0_buff, *cpu1_buff, *en_buff;
int sm_addr, cpu0_addr, cpu1_addr, recou_addr, en_addr;
long long chipid;
iPageSize = nand_data.szofpg ;
iBlockSize = nand_data.szofblk;
#ifdef ENABLE_CONNECT_BTN
/* the second time to check connect btn */
Check_connectbtnGPIO();
#endif
if((vt_img3.part1_version.major_version > vt_img3.part2_version.major_version)
|| ((vt_img3.part1_version.major_version == vt_img3.part2_version.major_version)
&&(vt_img3.part1_version.minor_version > vt_img3.part2_version.minor_version)))
{
img3_start = vt_img3.part1_start_blkind;
img3_end = img3_start + vt_img3.part1_blks;
img3_start *= iBlockSize;
img3_end *= iBlockSize;
}
else
{
img3_start = vt_img3.part2_start_blkind;
img3_end = img3_start + vt_img3.part2_blks;
img3_start *= iBlockSize;
img3_end *= iBlockSize;
}
/****************************************************************
* Read Image 3 Header
****************************************************************/
debug_printf("Image3 start:%08x, end: %08x\n", img3_start, img3_end);
debug_printf("Reading image3 attribute ...\n");
sm_addr = nand_read_generic(img3_start, img3_end, &img3_hdr, sizeof(Image3_Attr));
if(sm_addr < 0)
{
lgpl_printf("Read image3 header error!\n");
return -1;
}
//strcpy(img3_hdr.linux_bootargs, LINUX_PARAM_COMMON_PART);
UtilMemCpy(img3_hdr.linux_bootargs, linux_bootargs, ((sizeof(linux_bootargs)+3)&~3));
sm_hdr = &img3_hdr.sm_param;
cpu0_hdr = &img3_hdr.cpu0_param;
cpu1_hdr = &img3_hdr.cpu1_param;
recou_hdr = &img3_hdr.recou_param;
sMem_Layout = &img3_hdr.mem_layout;
#ifdef CONFIG_FORCE_ENCRYPTION
sm_hdr->bsm_image_encrypt = 1;
cpu0_hdr->bcpu0_image_encrypt = 1;
cpu1_hdr->bcpu1_image_encrypt = 1;
#endif // CONFIG_FORCE_ENCRYPTION
en_size = sm_hdr->bsm_image_encrypt | cpu0_hdr->bcpu0_image_encrypt | cpu1_hdr->bcpu1_image_encrypt;
cpu0_addr = get_next_img_addr(sm_addr, img3_end, sm_hdr->uism_image_final_size);
cpu1_addr = get_next_img_addr(cpu0_addr, img3_end, cpu0_hdr->uicpu0_image_final_size);
recou_addr = get_next_img_addr(cpu1_addr, img3_end, cpu1_hdr->uicpu1_image_final_size);
en_addr = get_next_img_addr(recou_addr, img3_end, recou_hdr->size);
debug_printf("sm_addr: %08x, cpu0_addr: %08x, cpu1_addr: %08x, recou_addr: %08x, en_addr: %08x\n",
sm_addr, cpu0_addr, cpu1_addr, recou_addr, en_addr);
debug_printf("Memory map: CPU0 %uM, CPU1 %uM, ZSP: %uM, SHR %uM\n",
sMem_Layout->uicpu0_mem_size>>20, sMem_Layout->uicpu1_mem_size>>20,
sMem_Layout->uizsp_mem_size>>20, sMem_Layout->uishm_mem_size>>20);
if((cpu0_addr < 0) || (cpu1_addr < 0) || (recou_addr < 0) || (en_addr < 0))
{
lgpl_printf("Scan image3 error.\n");
lgpl_printf("sm_addr: %08x, cpu0_addr: %08x, cpu1_addr: %08x, recou_addr: %08x, en_addr: %08x\n",
sm_addr, cpu0_addr, cpu1_addr, recou_addr, en_addr);
return -1;
}
if (!en_size)
{
UtilMemSet((void *)&en_hdr, 0, sizeof(en_hdr));
}
else
{
if(nand_read_generic(en_addr, img3_end, &en_hdr, sizeof(en_hdr)) < 0)
{
lgpl_printf("Read image3 header error!\n");
return -1;
}
// debug_printf("Encryption atrribute:\n");
// for(k=0;k<sizeof(en_hdr)/4;k++) debug_printf("0x%08x.\n", ((int *)&en_hdr)[k]);
// currently, we don't support CPU1 image
en_size = en_hdr.uiCPU0_Encrypt_Image_Header_Offset + en_hdr.uiCPU0_Encrypt_Image_Header_Size;
debug_printf("Encryption image size= %d\n", en_size);
en_buff = UtilMemAlloc(en_size);
if(!en_buff) {
lgpl_printf("Malloc failed.\n");
return -1;
}
if(nand_read_generic(en_addr, img3_end, (unsigned char *)en_buff, en_size) < 0)
{
lgpl_printf("Read image3 header error!\n");
return -1;
}
}
debug_printf("encryption header copied\n");
#ifdef BG2CDP
#else
/****************************************************************
* Load and start SM
****************************************************************/
{
// make Beetle "DDR_Off" case like the other warmups: there's no need to reload
// SM. Even though DDR is gone, it doesn't affect SM.
/* ( MV_SoC_STATE_SYSRESET != uiBoot ) */ ))
{
// for cold boot up, Image-2 load SM's image and kick off Sm
// when box product release is defined, SM will shut down SoC after power on.
// this can be done by write the cold boot flag to SM's register
#ifdef BOX_PRODUCT_RELEASE
{
#else
if(false) {
#endif
debug_printf("Set cold boot flag: %08x@%08x\n", MV_SM_RSTFLAG_COLD, SM_BOOT_FLAG_REG);
writel(MV_SM_RSTFLAG_COLD, SM_BOOT_FLAG_REG);
}
// copy SM image from NAND
debug_printf("Loading SM image... final size %u\n", sm_hdr->uism_image_final_size);
if(!sm_hdr->bsm_image_encrypt)
en_hdr.uiSM_Encrypt_Image_Header_Size = 0;
sm_buff = UtilMemAlloc(sm_hdr->uism_image_final_size + en_hdr.uiSM_Encrypt_Image_Header_Size);
if(!sm_buff) {
lgpl_printf("Malloc failed.\n");
return -1;
}
UtilMemCpy(sm_buff, en_buff + en_hdr.uiSM_Encrypt_Image_Header_Offset, en_hdr.uiSM_Encrypt_Image_Header_Size);
if(nand_read_generic(sm_addr, cpu0_addr, (sm_buff+en_hdr.uiSM_Encrypt_Image_Header_Size), sm_hdr->uism_image_final_size) < 0)
{
lgpl_printf("Read sm image error!\n");
return -1;
}
if(sm_hdr->bsm_image_encrypt) {
debug_printf("Encryption key index: %u\n", sm_buff[0]);
ret = VerifyImage((unsigned int)sm_buff, sm_hdr->uism_encrypt_image_size, (unsigned int)sm_buff);
if(ret) {
lgpl_printf("Verify SM image failed! ret=%d\n", ret);
return -1;
}
debug_printf("verify passed.\n");
}
if(sm_hdr->bsm_image_bss_init)
UtilMemSet(sm_buff + sm_hdr->uism_bss_start_addr - sm_hdr->uism_image_load_addr, 0, sm_hdr->uism_bss_length);
#ifdef ENABLE_CONNECT_BTN
/* the third time to check connect btn */
Check_connectbtnGPIO();
#endif
debug_printf("Done.\n");
// download SM image from DDR to ITCM and kick off SM
MV_SM_Dev_Init((unsigned char*)sm_buff, sm_hdr->uism_image_ori_size ) ;
debug_printf("SM CPU is kicked off.\n");
// send msg to SM to power off SoC
// FIGO_SRAM_ENTRY() ;
}
#endif // CONFIG_SM
/****************************************************************
* Read and setup kernel Image
****************************************************************/
#define mem_buff cpu0_buff
cpu0_buff = (char *)cpu0_hdr->uicpu0_image_load_addr - sizeof(linux_hdr_t);
{
debug_printf("Loading CPU0 image... load address: 0x%x, final size %u\n", (int)cpu0_buff,cpu0_hdr->uicpu0_image_final_size);
if(cpu0_hdr->bcpu0_image_encrypt)
UtilMemCpy(cpu0_buff, en_buff + en_hdr.uiCPU0_Encrypt_Image_Header_Offset, en_hdr.uiCPU0_Encrypt_Image_Header_Size);
else
en_hdr.uiCPU0_Encrypt_Image_Header_Size = 0;
if(nand_read_generic(cpu0_addr, cpu1_addr, (cpu0_buff+en_hdr.uiCPU0_Encrypt_Image_Header_Size), cpu0_hdr->uicpu0_image_final_size) < 0)
{
lgpl_printf("Read CPU0 image error!\n");
return -1;
}
if(cpu0_hdr->bcpu0_image_encrypt) {
#if BG2CDP
ret = load_lastk(g.lastk);
if (ret)
{
lgpl_printf("load last key failed!ret=0x%x\n", ret);
return -1;
}
ret = bcm_image_verify(BCM_IMG_KERNEL_TYPE, (unsigned) mem_buff, (unsigned) cpu0_buff);
if (ret)
{
lgpl_printf("Verify cpu0 image failed!ret=0x%x\n", ret);
return -1;
}
#else
debug_printf("Encryption key index: %u\n", cpu0_buff[0]);
ret = VerifyImage((unsigned int)cpu0_buff, cpu0_hdr->uicpu0_encrypt_image_size, (unsigned int)cpu0_buff);
if(ret) {
lgpl_printf("Verify cpu0 image failed!ret=%d\n", ret);
return -1;
}
#endif
debug_printf("verify passed.\n");
}
// Xiufeng: do not use ramdisk for BG2
#if 1
{
linux_hdr_t *lhdr = cpu0_buff;
int len;
debug_printf("kernel_size=%d, ramdisk_size=%d, ramdisk_addr=%x\n",
lhdr->kernel_size, lhdr->ramdisk_size, lhdr->ramdisk_addr);
debug_printf("reloading ramdisk...");
UtilMemCpy(lhdr->ramdisk_addr,
cpu0_hdr->uicpu0_image_load_addr+lhdr->kernel_size,
lhdr->ramdisk_size);
debug_printf("DONE!\n");
debug_printf("append initrd to linux bootargs\n");
len = strlen((char *)img3_hdr.linux_bootargs);
snprintf(img3_hdr.linux_bootargs + len,
sizeof(img3_hdr.linux_bootargs) - len, " initrd=0x%x,0x%x",
lhdr->ramdisk_addr, lhdr->ramdisk_size);
#if defined(ROOTFS_SQUASHFS)
debug_printf("append rootfs type to linux bootargs\n");
len = strlen((char *)img3_hdr.linux_bootargs);
snprintf(img3_hdr.linux_bootargs + len,
sizeof(img3_hdr.linux_bootargs) - len),
" rootfstype=squashfs");
#endif
debug_printf("%s\n", img3_hdr.linux_bootargs);
}
#endif
if(cpu0_hdr->bcpu0_image_bss_init)
UtilMemSet((void*)cpu0_hdr->uicpu0_bss_start_addr, 0, cpu0_hdr->uicpu0_bss_length);
}
debug_printf("Done.\n");
/*
* setup linux boot parameter
*/
// if MV88DE3010, try to use CPUID as MAC address
#if !CDP_A0
chipid = readl(MV88DE3100_CHIPID_REG1) ;
chipid += (long long)(readl(MV88DE3100_CHIPID_REG2)) << 32;
#else
chipid = 0x12345678abcdef0;
#endif /* FIXME: A0 bring up */
if(chipid && block0.first_burn_flag){
char tmp_param[1024];
char tmp_buf[64];
init_mac_address(chipid, (char *)(&img3_hdr.linux_bootargs), tmp_param);
debug_printf("Real bootargs: %s\n", tmp_param);
setup_linux_bootparam(cpu0_hdr->uicpu0_image_load_addr-0x8000, sMem_Layout->uicpu0_mem_size, tmp_param);
} else {
char tmp_param1[1024];
char mac_addr[32];
get_mac_addr(mac_addr);
set_wol_macaddr(&mac_addr[8]);
strlcpy(tmp_param1, img3_hdr.linux_bootargs, sizeof(tmp_param1));
strcat(tmp_param1, " ");
strncat(tmp_param1, mac_addr, sizeof(mac_addr));
{
char tmp_buf[64];
// Xiufeng: Fix me
// The No.2 parameter uicpu0_mem_size, is not used by Linux.
debug_printf("REal bootargs: %s\n", tmp_param1);
setup_linux_bootparam(cpu0_hdr->uicpu0_image_load_addr-0x8000,
sMem_Layout->uicpu0_mem_size, tmp_param1);
}
debug_printf("%d: Done!\n", __LINE__);
}
#if 0
setup_linux_bootparam(cpu0_hdr->uicpu0_image_load_addr-0x8000,
sMem_Layout->uicpu0_mem_size, LINUX_BOOTARGS);
#endif
// Xiufeng: Here we set CHIP_CTRL_SW_GENERIC3_REG to 1 to keep consistent with Berlin
// In ideal case, BG2 Linux does not need NFC sync, but bootflow does not
// rely on this
reg(CHIP_CTRL_SW_GENERIC3_REG) = 1;//allow Linux to use NFC
return 0;
}
#endif // ANDROID_BOOT
#include "bcm_primitive.h"
#include "bcm_status.h"
#include "bcm_mailbox.h"
// if here, Image-3 is copied into DDR
int Image_3_Verify_Jump(void)
{
// write 0xBF0A0001 to CHIP_CTRL_SW_GENERIC0_REG
// This is the flag to eCos passed by Bootflow. This value means the AVPLL
// has been set by bootflow, eCos shall not reset AVPLL
GA_REG_WORD32_WRITE(CHIP_CTRL_SW_GENERIC0_REG, 0xBF0A0001) ;
// any state reach here should start/resume kernel
#if ANDROID_BOOT
{
/* flush the console output */
putchar('\n');
bcm_usb_console_func(EROM_TURN_OFF_USB_DEVICE);
start_android_kernel();
}
#else /* #if ANDROID_BOOT */
reg(CHIP_CTRL_SW_GENERIC3_REG) = 0x1 ;
{
lgpl_printf("JUMp to kernel entrance 0x%08x\n", cpu0_hdr->uicpu0_image_load_addr);
//parameter0: Linux load address
//parameter1: 1330
//parameter2: Linux Command line address
/* flush the console output */
putchar('\n');
bcm_usb_console_func(EROM_TURN_OFF_USB_DEVICE);
__reset_cpu(cpu0_hdr->uicpu0_image_load_addr, 1330, cpu0_hdr->uicpu0_image_load_addr-0x8000) ;
}
#endif // ANDROID_BOOT
return 0;
}
void dump_version_entry(ver_table_entry_t * vte)
{
printf("%s: part1(start=%d, blks=%d, version=%08u%04u), part2(start=%d, blks=%d, version=%08u%04u)\n", vte->name,
vte->part1_start_blkind, vte->part1_blks, vte->part1_version.major_version, vte->part1_version.minor_version,
vte->part2_start_blkind, vte->part2_blks, vte->part2_version.major_version, vte->part2_version.minor_version);
}
unsigned int crc32(unsigned int crc, unsigned char *buf, unsigned int len);
#define CRC32_SIZE (4)
int get_version_table()
{
unsigned int i,j,ret=0;
int img3_found;
#if ANDROID_BOOT
int android_kernel_found=0;
int android_recovery_found=0;
#endif
version_table_t *vt = (version_table_t *)g.partition_info_buff;
ver_table_entry_t * vt_entry;
unsigned vt_size = 0;
unsigned int dev_id = 0;
unsigned iVT_OFFSET;
#if BG2CDP
iVT_OFFSET = nand_data.szofblk - 4096;
#else
iVT_OFFSET = VT_OFFSET;
#endif
for(i=1; i<9;i++) {
if(is_block_bad((loff_t)i*nand_data.szofblk)) {
debug_printf("Bad block found @0x%08x.\n", i*nand_data.szofblk);
continue;
}
ret = mv_nand_read_block( (long long)i*nand_data.szofblk + iVT_OFFSET,
g.partition_info_buff, sizeof(g.partition_info_buff) );
if( ret != sizeof(g.partition_info_buff) ) {
debug_printf("Read version table failed, i=%u, ret=%u.\n", i, ret);
continue;
}
vt_size = sizeof(version_table_t) + vt->num_entries * sizeof(ver_table_entry_t);
/* verify the version table data */
if(vt->magic != MAGIC_NUMBER || 0xffffffff != crc32(0, (UCHAR *)g.partition_info_buff, vt_size + CRC32_SIZE)) {
lgpl_printf("error magic number! %x\n", vt->magic);
continue;
}
UtilMemCpy(g.lastk, &g.partition_info_buff[3*1024], 1024);
dev_id = 0;
img3_found = 0;
for(j=0;j<vt->num_entries;j++) {
vt_entry = &vt->table[j];
printf("[%02d,d%02d] ", j, dev_id);
dump_version_entry(vt_entry);
if(UtilMemCmp(IMG3_NAME, vt_entry->name, sizeof(IMG3_NAME)) == 0) {
UtilMemCpy(&vt_img3, vt_entry, sizeof(ver_table_entry_t));
img3_found = 1;
}
#if 0
if(UtilMemCmp(SYSCONF_NAME, vt_entry->name, sizeof(SYSCONF_NAME)) == 0) {
UtilMemCpy(&vt_sysconf, vt_entry, sizeof(ver_table_entry_t));
}
if(UtilMemCmp(FLASHLESS_NAME, vt_entry->name, sizeof(FLASHLESS_NAME)) == 0) {
UtilMemCpy(&vt_flashless, vt_entry, sizeof(ver_table_entry_t));
}
#endif
#if ANDROID_BOOT
if(UtilMemCmp(FTS_NAME, vt_entry->name, sizeof(FTS_NAME)) == 0) {
fts_dev_id = dev_id;
UtilMemCpy((void *)&vt_fts, vt_entry, sizeof(ver_table_entry_t));
}
if(UtilMemCmp(KERNEL_NAME, vt_entry->name, sizeof(KERNEL_NAME)) == 0) {
UtilMemCpy((void *)&vt_kernel, vt_entry, sizeof(ver_table_entry_t));
android_kernel_found = 1;
}
if(UtilMemCmp(RECOVERY_NAME, vt_entry->name, sizeof(RECOVERY_NAME)) == 0) {
UtilMemCpy((void *)&vt_recovery, vt_entry, sizeof(ver_table_entry_t));
android_recovery_found = 1;
}
#endif
if (vt_entry->part1_start_blkind != vt_entry->part2_start_blkind)
/* double copy of the partition */
dev_id += 2;
else
dev_id += 1;
}
#if ANDROID_BOOT
if(img3_found && android_kernel_found && android_recovery_found)
break;
#else
if(img3_found)
break;
#endif
}
if(i==9) {
lgpl_printf("Scan version table error!\n");
return -1;
}
return 0;
}
#if 0 //BG2CDP
MV_Block1_Item layout_item;
MV_Block1_Item *loader_item;
int get_block1_layout(void *buf)
{
int i, type;
int iVT_OFFSET = VT_OFFSET;
MV_Block1 *Layout = (MV_Block1 *) buf;
if (Layout->head.MagicNumber == 0xda7a)
{
for (i=0; i<8; i++)
{
type = Layout->item[i].param&0xF;
if (type == BLOCK1_IMAGE_TYPE_VT)
{
iVT_OFFSET = Layout->item[i].start;
//debug_printf("VT block @0x%08x.\n", iVT_OFFSET);
break;
}
}
}
return iVT_OFFSET;
}
unsigned status_32[17];
int bcm_image_verify(unsigned int type, unsigned int src, unsigned int dst)
{
unsigned waitCount;
unsigned i, *p32;
NOT_MAILBOX volatile *mb = (NOT_MAILBOX *) BCM_MAILBOX;
p32 = &mb->primitive_command_parameter0;
p32[0] = type;
p32[1] = src;
p32[2] = dst;
for (i=3; i<16; i++)
p32[i] = 0;
p32[i] = BCM_PI_IMAGE_VERIFY;
lgpl_printf("Verifying cpu0 image @0x%x ... ", src);
//for (waitCount=0x10000000; waitCount; waitCount--) // Wait_For_WTM_Complete( 0x10000, pCtrl );
//for (waitCount=0; waitCount<0x1000000; waitCount++) // Wait_For_WTM_Complete( 0x10000, pCtrl );
for (waitCount=0; ; waitCount++) // Wait_For_WTM_Complete( 0x10000, pCtrl );
{
// wait for "command complete" or timeout
if( mb-> host_interrupt_register & 0x1 )
break;
//if (waitCount>~7)
//break;
}
lgpl_printf("countup = 0x%08x.\n", waitCount);
status_32[0] = ~0;
status_32[1] = 0;
//if( waitCount != 0 )
{
p32 = &mb-> command_return_status;
for (i=0; i<17; ++i)
status_32[i] = p32[i];
//mb-> host_interrupt_register = ~0; // Clear Interrupts
}
mb-> host_interrupt_register = 0x70001; // Clear Interrupts
lgpl_printf("Verify status=0x%x, size=%d.\n", status_32[0], status_32[1]);
return status_32[0];
}
#endif
//char partition_info_buff[4096 + 32];
unsigned char partition_type_s[16];
#if defined(CONFIG_SLC)
extern unsigned int slc_partition_start;
#endif
int gen_nand_partition_info()
{
unsigned int i, ret=0;
version_table_t *vt = (version_table_t *)g.partition_info_buff;
unsigned vt_size = 0;
unsigned iVT_OFFSET;
#if BG2CDP
iVT_OFFSET = nand_data.szofblk - 4096;
#else
iVT_OFFSET = VT_OFFSET;
#endif
strncpy((CHAR *)partition_type_s, "eslc", 4);
for(i=1; i<9;i++) {
if(is_block_bad((loff_t)i*nand_data.szofblk)) {
lgpl_printf("Bad block found @0x%08x.\n", i*nand_data.szofblk);
continue;
}
// go get vt
ret = mv_nand_read_block( (long long)i*nand_data.szofblk + iVT_OFFSET,
(CHAR *)g.partition_info_buff, sizeof(g.partition_info_buff) );
if( ret != sizeof(g.partition_info_buff) ) {
lgpl_printf("get partition info failed, i=%u, ret=%u.\n", i, ret);
continue;
}
vt_size = sizeof(version_table_t) + vt->num_entries * sizeof(ver_table_entry_t);
/* verify the version table data */
if(vt->magic != MAGIC_NUMBER || 0xffffffff != crc32(0, (UCHAR *)g.partition_info_buff, vt_size + CRC32_SIZE)){
lgpl_printf("error magic number! %x\n", vt->magic);
}else
break;
}
if(i == 9) {
lgpl_printf("Scan partition info error!\n");
return -1;
}
return 0;
}
void dump_mem(unsigned int addr, int count)
{
int i;
for (i = 0; i < count; i++, addr += 4) {
if (i % 4 == 0) {
if (i)
printf("\n");
printf("0x%08x: ", addr);
}
printf("%08x ", readl(addr));
}
printf("\n");
}
#if defined(DEBUG)
static unsigned int read_otp_status(void)
{
return readl(MV88DE3XXX_OTP_STS_REG);
}
static unsigned int read_otp_lkg_curr(void)
{
return readb(MV88DE3XXX_OTP_LKG_ID) * 4;
}
#endif
void reset_usb_console();
void StartBootLoader(int block_size, int page_size, int ecc_strength)
{
int ret = 0;
uiWarmDown_2_Linux_Addr = ~0; //readl((SM_WARMDOWN_2_LINUX_ADDR)) ;
UtilMemSet((unsigned char *)BSS_START, 0, BSS_END - BSS_START);
pin_init();
reset_usb_console();
#if BG2CDP
lgpl_printf("%s BG2CD+: %x\n", BOARD_NAME, BERLIN_CHIP_VERSION);
/* unmask WDT reset signal */
writel(0, 0xF7FCD03C);
/* enable CA7 CPU Timer*/
writel(1, 0xF7920034);
/* set up APB Timer*/
writel(1000*1000, 0xF7E82c00); /* reload value */
writel(7, 0xF7E82C08); /* ENABLE | PERIODIC | IRQ_MASK*/
#if !CDP_A0
/* pinmux */
writel(0x09004800, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x00);
writel(0x00000001, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x04);
writel(0x09000000, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x08);
writel(0x00001249, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x0c);
writel(0x00000009, SM_SYS_CTRL_REG_BASE + RA_smSysCtl_smPinMuxCntlBus);
/* invert the polarity of PMU IRQ */
writel(0x01800000, 0xF7CA00B8);
#else /* BG2-CDP A0 */
writel(0x08000000, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x04);
/* invert the polarity of PMU IRQ */
writel(0x01800000, MEMMAP_SOC_REG_BASE + 0x04);
#if (CFG_BOARD_NAME == BOARD_CHIRP_B1) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B3) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B4) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B1) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B3) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B4)
GPIO_PortWrite(TOUCH_RESET_GPIO, 1);
writel(0x00000252, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x00);
// TODO may be for uniformity, find an absoute value to write to this pinmux register instead of having to read it first
unsigned int reg_val = readl(MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x04);
reg_val = reg_val | 0x00C0000;
reg_val = reg_val & 0xFFEFFFFF;
writel(reg_val, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x04);
writel(0x0838A249, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x08);
writel(0x00009B64, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x0c);
writel(0x000000B6, SM_SYS_CTRL_REG_BASE + RA_smSysCtl_smPinMuxCntlBus);
udelay(100); // keep TOUCH_RESET_GPIO HIGH for 100 usec
GPIO_PortWrite(TOUCH_RESET_GPIO, 0);
udelay(1000); // add 1 ms delay to allow ATMEL MCU to go to booloader mode TODO: test that delay is really 1 ms
GPIO_PortWrite(TOUCH_RESET_GPIO, 1); //now toggle the reset pin back to 1
#elif (CFG_BOARD_NAME == BOARD_COCO_P1) \
|| (CFG_BOARD_NAME == BOARD_COCO_P2)
// This sets these four pins as GPIO12-GPIO15
unsigned pinmux0 = ((Gbl_pinMuxCntlBus_TW1_SCL_MODE_2 << 0) |
(Gbl_pinMuxCntlBus_TW1_SDA_MODE_2 << 3) |
(Gbl_pinMuxCntlBus_HDMI_CEC_MODE_1 << 6) |
(Gbl_pinMuxCntlBus_HDMI_HPD_MODE_1 << 9));
writel(pinmux0, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x00);
// Sets NAND_WEn to GPIO28 (touch reset), sets SD0_CLK as SD0_CLK
unsigned pinmux1 = ((Gbl_pinMuxCntlBus_SD0_CLK_MODE_1 << 27) |
(Gbl_pinMuxCntlBus_NAND_RDY_MODE_0 << 24) |
(Gbl_pinMuxCntlBus_NAND_CEn_MODE_0 << 21) |
(Gbl_pinMuxCntlBus_NAND_WEn_MODE_3 << 18));
writel(pinmux1, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x04);
// Enable both Rx and Tx UART pins vs wiring Rx to a GPIO
// Sets SD0_DATx, SD0_CMD pins as SD0 pins
// Sets SD0_CDn as PDM_DI and SD0_WP as I2S2_DO
// Sets SS0n to GPIO5
unsigned pinmux2 = ((Gbl_pinMuxCntlBus_SD0_DAT0_MODE_1 << 0) |
(Gbl_pinMuxCntlBus_SD0_DAT1_MODE_1 << 3) |
(Gbl_pinMuxCntlBus_SD0_DAT2_MODE_1 << 6) |
(Gbl_pinMuxCntlBus_SD0_DAT3_MODE_1 << 9) |
(Gbl_pinMuxCntlBus_SD0_CDn_MODE_2 << 12) |
(Gbl_pinMuxCntlBus_SD0_CMD_MODE_1 << 15) |
(Gbl_pinMuxCntlBus_SD0_WP_MODE_6 << 18) |
(Gbl_pinMuxCntlBus_URT0_RXD_MODE_0 << 21) |
(Gbl_pinMuxCntlBus_URT0_TXD_MODE_0 << 24) |
(Gbl_pinMuxCntlBus_SPI1_SS0n_MODE_1 << 27));
writel(pinmux2, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x08);
// Sets SPI1_SD1 to GPIO10, SPI1_SDO to PWM3, SPI1_SCLK to PWM2
// SPI1_SS2n to TWO_SDA and SPI1_SS1n to TWO_SCL
// COCO_P2 SPI1_SDO is GPIO9 SP1_SCLK is GPO8
// Sets USB0_DRV to GPIO11
unsigned pinmux3 = ((Gbl_pinMuxCntlBus_USB0_DRV_VBUS_MODE_1 << 15) |
(Gbl_pinMuxCntlBus_SPI1_SDI_MODE_1 << 12) |
#if (CFG_BOARD_NAME == BOARD_COCO_P1)
(Gbl_pinMuxCntlBus_SPI1_SDO_MODE_5 << 9) |
(Gbl_pinMuxCntlBus_SPI1_SCLK_MODE_5 << 6) |
#else
(Gbl_pinMuxCntlBus_SPI1_SDO_MODE_1 << 9) |
(Gbl_pinMuxCntlBus_SPI1_SCLK_MODE_1 << 6) |
#endif
(Gbl_pinMuxCntlBus_SPI1_SS2n_MODE_4 << 3) |
(Gbl_pinMuxCntlBus_SPI1_SS1n_MODE_4 << 0));
writel(pinmux3, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x0C);
// Sets SM_TMS to I2S1_BCLK, SM_TDI to I2S1_LRCLK, SM_TDO to PDM_CLK
unsigned pinmuxSM = ((smSysCtl_smPinMuxCntlBus_SM_TMS_MODE_6 << 0) |
(smSysCtl_smPinMuxCntlBus_SM_TDI_MODE_6 << 3) |
(smSysCtl_smPinMuxCntlBus_SM_TDO_MODE_2 << 6));
writel(pinmuxSM, SM_SYS_CTRL_REG_BASE + RA_smSysCtl_smPinMuxCntlBus);
#if (CFG_BOARD_NAME == BOARD_COCO_P2)
// Set the MUX to switch from JTAG pinout to serial pinout
GPIO_PortWrite(JTAG_MUX_GPIO, 1);
#endif
// Reset peripherals (Touch controller on Joplin, MCU on Lilo)
// Delay so the peripherals fully reset
GPIO_PortWrite(PERIPHERAL_RESET_GPIO, 1);
udelay(100);
GPIO_PortWrite(PERIPHERAL_RESET_GPIO, 0);
udelay(1000);
GPIO_PortWrite(PERIPHERAL_RESET_GPIO, 1);
#elif (CFG_BOARD_NAME == BOARD_HENDRIX_B1) \
|| (CFG_BOARD_NAME == BOARD_HENDRIX_B3) \
|| (CFG_BOARD_NAME == BOARD_HENDRIX_B4)
GPIO_PortWrite(AUD_MUTE_GPIO, 0); // set AUD_MUTE# pin to output 0
writel(0x00000252, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x00);
writel(0x08388249, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x08);
writel(0x00009B64, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x0c);
writel(0x000001B6, SM_SYS_CTRL_REG_BASE + RA_smSysCtl_smPinMuxCntlBus);
#else
writel(0x00000000, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x00);
writel(0x08208249, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x08);
writel(0x00009264, MEMMAP_CHIP_CTRL_REG_BASE + RA_Gbl_pinMuxCntlBus + 0x0c);
writel(0x00000064, SM_SYS_CTRL_REG_BASE + RA_smSysCtl_smPinMuxCntlBus);
#endif
#endif /* CDP_A0 */
#else
lgpl_printf("\n%s %s\n", BOARD_NAME, CHIP_VERSION);
#endif
// initialize nand flash
init_nfc(block_size, page_size, ecc_strength);
if(gen_nand_partition_info()){
printf("Cannot get NAND partition info");
while(1);
}
UtilMemReset();
#ifndef ANDROID_BOOT
// always get version table for all the boot state
if (get_version_table()) {
lgpl_printf("get version table error!\n");
while(1);
}
#endif //! ANDROID_BOOT
#if ANDROID_BOOT
ret = flash_ts_init(vt_fts.part1_start_blkind, vt_fts.part1_blks);
if (ret){
lgpl_printf("flash_ts_init() init fail.\n");
while(1);
}
#endif
board_gpio_init();
#ifdef LED_RED_PWM
/* Turn on red LED */
set_led_backlight(LED_RED_PWM, 100);
#endif
#if (CFG_BOARD_NAME == BOARD_CHIRP_B1) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B3) \
|| (CFG_BOARD_NAME == BOARD_CHIRP_B4)
diag_i2c_led_init(LED_MASTER_ID, 0x15, LED_MODEL_PCA9956B);
diag_i2c_led_init(LED_MASTER_ID, 0x17, LED_MODEL_PCA9956B);
// Bootloader fast logo
unsigned char led_frame_15[18] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char led_frame_17[18] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00};
set_topboard_leds(0x15, led_frame_15, ARRAY_SIZE(led_frame_15),
LED_MODEL_PCA9956B);
set_topboard_leds(0x17, led_frame_17, ARRAY_SIZE(led_frame_17),
LED_MODEL_PCA9956B);
#elif (CFG_BOARD_NAME == BOARD_COCO_P1) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B1) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B3) \
|| (CFG_BOARD_NAME == BOARD_JOPLIN_B4)
diag_i2c_led_init(LED_MASTER_ID, 0x17, LED_MODEL_PCA9955B);
char color[64] = {0};
get_device_color(color, sizeof(color));
// Reduce Red by 50% on campari color devices
if (!strcmp("campari", color)) {
unsigned char led_frame_17[16] = {0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x80, 0x64,
0x00, 0x64, 0x80, 0xFF,
0x00, 0x00, 0x00, 0x00};
set_topboard_leds(0x17, led_frame_17, ARRAY_SIZE(led_frame_17),
LED_MODEL_PCA9955B);
} else {
unsigned char led_frame_17[16] = {0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x64,
0x00, 0x64, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00};
set_topboard_leds(0x17, led_frame_17, ARRAY_SIZE(led_frame_17),
LED_MODEL_PCA9955B);
}
#endif // BOARD_CHIRP_B{1,3,4} BOARD_COCO_P1 BOARD_JOPLIN_B{1,3,4}
init_clock();
power_tuning();
/* show public OTP fields */
{
const volatile BERLIN_BOOTINFO *pinfo = (BERLIN_BOOTINFO *)BERLIN_BOOTINFO_ADDR;
lgpl_printf("OTP/RKEK ID: ");
lgpl_printf("%08X", pinfo->otp_rkek_id[0]);
lgpl_printf("%08X", pinfo->otp_rkek_id[1]);
lgpl_printf("\n");
lgpl_printf("OTP/VERSION: ");
lgpl_printf("%08X", pinfo->otp_version);
lgpl_printf("\n");
lgpl_printf("EROM ID :%08X\n", pinfo->erom_id);
lgpl_printf("RSA KEY INDEX:%1X\n", pinfo->rsa_key_index);
lgpl_printf("USB BOOT TO :%1X\n", pinfo->usb_boot_timeout);
lgpl_printf("ROMK DISABLE :%1x\n", pinfo->romkey_disable);
lgpl_printf("DIS USB BOOT :%1x\n", pinfo->disable_usb_boot);
lgpl_printf("DIS BOOTSTRAP:%1x\n", pinfo->usb_disable_bootstrap);
lgpl_printf("DIS BLANK MED:%1x\n", pinfo->usb_disable_blank_media);
lgpl_printf("OTP/MID: ");
lgpl_printf("%08X", pinfo->otp_market_id);
lgpl_printf("\n");
lgpl_printf("OTP/ULT: ");
lgpl_printf("%08X", pinfo->otp_ult[0]);
lgpl_printf("%08X", pinfo->otp_ult[1]);
lgpl_printf("\n");
lgpl_printf("OTP LOCK :%1X\n", pinfo->otp_locked);
lgpl_printf("RKEK CRC :%08X\n", pinfo->rkek_crc);
lgpl_printf("AESK0 CRC :%08X\n", pinfo->aesk0_crc);
lgpl_printf("SIGNK7 CRC :%08X\n", pinfo->signk7_crc);
lgpl_printf("MRVL SIGN R :%04X\n", pinfo->mrvl_sign_right);
lgpl_printf("CUST SIGN R :%04X\n", pinfo->cust_sign_right);
}
#if BG2CDP
dump_mem(SYSPLL_CTRL_BASE + RA_pll_ctrl, 4); // SYSPLL Registers
dump_mem(MEMPLL_CTRL_BASE + RA_pll_ctrl, 4); // MEMPLL Registers
dump_mem(CPUPLL_CTRL_BASE + RA_pll_ctrl, 4); // CPUPLL Registers
#else
dump_mem(0xF7EA0014, 4); // SYSPLL Registers
dump_mem(0xF7EA0028, 4); // MEMPLL Registers
dump_mem(0xF7EA003C, 4); // CPUPLL Registers
#endif
lgpl_printf("Clock configuration:\n");
#if BG2CDP
list_speed(2);
#if !CDP_A0
/* BG2-CDP Z1/Z2 */
/* adjust vcore */
diag_i2c_vcore_control(VCORE_MASTER_ID, VCORE_VOLT_INDEX);
#endif /* CDP_A0 */
#else
show_speed();
#endif /* BG2CDP */
{
// note: in the case of STATE_WARMUP_0/1/2, we expect RAM is OK. In the case of
// Beetle DDR_OFF, it's not. So make sure Image_Load_And_Start is called for the Beetle case.
// note: MV_SoC_STATE_BOOT_RECOVERY_KERNEL takes this branch.
//TODO FOR BG2CDPbootloader_customize_load_image_preprocess(uiBoot);
#ifdef ENABLE_CONNECT_BTN
#ifndef BG2CDP
Check_connectbtnGPIO();
#endif
#endif
if(Image_Load_And_Start())
{
lgpl_printf("tbdzz---- Img_Ld_And_Start error! Spinning now!\n");
#if defined(CDP_A0) && defined(BOOTLOADER_SHOWLOGO)
fastlogo_init();
showlogo_start(1);
#endif
while(1);
}
#ifdef BG2CDP
//TODO FOR BG2CDPbootloader_customize_load_image_preprocess(uiBoot);
#else
bootloader_customize_load_image_preprocess(uiBoot);
#endif
}
#ifdef BG2CDP
//TODO FOR BG2CDPbootloader_customize_load_image_preprocess(uiBoot);
#else
bootloader_customize_load_image_preprocess(uiBoot);
#endif
#if BOOTLOADER_SHOWLOGO
#if CDP_A0
// Still needed. Otherwise kernel fast logo doesn't display.
fastlogo_init();
showlogo_start(0);
showlogo_stop();
#endif
#else
#if CDP_A0
AVPLL_Enable();
#endif
#endif // BOOTLOADER_SHOWLOGO
Image_3_Verify_Jump() ;
while(1);
}
/* TODO(kolla): This seem to be a result of statically linking libgcc.a,
* one of the u-boot forums recommended locally defining this function.
* Find cleaner fix.
*/
void __aeabi_unwind_cpp_pr0(void)
{
}