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