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