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