safety checkin: more pffs
[my-code/arm.git] / betty / flash.c
1 /*
2  * flash.c - low level flash handling
3  *
4  * author: hackbard@hackdaworld.org
5  *
6  */
7
8 #include "flash.h"
9
10 /*
11  * sector addresses
12  */
13
14 unsigned long sector_address[20]={
15         0x00000,0x02000,0x03000,0x04000,0x08000,
16         0x10000,0x18000,
17         0x20000,0x28000,
18         0x30000,0x38000,
19         0x40000,0x48000,
20         0x50000,0x58000,
21         0x60000,0x68000,
22         0x70000,0x78000,
23         0x80000                 // not a sector, end of flash!
24 };
25
26 /*
27  * functions
28  */
29
30 void flash_init(void) {
31
32         /*
33          * idle clocks between rad & write: 0+1
34          * length of read access: 1+3
35          * bls lines high during write access
36          * length of write access: 0+1
37          * no write protect, no burst-rom
38          * 16 bit data width
39          */
40
41         BCFG0=0x10000420;       // flash 1
42         BCFG2=0x10000420;       // flash 2
43
44         /*
45          * p3.27: write enable
46          * p3.25: chip select 2
47          * p2.15 - p2.8: data bus
48          * a[1:15] -> address lines
49          */
50
51         PINSEL2=(PINSEL2&P2MASK)|(1<<8);
52         PINSEL2=(PINSEL2&P2MASK&~((1<<15)|(1<<14)))|(1<<14);
53         PINSEL2=(PINSEL2&P2MASK&~((1<<5)|(1<<4)))|(1<<4);
54         PINSEL2=(PINSEL2&P2MASK)|(1<<24);
55         PINSEL2=(PINSEL2&P2MASK&~((1<<27)|(1<<26)|(1<<25)))|(1<<27)|(1<<26);
56 }
57
58 void flash_reset(u8 bank) {
59
60         if((bank!='0')&(bank!='2'))
61                 return;
62
63         if(bank=='0')
64                 FLASH_B0F=0xf0;
65         else
66                 FLASH_B2F=0xf0;
67 }
68
69 void flash_sector_erase(u8 bank,u8 sector) {
70
71         u32 a18_12;
72
73         if(sector>18)
74                 return;
75         a18_12=sector_address[sector]<<1;
76
77         switch(bank) {
78                 case '0':
79                         FLASH_B0F555=0xaa;
80                         FLASH_B0F2AA=0x55;
81                         FLASH_B0F555=0x80;
82                         FLASH_B0F555=0xaa;
83                         FLASH_B0F2AA=0x55;
84                         *((volatile u16 *)(FLASH_BANK0|a18_12))=0x30;
85                         break;
86                 case '2': 
87                         FLASH_B2F555=0xaa;
88                         FLASH_B2F2AA=0x55;
89                         FLASH_B2F555=0x80;
90                         FLASH_B2F555=0xaa;
91                         FLASH_B2F2AA=0x55;
92                         *((volatile u16 *)(FLASH_BANK2|a18_12))=0x30;
93                         break;
94                 default:
95                         return;
96         }
97
98         return;
99 }
100
101 int flash_sec_erase(u32 addr) {
102
103         u32 a18_12;
104         u32 base;
105
106         a18_12=addr&0x00000fffff;
107         base=addr&0xff000000;
108         
109         *((volatile u16 *)(base|(0x555<<1)))=0xaa;
110         *((volatile u16 *)(base|(0x2aa<<1)))=0x55;
111         *((volatile u16 *)(base|(0x555<<1)))=0x80;
112         *((volatile u16 *)(base|(0x555<<1)))=0xaa;
113         *((volatile u16 *)(base|(0x2aa<<1)))=0x55;
114         *((volatile u16 *)(base|(a18_12<<1)))=0x30;
115
116         return 0;
117 }
118
119 void flash_chip_erase(u8 bank) {
120
121         u8 status;
122
123         if((bank!='0')&(bank!='2'))
124                 return;
125
126         if(bank=='0') {
127                 FLASH_B0F555=0xaa;
128                 FLASH_B0F2AA=0x55;
129                 FLASH_B0F555=0x80;
130                 FLASH_B0F555=0xaa;
131                 FLASH_B0F2AA=0x55;
132                 FLASH_B0F555=0x10;
133         }
134         else {
135                 FLASH_B2F555=0xaa;
136                 FLASH_B2F2AA=0x55;
137                 FLASH_B2F555=0x80;
138                 FLASH_B2F555=0xaa;
139                 FLASH_B2F2AA=0x55;
140                 FLASH_B2F555=0x10;
141         }
142
143         while(1) {
144                 if(bank=='0')
145                         status=FLASH_B0F;
146                 else
147                         status=FLASH_B2F;
148                 if(status&0x80)
149                         break;
150         }
151 }
152
153 void flash_unlock_bypass(u8 bank) {
154
155         if((bank!='0')&(bank!='2'))
156                 return;
157
158         if(bank=='0') {
159                 FLASH_B0F555=0xaa;
160                 FLASH_B0F2AA=0x55;
161                 FLASH_B0F555=0x20;
162         }
163         else {
164                 FLASH_B2F555=0xaa;
165                 FLASH_B2F2AA=0x55;
166                 FLASH_B2F555=0x20;
167         }
168 }
169
170 void flash_unlock_bypass_reset(u8 bank) {
171
172         if((bank!='0')&(bank!='2'))
173                 return;
174
175         if(bank=='0') {
176                 FLASH_B0F=0x90;
177                 FLASH_B0F=0x00;
178         }
179         else {
180                 FLASH_B2F=0x90;
181                 FLASH_B2F=0x00;
182         }
183 }
184
185 int flash_write_word(u32 addr,u16 data) {
186
187         u16 check;
188
189         if(data==0xffff)
190                 return 0;
191
192         *((unsigned volatile short *)addr)=0xa0;
193         *((unsigned volatile short *)addr)=data;
194         while(1) {
195                 check=*((unsigned short *)addr);
196                 if((data&0x80)==(check&0x80))
197                         break;
198         }
199         if(data!=check)
200                 return -1;
201
202         return 0;
203 }
204
205 #define flash_read_word(addr,data) *(data)=*((unsigned volatile short *)(addr))
206
207 int flash_write_buf(u32 addr,u16 *buf,int len) {
208
209         int cnt,ret;
210         u8 bank;
211
212         /* len must be a multiple of 2 */
213         if(len&0x1)
214                 return -1;
215
216         /* decide the bank */
217         if(addr<0x82000000)
218                 bank='0';
219         else
220                 bank='2';
221
222         /* unlock */
223         flash_unlock_bypass(bank);
224
225         /* write the data */
226         ret=0;
227         for(cnt=0;cnt<len/2;cnt++) {
228                 if(flash_write_word(addr,*(buf+cnt))==0)
229                         ret+=2;
230                 addr+=2;
231         }
232
233         /* relock */
234         flash_unlock_bypass_reset(bank);
235
236         return ret;
237 }
238
239 void flash_read_buf(u32 addr,u16 *buf,int len) {
240
241         int cnt;
242
243         /* len must be a multiple of 2 */
244         if(len&0x1)
245                 return;
246
247         for(cnt=0;cnt<len/2;cnt++)
248                 flash_read_word(addr,buf+cnt);
249 }
250