cksm implemented (still basic flash access not working!)
[my-code/arm.git] / betty / fwflash.c
1 /*
2  * fwflash.c - handling the betty flashes
3  *
4  * author: hackbard@hackdaworld.org
5  *
6  */
7
8 /*
9  * include files
10  */
11
12 #include <stdio.h>
13
14 #include "lpc2xxx.h"
15
16 /*
17  * defines
18  */
19
20 /* bank 0/2 and boootloader addr/size */
21 #define BANK0                   0x80000000
22 #define BANK2                   0x82000000
23 #define BANK_SIZE               0x00100000
24 #define BOOTLOADER              0x7fffe000
25 #define BL_SIZE                 0x00002000
26
27 /* flash cmd addresses - flash[0-18] <--> arm[1-19]*/
28 #define B0F555  (*((volatile unsigned short *)(BANK0|0xaaa)))   // 0x555
29 #define B0F2AA  (*((volatile unsigned short *)(BANK0|0x554)))   // 0x2aa
30 #define B0F     (*((volatile unsigned short *)(BANK0)))
31 #define B2F555  (*((volatile unsigned short *)(BANK2|0xaaa)))   // 0x555
32 #define B2F2AA  (*((volatile unsigned short *)(BANK2|0x554)))   // 0x2aa
33 #define B2F     (*((volatile unsigned short *)(BANK2)))
34
35 /* commands */
36 #define CMD_READ                'R'
37 #define CMD_WRITE               'W'
38 #define CMD_CHIP_ERASE          'E'
39 #define CMD_SECTOR_ERASE        'S'
40 #define CMD_CHIP_ID             'I'
41
42 #define BUFSIZE                 16
43
44 /*
45  * type definitions
46  */
47
48 typedef unsigned char u8;
49 typedef unsigned short u16;
50 typedef unsigned int u32;
51
52 /*
53  * sector addresses
54  */
55
56 unsigned long sector_address[19]={
57         0x00000,0x02000,0x03000,0x04000,0x08000,
58         0x10000,0x18000,
59         0x20000,0x28000,
60         0x30000,0x38000,
61         0x40000,0x48000,
62         0x50000,0x58000,
63         0x60000,0x68000,
64         0x70000,0x78000
65 };
66
67 /*
68  * functions
69  */
70
71 void mmap_init(u8 memtype) {
72
73         MEMMAP=memtype;
74 }
75
76 void pll_init(void) {
77
78         /* configuration */
79         PLLCFG=0x42;    // multiplier = 3 (for cclk), dividor = 4 (for f_cco)
80         PLLCON=0x03;    // enable and set as clk source for the lpc
81         /* feed sequence */
82         PLLFEED=0xaa;
83         PLLFEED=0x55;
84         /* wait for lock */
85         while(!(PLLSTAT&(1<<10)))
86                 continue;
87 }
88
89 int flash_sector_erase(u8 flash,u8 sector) {
90
91         u32 a18_12;
92         u32 base;
93
94         if(sector>18)
95                 return -1;
96         a18_12=sector_address[sector]<<1;
97
98         if((flash!='0')|(flash!='2'))
99                 return -1;
100
101         switch(flash) {
102                 case '0':
103                         base=0x80000000;
104                         B0F555=0xaa;
105                         B0F2AA=0x55;
106                         B0F555=0x80;
107                         B0F555=0xaa;
108                         B0F2AA=0x55;
109                         *((volatile u16 *)(base|a18_12))=0x30;
110                         break;
111                 case '2': 
112                         base=0x82000000;
113                         B2F555=0xaa;
114                         B2F2AA=0x55;
115                         B2F555=0x80;
116                         B2F555=0xaa;
117                         B2F2AA=0x55;
118                         *((volatile u16 *)(base|a18_12))=0x30;
119                         break;
120                 default:
121                         return -1;
122         }
123
124         return 0;
125 }
126
127 int flash_chip_erase(u8 bank) {
128
129         if((bank!='0')|(bank!='2'))
130                 return -1;
131
132         if(bank=='0') {
133                 B0F555=0xaa;
134                 B0F2AA=0x55;
135                 B0F555=0x80;
136                 B0F555=0xaa;
137                 B0F2AA=0x55;
138                 B0F555=0x10;
139         }
140         else {
141                 B2F555=0xaa;
142                 B2F2AA=0x55;
143                 B2F555=0x80;
144                 B2F555=0xaa;
145                 B2F2AA=0x55;
146                 B2F555=0x10;
147         }
148 }
149
150 void unlock_bypass(u8 bank) {
151
152         if((bank!='0')|(bank!='2'))
153                 return;
154
155         if(bank=='0') {
156                 B0F555=0xaa;
157                 B0F2AA=0x55;
158                 B0F555=0x20;
159         }
160         else {
161                 B2F555=0xaa;
162                 B2F2AA=0x55;
163                 B2F555=0x20;
164         }
165 }
166
167 void unlock_bypass_reset(u8 bank) {
168
169         if((bank!='0')|(bank!='2'))
170                 return;
171
172         if(bank=='0') {
173                 B0F=0x90;
174                 B0F=0x00;
175         }
176         else {
177                 B2F=0x90;
178                 B2F=0x00;
179         }
180 }
181
182 void flash_write(u32 addr,u16 data) {
183
184         *((volatile unsigned short *)addr)=0xa0;
185         *((volatile unsigned short *)addr)=data;
186 }
187
188 void ext_mem_bank_init(void) {
189
190         BCFG0=0x10000420;       // flash 1
191         BCFG1=0x00000c42;       // lcd
192         BCFG2=0x10000420;       // flash 2
193 }
194
195 void pin_select_init() {
196
197         /*
198          * a[19:2] -> address lines
199          */
200
201         PINSEL2=0x0d6041d4;
202 }
203
204 void uart0_init(void) {
205
206         PINSEL0=0x05;                   // pin select -> tx, rx
207         UART0_FCR=0x07;                 // enable fifo
208         UART0_LCR=0x83;                 // set dlab + word length
209         UART0_DLL=0x04;                 // br: 38400 @ 10/4 mhz
210         UART0_DLM=0x00;
211         UART0_LCR=0x03;                 // unset dlab
212 }
213
214 void uart0_send_string(char *txbuf) {
215
216         int i;
217
218         i=0;
219
220         while(txbuf[i]) {
221                 UART0_THR=txbuf[i++];
222                 /* flush if tx buffer maximum reached */
223                 if(!(i%16))
224                         while(!(UART0_LSR&(1<<6)))
225                                 continue;
226         }
227         
228         /* flush if \n and \r do not fit in the tx buffer */
229         if(i>14)
230                 while(!(UART0_LSR&(1<<6)))
231                         continue;
232
233         UART0_THR='\n';
234         UART0_THR='\r';
235
236         /* flush uart0 anyways */
237         while(!(UART0_LSR&(1<<6)))
238                 continue;
239 }
240
241 void uart0_send_buf16(u16 *buf,int len) {
242
243         int i;
244
245         i=0;
246
247         for(i=0;i<len/2;i++) {
248                 if(!(i%8))
249                         while(!(UART0_LSR&(1<<6)))
250                                 continue;
251                 UART0_THR=buf[i]&0xff;
252                 UART0_THR=(buf[i]>>8)&0xff;
253         }
254 }
255
256 void uart0_send_buf32(u32 *buf,int len) {
257
258         int i;
259
260         i=0;
261
262         for(i=0;i<len/4;i++) {
263                 if(!(i%4))
264                         while(!(UART0_LSR&(1<<6)))
265                                 continue;
266                 UART0_THR=buf[i]&0xff;
267                 UART0_THR=(buf[i]>>8)&0xff;
268                 UART0_THR=(buf[i]>>16)&0xff;
269                 UART0_THR=(buf[i]>>24)&0xff;
270         }
271 }
272
273 void uart0_send_byte(u8 send) {
274
275         while(!(UART0_LSR&(1<<5)))
276                 continue;
277
278         UART0_THR=send;
279 }
280
281 u8 uart0_get_byte(void) {
282
283         u8 rx;
284
285         while(!(UART0_LSR&(1<<0)))
286                 continue;
287
288         rx=UART0_RBR;
289
290         return rx;
291 }
292
293 void receive_data_and_write_to_flash(u32 addr,u32 datalen) {
294
295         u8 bank;
296         u32 i;
297         u16 data;
298         u8 byte;
299         u8 cksm;
300
301         /* which bank to program */
302         if(addr<0x82000000)
303                 bank='0';
304         else
305                 bank='2';
306
307         /* unlock bypass */
308         unlock_bypass(bank);
309
310         /* receive and write data */
311         cksm=0;
312         for(i=0;i<datalen/2;i++) {
313                 byte=uart0_get_byte();
314                 data=byte;
315                 cksm+=byte;
316                 byte=uart0_get_byte();
317                 cksm+=byte;
318                 data|=byte<<8;
319                 *((unsigned volatile short *)addr)=0xa0;
320                 *((unsigned volatile short *)addr)=data;
321                 addr+=2;
322         }
323
324         /* relock bypass */
325         unlock_bypass_reset(bank);
326
327         /* send an ack */
328         uart0_send_byte(cksm);
329 }
330
331 /*
332  * main function
333  */
334
335 int main(void) {
336
337         /* variables */
338
339         u32 i,addrlen,datalen,addr;
340         u8 buf[BUFSIZE];
341         u16 data;
342         u8 cmd;
343         u8 txrx;
344
345         /* memory mapping of interrupt vectors to static ram */
346
347         //mmap_init(MMAP_RAM);
348         
349         /* pll initialization */
350         pll_init();
351
352         /* uart initialization */
353         uart0_init();
354
355         /* external memory init */
356         ext_mem_bank_init();
357
358         /* pin select init */
359         pin_select_init();
360
361         /* begin the main loop */
362         while(1) {
363
364         /* receive cmd */
365         while(1) {
366
367                 cmd=uart0_get_byte();
368                 txrx=1;
369                 switch(cmd) {
370                         case CMD_CHIP_ERASE:
371                                 addrlen=0;
372                                 datalen=1;
373                                 break;
374                         case CMD_SECTOR_ERASE:
375                                 addrlen=0;
376                                 datalen=2;
377                                 break;
378                         case CMD_READ:
379                                 addrlen=4;
380                                 datalen=4;
381                         case CMD_WRITE:
382                                 addrlen=4;
383                                 datalen=4;
384                                 break;
385                         case CMD_CHIP_ID:
386                                 addrlen=0;
387                                 datalen=1;
388                                 break;
389                         default:
390                                 txrx=0;
391                                 break;
392                 }
393
394                 if(txrx)
395                         break;
396         }
397
398         /* receive (only if there is) more data from uart0 */
399         addr=0;
400         for(i=0;i<addrlen;i++) {
401                 txrx=uart0_get_byte();
402                 addr|=(txrx<<((addrlen-i-1)*8));
403         }
404
405         for(i=0;i<datalen;i++)
406                 buf[i]=uart0_get_byte();
407
408         /* process the cmd */
409         switch(cmd) {
410                 case CMD_SECTOR_ERASE:
411                         flash_sector_erase(buf[0],buf[1]);
412                         break;
413                 case CMD_READ:
414                         /* data length to read */
415                         datalen=buf[0]<<24|buf[1]<<16|buf[2]<<8|buf[3];
416                         /* check addr and datalen */
417                         if((addr>=BANK0)&(addr+datalen<=BANK0+BANK_SIZE))
418                                 uart0_send_buf16((u16 *)addr,datalen);
419                         if((addr>=BANK2)&(addr+datalen<=BANK2+BANK_SIZE))
420                                 uart0_send_buf16((u16 *)addr,datalen);
421                         if((addr>=BOOTLOADER)&(addr+datalen<=BOOTLOADER+BL_SIZE))
422                                 uart0_send_buf32((u32 *)addr,datalen);
423                         break;
424                 case CMD_WRITE:
425                         /* data length */
426                         datalen=buf[0]<<24|buf[1]<<16|buf[2]<<8|buf[3];
427                         /* check addr and data len */
428                         if(((addr>=BANK0)&(addr+datalen<=BANK0+BANK_SIZE))|
429                            ((addr>=BANK2)&(addr+datalen<=BANK2+BANK_SIZE)))
430                                 receive_data_and_write_to_flash(addr,datalen);
431                         break;
432                 case CMD_CHIP_ERASE:
433                         flash_chip_erase(buf[0]);
434                         break;
435                 case CMD_CHIP_ID:
436                         if(buf[0]=='0') {
437                                 B0F555=0xaa;
438                                 B0F2AA=0x55;
439                                 B0F555=0x90;
440                                 data=*((u16 *)BANK0);
441                                 uart0_send_buf16(&data,2);
442                                 data=*((u16 *)(BANK0|0x200));
443                                 uart0_send_buf16(&data,2);
444                         }
445                         else if(buf[0]=='2') {
446                                 B2F555=0xaa;
447                                 B2F2AA=0x55;
448                                 B2F555=0x90;
449                                 data=*((u16 *)BANK2);
450                                 uart0_send_buf16(&data,2);
451                                 data=*((u16 *)(BANK2|0x200));
452                                 uart0_send_buf16(&data,2);
453                         }
454                         break;
455                 default:
456                         break;
457         }
458                 
459         }
460
461         return 0;
462 }
463