/* ********************************************************************* * Broadcom Common Firmware Environment (CFE) * * Main Module File: bcm63xxBoot_main.c * * This module contains the main "C" routine for CFE bootstrap loader * and decompressor to decompress the real CFE to ram and jump over. * * Author: Mitch Lichtenberg (mpl@broadcom.com) * Revised: seanl * ********************************************************************* * * Copyright 2000,2001,2002,2003 * Broadcom Corporation. All rights reserved. * * This software is furnished under license and may be used and * copied only in accordance with the following terms and * conditions. Subject to these conditions, you may download, * copy, install, use, modify and distribute modified or unmodified * copies of this software in source and/or binary form. No title * or ownership is transferred hereby. * * 1) Any source code used, modified or distributed must reproduce * and retain this copyright notice and list of conditions * as they appear in the source file. * * 2) No right is granted to use any trade name, trademark, or * logo of Broadcom Corporation. The "Broadcom Corporation" * name may not be used to endorse or promote products derived * from this software without the prior written permission of * Broadcom Corporation. * * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ********************************************************************* */ #include "lib_types.h" #include "lib_string.h" #include "lib_malloc.h" #include "lib_printf.h" #include "cfe_iocb.h" #include "cfe_device.h" #include "cfe_console.h" #include "cfe_timer.h" #include "env_subr.h" #include "ui_command.h" #include "cfe_mem.h" #include "cfe.h" #include "bsp_config.h" #include "bcm_hwdefs.h" #include "bcm_map.h" #include "exception.h" #include "segtable.h" #include "initdata.h" #if defined(_BCM96368_) || defined(_BCM96362_) || defined(_BCM96328_) || defined(_BCM96816_) #include "flash_api.h" #include "jffs2.h" #endif #if CFG_PCI #include "pcivar.h" #endif int cfe_size_ram(void); inline static int is_aliased(int max_bits) __attribute__((always_inline)); /* ********************************************************************* * Constants ********************************************************************* */ #ifndef CFG_STACK_SIZE #define STACK_SIZE 8192 #else #define STACK_SIZE ((CFG_STACK_SIZE+1023) & ~1023) #endif inline static int is_aliased(int max_bits) { volatile uint32 *mem_base; volatile uint32 *test_ptr; uint32 tmp; int bit; int res = 0; mem_base = (uint32*)DRAM_BASE_NOCACHE; *mem_base = 0; for (bit = 8; bit < max_bits; bit++) { test_ptr = (uint32*)((uint32)mem_base | 1 << bit); /* ram may contain useful data, save location before modifying */ tmp = *test_ptr; *test_ptr = -1; if (*mem_base == *test_ptr) { *test_ptr = tmp; res = 1; break; } *test_ptr = tmp; } return res; } #define MEMC_MAX_ROWS 14 int cfe_size_ram(void) { #if !(defined(_BCM96328_) || defined (_BCM96362_) || defined(_BCM96816_)) uint32 col_bits, row_bits, bus_bits, bank_bits; uint32 size; /* Bus width is configured during early boot */ if (((MEMC->Config & MEMC_WIDTH_MASK) >> MEMC_WIDTH_SHFT) == MEMC_32BIT_BUS) bus_bits = 2; else bus_bits = 1; bank_bits = 2; /* Start from setting to the lowest possible configuration */ col_bits = 8; row_bits = 11; MEMC->Config &= ~MEMC_COL_MASK; MEMC->Config |= ((col_bits - 8) << MEMC_COL_SHFT); MEMC->Config &= ~MEMC_ROW_MASK; MEMC->Config |= ((row_bits - 11) << MEMC_ROW_SHFT); /* Determine number of rows */ for (row_bits = 12; row_bits <= MEMC_MAX_ROWS; row_bits++) { MEMC->Config &= ~MEMC_ROW_MASK; MEMC->Config |= ((row_bits - 11) << MEMC_ROW_SHFT); /* check if this address bit is valid */ if (is_aliased (col_bits + row_bits + bus_bits + bank_bits)) break; } row_bits -= 1; MEMC->Config &= ~MEMC_ROW_MASK; MEMC->Config |= ((row_bits - 11) << MEMC_ROW_SHFT); /* Determine number of columns */ for (col_bits = 9; col_bits <= 11; col_bits++) { MEMC->Config &= ~MEMC_COL_MASK; MEMC->Config |= ((col_bits - 8) << MEMC_COL_SHFT); /* check if this address bit is valid */ if (is_aliased (col_bits + row_bits + bus_bits + bank_bits)) break; } col_bits -= 1; MEMC->Config &= ~MEMC_COL_MASK; MEMC->Config |= ((col_bits - 8) << MEMC_COL_SHFT); /* Compute memory size in MB */ size = 1 << (bus_bits + col_bits + row_bits + bank_bits - 20); return size; #else return (DDR->CSEND << 24); #endif } // fake functions for not to modifying init_mips.S void _exc_entry(void); void cfe_command_restart(void); void cfe_doxreq(void); void _exc_entry(void) { } void cfe_command_restart(void) { } void cfe_doxreq(void) { } /* ********************************************************************* * Externs ********************************************************************* */ void cfe_main(int,int); /* ********************************************************************* * Globals ********************************************************************* */ void cfe_ledstr(const char *leds) { } #if !defined(CONFIG_BRCM_IKOS) extern void _binArrayStart(void); extern void _binArrayEnd(void); extern int decompressLZMA(unsigned char *in, unsigned insize, unsigned char *out, unsigned outsize); #if (INC_NAND_FLASH_DRIVER==1) || (INC_SPI_PROG_NAND==1) #define je16_to_cpu(x) ((x).v16) #define je32_to_cpu(x) ((x).v32) extern void rom_nand_flash_init(void); extern int nand_flash_get_sector_size(unsigned short sector); extern int nand_flash_get_numsectors(void); extern int nand_flash_read_buf(unsigned short blk, int offset, unsigned char *buffer, int len); extern void board_setleds(unsigned long); void *lib_memcpy(void *dest,const void *src,size_t cnt) { unsigned char *d; const unsigned char *s; d = (unsigned char *) dest; s = (const unsigned char *) src; while (cnt) { *d++ = *s++; cnt--; } return dest; } int lib_memcmp(const void *dest,const void *src,size_t cnt) { const unsigned char *d; const unsigned char *s; d = (const unsigned char *) dest; s = (const unsigned char *) src; while (cnt) { if (*d < *s) return -1; if (*d > *s) return 1; d++; s++; cnt--; } return 0; } #if (INC_NAND_FLASH_DRIVER==1) /* Find uncompressed file cferam.bin on the JFFS2 file system, load it into * memory and jump to its entry point function. */ char g_fname[] = NAND_CFE_RAM_NAME; int g_fname_actual_len = sizeof(g_fname) - 1; int g_fname_cmp_len = sizeof(g_fname) - 4; /* last three are digits */ static void bootImageFromNand(void) { const unsigned long bv_invalid = 0xfffffff; const int max_not_jffs2 = 10; struct rootfs_info { int rootfs; int start_blk; int end_blk; unsigned long boot_val; unsigned long ino; } rfs_info[2], *prfs_info[2], *rfsi; unsigned char *buf = (unsigned char *) mem_heapstart; unsigned long version = 0; struct jffs2_raw_dirent *pdir; struct jffs2_raw_inode *pino; unsigned char *p; int i, j, k, done, not_jffs2; int num_blks; int len; int boot_prev; PNVRAM_DATA nd; static int err0=0, err1=1; rom_nand_flash_init(); num_blks = nand_flash_get_numsectors(); len = nand_flash_get_sector_size(0); nd = (PNVRAM_DATA) (buf + len); NAND->NandNandBootConfig = NBC_AUTO_DEV_ID_CFG | 0x101; NAND->NandCsNandXor = 1; memcpy((unsigned char *) nd, (unsigned char *) FLASH_BASE + NVRAM_DATA_OFFSET, sizeof(NVRAM_DATA)); NAND->NandNandBootConfig = NBC_AUTO_DEV_ID_CFG | 0x2; NAND->NandCsNandXor = 0; /* Look at config to determine whether to boot current or previous image.*/ for( i = 0, p = (unsigned char *) nd->szBootline, boot_prev = 0; i < NVRAM_BOOTLINE_LEN; i++, p++ ) { if( p[0] == ' ' && p[1] == 'p' && p[2] == '=' ) { boot_prev = p[3] - '0'; if( boot_prev != 0 && boot_prev != 1 ) boot_prev = '0'; break; } } /* Find the CFE ram inode entry point for both root file systems. */ board_setleds((boot_prev == 0) ? 0x4e414e30 : 0x4e414e31); for( k = 0, rfsi = rfs_info; k < 2; k++, rfsi++ ) { version = 0; not_jffs2 = 0; rfsi->rootfs = k + NP_ROOTFS_1; rfsi->boot_val = bv_invalid; if( nd->ulNandPartOfsKb[rfsi->rootfs] > 0 && nd->ulNandPartOfsKb[rfsi->rootfs] < ((num_blks * len) / 1024)) { rfsi->start_blk = nd->ulNandPartOfsKb[rfsi->rootfs] / (len/1024); rfsi->end_blk = rfsi->start_blk + (nd->ulNandPartSizeKb[rfsi->rootfs] / (len / 1024)); } else rfsi->start_blk = rfsi->end_blk = 0; if( rfsi->start_blk == 0 || rfsi->start_blk >= rfsi->end_blk || rfsi->start_blk >= num_blks || rfsi->end_blk >= num_blks ) { /* NVRAM_DATA fields for this rootfs are not valid. */ if( k == 0 ) { /* Skip this rootfs. */ board_setleds(0x4e414e36); continue; } if( rfs_info[0].boot_val == bv_invalid ) { /* File system info cannot be found for either rootfs. * NVRAM_DATA may not be set. Use default values. */ board_setleds(0x4e414e37); rfsi = rfs_info; rfsi->start_blk = 1; rfsi->end_blk = num_blks; } } /* Find the directory entry. */ for( i = rfsi->start_blk, done = 0; i < rfsi->end_blk && done == 0; i++ ) { /* This loop sequentially reads a NAND flash block into memory and * processes it. */ if( nand_flash_read_buf(i, 0, buf, len) > 0 ) { /* This loop reads inodes in a block. */ p = buf; while( p < buf + len ) { pdir = (struct jffs2_raw_dirent *) p; if( je16_to_cpu(pdir->magic) == JFFS2_MAGIC_BITMASK ) { if( je16_to_cpu(pdir->nodetype) == JFFS2_NODETYPE_DIRENT && g_fname_actual_len == pdir->nsize && !memcmp(g_fname, pdir->name, g_fname_cmp_len) ) { /* The desired directory was found. */ if( je32_to_cpu(pdir->version) > version ) { if( (rfsi->ino = je32_to_cpu(pdir->ino)) != 0 ) { unsigned char *fname = pdir->name + g_fname_cmp_len; rfsi->boot_val = ((fname[0] - '0') * 100) + ((fname[1] - '0') * 10) + ((fname[2] - '0') * 1); version = je32_to_cpu(pdir->version); board_setleds(0x42540000 + ((unsigned long) fname[1] << 8) + (unsigned long) fname[2]); /* Setting 'done = 1' assumes there is only * one version of the directory entry. This * may not be correct if the file is * updated after it was initially flashed. * * TBD. Look for a higher version of the * directory entry without searching the * entire flash part. */ done = 1; break; } } } p += (je32_to_cpu(pdir->totlen) + 0x03) & ~0x03; not_jffs2 = 0; } else { if( not_jffs2++ > max_not_jffs2 ) { /* No JFFS2 magic bitmask for consecutive blocks. * Assume this partion does not have a file system * on it. */ board_setleds(0x53544F50); done = 1; } break; } } } else { if(!err0) { err0=1; board_setleds(0x45525230); } } } board_setleds(0x4e414e39); } /* Set the rfs_info to the index to boot from. */ if( (boot_prev == 0 && rfs_info[0].boot_val > rfs_info[1].boot_val) || (boot_prev == 1 && rfs_info[0].boot_val < rfs_info[1].boot_val) || rfs_info[1].boot_val == bv_invalid ) { /* Boot from the most recent image. */ prfs_info[0] = &rfs_info[0]; prfs_info[1] = &rfs_info[1]; } else { /* Boot from the previous image. */ prfs_info[0] = &rfs_info[1]; prfs_info[1] = &rfs_info[0]; } /* If the directory entry for the desired file, which is the CFE RAM image, * is found, read it into memory and jump to its entry point function. * This loop checks for CFE RAM image in two possible rootfs file sytems. */ for( k = 0; k < 2; k++ ) { unsigned char *pucDest = NULL; unsigned char *pucEntry = NULL; long isize = 0; board_setleds(0x4e414e33); rfsi = prfs_info[k]; if( rfsi->boot_val == bv_invalid ) continue; /* When j == 0, get the first inode to find the entry point address. * When j == 1, read the file contents into memory. */ for( j = 0; j < 2; j++ ) { /* This loop sequentially reads a NAND flash block into memory and * processes it. */ for(i = rfsi->start_blk, done = 0; iend_blk && done==0; i++) { if( nand_flash_read_buf(i, 0, buf, len) > 0 ) { /* This loop reads inodes in a block. */ p = buf; while( p < buf + len ) { /* Verify the first short word is the JFFS2 magic * number. */ pino = (struct jffs2_raw_inode *) p; if( je16_to_cpu(pino->magic) == JFFS2_MAGIC_BITMASK ) { if( je16_to_cpu(pino->nodetype) == JFFS2_NODETYPE_INODE && je32_to_cpu(pino->ino) == rfsi->ino ) { unsigned long size = je32_to_cpu(pino->dsize); unsigned long ofs = je32_to_cpu(pino->offset); if( size ) { /* A node of the CFE RAM file was found * with data. */ if( pucDest == NULL ) { /* The entry point and copy destination * addresses have not been obtained. * If this is the first node of the CFE * RAM file, obtain this information. */ if( ofs == 0 ) { /* The first 12 bytes contain a * header. The first word is the * entry point address. */ pucEntry = (unsigned char *) *(unsigned long *) pino->data; pucDest = pucEntry - 12; isize = je32_to_cpu(pino->isize); done = 1; board_setleds(0x52465330 | rfsi->rootfs); break; } } else { /* Copy the image to memory. Stop when * the entire image has been copied. */ memcpy(pucDest+ofs, pino->data, size); if( (isize -= size) <= 0 ) { done = 1; break; } } } } /* Skip to the next inode entry. */ p += (je32_to_cpu(pino->totlen) + 0x03) & ~0x03; } else break; } } else { if(!err1) { err1=1; board_setleds(0x45525231); } } } } if( pucEntry && isize <= 0 ) { board_setleds(0x4e414e35); /* Save the rootfs partition that the CFE RAM image boots from * at the memory location before the CFE RAM load address. The * CFE RAM image uses this value to determine the partition to * flash a new rootfs to. */ *(pucEntry - 1) = (unsigned char) rfsi->rootfs; cfe_launch((unsigned long) pucEntry); // never return... } board_setleds(0x4e414e38); } /* Error occurred. */ board_setleds(0x44494530); while(1); } #endif #endif /* ********************************************************************* * cfe_main(a,b) * * It's gotta start somewhere. * Input parameters: * a,b - not used * * Return value: * does not return ********************************************************************* */ void cfe_main(int a,int b) { unsigned char *pucSrc; unsigned char *pucDst; unsigned int *entryPoint; unsigned int binArrayStart = (unsigned int) _binArrayStart; unsigned int binArrayEnd = (unsigned int) _binArrayEnd; unsigned int dataLen = binArrayEnd - binArrayStart - 4; int ret; KMEMINIT((unsigned char *) (uint32_t) mem_heapstart, ((CFG_HEAP_SIZE)*1024)); #if (INC_NAND_FLASH_DRIVER==1) && (defined(_BCM96816_) || defined(_BCM96362_) || defined(_BCM96328_)) if( ((MISC->miscStrapBus & MISC_STRAP_BUS_BOOT_SEL_MASK) >> MISC_STRAP_BUS_BOOT_SEL_SHIFT) == MISC_STRAP_BUS_BOOT_NAND ) { bootImageFromNand(); /* Will not return. */ } #elif (INC_NAND_FLASH_DRIVER==1) && defined(_BCM96368_) if( ((GPIO->StrapBus & MISC_STRAP_BUS_BOOT_SEL_MASK) >> MISC_STRAP_BUS_BOOT_SEL_SHIFT) == MISC_STRAP_BUS_BOOT_NAND ) { bootImageFromNand(); /* Will not return. */ } #endif entryPoint = (unsigned int*) binArrayStart; pucSrc = (unsigned char *) (binArrayStart + 4); pucDst = (unsigned char *) *entryPoint; ret = decompressLZMA((unsigned char*)pucSrc, (unsigned int)dataLen, (unsigned char *) pucDst, 23*1024*1024); if (ret != 0) while (1); // if not decompressed ok, loop for EJTAG cfe_launch((unsigned long) pucDst); // never return... } #else /* 0x694b6f31 (iKo1) is replaced with actual address during the build process.*/ unsigned long cfeRamStartAddr=0x694b6f31; void cfe_main(int a,int b) { cfe_size_ram(); cfe_launch(cfeRamStartAddr); // never return... } #endif