samflash.c 5.39 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/***************************************************************************
 *   Copyright (C) 2007 by Pavel Chromy                                    *
 *   chromy@asix.cz                                                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "samflash.h"


zwelch's avatar
zwelch committed
23
24
unsigned int flash_page_count = 1024;
unsigned int flash_page_size = 256;
25
26

/* pages per lock bit */
zwelch's avatar
zwelch committed
27
unsigned int flash_lock_pages = 1024/16;
28
29
30
31
32
33
34


/* detect chip and set loader parameters */
int flash_init(void)
{
	unsigned int nvpsiz;

zwelch's avatar
zwelch committed
35
	nvpsiz = (inr(DBGU_CIDR) >> 8)&0xf;
36
37
38
39

	switch (nvpsiz) {
		case 3:
			/* AT91SAM7x32 */
zwelch's avatar
zwelch committed
40
41
42
			flash_page_count = 256;
			flash_page_size = 128;
			flash_lock_pages = 256/8;
43
44
45
			break;
		case 5:
			/* AT91SAM7x64 */
zwelch's avatar
zwelch committed
46
47
48
			flash_page_count = 512;
			flash_page_size = 128;
			flash_lock_pages = 512/16;
49
50
51
			break;
		case 7:
			/* AT91SAM7x128*/
zwelch's avatar
zwelch committed
52
53
54
			flash_page_count = 512;
			flash_page_size = 256;
			flash_lock_pages = 512/8;
55
56
57
			break;
		case 9:
			/* AT91SAM7x256 */
zwelch's avatar
zwelch committed
58
59
60
			flash_page_count = 1024;
			flash_page_size = 256;
			flash_lock_pages = 1024/16;
61
62
63
			break;
		case 10:
			/* AT91SAM7x512 */
zwelch's avatar
zwelch committed
64
65
66
			flash_page_count = 2048;
			flash_page_size = 256;
			flash_lock_pages = 2048/32;
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
			break;
		default:
			return FLASH_STAT_INITE;
	}
	return FLASH_STAT_OK;
}


/* program single flash page */
int flash_page_program(uint32 *data, int page_num)
{
	int i;
	int efc_ofs;

	uint32 *flash_ptr;
	uint32 *data_ptr;

	/* select proper controller */
zwelch's avatar
zwelch committed
85
86
	if (page_num >= 1024) efc_ofs = 0x10;
	else efc_ofs = 0;
87
88

	/* wait until FLASH is ready, just for sure */
zwelch's avatar
zwelch committed
89
	while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0);
90
91
92

	/* calculate page address, only lower 8 bits are used to address the latch,
		 but the upper part of address is needed for writing to proper EFC */
zwelch's avatar
zwelch committed
93
	flash_ptr = (uint32 *)(FLASH_AREA_ADDR + (page_num*flash_page_size));
zwelch's avatar
zwelch committed
94
	data_ptr = data;
95
96

	/* copy data to latch */
zwelch's avatar
zwelch committed
97
	for (i = flash_page_size/4; i; i--) {
98
99
100
101
102
		/* we do not use memcpy to be sure that only 32 bit access is used */
		*(flash_ptr++)=*(data_ptr++);
	}

	/* page number and page write command to FCR */
zwelch's avatar
zwelch committed
103
	outr(MC_FCR + efc_ofs, ((page_num&0x3ff) << 8) | MC_KEY | MC_FCMD_WP);
104
105

	/* wait until it's done */
zwelch's avatar
zwelch committed
106
	while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0);
107
108

	/* check for errors */
zwelch's avatar
zwelch committed
109
110
	if ((inr(MC_FSR + efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE;
	if ((inr(MC_FSR + efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE;
111
112
113

#if 0
	/* verify written data */
zwelch's avatar
zwelch committed
114
	flash_ptr = (uint32 *)(FLASH_AREA_ADDR + (page_num*flash_page_size));
zwelch's avatar
zwelch committed
115
	data_ptr = data;
116

zwelch's avatar
zwelch committed
117
	for (i = flash_page_size/4; i; i--) {
118
119
120
121
122
123
124
125
126
127
128
129
130
		if (*(flash_ptr++)!=*(data_ptr++)) return FLASH_STAT_VERIFE;
	}
#endif

	return FLASH_STAT_OK;
}


int flash_erase_plane(int efc_ofs)
{
	unsigned int lockbits;
	int page_num;

zwelch's avatar
zwelch committed
131
	page_num = 0;
zwelch's avatar
zwelch committed
132
	lockbits = inr(MC_FSR + efc_ofs) >> 16;
133
134
135
136
	while (lockbits) {
		if (lockbits&1) {

			/* wait until FLASH is ready, just for sure */
zwelch's avatar
zwelch committed
137
			while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0);
138

zwelch's avatar
zwelch committed
139
			outr(MC_FCR + efc_ofs, ((page_num&0x3ff) << 8) | 0x5a000004);
140
141

			/* wait until it's done */
zwelch's avatar
zwelch committed
142
			while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0);
143
144

			/* check for errors */
zwelch's avatar
zwelch committed
145
146
			if ((inr(MC_FSR + efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE;
			if ((inr(MC_FSR + efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE;
147
148

		}
zwelch's avatar
zwelch committed
149
		if ((page_num += flash_lock_pages)>flash_page_count) break;
150
151
152
153
		lockbits>>=1;
	}

	/* wait until FLASH is ready, just for sure */
zwelch's avatar
zwelch committed
154
	while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0);
155
156

	/* erase all command to FCR */
zwelch's avatar
zwelch committed
157
	outr(MC_FCR + efc_ofs, 0x5a000008);
158
159

	/* wait until it's done */
zwelch's avatar
zwelch committed
160
	while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0);
161
162

	/* check for errors */
zwelch's avatar
zwelch committed
163
164
	if ((inr(MC_FSR + efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE;
	if ((inr(MC_FSR + efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE;
165
166

	/* set no erase before programming */
zwelch's avatar
zwelch committed
167
	outr(MC_FMR + efc_ofs, inr(MC_FMR + efc_ofs) | 0x80);
168
169
170
171
172
173
174
175
176
177

	return FLASH_STAT_OK;
}


/* erase whole chip */
int flash_erase_all(void)
{
	int result;
	
zwelch's avatar
zwelch committed
178
	if ((result = flash_erase_plane(0)) != FLASH_STAT_OK) return result;
179
180

	/* the second flash controller, if any */
zwelch's avatar
zwelch committed
181
	if (flash_page_count>1024) result = flash_erase_plane(0x10);
182
183
184
185
186
187
188
189
190

	return result;
}


int flash_verify(uint32 adr, unsigned int len, uint8 *src)
{
	unsigned char *flash_ptr;

zwelch's avatar
zwelch committed
191
	flash_ptr = (uint8 *)FLASH_AREA_ADDR + adr;
192
193
194
195
196
	for ( ;len; len--) {
		if (*(flash_ptr++)!=*(src++)) return FLASH_STAT_VERIFE;
	}
	return FLASH_STAT_OK;
}