root/ar5315_microredboot/microredboot/ecos/packages/devs/flash/atheros/spiflash/current/src/spiflash.c

Revision 12429, 11.1 kB (checked in by BrainSlayer, 5 months ago)

compressed ELF support is required for ubnt images

Line 
1 //==========================================================================
2 //
3 //      spiflash.c
4 //
5 //      Flash programming
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):    gthomas, hmt
44 // Contributors: gthomas
45 // Date:         2001-02-14
46 // Purpose:     
47 // Description: 
48 //             
49 //####DESCRIPTIONEND####
50 //
51 //==========================================================================
52
53 #include <pkgconf/system.h>
54 #include <pkgconf/hal.h>
55 #include <cyg/hal/hal_arch.h>
56 #define _FLASH_PRIVATE_
57 #include <cyg/io/flash.h>
58 #include <cyg/infra/diag.h>
59 #include <cyg/hal/hal_io.h>
60
61 #include "spiflash.h"
62
63 static cyg_uint32
64 sfi_Command(cyg_uint32 opcode, int write_len, int read_len)
65 {
66     cyg_uint32 reg, mask;
67
68     do {
69         HAL_READ_UINT32(AR2316_SPI_CTL, reg);
70     } while (reg & SPI_CTL_BUSY);
71     HAL_WRITE_UINT32(AR2316_SPI_OPCODE, opcode);
72     reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | (write_len<<0) | (read_len<<4) | SPI_CTL_START;
73     HAL_WRITE_UINT32(AR2316_SPI_CTL,reg);
74     if (read_len > 0) {
75         do {
76             HAL_READ_UINT32(AR2316_SPI_CTL, reg);
77         } while (reg & SPI_CTL_BUSY);
78         HAL_READ_UINT32(AR2316_SPI_DATA, reg);
79         switch (read_len) {
80         case 1:
81             mask = 0x000000ff;
82             break;
83         case 2:
84             mask = 0x0000ffff;
85             break;
86         case 3:
87             mask = 0x00ffffff;
88             break;
89         default:
90             mask = 0xffffffff;
91             break;
92         }
93         reg &= mask;
94     } else {
95         reg = 0;
96     }
97     return reg;
98 }
99
100 /*
101  * List of supported flash devices. The first index is the
102  * flash id returned by the probe.  The second is the number
103  * of blocks. The list is terminated with an id of -1
104  */
105 static cyg_int32 suppFlashList[][2] = {
106     {0x13, 16},
107     {0x14, 32},
108     {0x15, 64},
109     {0x16, 128},
110     {-1, -1}};
111
112 static cyg_int32
113 get_num_blocks(cyg_uint32 id)
114 {
115     cyg_int32 cnt=0;
116
117     while (suppFlashList[cnt][0] != -1) {
118         if (suppFlashList[cnt][0] == id) {
119             return(suppFlashList[cnt][1]);
120         }
121         cnt++;
122     }
123     return 0;
124 }
125
126 int
127 flash_hwr_init(void)
128 {
129     cyg_uint32 id;
130
131     id = sfi_Command(STM_OP_RD_SIG, 4, 1);
132
133     flash_info.buffer_size = 0;
134     flash_info.block_size = CYGNUM_FLASH_BLOCK_SIZE;
135     flash_info.blocks = get_num_blocks(id);
136     if (flash_info.blocks == 0) {
137         diag_printf("%s: Unsupported flash device - id=%d\n",__func__,id);
138         return FLASH_ERR_DRV_WRONG_PART;
139     }
140
141     flash_info.start = (void *)CYGNUM_FLASH_BASE;
142     flash_info.end = (void *)( CYGNUM_FLASH_BASE + (flash_info.block_size * flash_info.blocks));
143 #ifdef CYGNUM_FLASH_END_RESERVED_BYTES
144     flash_info.end = (void *)((unsigned int) flash_info.end - CYGNUM_FLASH_END_RESERVED_BYTES);
145 #endif
146     return FLASH_ERR_OK;
147 }
148
149 // Map a hardware status to a package error
150 int
151 flash_hwr_map_error(int err)
152 {
153     return err;
154 }
155
156 // See if a range of FLASH addresses overlaps currently running code
157 bool
158 flash_code_overlaps(void *start, void *end)
159 {
160     extern char _stext[], _etext[];
161
162     return ((((unsigned long)&_stext >= (unsigned long)start) &&
163              ((unsigned long)&_stext < (unsigned long)end)) ||
164             (((unsigned long)&_etext >= (unsigned long)start) &&
165              ((unsigned long)&_etext < (unsigned long)end)));
166 }
167
168 void udelay(int usec);
169
170 int flash_erase_block(volatile flash_t *block, unsigned int block_size)
171         __attribute__ ((section (".2ram.flash_erase_block")));
172 int flash_erase_block(volatile flash_t *block, unsigned int block_size)
173 {
174     cyg_uint32 res;
175     cyg_uint32 offset = (cyg_uint32)block -  CYGNUM_FLASH_BASE;
176
177     sfi_Command(STM_OP_WR_ENABLE, 1, 0);
178         do {
179                 res = sfi_Command(STM_OP_RD_STATUS, 1, 1);
180                 if ((res & 0x3)==0x2) {
181                         break;
182                 }
183                 udelay(20);
184                 sfi_Command(STM_OP_WR_ENABLE, 1, 0);
185         } while (1);
186     sfi_Command(STM_OP_SECTOR_ERASE | (offset << 8), 4, 0);
187     while (true) {
188         res = sfi_Command(STM_OP_RD_STATUS, 1, 1);
189         if ((res & STM_STATUS_WIP) == 0) {
190             break;
191         }
192     }
193     return FLASH_ERR_OK;
194 }
195
196 int
197 flash_program_buf(volatile flash_t *addr, flash_t *buf, int len,
198                   unsigned long block_mask, int buffer_size)
199  __attribute__ ((section (".2ram.flash_program_buf")));
200  
201 /*GPIO0 based page programming support, stoneshih, 20Aug2007*/
202 #define AP61_R02HW 1
203 #ifdef AP61_R02HW
204
205 #define STM_PAGE_SIZE 256
206 #define PAGE_PROGRAM_OPCODE 2
207
208 extern int page_programming_supported;
209 extern int page_gpio;
210
211 static unsigned
212 spiflash_send_one_data_byte (unsigned char byte_in)  /*for page programming*/
213 {
214         unsigned reg;
215          
216         do {
217                 HAL_READ_UINT32(AR2316_SPI_CTL, reg);
218         } while (reg & SPI_CTL_BUSY);
219        
220         HAL_WRITE_UINT32(AR2316_SPI_OPCODE, byte_in);
221        
222         reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | 1 | SPI_CTL_START;/*send just 1 byte*/
223        
224         HAL_WRITE_UINT32(AR2316_SPI_CTL,reg);
225                
226         return reg;
227 }
228 void udelay(int usecs)
229 {
230         unsigned u1, clks;             
231         clks = usecs*40;
232         u1 = *(volatile unsigned*)0xb1000030;
233         while (u1 - *(volatile unsigned*)0xb1000030 < clks);
234 }
235
236 int
237 flash_program_buf(volatile flash_t *addr, flash_t *buf, int len,
238                   unsigned long block_mask, int buffer_size)
239 {
240     cyg_uint32 res;
241     cyg_uint32 offset = (cyg_uint32)addr -  CYGNUM_FLASH_BASE;
242     cyg_uint32 data = 0;
243     int data_len;
244     cyg_uint8 *cb = (cyg_uint8 *)buf;
245         int page_offset;
246         unsigned opcode, reg;
247         int first_spi_write_data_length,second_direct_byte_write_data_length,i;
248
249     while (len > 0) {
250         sfi_Command(STM_OP_WR_ENABLE, 1, 0);
251                 do {
252                         res = sfi_Command(STM_OP_RD_STATUS, 1, 1);
253                         if ((res & 0x3)==0x2) {
254                                 break;
255                         }
256                         udelay(20);
257                         sfi_Command(STM_OP_WR_ENABLE, 1, 0);
258                 } while (1);
259        
260                 if (page_programming_supported){
261                         if (len < STM_PAGE_SIZE)
262                                 data_len = len;
263                         else
264                                 data_len = STM_PAGE_SIZE;
265                 }
266                 else {
267                         if (len < 4)
268                                 data_len = len;
269                         else
270                                 data_len = 4;
271                 }
272                
273                 page_offset = (offset & (STM_PAGE_SIZE - 1)) + data_len;
274
275                 if (page_offset > STM_PAGE_SIZE) {
276                         data_len -= (page_offset - STM_PAGE_SIZE);
277                 }
278
279         do {
280                 HAL_READ_UINT32(AR2316_SPI_CTL, reg);
281         } while (reg & SPI_CTL_BUSY);
282
283                 if (data_len <= 4) {
284                 switch (data_len) {
285             case 1:
286                     data = *cb;
287                 break;
288                 case 2:
289                 data = (cb[1] << 8) | cb[0];
290                 break;
291                 case 3:
292                 data = (cb[2] << 16) | (cb[1] << 8) | cb[0];
293                 break;
294                 case 4:
295                 data = (cb[3] << 24) | (cb[2] << 16) | (cb[1] << 8) | cb[0];
296                 break;
297                 }
298                         first_spi_write_data_length = data_len;
299                         second_direct_byte_write_data_length = 0;
300                 }
301                 else {
302                         data = (cb[3] << 24) | (cb[2] << 16) | (cb[1] << 8) | cb[0];
303                         first_spi_write_data_length = 4;
304                         second_direct_byte_write_data_length = data_len - 4;
305                 }
306                
307                 if ((page_programming_supported) || (data != 0xffffffff)) {
308
309                         //should disable interrupt here to avoid time gap between writes
310                         //__asm("di");//disable interrupt
311
312                         HAL_WRITE_UINT32(AR2316_SPI_DATA, data);                       
313                        
314                         opcode = (PAGE_PROGRAM_OPCODE) | ((cyg_uint32)offset << 8);
315                         HAL_WRITE_UINT32(AR2316_SPI_OPCODE, opcode);
316                         if (page_programming_supported)
317                         *(volatile unsigned*)0xB1000090 &= ~(1<<page_gpio);//0xfffffffe;/*set GPIO0 to 0 to dominate spi flash CS to low active*/
318                 reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | (first_spi_write_data_length + 4) | SPI_CTL_START;
319                 HAL_WRITE_UINT32(AR2316_SPI_CTL,reg);
320                                                                                                
321                         for (i=0; i<second_direct_byte_write_data_length; i++) {
322                                 spiflash_send_one_data_byte(cb[4+i]);
323                         }
324                
325                         /*wait for spi data write complete*/
326                 do {
327                 HAL_READ_UINT32(AR2316_SPI_CTL, reg);
328                 } while (reg & SPI_CTL_BUSY);
329
330                         if (page_programming_supported)
331                         *(volatile unsigned*)0xB1000090 |= 1<<page_gpio;/*set GPIO0 to 1 to spi flash CS normal state, this will start programming*/
332
333                         //As soon as Chip Select (S) is driven High, the self-timed Page Program cycle (whose
334                         //duration is tPP) is initiated.
335                
336                         //__asm("ei");//enable interrupt
337                                
338                 while (true) {
339                 res = sfi_Command(STM_OP_RD_STATUS, 1, 1);
340                     if ((res & STM_STATUS_WIP) == 0) {
341                     break;
342                 }
343                 }
344                 }
345                
346         offset += data_len;
347         cb += data_len;
348         len -= data_len;
349     }
350     return FLASH_ERR_OK;
351 }
352
353 #else
354 int
355 flash_program_buf(volatile flash_t *addr, flash_t *buf, int len,
356                   unsigned long block_mask, int buffer_size)
357 {
358     cyg_uint32 res;
359     cyg_uint32 offset = (cyg_uint32)addr -  CYGNUM_FLASH_BASE;
360     cyg_uint32 data = 0;
361     int data_len;
362     cyg_uint8 *cb = (cyg_uint8 *)buf;
363
364     while (len > 0) {
365         sfi_Command(STM_OP_WR_ENABLE, 1, 0);
366         data_len = len & 0x03;
367         if (data_len == 0) data_len = 4;
368         switch (data_len) {
369         case 1:
370             data = *cb;
371             break;
372         case 2:
373             data = (cb[1] << 8) | cb[0];
374             break;
375         case 3:
376             data = (cb[2] << 16) | (cb[1] << 8) | cb[0];
377             break;
378         case 4:
379             data = (cb[3] << 24) | (cb[2] << 16) | (cb[1] << 8) | cb[0];
380             break;
381         }
382         HAL_WRITE_UINT32(AR2316_SPI_DATA, data);
383         sfi_Command(STM_OP_PAGE_PGRM | (offset << 8), data_len+4, 0);
384         while (true) {
385             res = sfi_Command(STM_OP_RD_STATUS, 1, 1);
386             if ((res & STM_STATUS_WIP) == 0) {
387                 break;
388             }
389         }
390         offset += data_len;
391         cb += data_len;
392         len -= data_len;
393     }
394     return FLASH_ERR_OK;
395 }
396 #endif
397
398 // EOF spiflash.c
Note: See TracBrowser for help on using the browser.