parent
fdabcaaceb
commit
49eba1d322
@ -1,283 +0,0 @@ |
||||
/*
|
||||
* 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); |
Loading…
Reference in new issue