123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- /*
- * (C) Copyright 2010
- * Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
- /*
- * this driver supports the enhanced embedded flash in the Atmel
- * AT91SAM9XE devices with the following geometry:
- *
- * AT91SAM9XE128: 1 plane of 8 regions of 32 pages (total 256 pages)
- * AT91SAM9XE256: 1 plane of 16 regions of 32 pages (total 512 pages)
- * AT91SAM9XE512: 1 plane of 32 regions of 32 pages (total 1024 pages)
- * (the exact geometry is read from the flash at runtime, so any
- * future devices should already be covered)
- *
- * Regions can be write/erase protected.
- * Whole (!) pages can be individually written with erase on the fly.
- * Writing partial pages will corrupt the rest of the page.
- *
- * The flash is presented to u-boot with each region being a sector,
- * having the following effects:
- * Each sector can be hardware protected (protect on/off).
- * Each page in a sector can be rewritten anytime.
- * Since pages are erased when written, the "erase" does nothing.
- * The first "CONFIG_EFLASH_PROTSECTORS" cannot be unprotected
- * by u-Boot commands.
- *
- * Note: Redundant environment will not work in this flash since
- * it does use partial page writes. Make sure the environent spans
- * whole pages!
- */
- /*
- * optional TODOs (nice to have features):
- *
- * make the driver coexist with other NOR flash drivers
- * (use an index into flash_info[], requires work
- * in those other drivers, too)
- * Make the erase command fill the sectors with 0xff
- * (if the flashes grow larger in the future and
- * someone puts a jffs2 into them)
- * do a read-modify-write for partially programmed pages
- */
- #include <common.h>
- #include <asm/arch/hardware.h>
- #include <asm/arch/io.h>
- #include <asm/arch/at91_common.h>
- #include <asm/arch/at91_eefc.h>
- #include <asm/arch/at91_dbu.h>
- /* checks to detect configuration errors */
- #if CONFIG_SYS_MAX_FLASH_BANKS!=1
- #error eflash: this driver can only handle 1 bank
- #endif
- /* global structure */
- flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
- static u32 pagesize;
- unsigned long flash_init (void)
- {
- at91_eefc_t *eefc = (at91_eefc_t *) 0xfffffa00;
- at91_dbu_t *dbu = (at91_dbu_t *) 0xfffff200;
- u32 id, size, nplanes, planesize, nlocks;
- u32 addr, i, tmp=0;
- debug("eflash: init\n");
- flash_info[0].flash_id = FLASH_UNKNOWN;
- /* check if its an AT91ARM9XE SoC */
- if ((readl(&dbu->cidr) & AT91_DBU_CID_ARCH_MASK) != AT91_DBU_CID_ARCH_9XExx) {
- puts("eflash: not an AT91SAM9XE\n");
- return 0;
- }
- /* now query the eflash for its structure */
- writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_GETD, &eefc->fcr);
- while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0)
- ;
- id = readl(&eefc->frr); /* word 0 */
- size = readl(&eefc->frr); /* word 1 */
- pagesize = readl(&eefc->frr); /* word 2 */
- nplanes = readl(&eefc->frr); /* word 3 */
- planesize = readl(&eefc->frr); /* word 4 */
- debug("id=%08x size=%u pagesize=%u planes=%u planesize=%u\n",
- id, size, pagesize, nplanes, planesize);
- for (i=1; i<nplanes; i++) {
- tmp = readl(&eefc->frr); /* words 5..4+nplanes-1 */
- };
- nlocks = readl(&eefc->frr); /* word 4+nplanes */
- debug("nlocks=%u\n", nlocks);
- /* since we are going to use the lock regions as sectors, check count */
- if (nlocks > CONFIG_SYS_MAX_FLASH_SECT) {
- printf("eflash: number of lock regions(%u) "\
- "> CONFIG_SYS_MAX_FLASH_SECT. reducing...\n",
- nlocks);
- nlocks = CONFIG_SYS_MAX_FLASH_SECT;
- }
- flash_info[0].size = size;
- flash_info[0].sector_count = nlocks;
- flash_info[0].flash_id = id;
- addr = AT91SAM9XE_FLASH_BASE;
- for (i=0; i<nlocks; i++) {
- tmp = readl(&eefc->frr); /* words 4+nplanes+1.. */
- flash_info[0].start[i] = addr;
- flash_info[0].protect[i] = 0;
- addr += tmp;
- };
- /* now read the protection information for all regions */
- writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_GLB, &eefc->fcr);
- while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0)
- ;
- for (i=0; i<flash_info[0].sector_count; i++) {
- if (i%32 == 0)
- tmp = readl(&eefc->frr);
- flash_info[0].protect[i] = (tmp >> (i%32)) & 1;
- #if defined(CONFIG_EFLASH_PROTSECTORS)
- if (i < CONFIG_EFLASH_PROTSECTORS)
- flash_info[0].protect[i] = 1;
- #endif
- }
- return size;
- }
- void flash_print_info (flash_info_t *info)
- {
- int i;
- puts("AT91SAM9XE embedded flash\n Size: ");
- print_size(info->size, " in ");
- printf("%d Sectors\n", info->sector_count);
- printf(" Sector Start Addresses:");
- for (i=0; i<info->sector_count; ++i) {
- if ((i % 5) == 0)
- printf("\n ");
- printf(" %08lX%s",
- info->start[i],
- info->protect[i] ? " (RO)" : " "
- );
- }
- printf ("\n");
- return;
- }
- int flash_real_protect (flash_info_t *info, long sector, int prot)
- {
- at91_eefc_t *eefc = (at91_eefc_t *) 0xfffffa00;
- u32 pagenum = (info->start[sector]-AT91SAM9XE_FLASH_BASE)/pagesize;
- u32 i, tmp=0;
- debug("protect sector=%ld prot=%d\n", sector, prot);
- #if defined(CONFIG_EFLASH_PROTSECTORS)
- if (sector < CONFIG_EFLASH_PROTSECTORS) {
- if (!prot) {
- printf("eflash: sector %lu cannot be unprotected\n",
- sector);
- }
- return 1; /* return anyway, caller does not care for result */
- }
- #endif
- if (prot) {
- writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_SLB |
- (pagenum << AT91_EEFC_FCR_FARG_SHIFT), &eefc->fcr);
- } else {
- writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_CLB |
- (pagenum << AT91_EEFC_FCR_FARG_SHIFT), &eefc->fcr);
- }
- while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0)
- ;
- /* now re-read the protection information for all regions */
- writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_GLB, &eefc->fcr);
- while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0)
- ;
- for (i=0; i<info->sector_count; i++) {
- if (i%32 == 0)
- tmp = readl(&eefc->frr);
- info->protect[i] = (tmp >> (i%32)) & 1;
- }
- return 0;
- }
- static u32 erase_write_page (u32 pagenum)
- {
- at91_eefc_t *eefc = (at91_eefc_t *) 0xfffffa00;
- debug("erase+write page=%u\n", pagenum);
- /* give erase and write page command */
- writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_EWP |
- (pagenum << AT91_EEFC_FCR_FARG_SHIFT), &eefc->fcr);
- while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0)
- ;
- /* return status */
- return readl(&eefc->fsr)
- & (AT91_EEFC_FSR_FCMDE | AT91_EEFC_FSR_FLOCKE);
- }
- int flash_erase (flash_info_t *info, int s_first, int s_last)
- {
- debug("erase first=%d last=%d\n", s_first, s_last);
- puts("this flash does not need and support erasing!\n");
- return 0;
- }
- /*
- * Copy memory to flash, returns:
- * 0 - OK
- * 1 - write timeout
- */
- int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
- {
- u32 pagenum;
- u32 *src32, *dst32;
- u32 i;
- debug("write src=%08lx addr=%08lx cnt=%lx\n",
- (ulong)src, addr, cnt);
- /* REQUIRE addr to be on a page start, abort if not */
- if (addr % pagesize) {
- printf ("eflash: start %08lx is not on page start\n"\
- " write aborted\n", addr);
- return 1;
- }
- /* now start copying data */
- pagenum = (addr-AT91SAM9XE_FLASH_BASE)/pagesize;
- src32 = (u32 *) src;
- dst32 = (u32 *) addr;
- while (cnt > 0) {
- i = pagesize / 4;
- /* fill page buffer */
- while (i--)
- *dst32++ = *src32++;
- /* write page */
- if (erase_write_page(pagenum))
- return 1;
- pagenum++;
- if (cnt > pagesize)
- cnt -= pagesize;
- else
- cnt = 0;
- }
- return 0;
- }
|