Pavel Chromy's on chip flash loader
[fw/openocd] / src / flash / ocl / at91sam7x / samflash.c
1 /***************************************************************************\r
2  *   Copyright (C) 2007 by Pavel Chromy                                    *\r
3  *   chromy@asix.cz                                                        *\r
4  *                                                                         *\r
5  *   This program is free software; you can redistribute it and/or modify  *\r
6  *   it under the terms of the GNU General Public License as published by  *\r
7  *   the Free Software Foundation; either version 2 of the License, or     *\r
8  *   (at your option) any later version.                                   *\r
9  *                                                                         *\r
10  *   This program is distributed in the hope that it will be useful,       *\r
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
13  *   GNU General Public License for more details.                          *\r
14  *                                                                         *\r
15  *   You should have received a copy of the GNU General Public License     *\r
16  *   along with this program; if not, write to the                         *\r
17  *   Free Software Foundation, Inc.,                                       *\r
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
19  ***************************************************************************/\r
20 #include "samflash.h"\r
21 \r
22 \r
23 unsigned int flash_page_count=1024;\r
24 unsigned int flash_page_size=256;\r
25 \r
26 /* pages per lock bit */\r
27 unsigned int flash_lock_pages=1024/16;\r
28 \r
29 \r
30 /* detect chip and set loader parameters */\r
31 int flash_init(void)\r
32 {\r
33         unsigned int nvpsiz;\r
34 \r
35         nvpsiz=(inr(DBGU_CIDR)>>8)&0xf;\r
36 \r
37         switch (nvpsiz) {\r
38                 case 3:\r
39                         /* AT91SAM7x32 */\r
40                         flash_page_count=256;\r
41                         flash_page_size=128;\r
42                         flash_lock_pages=256/8;\r
43                         break;\r
44                 case 5:\r
45                         /* AT91SAM7x64 */\r
46                         flash_page_count=512;\r
47                         flash_page_size=128;\r
48                         flash_lock_pages=512/16;\r
49                         break;\r
50                 case 7:\r
51                         /* AT91SAM7x128*/\r
52                         flash_page_count=512;\r
53                         flash_page_size=256;\r
54                         flash_lock_pages=512/8;\r
55                         break;\r
56                 case 9:\r
57                         /* AT91SAM7x256 */\r
58                         flash_page_count=1024;\r
59                         flash_page_size=256;\r
60                         flash_lock_pages=1024/16;\r
61                         break;\r
62                 case 10:\r
63                         /* AT91SAM7x512 */\r
64                         flash_page_count=2048;\r
65                         flash_page_size=256;\r
66                         flash_lock_pages=2048/32;\r
67                         break;\r
68                 default:\r
69                         return FLASH_STAT_INITE;\r
70         }\r
71         return FLASH_STAT_OK;\r
72 }\r
73 \r
74 \r
75 /* program single flash page */\r
76 int flash_page_program(uint32 *data, int page_num)\r
77 {\r
78         int i;\r
79         int efc_ofs;\r
80 \r
81         uint32 *flash_ptr;\r
82         uint32 *data_ptr;\r
83 \r
84         /* select proper controller */\r
85         if (page_num>=1024) efc_ofs=0x10;\r
86         else efc_ofs=0;\r
87 \r
88         /* wait until FLASH is ready, just for sure */\r
89         while ((inr(MC_FSR+efc_ofs)&MC_FRDY)==0);\r
90 \r
91         /* calculate page address, only lower 8 bits are used to address the latch,\r
92                  but the upper part of address is needed for writing to proper EFC */\r
93         flash_ptr=(uint32 *)(FLASH_AREA_ADDR+(page_num*flash_page_size));\r
94         data_ptr=data;\r
95 \r
96         /* copy data to latch */\r
97         for (i=flash_page_size/4; i; i--) {\r
98                 /* we do not use memcpy to be sure that only 32 bit access is used */\r
99                 *(flash_ptr++)=*(data_ptr++);\r
100         }\r
101 \r
102         /* page number and page write command to FCR */\r
103         outr(MC_FCR+efc_ofs, ((page_num&0x3ff)<<8) | MC_KEY | MC_FCMD_WP);\r
104 \r
105         /* wait until it's done */\r
106         while ((inr(MC_FSR+efc_ofs)&MC_FRDY)==0);\r
107 \r
108         /* check for errors */\r
109         if ((inr(MC_FSR+efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE;\r
110         if ((inr(MC_FSR+efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE;\r
111 \r
112 #if 0\r
113         /* verify written data */\r
114         flash_ptr=(uint32 *)(FLASH_AREA_ADDR+(page_num*flash_page_size));\r
115         data_ptr=data;\r
116 \r
117         for (i=flash_page_size/4; i; i--) {\r
118                 if (*(flash_ptr++)!=*(data_ptr++)) return FLASH_STAT_VERIFE;\r
119         }\r
120 #endif\r
121 \r
122         return FLASH_STAT_OK;\r
123 }\r
124 \r
125 \r
126 int flash_erase_plane(int efc_ofs)\r
127 {\r
128         unsigned int lockbits;\r
129         int page_num;\r
130 \r
131         page_num=0;\r
132         lockbits=inr(MC_FSR+efc_ofs)>>16;\r
133         while (lockbits) {\r
134                 if (lockbits&1) {\r
135 \r
136                         /* wait until FLASH is ready, just for sure */\r
137                         while ((inr(MC_FSR+efc_ofs)&MC_FRDY)==0);\r
138 \r
139                         outr(MC_FCR+efc_ofs, ((page_num&0x3ff)<<8) | 0x5a000004);\r
140 \r
141                         /* wait until it's done */\r
142                         while ((inr(MC_FSR+efc_ofs)&MC_FRDY)==0);\r
143 \r
144                         /* check for errors */\r
145                         if ((inr(MC_FSR+efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE;\r
146                         if ((inr(MC_FSR+efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE;\r
147 \r
148                 }\r
149                 if ((page_num+=flash_lock_pages)>flash_page_count) break;\r
150                 lockbits>>=1;\r
151         }\r
152 \r
153         /* wait until FLASH is ready, just for sure */\r
154         while ((inr(MC_FSR+efc_ofs)&MC_FRDY)==0);\r
155 \r
156         /* erase all command to FCR */\r
157         outr(MC_FCR+efc_ofs, 0x5a000008);\r
158 \r
159         /* wait until it's done */\r
160         while ((inr(MC_FSR+efc_ofs)&MC_FRDY)==0);\r
161 \r
162         /* check for errors */\r
163         if ((inr(MC_FSR+efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE;\r
164         if ((inr(MC_FSR+efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE;\r
165 \r
166         /* set no erase before programming */\r
167         outr(MC_FMR+efc_ofs, inr(MC_FMR+efc_ofs)|0x80);\r
168 \r
169         return FLASH_STAT_OK;\r
170 }\r
171 \r
172 \r
173 /* erase whole chip */\r
174 int flash_erase_all(void)\r
175 {\r
176         int result;\r
177         \r
178         if ((result=flash_erase_plane(0))!=FLASH_STAT_OK) return result;\r
179 \r
180         /* the second flash controller, if any */\r
181         if (flash_page_count>1024) result=flash_erase_plane(0x10);\r
182 \r
183         return result;\r
184 }\r
185 \r
186 \r
187 int flash_verify(uint32 adr, unsigned int len, uint8 *src)\r
188 {\r
189         unsigned char *flash_ptr;\r
190 \r
191         flash_ptr=(uint8 *)FLASH_AREA_ADDR+adr;\r
192         for ( ;len; len--) {\r
193                 if (*(flash_ptr++)!=*(src++)) return FLASH_STAT_VERIFE;\r
194         }\r
195         return FLASH_STAT_OK;\r
196 }\r