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