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