| 1 | /*************************************************************************** |
|---|
| 2 | * Copyright (c) 2011, Broadcom Corporation |
|---|
| 3 | * All Rights Reserved |
|---|
| 4 | * Confidential Property of Broadcom Corporation |
|---|
| 5 | * |
|---|
| 6 | * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE |
|---|
| 7 | * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR |
|---|
| 8 | * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. |
|---|
| 9 | * |
|---|
| 10 | * $brcm_Workfile: $ |
|---|
| 11 | * $brcm_Revision: $ |
|---|
| 12 | * $brcm_Date: $ |
|---|
| 13 | * |
|---|
| 14 | * Module Description: Jtag flash programming module. This module is |
|---|
| 15 | * concatenated with compressed flash image and used to update flash |
|---|
| 16 | * using EJTAG connection. This module must be used when bootloader already |
|---|
| 17 | * in flash or memory is initialized using some other method like BBS script. |
|---|
| 18 | * |
|---|
| 19 | * Revision History: |
|---|
| 20 | * |
|---|
| 21 | * $brcm_Log: $ |
|---|
| 22 | * |
|---|
| 23 | * |
|---|
| 24 | ***************************************************************************/ |
|---|
| 25 | |
|---|
| 26 | #include "fast_heap.h" |
|---|
| 27 | #include "zlib.h" |
|---|
| 28 | #include "bchp_rdc.h" |
|---|
| 29 | #include "bchp_sun_top_ctrl.h" |
|---|
| 30 | #include "jflu_spi.h" |
|---|
| 31 | |
|---|
| 32 | #define RAM_TEXT_BASE 0x80016000 |
|---|
| 33 | #define RAM_TEXT_SIZE 0x01000000 |
|---|
| 34 | |
|---|
| 35 | /** |
|---|
| 36 | The utility now supports programming any binary at a specified offset. |
|---|
| 37 | The offset and a magic number must be written the respective registers |
|---|
| 38 | before the _jflu binary runs. This can be done with a simple gdb |
|---|
| 39 | script or a simple bbs script. The magic number must be programmed in |
|---|
| 40 | the OFFSET_MAGIC_REG and the offset itself must be programmed in to |
|---|
| 41 | the OFFSET_REG. The magic number value is 0x4f464653 (OFFS). Code will |
|---|
| 42 | first look at presence of magic number in the register and if it is |
|---|
| 43 | present, code will apply the offset. If magic number is not present, |
|---|
| 44 | the offset will be 0. |
|---|
| 45 | */ |
|---|
| 46 | #define OFFSET_MAGIC 0x4f464653 |
|---|
| 47 | #define OFFSET_MAGIC_REG BCHP_RDC_scratch_i_ARRAY_BASE |
|---|
| 48 | #define OFFSET_REG (BCHP_RDC_scratch_i_ARRAY_BASE + 4) |
|---|
| 49 | #define REG_BASE 0xb0000000 |
|---|
| 50 | #define ReadReg32(reg) (*((volatile uint32_t *)((unsigned int)(reg) + REG_BASE))) |
|---|
| 51 | #define WriteReg32(reg, data) (*((volatile uint32_t *)((unsigned int)(reg) + REG_BASE)) = (data)) |
|---|
| 52 | |
|---|
| 53 | extern void clear_all_d_cache(void); |
|---|
| 54 | extern void invalidate_all_i_cache(void); |
|---|
| 55 | /* output character on serial port */ |
|---|
| 56 | extern void _writeasm(unsigned int a); |
|---|
| 57 | extern void udelay(int microseconds); |
|---|
| 58 | |
|---|
| 59 | static int decompress(unsigned char *in_buf, unsigned int in_size, unsigned char * out_buf, unsigned int out_size); |
|---|
| 60 | |
|---|
| 61 | void update_flash(unsigned int offset, unsigned char * data, int data_size); |
|---|
| 62 | void jflu_chip_reset(void); |
|---|
| 63 | |
|---|
| 64 | extern unsigned int comp_size; |
|---|
| 65 | extern unsigned int _edata; |
|---|
| 66 | extern unsigned int _end; |
|---|
| 67 | |
|---|
| 68 | void strout(char *s) |
|---|
| 69 | { |
|---|
| 70 | while (*s) |
|---|
| 71 | { |
|---|
| 72 | _writeasm(*s++); |
|---|
| 73 | } |
|---|
| 74 | return; |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | |
|---|
| 78 | void *memset(void *dest,int c,size_t count) |
|---|
| 79 | { |
|---|
| 80 | uint8_t *d = dest; |
|---|
| 81 | for(;count>0;count--) { |
|---|
| 82 | *d++ = c; |
|---|
| 83 | } |
|---|
| 84 | return dest; |
|---|
| 85 | } |
|---|
| 86 | |
|---|
| 87 | int decompress(unsigned char *in_buf, unsigned int in_size, unsigned char * out_buf, unsigned int out_size) |
|---|
| 88 | { |
|---|
| 89 | z_stream strm; |
|---|
| 90 | int ret; |
|---|
| 91 | |
|---|
| 92 | memset(&strm,0,sizeof(strm)); |
|---|
| 93 | strm.avail_in = in_size; |
|---|
| 94 | strm.next_in = in_buf; |
|---|
| 95 | strm.avail_out = out_size; |
|---|
| 96 | strm.next_out = out_buf; |
|---|
| 97 | ret = inflateInit2(&strm, 15+32); |
|---|
| 98 | if (ret == Z_OK) |
|---|
| 99 | { |
|---|
| 100 | ret = inflate(&strm, Z_FINISH); |
|---|
| 101 | inflateEnd(&strm); |
|---|
| 102 | if ((ret == Z_STREAM_END) || (ret == Z_OK)) |
|---|
| 103 | { |
|---|
| 104 | return strm.total_out; |
|---|
| 105 | } |
|---|
| 106 | else if (ret > 0) |
|---|
| 107 | { |
|---|
| 108 | return -ret; |
|---|
| 109 | } |
|---|
| 110 | } |
|---|
| 111 | return ret; |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | void bcm_main(void) |
|---|
| 115 | { |
|---|
| 116 | unsigned char * compressed_image; |
|---|
| 117 | unsigned int compressed_size; |
|---|
| 118 | int dlen; /* decompressed length */ |
|---|
| 119 | unsigned char * ddata; /* decompressed data */ |
|---|
| 120 | unsigned int flash_offset; |
|---|
| 121 | |
|---|
| 122 | fast_heap_init((unsigned long)&_end); |
|---|
| 123 | |
|---|
| 124 | compressed_image = (unsigned char *) &_edata; |
|---|
| 125 | compressed_size = (unsigned int) &comp_size; |
|---|
| 126 | ddata = (unsigned char *) RAM_TEXT_BASE; |
|---|
| 127 | strout("\r\n\r\n"); |
|---|
| 128 | strout("Decompressing flash image ... "); |
|---|
| 129 | dlen = decompress(compressed_image, compressed_size, ddata, RAM_TEXT_SIZE); |
|---|
| 130 | /* we got decompressed image at RAM_TEXT_BASE location and size of the |
|---|
| 131 | image is in dlen. */ |
|---|
| 132 | if(0 < dlen){ |
|---|
| 133 | strout("OK\r\n"); |
|---|
| 134 | }else{ |
|---|
| 135 | strout("Fail\r\n"); |
|---|
| 136 | goto ExitFunc; |
|---|
| 137 | } |
|---|
| 138 | flash_offset = ReadReg32(OFFSET_MAGIC_REG); |
|---|
| 139 | if(OFFSET_MAGIC == flash_offset){ |
|---|
| 140 | strout("Writing at specified offset ...\r\n"); |
|---|
| 141 | flash_offset = ReadReg32(OFFSET_REG); |
|---|
| 142 | }else{ |
|---|
| 143 | strout("Writing at default offset ...\r\n"); |
|---|
| 144 | flash_offset = 0; |
|---|
| 145 | } |
|---|
| 146 | update_flash(flash_offset, ddata, dlen); |
|---|
| 147 | udelay(2000000); |
|---|
| 148 | jflu_chip_reset(); |
|---|
| 149 | ExitFunc: |
|---|
| 150 | while(1); |
|---|
| 151 | } |
|---|
| 152 | |
|---|
| 153 | spi_flash_t fl; |
|---|
| 154 | char indicator1[4] = "|/-\\"; |
|---|
| 155 | |
|---|
| 156 | void update_flash(unsigned int offset, unsigned char * data, int data_size) |
|---|
| 157 | { |
|---|
| 158 | int res; |
|---|
| 159 | int sector_count; |
|---|
| 160 | unsigned int curr_offset; |
|---|
| 161 | int i, in; |
|---|
| 162 | unsigned char * page_data; |
|---|
| 163 | int remaining_size; |
|---|
| 164 | int block_size; |
|---|
| 165 | |
|---|
| 166 | jflu_spi_init(&fl); |
|---|
| 167 | res = jflu_spi_identify(&fl); |
|---|
| 168 | if(SPI_OK != res){ |
|---|
| 169 | strout("Unable to identify SPI flash.\n\r"); |
|---|
| 170 | goto ExitFunc; |
|---|
| 171 | } |
|---|
| 172 | sector_count = data_size / fl.sector_size; |
|---|
| 173 | if(data_size % fl.sector_size){ |
|---|
| 174 | sector_count += 1; |
|---|
| 175 | } |
|---|
| 176 | /* erase sectors */ |
|---|
| 177 | curr_offset = offset; |
|---|
| 178 | in = 0; |
|---|
| 179 | strout("Erasing ... "); |
|---|
| 180 | for(i = 0; i < sector_count; i++){ |
|---|
| 181 | res = jflu_spi_sector_erase(&fl, curr_offset); |
|---|
| 182 | _writeasm(indicator1[in]); |
|---|
| 183 | _writeasm('\b'); |
|---|
| 184 | in++; in &= 3; |
|---|
| 185 | if(SPI_OK != res){ |
|---|
| 186 | strout("Unable to erase sector.\n\r"); |
|---|
| 187 | goto ExitFunc; |
|---|
| 188 | } |
|---|
| 189 | curr_offset += fl.sector_size; |
|---|
| 190 | } |
|---|
| 191 | strout("Done\n\r"); |
|---|
| 192 | curr_offset = offset; |
|---|
| 193 | page_data = data; |
|---|
| 194 | remaining_size = data_size; |
|---|
| 195 | in = 0; |
|---|
| 196 | strout("Writing ... "); |
|---|
| 197 | while(remaining_size > 0){ |
|---|
| 198 | if(remaining_size > fl.page_size){ |
|---|
| 199 | block_size = fl.page_size; |
|---|
| 200 | }else{ |
|---|
| 201 | block_size = remaining_size; |
|---|
| 202 | } |
|---|
| 203 | res = jflu_spi_page_program(&fl, curr_offset, page_data, block_size); |
|---|
| 204 | if(SPI_OK != res){ |
|---|
| 205 | strout("Unable to program page.\n\r"); |
|---|
| 206 | goto ExitFunc; |
|---|
| 207 | } |
|---|
| 208 | if(curr_offset % 0x8000){ |
|---|
| 209 | _writeasm(indicator1[in]); |
|---|
| 210 | _writeasm('\b'); |
|---|
| 211 | in++; in &= 3; |
|---|
| 212 | } |
|---|
| 213 | remaining_size -= block_size; |
|---|
| 214 | page_data = page_data + block_size; |
|---|
| 215 | curr_offset += block_size; |
|---|
| 216 | } |
|---|
| 217 | strout("Done\n\r"); |
|---|
| 218 | ExitFunc: |
|---|
| 219 | return; |
|---|
| 220 | } |
|---|
| 221 | |
|---|
| 222 | void jflu_chip_reset(void) |
|---|
| 223 | { |
|---|
| 224 | uint32_t value; |
|---|
| 225 | #if (BCHP_CHIP == 7550) |
|---|
| 226 | value = ReadReg32(BCHP_SUN_TOP_CTRL_RESET_CTRL); |
|---|
| 227 | value |= 0x8; /* master_reset_en */ |
|---|
| 228 | WriteReg32(BCHP_SUN_TOP_CTRL_RESET_CTRL, value); |
|---|
| 229 | value = ReadReg32(BCHP_SUN_TOP_CTRL_SW_RESET); |
|---|
| 230 | value |= 0x80000000; /* chip_master_reset */ |
|---|
| 231 | WriteReg32(BCHP_SUN_TOP_CTRL_SW_RESET, value); |
|---|
| 232 | #endif |
|---|
| 233 | #if (BCHP_CHIP == 7552) |
|---|
| 234 | value = ReadReg32(BCHP_SUN_TOP_CTRL_RESET_SOURCE_ENABLE); |
|---|
| 235 | value |= BCHP_SUN_TOP_CTRL_RESET_SOURCE_ENABLE_sw_master_reset_enable_MASK; |
|---|
| 236 | WriteReg32(BCHP_SUN_TOP_CTRL_RESET_SOURCE_ENABLE, value); |
|---|
| 237 | value = ReadReg32(BCHP_SUN_TOP_CTRL_SW_MASTER_RESET); |
|---|
| 238 | value |= BCHP_SUN_TOP_CTRL_SW_MASTER_RESET_chip_master_reset_MASK; |
|---|
| 239 | WriteReg32(BCHP_SUN_TOP_CTRL_SW_MASTER_RESET, value); |
|---|
| 240 | #endif |
|---|
| 241 | } |
|---|
| 242 | |
|---|
| 243 | /* Please do not remove! */ |
|---|
| 244 | /* Local Variables: */ |
|---|
| 245 | /* mode: C */ |
|---|
| 246 | /* indent-tabs-mode: nil */ |
|---|
| 247 | /* End: */ |
|---|