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