blob: 5be5f1b099645ee32e09f616773ae4bec3c44acc [file] [log] [blame]
wdenkc7de8292002-11-19 11:04:11 +00001/*
Marian Balakowicz66080432006-09-01 19:46:22 +02002 * (C) Copyright 2000-2006
wdenkc7de8292002-11-19 11:04:11 +00003 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <common.h>
25#include <flash.h>
26
Marian Balakowicze6f2e902005-10-11 19:09:42 +020027extern flash_info_t flash_info[]; /* info for FLASH chips */
wdenkc7de8292002-11-19 11:04:11 +000028
29/*-----------------------------------------------------------------------
30 * Functions
31 */
32
33/*-----------------------------------------------------------------------
34 * Set protection status for monitor sectors
35 *
36 * The monitor is always located in the _first_ Flash bank.
37 * If necessary you have to map the second bank at lower addresses.
38 */
39void
40flash_protect (int flag, ulong from, ulong to, flash_info_t *info)
41{
42 ulong b_end = info->start[0] + info->size - 1; /* bank end address */
43 short s_end = info->sector_count - 1; /* index of last sector */
44 int i;
45
46 /* Do nothing if input data is bad. */
47 if (info->sector_count == 0 || info->size == 0 || to < from) {
48 return;
49 }
50
51 /* There is nothing to do if we have no data about the flash
52 * or the protect range and flash range don't overlap.
53 */
54 if (info->flash_id == FLASH_UNKNOWN ||
55 to < info->start[0] || from > b_end) {
56 return;
57 }
58
59 for (i=0; i<info->sector_count; ++i) {
60 ulong end; /* last address in current sect */
61
62 end = (i == s_end) ? b_end : info->start[i + 1] - 1;
63
64 /* Update protection if any part of the sector
65 * is in the specified range.
66 */
67 if (from <= end && to >= info->start[i]) {
68 if (flag & FLAG_PROTECT_CLEAR) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020069#if defined(CONFIG_SYS_FLASH_PROTECTION)
wdenkc7de8292002-11-19 11:04:11 +000070 flash_real_protect(info, i, 0);
71#else
72 info->protect[i] = 0;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020073#endif /* CONFIG_SYS_FLASH_PROTECTION */
wdenkc7de8292002-11-19 11:04:11 +000074 }
75 else if (flag & FLAG_PROTECT_SET) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020076#if defined(CONFIG_SYS_FLASH_PROTECTION)
wdenkc7de8292002-11-19 11:04:11 +000077 flash_real_protect(info, i, 1);
78#else
79 info->protect[i] = 1;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020080#endif /* CONFIG_SYS_FLASH_PROTECTION */
wdenkc7de8292002-11-19 11:04:11 +000081 }
82 }
83 }
84}
85
86/*-----------------------------------------------------------------------
87 */
88
89flash_info_t *
90addr2info (ulong addr)
91{
92#ifndef CONFIG_SPD823TS
93 flash_info_t *info;
94 int i;
95
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020096 for (i=0, info = &flash_info[0]; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) {
wdenkc7de8292002-11-19 11:04:11 +000097 if (info->flash_id != FLASH_UNKNOWN &&
98 addr >= info->start[0] &&
99 /* WARNING - The '- 1' is needed if the flash
100 * is at the end of the address space, since
101 * info->start[0] + info->size wraps back to 0.
102 * Please don't change this unless you understand this.
103 */
104 addr <= info->start[0] + info->size - 1) {
105 return (info);
106 }
107 }
108#endif /* CONFIG_SPD823TS */
109
110 return (NULL);
111}
112
113/*-----------------------------------------------------------------------
114 * Copy memory to flash.
115 * Make sure all target addresses are within Flash bounds,
116 * and no protected sectors are hit.
117 * Returns:
118 * ERR_OK 0 - OK
119 * ERR_TIMOUT 1 - write timeout
120 * ERR_NOT_ERASED 2 - Flash not erased
121 * ERR_PROTECTED 4 - target range includes protected sectors
122 * ERR_INVAL 8 - target address not in Flash memory
123 * ERR_ALIGN 16 - target address not aligned on boundary
124 * (only some targets require alignment)
125 */
126int
Marian Balakowicz66080432006-09-01 19:46:22 +0200127flash_write (char *src, ulong addr, ulong cnt)
wdenkc7de8292002-11-19 11:04:11 +0000128{
129#ifdef CONFIG_SPD823TS
130 return (ERR_TIMOUT); /* any other error codes are possible as well */
131#else
132 int i;
133 ulong end = addr + cnt - 1;
134 flash_info_t *info_first = addr2info (addr);
135 flash_info_t *info_last = addr2info (end );
136 flash_info_t *info;
137 int j;
138
139 if (cnt == 0) {
140 return (ERR_OK);
141 }
142
143 if (!info_first || !info_last) {
144 return (ERR_INVAL);
145 }
146
147 for (info = info_first; info <= info_last; ++info) {
148 ulong b_end = info->start[0] + info->size; /* bank end addr */
149 short s_end = info->sector_count - 1;
150 for (i=0; i<info->sector_count; ++i) {
151 ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];
152
153 if ((end >= info->start[i]) && (addr < e_addr) &&
154 (info->protect[i] != 0) ) {
155 return (ERR_PROTECTED);
156 }
157 }
158 }
159
wdenk27b207f2003-07-24 23:38:38 +0000160 printf("\rWriting ");
161 for (j=0; j<20; j++) putc(177);
162 printf("\rWriting ");
wdenkc7de8292002-11-19 11:04:11 +0000163
164 /* finally write data to flash */
165 for (info = info_first; info <= info_last && cnt>0; ++info) {
166 ulong len;
167
168 len = info->start[0] + info->size - addr;
169 if (len > cnt)
170 len = cnt;
171
172 if ((i = write_buff(info, src, addr, len)) != 0) {
173 return (i);
174 }
175 cnt -= len;
176 addr += len;
177 src += len;
178 }
179 return (ERR_OK);
180#endif /* CONFIG_SPD823TS */
181}
182
183/*-----------------------------------------------------------------------
184 */