uboot/common/flash.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2000
   3 * Wolfgang Denk, DENX Software Engineering, wd@denx.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/* #define DEBUG */
  25
  26#include <common.h>
  27#include <flash.h>
  28
  29#if !defined(CONFIG_SYS_NO_FLASH)
  30#include <mtd/cfi_flash.h>
  31
  32extern flash_info_t  flash_info[]; /* info for FLASH chips */
  33
  34/*-----------------------------------------------------------------------
  35 * Functions
  36 */
  37
  38/*-----------------------------------------------------------------------
  39 * Set protection status for monitor sectors
  40 *
  41 * The monitor is always located in the _first_ Flash bank.
  42 * If necessary you have to map the second bank at lower addresses.
  43 */
  44void
  45flash_protect (int flag, ulong from, ulong to, flash_info_t *info)
  46{
  47        ulong b_end;
  48        short s_end;
  49        int i;
  50
  51        /* Do nothing if input data is bad. */
  52        if (!info || info->sector_count == 0 || info->size == 0 || to < from) {
  53                return;
  54        }
  55
  56        s_end = info->sector_count - 1; /* index of last sector */
  57        b_end = info->start[0] + info->size - 1;        /* bank end address */
  58
  59        debug ("flash_protect %s: from 0x%08lX to 0x%08lX\n",
  60                (flag & FLAG_PROTECT_SET) ? "ON" :
  61                        (flag & FLAG_PROTECT_CLEAR) ? "OFF" : "???",
  62                from, to);
  63
  64        /* There is nothing to do if we have no data about the flash
  65         * or the protect range and flash range don't overlap.
  66         */
  67        if (info->flash_id == FLASH_UNKNOWN ||
  68            to < info->start[0] || from > b_end) {
  69                return;
  70        }
  71
  72        for (i=0; i<info->sector_count; ++i) {
  73                ulong end;              /* last address in current sect */
  74
  75                end = (i == s_end) ? b_end : info->start[i + 1] - 1;
  76
  77                /* Update protection if any part of the sector
  78                 * is in the specified range.
  79                 */
  80                if (from <= end && to >= info->start[i]) {
  81                        if (flag & FLAG_PROTECT_CLEAR) {
  82#if defined(CONFIG_SYS_FLASH_PROTECTION)
  83                                flash_real_protect(info, i, 0);
  84#else
  85                                info->protect[i] = 0;
  86#endif  /* CONFIG_SYS_FLASH_PROTECTION */
  87                                debug ("protect off %d\n", i);
  88                        }
  89                        else if (flag & FLAG_PROTECT_SET) {
  90#if defined(CONFIG_SYS_FLASH_PROTECTION)
  91                                flash_real_protect(info, i, 1);
  92#else
  93                                info->protect[i] = 1;
  94#endif  /* CONFIG_SYS_FLASH_PROTECTION */
  95                                debug ("protect on %d\n", i);
  96                        }
  97                }
  98        }
  99}
 100
 101/*-----------------------------------------------------------------------
 102 */
 103
 104flash_info_t *
 105addr2info (ulong addr)
 106{
 107#ifndef CONFIG_SPD823TS
 108        flash_info_t *info;
 109        int i;
 110
 111        for (i=0, info = &flash_info[0]; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) {
 112                if (info->flash_id != FLASH_UNKNOWN &&
 113                    addr >= info->start[0] &&
 114                    /* WARNING - The '- 1' is needed if the flash
 115                     * is at the end of the address space, since
 116                     * info->start[0] + info->size wraps back to 0.
 117                     * Please don't change this unless you understand this.
 118                     */
 119                    addr <= info->start[0] + info->size - 1) {
 120                        return (info);
 121                }
 122        }
 123#endif /* CONFIG_SPD823TS */
 124
 125        return (NULL);
 126}
 127
 128/*-----------------------------------------------------------------------
 129 * Copy memory to flash.
 130 * Make sure all target addresses are within Flash bounds,
 131 * and no protected sectors are hit.
 132 * Returns:
 133 * ERR_OK          0 - OK
 134 * ERR_TIMOUT      1 - write timeout
 135 * ERR_NOT_ERASED  2 - Flash not erased
 136 * ERR_PROTECTED   4 - target range includes protected sectors
 137 * ERR_INVAL       8 - target address not in Flash memory
 138 * ERR_ALIGN       16 - target address not aligned on boundary
 139 *                      (only some targets require alignment)
 140 */
 141int
 142flash_write (char *src, ulong addr, ulong cnt)
 143{
 144#ifdef CONFIG_SPD823TS
 145        return (ERR_TIMOUT);    /* any other error codes are possible as well */
 146#else
 147        int i;
 148        ulong         end        = addr + cnt - 1;
 149        flash_info_t *info_first = addr2info (addr);
 150        flash_info_t *info_last  = addr2info (end );
 151        flash_info_t *info;
 152
 153        if (cnt == 0) {
 154                return (ERR_OK);
 155        }
 156
 157        if (!info_first || !info_last) {
 158                return (ERR_INVAL);
 159        }
 160
 161        for (info = info_first; info <= info_last; ++info) {
 162                ulong b_end = info->start[0] + info->size;      /* bank end addr */
 163                short s_end = info->sector_count - 1;
 164                for (i=0; i<info->sector_count; ++i) {
 165                        ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];
 166
 167                        if ((end >= info->start[i]) && (addr < e_addr) &&
 168                            (info->protect[i] != 0) ) {
 169                                return (ERR_PROTECTED);
 170                        }
 171                }
 172        }
 173
 174        /* finally write data to flash */
 175        for (info = info_first; info <= info_last && cnt>0; ++info) {
 176                ulong len;
 177
 178                len = info->start[0] + info->size - addr;
 179                if (len > cnt)
 180                        len = cnt;
 181                if ((i = write_buff(info, (uchar *)src, addr, len)) != 0) {
 182                        return (i);
 183                }
 184                cnt  -= len;
 185                addr += len;
 186                src  += len;
 187        }
 188        return (ERR_OK);
 189#endif /* CONFIG_SPD823TS */
 190}
 191
 192/*-----------------------------------------------------------------------
 193 */
 194
 195void flash_perror (int err)
 196{
 197        switch (err) {
 198        case ERR_OK:
 199                break;
 200        case ERR_TIMOUT:
 201                puts ("Timeout writing to Flash\n");
 202                break;
 203        case ERR_NOT_ERASED:
 204                puts ("Flash not Erased\n");
 205                break;
 206        case ERR_PROTECTED:
 207                puts ("Can't write to protected Flash sectors\n");
 208                break;
 209        case ERR_INVAL:
 210                puts ("Outside available Flash\n");
 211                break;
 212        case ERR_ALIGN:
 213                puts ("Start and/or end address not on sector boundary\n");
 214                break;
 215        case ERR_UNKNOWN_FLASH_VENDOR:
 216                puts ("Unknown Vendor of Flash\n");
 217                break;
 218        case ERR_UNKNOWN_FLASH_TYPE:
 219                puts ("Unknown Type of Flash\n");
 220                break;
 221        case ERR_PROG_ERROR:
 222                puts ("General Flash Programming Error\n");
 223                break;
 224        default:
 225                printf ("%s[%d] FIXME: rc=%d\n", __FILE__, __LINE__, err);
 226                break;
 227        }
 228}
 229
 230/*-----------------------------------------------------------------------
 231 */
 232#endif /* !CONFIG_SYS_NO_FLASH */
 233