Merge branch 'master' of git://git.denx.de/u-boot-sunxi
[platform/kernel/u-boot.git] / common / flash.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2000
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6
7 /* #define DEBUG */
8
9 #include <common.h>
10 #include <flash.h>
11
12 #include <mtd/cfi_flash.h>
13
14 extern flash_info_t  flash_info[]; /* info for FLASH chips */
15
16 /*-----------------------------------------------------------------------
17  * Functions
18  */
19
20 /*-----------------------------------------------------------------------
21  * Set protection status for monitor sectors
22  *
23  * The monitor is always located in the _first_ Flash bank.
24  * If necessary you have to map the second bank at lower addresses.
25  */
26 void
27 flash_protect (int flag, ulong from, ulong to, flash_info_t *info)
28 {
29         ulong b_end;
30         short s_end;
31         int i;
32
33         /* Do nothing if input data is bad. */
34         if (!info || info->sector_count == 0 || info->size == 0 || to < from) {
35                 return;
36         }
37
38         s_end = info->sector_count - 1; /* index of last sector */
39         b_end = info->start[0] + info->size - 1;        /* bank end address */
40
41         debug ("flash_protect %s: from 0x%08lX to 0x%08lX\n",
42                 (flag & FLAG_PROTECT_SET) ? "ON" :
43                         (flag & FLAG_PROTECT_CLEAR) ? "OFF" : "???",
44                 from, to);
45
46         /* There is nothing to do if we have no data about the flash
47          * or the protect range and flash range don't overlap.
48          */
49         if (info->flash_id == FLASH_UNKNOWN ||
50             to < info->start[0] || from > b_end) {
51                 return;
52         }
53
54         for (i=0; i<info->sector_count; ++i) {
55                 ulong end;              /* last address in current sect */
56
57                 end = (i == s_end) ? b_end : info->start[i + 1] - 1;
58
59                 /* Update protection if any part of the sector
60                  * is in the specified range.
61                  */
62                 if (from <= end && to >= info->start[i]) {
63                         if (flag & FLAG_PROTECT_CLEAR) {
64 #if defined(CONFIG_SYS_FLASH_PROTECTION)
65                                 flash_real_protect(info, i, 0);
66 #else
67                                 info->protect[i] = 0;
68 #endif  /* CONFIG_SYS_FLASH_PROTECTION */
69                                 debug ("protect off %d\n", i);
70                         }
71                         else if (flag & FLAG_PROTECT_SET) {
72 #if defined(CONFIG_SYS_FLASH_PROTECTION)
73                                 flash_real_protect(info, i, 1);
74 #else
75                                 info->protect[i] = 1;
76 #endif  /* CONFIG_SYS_FLASH_PROTECTION */
77                                 debug ("protect on %d\n", i);
78                         }
79                 }
80         }
81 }
82
83 /*-----------------------------------------------------------------------
84  */
85
86 flash_info_t *
87 addr2info (ulong addr)
88 {
89         flash_info_t *info;
90         int i;
91
92         for (i=0, info = &flash_info[0]; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) {
93                 if (info->flash_id != FLASH_UNKNOWN &&
94                     addr >= info->start[0] &&
95                     /* WARNING - The '- 1' is needed if the flash
96                      * is at the end of the address space, since
97                      * info->start[0] + info->size wraps back to 0.
98                      * Please don't change this unless you understand this.
99                      */
100                     addr <= info->start[0] + info->size - 1) {
101                         return (info);
102                 }
103         }
104
105         return (NULL);
106 }
107
108 /*-----------------------------------------------------------------------
109  * Copy memory to flash.
110  * Make sure all target addresses are within Flash bounds,
111  * and no protected sectors are hit.
112  * Returns:
113  * ERR_OK          0 - OK
114  * ERR_TIMEOUT     1 - write timeout
115  * ERR_NOT_ERASED  2 - Flash not erased
116  * ERR_PROTECTED   4 - target range includes protected sectors
117  * ERR_INVAL       8 - target address not in Flash memory
118  * ERR_ALIGN       16 - target address not aligned on boundary
119  *                      (only some targets require alignment)
120  */
121 int
122 flash_write (char *src, ulong addr, ulong cnt)
123 {
124         int i;
125         ulong         end        = addr + cnt - 1;
126         flash_info_t *info_first = addr2info (addr);
127         flash_info_t *info_last  = addr2info (end );
128         flash_info_t *info;
129         __maybe_unused char *src_orig = src;
130         __maybe_unused char *addr_orig = (char *)addr;
131         __maybe_unused ulong cnt_orig = cnt;
132
133         if (cnt == 0) {
134                 return (ERR_OK);
135         }
136
137         if (!info_first || !info_last) {
138                 return (ERR_INVAL);
139         }
140
141         for (info = info_first; info <= info_last; ++info) {
142                 ulong b_end = info->start[0] + info->size;      /* bank end addr */
143                 short s_end = info->sector_count - 1;
144                 for (i=0; i<info->sector_count; ++i) {
145                         ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];
146
147                         if ((end >= info->start[i]) && (addr < e_addr) &&
148                             (info->protect[i] != 0) ) {
149                                 return (ERR_PROTECTED);
150                         }
151                 }
152         }
153
154         /* finally write data to flash */
155         for (info = info_first; info <= info_last && cnt>0; ++info) {
156                 ulong len;
157
158                 len = info->start[0] + info->size - addr;
159                 if (len > cnt)
160                         len = cnt;
161                 if ((i = write_buff(info, (uchar *)src, addr, len)) != 0) {
162                         return (i);
163                 }
164                 cnt  -= len;
165                 addr += len;
166                 src  += len;
167         }
168
169 #if defined(CONFIG_FLASH_VERIFY)
170         if (memcmp(src_orig, addr_orig, cnt_orig)) {
171                 printf("\nVerify failed!\n");
172                 return ERR_PROG_ERROR;
173         }
174 #endif /* CONFIG_SYS_FLASH_VERIFY_AFTER_WRITE */
175
176         return (ERR_OK);
177 }
178
179 /*-----------------------------------------------------------------------
180  */
181
182 void flash_perror (int err)
183 {
184         switch (err) {
185         case ERR_OK:
186                 break;
187         case ERR_TIMEOUT:
188                 puts ("Timeout writing to Flash\n");
189                 break;
190         case ERR_NOT_ERASED:
191                 puts ("Flash not Erased\n");
192                 break;
193         case ERR_PROTECTED:
194                 puts ("Can't write to protected Flash sectors\n");
195                 break;
196         case ERR_INVAL:
197                 puts ("Outside available Flash\n");
198                 break;
199         case ERR_ALIGN:
200                 puts ("Start and/or end address not on sector boundary\n");
201                 break;
202         case ERR_UNKNOWN_FLASH_VENDOR:
203                 puts ("Unknown Vendor of Flash\n");
204                 break;
205         case ERR_UNKNOWN_FLASH_TYPE:
206                 puts ("Unknown Type of Flash\n");
207                 break;
208         case ERR_PROG_ERROR:
209                 puts ("General Flash Programming Error\n");
210                 break;
211         case ERR_ABORTED:
212                 puts("Flash Programming Aborted\n");
213                 break;
214         default:
215                 printf ("%s[%d] FIXME: rc=%d\n", __FILE__, __LINE__, err);
216                 break;
217         }
218 }