linux/drivers/mtd/devices/bcm47xxsflash.c
<<
>>
Prefs
   1#include <linux/kernel.h>
   2#include <linux/module.h>
   3#include <linux/slab.h>
   4#include <linux/delay.h>
   5#include <linux/mtd/mtd.h>
   6#include <linux/platform_device.h>
   7#include <linux/bcma/bcma.h>
   8
   9#include "bcm47xxsflash.h"
  10
  11MODULE_LICENSE("GPL");
  12MODULE_DESCRIPTION("Serial flash driver for BCMA bus");
  13
  14static const char * const probes[] = { "bcm47xxpart", NULL };
  15
  16/**************************************************
  17 * Various helpers
  18 **************************************************/
  19
  20static void bcm47xxsflash_cmd(struct bcm47xxsflash *b47s, u32 opcode)
  21{
  22        int i;
  23
  24        b47s->cc_write(b47s, BCMA_CC_FLASHCTL, BCMA_CC_FLASHCTL_START | opcode);
  25        for (i = 0; i < 1000; i++) {
  26                if (!(b47s->cc_read(b47s, BCMA_CC_FLASHCTL) &
  27                      BCMA_CC_FLASHCTL_BUSY))
  28                        return;
  29                cpu_relax();
  30        }
  31        pr_err("Control command failed (timeout)!\n");
  32}
  33
  34static int bcm47xxsflash_poll(struct bcm47xxsflash *b47s, int timeout)
  35{
  36        unsigned long deadline = jiffies + timeout;
  37
  38        do {
  39                switch (b47s->type) {
  40                case BCM47XXSFLASH_TYPE_ST:
  41                        bcm47xxsflash_cmd(b47s, OPCODE_ST_RDSR);
  42                        if (!(b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
  43                              SR_ST_WIP))
  44                                return 0;
  45                        break;
  46                case BCM47XXSFLASH_TYPE_ATMEL:
  47                        bcm47xxsflash_cmd(b47s, OPCODE_AT_STATUS);
  48                        if (b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
  49                            SR_AT_READY)
  50                                return 0;
  51                        break;
  52                }
  53
  54                cpu_relax();
  55                udelay(1);
  56        } while (!time_after_eq(jiffies, deadline));
  57
  58        pr_err("Timeout waiting for flash to be ready!\n");
  59
  60        return -EBUSY;
  61}
  62
  63/**************************************************
  64 * MTD ops
  65 **************************************************/
  66
  67static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase)
  68{
  69        struct bcm47xxsflash *b47s = mtd->priv;
  70        int err;
  71
  72        switch (b47s->type) {
  73        case BCM47XXSFLASH_TYPE_ST:
  74                bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
  75                b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr);
  76                /* Newer flashes have "sub-sectors" which can be erased
  77                 * independently with a new command: ST_SSE. The ST_SE command
  78                 * erases 64KB just as before.
  79                 */
  80                if (b47s->blocksize < (64 * 1024))
  81                        bcm47xxsflash_cmd(b47s, OPCODE_ST_SSE);
  82                else
  83                        bcm47xxsflash_cmd(b47s, OPCODE_ST_SE);
  84                break;
  85        case BCM47XXSFLASH_TYPE_ATMEL:
  86                b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr << 1);
  87                bcm47xxsflash_cmd(b47s, OPCODE_AT_PAGE_ERASE);
  88                break;
  89        }
  90
  91        err = bcm47xxsflash_poll(b47s, HZ);
  92        if (err)
  93                erase->state = MTD_ERASE_FAILED;
  94        else
  95                erase->state = MTD_ERASE_DONE;
  96
  97        if (erase->callback)
  98                erase->callback(erase);
  99
 100        return err;
 101}
 102
 103static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
 104                              size_t *retlen, u_char *buf)
 105{
 106        struct bcm47xxsflash *b47s = mtd->priv;
 107
 108        /* Check address range */
 109        if ((from + len) > mtd->size)
 110                return -EINVAL;
 111
 112        memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(b47s->window + from),
 113                      len);
 114        *retlen = len;
 115
 116        return len;
 117}
 118
 119static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len,
 120                                  const u_char *buf)
 121{
 122        struct bcm47xxsflash *b47s = mtd->priv;
 123        int written = 0;
 124
 125        /* Enable writes */
 126        bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
 127
 128        /* Write first byte */
 129        b47s->cc_write(b47s, BCMA_CC_FLASHADDR, offset);
 130        b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
 131
 132        /* Program page */
 133        if (b47s->bcma_cc->core->id.rev < 20) {
 134                bcm47xxsflash_cmd(b47s, OPCODE_ST_PP);
 135                return 1; /* 1B written */
 136        }
 137
 138        /* Program page and set CSA (on newer chips we can continue writing) */
 139        bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | OPCODE_ST_PP);
 140        offset++;
 141        len--;
 142        written++;
 143
 144        while (len > 0) {
 145                /* Page boundary, another function call is needed */
 146                if ((offset & 0xFF) == 0)
 147                        break;
 148
 149                bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | *buf++);
 150                offset++;
 151                len--;
 152                written++;
 153        }
 154
 155        /* All done, drop CSA & poll */
 156        b47s->cc_write(b47s, BCMA_CC_FLASHCTL, 0);
 157        udelay(1);
 158        if (bcm47xxsflash_poll(b47s, HZ / 10))
 159                pr_err("Flash rejected dropping CSA\n");
 160
 161        return written;
 162}
 163
 164static int bcm47xxsflash_write_at(struct mtd_info *mtd, u32 offset, size_t len,
 165                                  const u_char *buf)
 166{
 167        struct bcm47xxsflash *b47s = mtd->priv;
 168        u32 mask = b47s->blocksize - 1;
 169        u32 page = (offset & ~mask) << 1;
 170        u32 byte = offset & mask;
 171        int written = 0;
 172
 173        /* If we don't overwrite whole page, read it to the buffer first */
 174        if (byte || (len < b47s->blocksize)) {
 175                int err;
 176
 177                b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
 178                bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_LOAD);
 179                /* 250 us for AT45DB321B */
 180                err = bcm47xxsflash_poll(b47s, HZ / 1000);
 181                if (err) {
 182                        pr_err("Timeout reading page 0x%X info buffer\n", page);
 183                        return err;
 184                }
 185        }
 186
 187        /* Change buffer content with our data */
 188        while (len > 0) {
 189                /* Page boundary, another function call is needed */
 190                if (byte == b47s->blocksize)
 191                        break;
 192
 193                b47s->cc_write(b47s, BCMA_CC_FLASHADDR, byte++);
 194                b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
 195                bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_WRITE);
 196                len--;
 197                written++;
 198        }
 199
 200        /* Program page with the buffer content */
 201        b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
 202        bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_PROGRAM);
 203
 204        return written;
 205}
 206
 207static int bcm47xxsflash_write(struct mtd_info *mtd, loff_t to, size_t len,
 208                               size_t *retlen, const u_char *buf)
 209{
 210        struct bcm47xxsflash *b47s = mtd->priv;
 211        int written;
 212
 213        /* Writing functions can return without writing all passed data, for
 214         * example when the hardware is too old or when we git page boundary.
 215         */
 216        while (len > 0) {
 217                switch (b47s->type) {
 218                case BCM47XXSFLASH_TYPE_ST:
 219                        written = bcm47xxsflash_write_st(mtd, to, len, buf);
 220                        break;
 221                case BCM47XXSFLASH_TYPE_ATMEL:
 222                        written = bcm47xxsflash_write_at(mtd, to, len, buf);
 223                        break;
 224                default:
 225                        BUG_ON(1);
 226                }
 227                if (written < 0) {
 228                        pr_err("Error writing at offset 0x%llX\n", to);
 229                        return written;
 230                }
 231                to += (loff_t)written;
 232                len -= written;
 233                *retlen += written;
 234                buf += written;
 235        }
 236
 237        return 0;
 238}
 239
 240static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
 241{
 242        struct mtd_info *mtd = &b47s->mtd;
 243
 244        mtd->priv = b47s;
 245        mtd->name = "bcm47xxsflash";
 246        mtd->owner = THIS_MODULE;
 247
 248        mtd->type = MTD_NORFLASH;
 249        mtd->flags = MTD_CAP_NORFLASH;
 250        mtd->size = b47s->size;
 251        mtd->erasesize = b47s->blocksize;
 252        mtd->writesize = 1;
 253        mtd->writebufsize = 1;
 254
 255        mtd->_erase = bcm47xxsflash_erase;
 256        mtd->_read = bcm47xxsflash_read;
 257        mtd->_write = bcm47xxsflash_write;
 258}
 259
 260/**************************************************
 261 * BCMA
 262 **************************************************/
 263
 264static int bcm47xxsflash_bcma_cc_read(struct bcm47xxsflash *b47s, u16 offset)
 265{
 266        return bcma_cc_read32(b47s->bcma_cc, offset);
 267}
 268
 269static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset,
 270                                        u32 value)
 271{
 272        bcma_cc_write32(b47s->bcma_cc, offset, value);
 273}
 274
 275static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
 276{
 277        struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
 278        struct bcm47xxsflash *b47s;
 279        int err;
 280
 281        b47s = devm_kzalloc(&pdev->dev, sizeof(*b47s), GFP_KERNEL);
 282        if (!b47s)
 283                return -ENOMEM;
 284        sflash->priv = b47s;
 285
 286        b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
 287        b47s->cc_read = bcm47xxsflash_bcma_cc_read;
 288        b47s->cc_write = bcm47xxsflash_bcma_cc_write;
 289
 290        switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
 291        case BCMA_CC_FLASHT_STSER:
 292                b47s->type = BCM47XXSFLASH_TYPE_ST;
 293                break;
 294        case BCMA_CC_FLASHT_ATSER:
 295                b47s->type = BCM47XXSFLASH_TYPE_ATMEL;
 296                break;
 297        }
 298
 299        b47s->window = sflash->window;
 300        b47s->blocksize = sflash->blocksize;
 301        b47s->numblocks = sflash->numblocks;
 302        b47s->size = sflash->size;
 303        bcm47xxsflash_fill_mtd(b47s);
 304
 305        err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
 306        if (err) {
 307                pr_err("Failed to register MTD device: %d\n", err);
 308                return err;
 309        }
 310
 311        if (bcm47xxsflash_poll(b47s, HZ / 10))
 312                pr_warn("Serial flash busy\n");
 313
 314        return 0;
 315}
 316
 317static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
 318{
 319        struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
 320        struct bcm47xxsflash *b47s = sflash->priv;
 321
 322        mtd_device_unregister(&b47s->mtd);
 323
 324        return 0;
 325}
 326
 327static struct platform_driver bcma_sflash_driver = {
 328        .probe  = bcm47xxsflash_bcma_probe,
 329        .remove = bcm47xxsflash_bcma_remove,
 330        .driver = {
 331                .name = "bcma_sflash",
 332                .owner = THIS_MODULE,
 333        },
 334};
 335
 336/**************************************************
 337 * Init
 338 **************************************************/
 339
 340module_platform_driver(bcma_sflash_driver);
 341