Blame view

common/flash.c 5.4 KB
affae2bff   wdenk   Initial revision
1
2
3
4
  /*
   * (C) Copyright 2000
   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
5
   * SPDX-License-Identifier:	GPL-2.0+
affae2bff   wdenk   Initial revision
6
   */
7e780369e   wdenk   * Patch by Mark J...
7
  /* #define DEBUG */
affae2bff   wdenk   Initial revision
8
9
  #include <common.h>
  #include <flash.h>
ca5def3f3   Stefan Roese   cfi_flash: Simpli...
10
  #include <mtd/cfi_flash.h>
affae2bff   wdenk   Initial revision
11

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