/*************************************************************************** * Copyright (c) 2011, Broadcom Corporation * All Rights Reserved * Confidential Property of Broadcom Corporation * * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. * * $brcm_Workfile: $ * $brcm_Revision: $ * $brcm_Date: $ * * Module Description: Jtag flash programming module. This module is * concatenated with compressed flash image and used to update flash * using EJTAG connection. This module must be used when bootloader already * in flash or memory is initialized using some other method like BBS script. * * Revision History: * * $brcm_Log: $ * * ***************************************************************************/ #include "fast_heap.h" #include "zlib.h" #include "bchp_rdc.h" #include "bchp_sun_top_ctrl.h" #include "jflu_spi.h" #define RAM_TEXT_BASE 0x80016000 #define RAM_TEXT_SIZE 0x01000000 /** The utility now supports programming any binary at a specified offset. The offset and a magic number must be written the respective registers before the _jflu binary runs. This can be done with a simple gdb script or a simple bbs script. The magic number must be programmed in the OFFSET_MAGIC_REG and the offset itself must be programmed in to the OFFSET_REG. The magic number value is 0x4f464653 (OFFS). Code will first look at presence of magic number in the register and if it is present, code will apply the offset. If magic number is not present, the offset will be 0. */ #define OFFSET_MAGIC 0x4f464653 #define OFFSET_MAGIC_REG BCHP_RDC_scratch_i_ARRAY_BASE #define OFFSET_REG (BCHP_RDC_scratch_i_ARRAY_BASE + 4) #define REG_BASE 0xb0000000 #define ReadReg32(reg) (*((volatile uint32_t *)((unsigned int)(reg) + REG_BASE))) #define WriteReg32(reg, data) (*((volatile uint32_t *)((unsigned int)(reg) + REG_BASE)) = (data)) extern void clear_all_d_cache(void); extern void invalidate_all_i_cache(void); /* output character on serial port */ extern void _writeasm(unsigned int a); extern void udelay(int microseconds); static int decompress(unsigned char *in_buf, unsigned int in_size, unsigned char * out_buf, unsigned int out_size); void update_flash(unsigned int offset, unsigned char * data, int data_size); void jflu_chip_reset(void); extern unsigned int comp_size; extern unsigned int _edata; extern unsigned int _end; void strout(char *s) { while (*s) { _writeasm(*s++); } return; } void *memset(void *dest,int c,size_t count) { uint8_t *d = dest; for(;count>0;count--) { *d++ = c; } return dest; } int decompress(unsigned char *in_buf, unsigned int in_size, unsigned char * out_buf, unsigned int out_size) { z_stream strm; int ret; memset(&strm,0,sizeof(strm)); strm.avail_in = in_size; strm.next_in = in_buf; strm.avail_out = out_size; strm.next_out = out_buf; ret = inflateInit2(&strm, 15+32); if (ret == Z_OK) { ret = inflate(&strm, Z_FINISH); inflateEnd(&strm); if ((ret == Z_STREAM_END) || (ret == Z_OK)) { return strm.total_out; } else if (ret > 0) { return -ret; } } return ret; } void bcm_main(void) { unsigned char * compressed_image; unsigned int compressed_size; int dlen; /* decompressed length */ unsigned char * ddata; /* decompressed data */ unsigned int flash_offset; fast_heap_init((unsigned long)&_end); compressed_image = (unsigned char *) &_edata; compressed_size = (unsigned int) &comp_size; ddata = (unsigned char *) RAM_TEXT_BASE; strout("\r\n\r\n"); strout("Decompressing flash image ... "); dlen = decompress(compressed_image, compressed_size, ddata, RAM_TEXT_SIZE); /* we got decompressed image at RAM_TEXT_BASE location and size of the image is in dlen. */ if(0 < dlen){ strout("OK\r\n"); }else{ strout("Fail\r\n"); goto ExitFunc; } flash_offset = ReadReg32(OFFSET_MAGIC_REG); if(OFFSET_MAGIC == flash_offset){ strout("Writing at specified offset ...\r\n"); flash_offset = ReadReg32(OFFSET_REG); }else{ strout("Writing at default offset ...\r\n"); flash_offset = 0; } update_flash(flash_offset, ddata, dlen); udelay(2000000); jflu_chip_reset(); ExitFunc: while(1); } spi_flash_t fl; char indicator1[4] = "|/-\\"; void update_flash(unsigned int offset, unsigned char * data, int data_size) { int res; int sector_count; unsigned int curr_offset; int i, in; unsigned char * page_data; int remaining_size; int block_size; jflu_spi_init(&fl); res = jflu_spi_identify(&fl); if(SPI_OK != res){ strout("Unable to identify SPI flash.\n\r"); goto ExitFunc; } sector_count = data_size / fl.sector_size; if(data_size % fl.sector_size){ sector_count += 1; } /* erase sectors */ curr_offset = offset; in = 0; strout("Erasing ... "); for(i = 0; i < sector_count; i++){ res = jflu_spi_sector_erase(&fl, curr_offset); _writeasm(indicator1[in]); _writeasm('\b'); in++; in &= 3; if(SPI_OK != res){ strout("Unable to erase sector.\n\r"); goto ExitFunc; } curr_offset += fl.sector_size; } strout("Done\n\r"); curr_offset = offset; page_data = data; remaining_size = data_size; in = 0; strout("Writing ... "); while(remaining_size > 0){ if(remaining_size > fl.page_size){ block_size = fl.page_size; }else{ block_size = remaining_size; } res = jflu_spi_page_program(&fl, curr_offset, page_data, block_size); if(SPI_OK != res){ strout("Unable to program page.\n\r"); goto ExitFunc; } if(curr_offset % 0x8000){ _writeasm(indicator1[in]); _writeasm('\b'); in++; in &= 3; } remaining_size -= block_size; page_data = page_data + block_size; curr_offset += block_size; } strout("Done\n\r"); ExitFunc: return; } void jflu_chip_reset(void) { uint32_t value; #if (BCHP_CHIP == 7550) value = ReadReg32(BCHP_SUN_TOP_CTRL_RESET_CTRL); value |= 0x8; /* master_reset_en */ WriteReg32(BCHP_SUN_TOP_CTRL_RESET_CTRL, value); value = ReadReg32(BCHP_SUN_TOP_CTRL_SW_RESET); value |= 0x80000000; /* chip_master_reset */ WriteReg32(BCHP_SUN_TOP_CTRL_SW_RESET, value); #endif #if (BCHP_CHIP == 7552) value = ReadReg32(BCHP_SUN_TOP_CTRL_RESET_SOURCE_ENABLE); value |= BCHP_SUN_TOP_CTRL_RESET_SOURCE_ENABLE_sw_master_reset_enable_MASK; WriteReg32(BCHP_SUN_TOP_CTRL_RESET_SOURCE_ENABLE, value); value = ReadReg32(BCHP_SUN_TOP_CTRL_SW_MASTER_RESET); value |= BCHP_SUN_TOP_CTRL_SW_MASTER_RESET_chip_master_reset_MASK; WriteReg32(BCHP_SUN_TOP_CTRL_SW_MASTER_RESET, value); #endif } /* Please do not remove! */ /* Local Variables: */ /* mode: C */ /* indent-tabs-mode: nil */ /* End: */