uboot/board/atmel/atstk1000/flash.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005-2006 Atmel Corporation
   3 *
   4 * See file CREDITS for list of people who contributed to this
   5 * project.
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License as
   9 * published by the Free Software Foundation; either version 2 of
  10 * the License, or (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20 * MA 02111-1307 USA
  21 */
  22#include <common.h>
  23
  24#ifdef CONFIG_ATSTK1000_EXT_FLASH
  25#include <asm/arch/cacheflush.h>
  26#include <asm/io.h>
  27#include <asm/sections.h>
  28
  29DECLARE_GLOBAL_DATA_PTR;
  30
  31flash_info_t flash_info[1];
  32
  33static void flash_identify(uint16_t *flash, flash_info_t *info)
  34{
  35        unsigned long flags;
  36
  37        flags = disable_interrupts();
  38
  39        dcache_flush_unlocked();
  40
  41        writew(0xaa, flash + 0x555);
  42        writew(0x55, flash + 0xaaa);
  43        writew(0x90, flash + 0x555);
  44        info->flash_id = readl(flash);
  45        writew(0xff, flash);
  46
  47        readw(flash);
  48
  49        if (flags)
  50                enable_interrupts();
  51}
  52
  53unsigned long flash_init(void)
  54{
  55        unsigned long addr;
  56        unsigned int i;
  57
  58        flash_info[0].size = CONFIG_SYS_FLASH_SIZE;
  59        flash_info[0].sector_count = 135;
  60
  61        flash_identify(uncached((void *)CONFIG_SYS_FLASH_BASE), &flash_info[0]);
  62
  63        for (i = 0, addr = 0; i < 8; i++, addr += 0x2000)
  64                flash_info[0].start[i] = addr;
  65        for (; i < flash_info[0].sector_count; i++, addr += 0x10000)
  66                flash_info[0].start[i] = addr;
  67
  68        return CONFIG_SYS_FLASH_SIZE;
  69}
  70
  71void flash_print_info(flash_info_t *info)
  72{
  73        printf("Flash: Vendor ID: 0x%02lx, Product ID: 0x%02lx\n",
  74               info->flash_id >> 16, info->flash_id & 0xffff);
  75        printf("Size: %ld MB in %d sectors\n",
  76               info->size >> 10, info->sector_count);
  77}
  78
  79int flash_erase(flash_info_t *info, int s_first, int s_last)
  80{
  81        unsigned long flags;
  82        unsigned long start_time;
  83        uint16_t *fb, *sb;
  84        unsigned int i;
  85        int ret;
  86        uint16_t status;
  87
  88        if ((s_first < 0) || (s_first > s_last)
  89            || (s_last >= info->sector_count)) {
  90                puts("Error: first and/or last sector out of range\n");
  91                return ERR_INVAL;
  92        }
  93
  94        for (i = s_first; i < s_last; i++)
  95                if (info->protect[i]) {
  96                        printf("Error: sector %d is protected\n", i);
  97                        return ERR_PROTECTED;
  98                }
  99
 100        fb = (uint16_t *)uncached(info->start[0]);
 101
 102        dcache_flush_unlocked();
 103
 104        for (i = s_first; (i <= s_last) && !ctrlc(); i++) {
 105                printf("Erasing sector %3d...", i);
 106
 107                sb = (uint16_t *)uncached(info->start[i]);
 108
 109                flags = disable_interrupts();
 110
 111                start_time = get_timer(0);
 112
 113                /* Unlock sector */
 114                writew(0xaa, fb + 0x555);
 115                writew(0x70, sb);
 116
 117                /* Erase sector */
 118                writew(0xaa, fb + 0x555);
 119                writew(0x55, fb + 0xaaa);
 120                writew(0x80, fb + 0x555);
 121                writew(0xaa, fb + 0x555);
 122                writew(0x55, fb + 0xaaa);
 123                writew(0x30, sb);
 124
 125                /* Wait for completion */
 126                ret = ERR_OK;
 127                do {
 128                        /* TODO: Timeout */
 129                        status = readw(sb);
 130                } while ((status != 0xffff) && !(status & 0x28));
 131
 132                writew(0xf0, fb);
 133
 134                /*
 135                 * Make sure the command actually makes it to the bus
 136                 * before we re-enable interrupts.
 137                 */
 138                readw(fb);
 139
 140                if (flags)
 141                        enable_interrupts();
 142
 143                if (status != 0xffff) {
 144                        printf("Flash erase error at address 0x%p: 0x%02x\n",
 145                               sb, status);
 146                        ret = ERR_PROG_ERROR;
 147                        break;
 148                }
 149        }
 150
 151        if (ctrlc())
 152                printf("User interrupt!\n");
 153
 154        return ERR_OK;
 155}
 156
 157int write_buff(flash_info_t *info, uchar *src,
 158                           ulong addr, ulong count)
 159{
 160        unsigned long flags;
 161        uint16_t *base, *p, *s, *end;
 162        uint16_t word, status, status1;
 163        int ret = ERR_OK;
 164
 165        if (addr < info->start[0]
 166            || (addr + count) > (info->start[0] + info->size)
 167            || (addr + count) < addr) {
 168                puts("Error: invalid address range\n");
 169                return ERR_INVAL;
 170        }
 171
 172        if (addr & 1 || count & 1 || (unsigned int)src & 1) {
 173                puts("Error: misaligned source, destination or count\n");
 174                return ERR_ALIGN;
 175        }
 176
 177        base = (uint16_t *)uncached(info->start[0]);
 178        end = (uint16_t *)uncached(addr + count);
 179
 180        flags = disable_interrupts();
 181
 182        dcache_flush_unlocked();
 183        sync_write_buffer();
 184
 185        for (p = (uint16_t *)uncached(addr), s = (uint16_t *)src;
 186             p < end && !ctrlc(); p++, s++) {
 187                word = *s;
 188
 189                writew(0xaa, base + 0x555);
 190                writew(0x55, base + 0xaaa);
 191                writew(0xa0, base + 0x555);
 192                writew(word, p);
 193
 194                sync_write_buffer();
 195
 196                /* Wait for completion */
 197                status1 = readw(p);
 198                do {
 199                        /* TODO: Timeout */
 200                        status = status1;
 201                        status1 = readw(p);
 202                } while (((status ^ status1) & 0x40)    /* toggled */
 203                         && !(status1 & 0x28));         /* error bits */
 204
 205                /*
 206                 * We'll need to check once again for toggle bit
 207                 * because the toggle bit may stop toggling as I/O5
 208                 * changes to "1" (ref at49bv642.pdf p9)
 209                 */
 210                status1 = readw(p);
 211                status = readw(p);
 212                if ((status ^ status1) & 0x40) {
 213                        printf("Flash write error at address 0x%p: "
 214                               "0x%02x != 0x%02x\n",
 215                               p, status,word);
 216                        ret = ERR_PROG_ERROR;
 217                        writew(0xf0, base);
 218                        readw(base);
 219                        break;
 220                }
 221
 222                writew(0xf0, base);
 223                readw(base);
 224        }
 225
 226        if (flags)
 227                enable_interrupts();
 228
 229        return ret;
 230}
 231
 232#endif /* CONFIG_ATSTK1000_EXT_FLASH */
 233