uboot/drivers/mtd/spi/stmicro.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2000-2002
   3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   4 *
   5 * Copyright 2008, Network Appliance Inc.
   6 * Jason McMullan <mcmullan@netapp.com>
   7 *
   8 * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
   9 * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
  10 *
  11 * See file CREDITS for list of people who contributed to this
  12 * project.
  13 *
  14 * This program is free software; you can redistribute it and/or
  15 * modify it under the terms of the GNU General Public License as
  16 * published by the Free Software Foundation; either version 2 of
  17 * the License, or (at your option) any later version.
  18 *
  19 * This program is distributed in the hope that it will be useful,
  20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22 * GNU General Public License for more details.
  23 *
  24 * You should have received a copy of the GNU General Public License
  25 * along with this program; if not, write to the Free Software
  26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  27 * MA 02111-1307 USA
  28 */
  29
  30#include <common.h>
  31#include <malloc.h>
  32#include <spi_flash.h>
  33
  34#include "spi_flash_internal.h"
  35
  36/* M25Pxx-specific commands */
  37#define CMD_M25PXX_WREN         0x06    /* Write Enable */
  38#define CMD_M25PXX_WRDI         0x04    /* Write Disable */
  39#define CMD_M25PXX_RDSR         0x05    /* Read Status Register */
  40#define CMD_M25PXX_WRSR         0x01    /* Write Status Register */
  41#define CMD_M25PXX_READ         0x03    /* Read Data Bytes */
  42#define CMD_M25PXX_FAST_READ    0x0b    /* Read Data Bytes at Higher Speed */
  43#define CMD_M25PXX_PP           0x02    /* Page Program */
  44#define CMD_M25PXX_SE           0xd8    /* Sector Erase */
  45#define CMD_M25PXX_BE           0xc7    /* Bulk Erase */
  46#define CMD_M25PXX_DP           0xb9    /* Deep Power-down */
  47#define CMD_M25PXX_RES          0xab    /* Release from DP, and Read Signature */
  48
  49#define STM_ID_M25P16           0x15
  50#define STM_ID_M25P20           0x12
  51#define STM_ID_M25P32           0x16
  52#define STM_ID_M25P40           0x13
  53#define STM_ID_M25P64           0x17
  54#define STM_ID_M25P80           0x14
  55#define STM_ID_M25P128          0x18
  56
  57#define STMICRO_SR_WIP          (1 << 0)        /* Write-in-Progress */
  58
  59struct stmicro_spi_flash_params {
  60        u8 idcode1;
  61        u16 page_size;
  62        u16 pages_per_sector;
  63        u16 nr_sectors;
  64        const char *name;
  65};
  66
  67/* spi_flash needs to be first so upper layers can free() it */
  68struct stmicro_spi_flash {
  69        struct spi_flash flash;
  70        const struct stmicro_spi_flash_params *params;
  71};
  72
  73static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash
  74                                                             *flash)
  75{
  76        return container_of(flash, struct stmicro_spi_flash, flash);
  77}
  78
  79static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = {
  80        {
  81                .idcode1 = STM_ID_M25P16,
  82                .page_size = 256,
  83                .pages_per_sector = 256,
  84                .nr_sectors = 32,
  85                .name = "M25P16",
  86        },
  87        {
  88                .idcode1 = STM_ID_M25P20,
  89                .page_size = 256,
  90                .pages_per_sector = 256,
  91                .nr_sectors = 4,
  92                .name = "M25P20",
  93        },
  94        {
  95                .idcode1 = STM_ID_M25P32,
  96                .page_size = 256,
  97                .pages_per_sector = 256,
  98                .nr_sectors = 64,
  99                .name = "M25P32",
 100        },
 101        {
 102                .idcode1 = STM_ID_M25P40,
 103                .page_size = 256,
 104                .pages_per_sector = 256,
 105                .nr_sectors = 8,
 106                .name = "M25P40",
 107        },
 108        {
 109                .idcode1 = STM_ID_M25P64,
 110                .page_size = 256,
 111                .pages_per_sector = 256,
 112                .nr_sectors = 128,
 113                .name = "M25P64",
 114        },
 115        {
 116                .idcode1 = STM_ID_M25P80,
 117                .page_size = 256,
 118                .pages_per_sector = 256,
 119                .nr_sectors = 16,
 120                .name = "M25P80",
 121        },
 122        {
 123                .idcode1 = STM_ID_M25P128,
 124                .page_size = 256,
 125                .pages_per_sector = 1024,
 126                .nr_sectors = 64,
 127                .name = "M25P128",
 128        },
 129};
 130
 131static int stmicro_wait_ready(struct spi_flash *flash, unsigned long timeout)
 132{
 133        struct spi_slave *spi = flash->spi;
 134        unsigned long timebase;
 135        int ret;
 136        u8 cmd = CMD_M25PXX_RDSR;
 137        u8 status;
 138
 139        ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
 140        if (ret) {
 141                debug("SF: Failed to send command %02x: %d\n", cmd, ret);
 142                return ret;
 143        }
 144
 145        timebase = get_timer(0);
 146        do {
 147                ret = spi_xfer(spi, 8, NULL, &status, 0);
 148                if (ret)
 149                        return -1;
 150
 151                if ((status & STMICRO_SR_WIP) == 0)
 152                        break;
 153
 154        } while (get_timer(timebase) < timeout);
 155
 156        spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
 157
 158        if ((status & STMICRO_SR_WIP) == 0)
 159                return 0;
 160
 161        /* Timed out */
 162        return -1;
 163}
 164
 165static int stmicro_read_fast(struct spi_flash *flash,
 166                             u32 offset, size_t len, void *buf)
 167{
 168        struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
 169        unsigned long page_addr;
 170        unsigned long page_size;
 171        u8 cmd[5];
 172
 173        page_size = stm->params->page_size;
 174        page_addr = offset / page_size;
 175
 176        cmd[0] = CMD_READ_ARRAY_FAST;
 177        cmd[1] = page_addr >> 8;
 178        cmd[2] = page_addr;
 179        cmd[3] = offset % page_size;
 180        cmd[4] = 0x00;
 181
 182        return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len);
 183}
 184
 185static int stmicro_write(struct spi_flash *flash,
 186                         u32 offset, size_t len, const void *buf)
 187{
 188        struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
 189        unsigned long page_addr;
 190        unsigned long byte_addr;
 191        unsigned long page_size;
 192        size_t chunk_len;
 193        size_t actual;
 194        int ret;
 195        u8 cmd[4];
 196
 197        page_size = stm->params->page_size;
 198        page_addr = offset / page_size;
 199        byte_addr = offset % page_size;
 200
 201        ret = spi_claim_bus(flash->spi);
 202        if (ret) {
 203                debug("SF: Unable to claim SPI bus\n");
 204                return ret;
 205        }
 206
 207        ret = 0;
 208        for (actual = 0; actual < len; actual += chunk_len) {
 209                chunk_len = min(len - actual, page_size - byte_addr);
 210
 211                cmd[0] = CMD_M25PXX_PP;
 212                cmd[1] = page_addr >> 8;
 213                cmd[2] = page_addr;
 214                cmd[3] = byte_addr;
 215
 216                debug
 217                    ("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %d\n",
 218                     buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
 219
 220                ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0);
 221                if (ret < 0) {
 222                        debug("SF: Enabling Write failed\n");
 223                        break;
 224                }
 225
 226                ret = spi_flash_cmd_write(flash->spi, cmd, 4,
 227                                          buf + actual, chunk_len);
 228                if (ret < 0) {
 229                        debug("SF: STMicro Page Program failed\n");
 230                        break;
 231                }
 232
 233                ret = stmicro_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
 234                if (ret < 0) {
 235                        debug("SF: STMicro page programming timed out\n");
 236                        break;
 237                }
 238
 239                page_addr++;
 240                byte_addr = 0;
 241        }
 242
 243        debug("SF: STMicro: Successfully programmed %u bytes @ 0x%x\n",
 244              len, offset);
 245
 246        spi_release_bus(flash->spi);
 247        return ret;
 248}
 249
 250int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len)
 251{
 252        struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
 253        unsigned long sector_size;
 254        size_t actual;
 255        int ret;
 256        u8 cmd[4];
 257
 258        /*
 259         * This function currently uses sector erase only.
 260         * probably speed things up by using bulk erase
 261         * when possible.
 262         */
 263
 264        sector_size = stm->params->page_size * stm->params->pages_per_sector;
 265
 266        if (offset % sector_size || len % sector_size) {
 267                debug("SF: Erase offset/length not multiple of sector size\n");
 268                return -1;
 269        }
 270
 271        len /= sector_size;
 272        cmd[0] = CMD_M25PXX_SE;
 273        cmd[2] = 0x00;
 274        cmd[3] = 0x00;
 275
 276        ret = spi_claim_bus(flash->spi);
 277        if (ret) {
 278                debug("SF: Unable to claim SPI bus\n");
 279                return ret;
 280        }
 281
 282        ret = 0;
 283        for (actual = 0; actual < len; actual++) {
 284                cmd[1] = offset >> 16;
 285                offset += sector_size;
 286
 287                ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0);
 288                if (ret < 0) {
 289                        debug("SF: Enabling Write failed\n");
 290                        break;
 291                }
 292
 293                ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0);
 294                if (ret < 0) {
 295                        debug("SF: STMicro page erase failed\n");
 296                        break;
 297                }
 298
 299                ret = stmicro_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
 300                if (ret < 0) {
 301                        debug("SF: STMicro page erase timed out\n");
 302                        break;
 303                }
 304        }
 305
 306        debug("SF: STMicro: Successfully erased %u bytes @ 0x%x\n",
 307              len * sector_size, offset);
 308
 309        spi_release_bus(flash->spi);
 310        return ret;
 311}
 312
 313struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode)
 314{
 315        const struct stmicro_spi_flash_params *params;
 316        struct stmicro_spi_flash *stm;
 317        unsigned int i;
 318
 319        for (i = 0; i < ARRAY_SIZE(stmicro_spi_flash_table); i++) {
 320                params = &stmicro_spi_flash_table[i];
 321                if (params->idcode1 == idcode[2]) {
 322                        break;
 323                }
 324        }
 325
 326        if (i == ARRAY_SIZE(stmicro_spi_flash_table)) {
 327                debug("SF: Unsupported STMicro ID %02x\n", idcode[1]);
 328                return NULL;
 329        }
 330
 331        stm = malloc(sizeof(struct stmicro_spi_flash));
 332        if (!stm) {
 333                debug("SF: Failed to allocate memory\n");
 334                return NULL;
 335        }
 336
 337        stm->params = params;
 338        stm->flash.spi = spi;
 339        stm->flash.name = params->name;
 340
 341        stm->flash.write = stmicro_write;
 342        stm->flash.erase = stmicro_erase;
 343        stm->flash.read = stmicro_read_fast;
 344        stm->flash.size = params->page_size * params->pages_per_sector
 345            * params->nr_sectors;
 346
 347        debug("SF: Detected %s with page size %u, total %u bytes\n",
 348              params->name, params->page_size, stm->flash.size);
 349
 350        return &stm->flash;
 351}
 352