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