bullshit commit, sync for travel (to zn00H!) :)
[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 uart0_send_byte(u8 send);
72
73 void mmap_init(u8 memtype) {
74
75         MEMMAP=memtype;
76 }
77
78 void pll_init(void) {
79
80         /* configuration */
81         PLLCFG=0x42;    // multiplier = 3 (for cclk), dividor = 4 (for f_cco)
82         PLLCON=0x03;    // enable and set as clk source for the lpc
83         /* feed sequence */
84         PLLFEED=0xaa;
85         PLLFEED=0x55;
86         /* wait for lock */
87         while(!(PLLSTAT&(1<<10)))
88                 continue;
89 }
90
91 void ext_mem_bank_init(void) {
92
93         BCFG0=0x10000420;       // flash 1
94         BCFG1=0x00000c42;       // lcd
95         BCFG2=0x10000420;       // flash 2
96 }
97
98 void pin_select_init() {
99
100         /*
101          * a[19:2] -> address lines
102          */
103
104         PINSEL2=0x0d6041d4;
105 }
106
107 void uart0_init(void) {
108
109         PINSEL0=0x05;                   // pin select -> tx, rx
110         UART0_FCR=0x07;                 // enable fifo
111         UART0_LCR=0x83;                 // set dlab + word length
112         UART0_DLL=0x04;                 // br: 38400 @ 10/4 mhz
113         UART0_DLM=0x00;
114         UART0_LCR=0x03;                 // unset dlab
115 }
116
117 void uart0_send_string(char *txbuf) {
118
119         int i;
120
121         i=0;
122
123         while(txbuf[i]) {
124                 UART0_THR=txbuf[i++];
125                 /* flush if tx buffer maximum reached */
126                 if(!(i%16))
127                         while(!(UART0_LSR&(1<<6)))
128                                 continue;
129         }
130         
131         /* flush if \n and \r do not fit in the tx buffer */
132         if(i>14)
133                 while(!(UART0_LSR&(1<<6)))
134                         continue;
135
136         UART0_THR='\n';
137         UART0_THR='\r';
138
139         /* flush uart0 anyways */
140         while(!(UART0_LSR&(1<<6)))
141                 continue;
142 }
143
144 void uart0_send_buf16(u16 *buf,int len) {
145
146         int i;
147
148         i=0;
149
150         for(i=0;i<len/2;i++) {
151                 if(!(i%8))
152                         while(!(UART0_LSR&(1<<6)))
153                                 continue;
154                 UART0_THR=buf[i]&0xff;
155                 UART0_THR=(buf[i]>>8)&0xff;
156         }
157 }
158
159 void uart0_send_buf32(u32 *buf,int len) {
160
161         int i;
162
163         i=0;
164
165         for(i=0;i<len/4;i++) {
166                 if(!(i%4))
167                         while(!(UART0_LSR&(1<<6)))
168                                 continue;
169                 UART0_THR=buf[i]&0xff;
170                 UART0_THR=(buf[i]>>8)&0xff;
171                 UART0_THR=(buf[i]>>16)&0xff;
172                 UART0_THR=(buf[i]>>24)&0xff;
173         }
174 }
175
176 void uart0_send_byte(u8 send) {
177
178         while(!(UART0_LSR&(1<<5)))
179                 continue;
180
181         UART0_THR=send;
182 }
183
184 u8 uart0_get_byte(void) {
185
186         u8 rx;
187
188         while(!(UART0_LSR&(1<<0)))
189                 continue;
190
191         rx=UART0_RBR;
192
193         return rx;
194 }
195
196 void flash_reset(u8 bank) {
197
198         if((bank!='0')&(bank!='2'))
199                 return;
200
201         if(bank=='0')
202                 B0F=0xf0;
203         else
204                 B2F=0xf0;
205 }
206
207 void flash_sector_erase(u8 flash,u8 sector) {
208
209         u32 a18_12;
210         u32 base;
211
212         if(sector>18)
213                 return;
214         a18_12=sector_address[sector]<<1;
215
216         if((flash!='0')&(flash!='2'))
217                 return;
218
219         switch(flash) {
220                 case '0':
221                         base=0x80000000;
222                         B0F555=0xaa;
223                         B0F2AA=0x55;
224                         B0F555=0x80;
225                         B0F555=0xaa;
226                         B0F2AA=0x55;
227                         *((volatile u16 *)(base|a18_12))=0x30;
228                         break;
229                 case '2': 
230                         base=0x82000000;
231                         B2F555=0xaa;
232                         B2F2AA=0x55;
233                         B2F555=0x80;
234                         B2F555=0xaa;
235                         B2F2AA=0x55;
236                         *((volatile u16 *)(base|a18_12))=0x30;
237                         break;
238                 default:
239                         return;
240         }
241
242         return;
243 }
244
245 void flash_chip_erase(u8 bank) {
246
247         u8 status;
248
249         if((bank!='0')&(bank!='2'))
250                 return;
251
252         if(bank=='0') {
253                 B0F555=0xaa;
254                 B0F2AA=0x55;
255                 B0F555=0x80;
256                 B0F555=0xaa;
257                 B0F2AA=0x55;
258                 B0F555=0x10;
259         }
260         else {
261                 B2F555=0xaa;
262                 B2F2AA=0x55;
263                 B2F555=0x80;
264                 B2F555=0xaa;
265                 B2F2AA=0x55;
266                 B2F555=0x10;
267         }
268
269         while(1) {
270                 if(bank=='0')
271                         status=B0F;
272                 else
273                         status=B2F;
274
275                 if(status&0x80) {
276                         /* send an ack */
277                         uart0_send_byte(status);
278                         break;
279                 }
280         }
281 }
282
283 void unlock_bypass(u8 bank) {
284
285         if((bank!='0')&(bank!='2'))
286                 return;
287
288         if(bank=='0') {
289                 B0F555=0xaa;
290                 B0F2AA=0x55;
291                 B0F555=0x20;
292         }
293         else {
294                 B2F555=0xaa;
295                 B2F2AA=0x55;
296                 B2F555=0x20;
297         }
298 }
299
300 void unlock_bypass_reset(u8 bank) {
301
302         if((bank!='0')&(bank!='2'))
303                 return;
304
305         if(bank=='0') {
306                 B0F=0x90;
307                 B0F=0x00;
308         }
309         else {
310                 B2F=0x90;
311                 B2F=0x00;
312         }
313 }
314
315 int flash_write(u32 addr,u16 data) {
316
317         u16 check;
318
319         if(data==0xffff)
320                 return 0;
321
322         *((unsigned volatile short *)addr)=0xa0;
323         *((unsigned volatile short *)addr)=data;
324         while(1) {
325                 check=*((unsigned short *)addr);
326                 if((data&0x80)==(check&0x80))
327                         break;
328         }
329         if(data!=check)
330                 return -1;
331
332         return 0;
333 }
334
335 int receive_data_and_write_to_flash(u32 addr,u32 datalen) {
336
337         u8 bank;
338         u32 i,ret;
339         u16 data;
340         u8 cksm;
341         u8 byte;
342
343         /* which bank to program */
344         if(addr<0x82000000)
345                 bank='0';
346         else
347                 bank='2';
348
349         /* unlock bypass */
350         unlock_bypass(bank);
351
352         /* receive and write data */
353         cksm=0;
354         ret=0;
355         for(i=0;i<datalen/2;i++) {
356                 byte=uart0_get_byte();
357                 data=byte;
358                 cksm+=byte;
359                 byte=uart0_get_byte();
360                 cksm+=byte;
361                 data|=byte<<8;
362                 if(flash_write(addr,data)<0)
363                         ret=-1;
364                 addr+=2;
365         }
366
367         /* relock bypass */
368         unlock_bypass_reset(bank);
369
370         /* modify cksm on purpose, so the user knows ... */
371         if(ret==-1)
372                 cksm+=1;
373
374         /* send the cksm */
375         uart0_send_byte(cksm);
376
377         return ret;
378 }
379
380 /*
381  * main function
382  */
383
384 int main(void) {
385
386         /* variables */
387
388         u32 i,addrlen,datalen,addr;
389         u8 buf[BUFSIZE];
390         u16 data;
391         u8 cmd;
392         u8 txrx;
393
394         /* memory mapping of interrupt vectors to static ram */
395
396         //mmap_init(MMAP_RAM);
397         
398         /* pll initialization */
399         pll_init();
400
401         /* uart initialization */
402         uart0_init();
403
404         /* external memory init */
405         ext_mem_bank_init();
406
407         /* pin select init */
408         pin_select_init();
409
410         /* begin the main loop */
411         while(1) {
412
413         /* receive cmd */
414         while(1) {
415
416                 cmd=uart0_get_byte();
417                 txrx=1;
418                 switch(cmd) {
419                         case CMD_CHIP_ERASE:
420                                 addrlen=0;
421                                 datalen=1;
422                                 break;
423                         case CMD_SECTOR_ERASE:
424                                 addrlen=0;
425                                 datalen=2;
426                                 break;
427                         case CMD_READ:
428                                 addrlen=4;
429                                 datalen=4;
430                         case CMD_WRITE:
431                                 addrlen=4;
432                                 datalen=4;
433                                 break;
434                         case CMD_CHIP_ID:
435                                 addrlen=0;
436                                 datalen=1;
437                                 break;
438                         default:
439                                 txrx=0;
440                                 break;
441                 }
442
443                 if(txrx)
444                         break;
445         }
446
447         /* receive (only if there is) more data from uart0 */
448         addr=0;
449         for(i=0;i<addrlen;i++) {
450                 txrx=uart0_get_byte();
451                 addr|=(txrx<<((addrlen-i-1)*8));
452         }
453
454         for(i=0;i<datalen;i++)
455                 buf[i]=uart0_get_byte();
456
457         /* process the cmd */
458         switch(cmd) {
459                 case CMD_SECTOR_ERASE:
460                         flash_sector_erase(buf[0],buf[1]);
461                         break;
462                 case CMD_READ:
463                         /* data length to read */
464                         datalen=buf[0]<<24|buf[1]<<16|buf[2]<<8|buf[3];
465                         /* check addr and datalen */
466                         if((addr>=BANK0)&(addr+datalen<=BANK0+BANK_SIZE))
467                                 uart0_send_buf16((u16 *)addr,datalen);
468                         if((addr>=BANK2)&(addr+datalen<=BANK2+BANK_SIZE))
469                                 uart0_send_buf16((u16 *)addr,datalen);
470                         if((addr>=BOOTLOADER)&
471                            (addr+datalen<BOOTLOADER-1+BL_SIZE))
472                                 uart0_send_buf32((u32 *)addr,datalen);
473                         break;
474                 case CMD_WRITE:
475                         /* data length */
476                         datalen=buf[0]<<24|buf[1]<<16|buf[2]<<8|buf[3];
477                         /* check addr and data len */
478                         if(((addr>=BANK0)&(addr+datalen<=BANK0+BANK_SIZE))|
479                            ((addr>=BANK2)&(addr+datalen<=BANK2+BANK_SIZE)))
480                                 receive_data_and_write_to_flash(addr,datalen);
481                         break;
482                 case CMD_CHIP_ERASE:
483                         flash_chip_erase(buf[0]);
484                         break;
485                 case CMD_CHIP_ID:
486                         if(buf[0]=='0') {
487                                 B0F555=0xaa;
488                                 B0F2AA=0x55;
489                                 B0F555=0x90;
490                                 data=*((u16 *)BANK0);
491                                 uart0_send_buf16(&data,2);
492                                 data=*((u16 *)(BANK0|0x200));
493                                 uart0_send_buf16(&data,2);
494                         }
495                         else if(buf[0]=='2') {
496                                 B2F555=0xaa;
497                                 B2F2AA=0x55;
498                                 B2F555=0x90;
499                                 data=*((u16 *)BANK2);
500                                 uart0_send_buf16(&data,2);
501                                 data=*((u16 *)(BANK2|0x200));
502                                 uart0_send_buf16(&data,2);
503                         }
504                         break;
505                 default:
506                         break;
507         }
508                 
509         }
510
511         return 0;
512 }
513