blob: b0c1e1e81416b704feff87079b93b59c90b0cd8a [file] [log] [blame]
Reinhard Meyer8ec18f42010-07-27 15:18:38 +02001/*
2 * (C) Copyright 2010
3 * Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.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/*
25 * this driver supports the enhanced embedded flash in the Atmel
26 * AT91SAM9XE devices with the following geometry:
27 *
28 * AT91SAM9XE128: 1 plane of 8 regions of 32 pages (total 256 pages)
29 * AT91SAM9XE256: 1 plane of 16 regions of 32 pages (total 512 pages)
30 * AT91SAM9XE512: 1 plane of 32 regions of 32 pages (total 1024 pages)
31 * (the exact geometry is read from the flash at runtime, so any
32 * future devices should already be covered)
33 *
34 * Regions can be write/erase protected.
35 * Whole (!) pages can be individually written with erase on the fly.
36 * Writing partial pages will corrupt the rest of the page.
37 *
38 * The flash is presented to u-boot with each region being a sector,
39 * having the following effects:
40 * Each sector can be hardware protected (protect on/off).
41 * Each page in a sector can be rewritten anytime.
42 * Since pages are erased when written, the "erase" does nothing.
43 * The first "CONFIG_EFLASH_PROTSECTORS" cannot be unprotected
44 * by u-Boot commands.
45 *
46 * Note: Redundant environment will not work in this flash since
47 * it does use partial page writes. Make sure the environent spans
48 * whole pages!
49 */
50
51/*
52 * optional TODOs (nice to have features):
53 *
54 * make the driver coexist with other NOR flash drivers
55 * (use an index into flash_info[], requires work
56 * in those other drivers, too)
57 * Make the erase command fill the sectors with 0xff
58 * (if the flashes grow larger in the future and
59 * someone puts a jffs2 into them)
60 * do a read-modify-write for partially programmed pages
61 */
62#include <common.h>
Reinhard Meyerb06208c2010-11-07 13:26:14 +010063#include <asm/io.h>
Reinhard Meyer8ec18f42010-07-27 15:18:38 +020064#include <asm/arch/hardware.h>
Reinhard Meyer8ec18f42010-07-27 15:18:38 +020065#include <asm/arch/at91_common.h>
66#include <asm/arch/at91_eefc.h>
67#include <asm/arch/at91_dbu.h>
68
69/* checks to detect configuration errors */
70#if CONFIG_SYS_MAX_FLASH_BANKS!=1
71#error eflash: this driver can only handle 1 bank
72#endif
73
74/* global structure */
75flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
76static u32 pagesize;
77
78unsigned long flash_init (void)
79{
Reinhard Meyere260d0b2010-11-03 15:39:55 +010080 at91_eefc_t *eefc = (at91_eefc_t *) ATMEL_BASE_EEFC;
81 at91_dbu_t *dbu = (at91_dbu_t *) ATMEL_BASE_DBGU;
Reinhard Meyer8ec18f42010-07-27 15:18:38 +020082 u32 id, size, nplanes, planesize, nlocks;
83 u32 addr, i, tmp=0;
84
85 debug("eflash: init\n");
86
87 flash_info[0].flash_id = FLASH_UNKNOWN;
88
89 /* check if its an AT91ARM9XE SoC */
90 if ((readl(&dbu->cidr) & AT91_DBU_CID_ARCH_MASK) != AT91_DBU_CID_ARCH_9XExx) {
91 puts("eflash: not an AT91SAM9XE\n");
92 return 0;
93 }
94
95 /* now query the eflash for its structure */
96 writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_GETD, &eefc->fcr);
97 while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0)
98 ;
99 id = readl(&eefc->frr); /* word 0 */
100 size = readl(&eefc->frr); /* word 1 */
101 pagesize = readl(&eefc->frr); /* word 2 */
102 nplanes = readl(&eefc->frr); /* word 3 */
103 planesize = readl(&eefc->frr); /* word 4 */
104 debug("id=%08x size=%u pagesize=%u planes=%u planesize=%u\n",
105 id, size, pagesize, nplanes, planesize);
106 for (i=1; i<nplanes; i++) {
107 tmp = readl(&eefc->frr); /* words 5..4+nplanes-1 */
108 };
109 nlocks = readl(&eefc->frr); /* word 4+nplanes */
110 debug("nlocks=%u\n", nlocks);
111 /* since we are going to use the lock regions as sectors, check count */
112 if (nlocks > CONFIG_SYS_MAX_FLASH_SECT) {
113 printf("eflash: number of lock regions(%u) "\
114 "> CONFIG_SYS_MAX_FLASH_SECT. reducing...\n",
115 nlocks);
116 nlocks = CONFIG_SYS_MAX_FLASH_SECT;
117 }
118 flash_info[0].size = size;
119 flash_info[0].sector_count = nlocks;
120 flash_info[0].flash_id = id;
121
Reinhard Meyere260d0b2010-11-03 15:39:55 +0100122 addr = ATMEL_BASE_FLASH;
Reinhard Meyer8ec18f42010-07-27 15:18:38 +0200123 for (i=0; i<nlocks; i++) {
124 tmp = readl(&eefc->frr); /* words 4+nplanes+1.. */
125 flash_info[0].start[i] = addr;
126 flash_info[0].protect[i] = 0;
127 addr += tmp;
128 };
129
130 /* now read the protection information for all regions */
131 writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_GLB, &eefc->fcr);
132 while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0)
133 ;
134 for (i=0; i<flash_info[0].sector_count; i++) {
135 if (i%32 == 0)
136 tmp = readl(&eefc->frr);
137 flash_info[0].protect[i] = (tmp >> (i%32)) & 1;
138#if defined(CONFIG_EFLASH_PROTSECTORS)
139 if (i < CONFIG_EFLASH_PROTSECTORS)
140 flash_info[0].protect[i] = 1;
141#endif
142 }
143
144 return size;
145}
146
147void flash_print_info (flash_info_t *info)
148{
149 int i;
150
151 puts("AT91SAM9XE embedded flash\n Size: ");
152 print_size(info->size, " in ");
153 printf("%d Sectors\n", info->sector_count);
154
155 printf(" Sector Start Addresses:");
156 for (i=0; i<info->sector_count; ++i) {
157 if ((i % 5) == 0)
158 printf("\n ");
159 printf(" %08lX%s",
160 info->start[i],
161 info->protect[i] ? " (RO)" : " "
162 );
163 }
164 printf ("\n");
165 return;
166}
167
168int flash_real_protect (flash_info_t *info, long sector, int prot)
169{
Reinhard Meyere260d0b2010-11-03 15:39:55 +0100170 at91_eefc_t *eefc = (at91_eefc_t *) ATMEL_BASE_EEFC;
171 u32 pagenum = (info->start[sector]-ATMEL_BASE_FLASH)/pagesize;
Reinhard Meyer8ec18f42010-07-27 15:18:38 +0200172 u32 i, tmp=0;
173
174 debug("protect sector=%ld prot=%d\n", sector, prot);
175
176#if defined(CONFIG_EFLASH_PROTSECTORS)
177 if (sector < CONFIG_EFLASH_PROTSECTORS) {
178 if (!prot) {
179 printf("eflash: sector %lu cannot be unprotected\n",
180 sector);
181 }
182 return 1; /* return anyway, caller does not care for result */
183 }
184#endif
185 if (prot) {
186 writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_SLB |
187 (pagenum << AT91_EEFC_FCR_FARG_SHIFT), &eefc->fcr);
188 } else {
189 writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_CLB |
190 (pagenum << AT91_EEFC_FCR_FARG_SHIFT), &eefc->fcr);
191 }
192 while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0)
193 ;
194 /* now re-read the protection information for all regions */
195 writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_GLB, &eefc->fcr);
196 while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0)
197 ;
198 for (i=0; i<info->sector_count; i++) {
199 if (i%32 == 0)
200 tmp = readl(&eefc->frr);
201 info->protect[i] = (tmp >> (i%32)) & 1;
202 }
203 return 0;
204}
205
206static u32 erase_write_page (u32 pagenum)
207{
Reinhard Meyere260d0b2010-11-03 15:39:55 +0100208 at91_eefc_t *eefc = (at91_eefc_t *) ATMEL_BASE_EEFC;
Reinhard Meyer8ec18f42010-07-27 15:18:38 +0200209
210 debug("erase+write page=%u\n", pagenum);
211
212 /* give erase and write page command */
213 writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_EWP |
214 (pagenum << AT91_EEFC_FCR_FARG_SHIFT), &eefc->fcr);
215 while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0)
216 ;
217 /* return status */
218 return readl(&eefc->fsr)
219 & (AT91_EEFC_FSR_FCMDE | AT91_EEFC_FSR_FLOCKE);
220}
221
222int flash_erase (flash_info_t *info, int s_first, int s_last)
223{
224 debug("erase first=%d last=%d\n", s_first, s_last);
225 puts("this flash does not need and support erasing!\n");
226 return 0;
227}
228
229/*
230 * Copy memory to flash, returns:
231 * 0 - OK
232 * 1 - write timeout
233 */
234
235int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
236{
237 u32 pagenum;
238 u32 *src32, *dst32;
239 u32 i;
240
241 debug("write src=%08lx addr=%08lx cnt=%lx\n",
242 (ulong)src, addr, cnt);
243
244 /* REQUIRE addr to be on a page start, abort if not */
245 if (addr % pagesize) {
246 printf ("eflash: start %08lx is not on page start\n"\
247 " write aborted\n", addr);
248 return 1;
249 }
250
251 /* now start copying data */
Reinhard Meyere260d0b2010-11-03 15:39:55 +0100252 pagenum = (addr-ATMEL_BASE_FLASH)/pagesize;
Reinhard Meyer8ec18f42010-07-27 15:18:38 +0200253 src32 = (u32 *) src;
254 dst32 = (u32 *) addr;
255 while (cnt > 0) {
256 i = pagesize / 4;
257 /* fill page buffer */
258 while (i--)
259 *dst32++ = *src32++;
260 /* write page */
261 if (erase_write_page(pagenum))
262 return 1;
263 pagenum++;
264 if (cnt > pagesize)
265 cnt -= pagesize;
266 else
267 cnt = 0;
268 }
269 return 0;
270}