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