+++ /dev/null
-/*
- * Broadcom SiliconBackplane chipcommon serial flash interface
- *
- * Copyright 2004, Broadcom Corporation
- * All Rights Reserved.
- *
- * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
- * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
- * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
- *
- * $Id$
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/mtd/compatmac.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-#include <typedefs.h>
-#include <bcmdevs.h>
-#include <bcmutils.h>
-#include <osl.h>
-#include <bcmutils.h>
-#include <bcmnvram.h>
-#include <sbconfig.h>
-#include <sbchipc.h>
-#include <sflash.h>
-
-#ifdef CONFIG_MTD_PARTITIONS
-extern struct mtd_partition * init_mtd_partitions(struct mtd_info *mtd, size_t size);
-#endif
-
-struct sflash_mtd {
- chipcregs_t *cc;
- struct semaphore lock;
- struct mtd_info mtd;
- struct mtd_erase_region_info region;
-};
-
-/* Private global state */
-static struct sflash_mtd sflash;
-
-static int
-sflash_mtd_poll(struct sflash_mtd *sflash, unsigned int offset, int timeout)
-{
- int now = jiffies;
- int ret = 0;
-
- for (;;) {
- if (!sflash_poll(sflash->cc, offset)) {
- ret = 0;
- break;
- }
- if (time_after(jiffies, now + timeout)) {
- printk(KERN_ERR "sflash: timeout\n");
- ret = -ETIMEDOUT;
- break;
- }
- if (current->need_resched) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(timeout / 10);
- } else
- udelay(1);
- }
-
- return ret;
-}
-
-static int
-sflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-{
- struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
- int bytes, ret = 0;
-
- /* Check address range */
- if (!len)
- return 0;
- if ((from + len) > mtd->size)
- return -EINVAL;
-
- down(&sflash->lock);
-
- *retlen = 0;
- while (len) {
- if ((bytes = sflash_read(sflash->cc, (uint) from, len, buf)) < 0) {
- ret = bytes;
- break;
- }
- from += (loff_t) bytes;
- len -= bytes;
- buf += bytes;
- *retlen += bytes;
- }
-
- up(&sflash->lock);
-
- return ret;
-}
-
-static int
-sflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
-{
- struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
- int bytes, ret = 0;
-
- /* Check address range */
- if (!len)
- return 0;
- if ((to + len) > mtd->size)
- return -EINVAL;
-
- down(&sflash->lock);
-
- *retlen = 0;
- while (len) {
- if ((bytes = sflash_write(sflash->cc, (uint) to, len, buf)) < 0) {
- ret = bytes;
- break;
- }
- if ((ret = sflash_mtd_poll(sflash, (unsigned int) to, HZ / 10)))
- break;
- to += (loff_t) bytes;
- len -= bytes;
- buf += bytes;
- *retlen += bytes;
- }
-
- up(&sflash->lock);
-
- return ret;
-}
-
-static int
-sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
-{
- struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
- int i, j, ret = 0;
- unsigned int addr, len;
-
- /* Check address range */
- if (!erase->len)
- return 0;
- if ((erase->addr + erase->len) > mtd->size)
- return -EINVAL;
-
- addr = erase->addr;
- len = erase->len;
-
- down(&sflash->lock);
-
- /* Ensure that requested region is aligned */
- for (i = 0; i < mtd->numeraseregions; i++) {
- for (j = 0; j < mtd->eraseregions[i].numblocks; j++) {
- if (addr == mtd->eraseregions[i].offset + mtd->eraseregions[i].erasesize * j &&
- len >= mtd->eraseregions[i].erasesize) {
- if ((ret = sflash_erase(sflash->cc, addr)) < 0)
- break;
- if ((ret = sflash_mtd_poll(sflash, addr, 10 * HZ)))
- break;
- addr += mtd->eraseregions[i].erasesize;
- len -= mtd->eraseregions[i].erasesize;
- }
- }
- if (ret)
- break;
- }
-
- up(&sflash->lock);
-
- /* Set erase status */
- if (ret)
- erase->state = MTD_ERASE_FAILED;
- else
- erase->state = MTD_ERASE_DONE;
-
- /* Call erase callback */
- if (erase->callback)
- erase->callback(erase);
-
- return ret;
-}
-
-#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-#define sflash_mtd_init init_module
-#define sflash_mtd_exit cleanup_module
-#endif
-
-mod_init_t
-sflash_mtd_init(void)
-{
- struct pci_dev *pdev;
- int ret = 0;
- struct sflash *info;
- uint i;
-#ifdef CONFIG_MTD_PARTITIONS
- struct mtd_partition *parts;
-#endif
-
- if (!(pdev = pci_find_device(VENDOR_BROADCOM, SB_CC, NULL))) {
- printk(KERN_ERR "sflash: chipcommon not found\n");
- return -ENODEV;
- }
-
- memset(&sflash, 0, sizeof(struct sflash_mtd));
- init_MUTEX(&sflash.lock);
-
- /* Map registers and flash base */
- if (!(sflash.cc = ioremap_nocache(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0)))) {
- printk(KERN_ERR "sflash: error mapping registers\n");
- ret = -EIO;
- goto fail;
- }
-
- /* Initialize serial flash access */
- info = sflash_init(sflash.cc);
-
- if (!info) {
- printk(KERN_ERR "sflash: found no supported devices\n");
- ret = -ENODEV;
- goto fail;
- }
-
- /* Setup region info */
- sflash.region.offset = 0;
- sflash.region.erasesize = info->blocksize;
- sflash.region.numblocks = info->numblocks;
- if (sflash.region.erasesize > sflash.mtd.erasesize)
- sflash.mtd.erasesize = sflash.region.erasesize;
- sflash.mtd.size = info->size;
- sflash.mtd.numeraseregions = 1;
-
- /* Register with MTD */
- sflash.mtd.name = "sflash";
- sflash.mtd.type = MTD_NORFLASH;
- sflash.mtd.flags = MTD_CAP_NORFLASH;
- sflash.mtd.eraseregions = &sflash.region;
- sflash.mtd.module = THIS_MODULE;
- sflash.mtd.erase = sflash_mtd_erase;
- sflash.mtd.read = sflash_mtd_read;
- sflash.mtd.write = sflash_mtd_write;
- sflash.mtd.priv = &sflash;
-
-#ifdef CONFIG_MTD_PARTITIONS
- parts = init_mtd_partitions(&sflash.mtd, sflash.mtd.size);
- for (i = 0; parts[i].name; i++);
- ret = add_mtd_partitions(&sflash.mtd, parts, i);
-#else
- ret = add_mtd_device(&sflash.mtd);
-#endif
- if (ret) {
- printk(KERN_ERR "sflash: add_mtd failed\n");
- goto fail;
- }
-
- return 0;
-
- fail:
- if (sflash.cc)
- iounmap((void *) sflash.cc);
- return ret;
-}
-
-mod_exit_t
-sflash_mtd_exit(void)
-{
-#ifdef CONFIG_MTD_PARTITIONS
- del_mtd_partitions(&sflash.mtd);
-#else
- del_mtd_device(&sflash.mtd);
-#endif
- iounmap((void *) sflash.cc);
-}
-
-module_init(sflash_mtd_init);
-module_exit(sflash_mtd_exit);