]> git.sur5r.net Git - u-boot/blob - arch/arm/cpu/arm926ejs/at91/eflash.c
Prepare v2010.09-rc1
[u-boot] / arch / arm / cpu / arm926ejs / at91 / eflash.c
1 /*
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>
63 #include <asm/arch/hardware.h>
64 #include <asm/arch/io.h>
65 #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 */
75 flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
76 static u32 pagesize;
77
78 unsigned long flash_init (void)
79 {
80         at91_eefc_t *eefc = (at91_eefc_t *) 0xfffffa00;
81         at91_dbu_t *dbu = (at91_dbu_t *) 0xfffff200;
82         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
122         addr = AT91SAM9XE_FLASH_BASE;
123         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
147 void 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
168 int flash_real_protect (flash_info_t *info, long sector, int prot)
169 {
170         at91_eefc_t *eefc = (at91_eefc_t *) 0xfffffa00;
171         u32 pagenum = (info->start[sector]-AT91SAM9XE_FLASH_BASE)/pagesize;
172         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
206 static u32 erase_write_page (u32 pagenum)
207 {
208         at91_eefc_t *eefc = (at91_eefc_t *) 0xfffffa00;
209
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
222 int 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
235 int 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 */
252         pagenum = (addr-AT91SAM9XE_FLASH_BASE)/pagesize;
253         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 }