You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'for-linus-20141015' of git://git.infradead.org/linux-mtd
Pull MTD update from Brian Norris:
"Sorry for delaying this a bit later than usual. There's one mild
regression from 3.16 that was noticed during the 3.17 cycle, and I
meant to send a fix for it along with this pull request. I'll
probably try to queue it up for a later pull request once I've had a
better look at it, hopefully by -rc2 at the latest.
Summary for this pull:
NAND
- Cleanup for Denali driver
- Atmel: add support for new page sizes
- Atmel: fix up 'raw' mode support
- Atmel: miscellaneous cleanups
- New timing mode helpers for non-ONFI NAND
- OMAP: allow driver to be (properly) built as a module
- bcm47xx: RESET support and other cleanups
SPI NOR
- Miscellaneous cleanups, to prepare framework for wider use (some
further work still pending)
- Compile-time configuration to select 4K vs. 64K support for flash
that support both (necessary for using UBIFS on some SPI NOR)
A few scattered code quality fixes, detected by Coverity
See the changesets for more"
* tag 'for-linus-20141015' of git://git.infradead.org/linux-mtd: (59 commits)
mtd: nand: omap: Correct CONFIG_MTD_NAND_OMAP_BCH help message
mtd: nand: Force omap_elm to be built as a module if omap2_nand is a module
mtd: move support for struct flash_platform_data into m25p80
mtd: spi-nor: add Kconfig option to disable 4K sectors
mtd: nand: Move ELM driver and rename as omap_elm
nand: omap2: Replace pr_err with dev_err
nand: omap2: Remove horrible ifdefs to fix module probe
mtd: nand: add Hynix's H27UCG8T2ATR-BC to nand_ids table
mtd: nand: support ONFI timing mode retrieval for non-ONFI NANDs
mtd: physmap_of: Add non-obsolete map_rom probe
mtd: physmap_of: Fix ROM support via OF
MAINTAINERS: add l2-mtd.git, 'next' tree for MTD
mtd: denali: fix indents and other trivial things
mtd: denali: remove unnecessary parentheses
mtd: denali: remove another set-but-unused variable
mtd: denali: fix include guard and license block of denali.h
mtd: nand: don't break long print messages
mtd: bcm47xxnflash: replace some magic numbers
mtd: bcm47xxnflash: NAND_CMD_RESET support
mtd: bcm47xxnflash: add cmd_ctrl handler
...
This commit is contained in:
@@ -36,6 +36,7 @@ Optional properties:
|
||||
- reg : should specify the address and size used for NFC command registers,
|
||||
NFC registers and NFC Sram. NFC Sram address and size can be absent
|
||||
if don't want to use it.
|
||||
- clocks: phandle to the peripheral clock
|
||||
- Optional properties:
|
||||
- atmel,write-by-sram: boolean to enable NFC write by sram.
|
||||
|
||||
@@ -98,6 +99,7 @@ nand0: nand@40000000 {
|
||||
compatible = "atmel,sama5d3-nfc";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
clocks = <&hsmc_clk>
|
||||
reg = <
|
||||
0x70000000 0x10000000 /* NFC Command Registers */
|
||||
0xffffc000 0x00000070 /* NFC HSMC regs */
|
||||
|
||||
@@ -4,8 +4,8 @@ Flash chips (Memory Technology Devices) are often used for solid state
|
||||
file systems on embedded devices.
|
||||
|
||||
- compatible : should contain the specific model of mtd chip(s)
|
||||
used, if known, followed by either "cfi-flash", "jedec-flash"
|
||||
or "mtd-ram".
|
||||
used, if known, followed by either "cfi-flash", "jedec-flash",
|
||||
"mtd-ram" or "mtd-rom".
|
||||
- reg : Address range(s) of the mtd chip(s)
|
||||
It's possible to (optionally) define multiple "reg" tuples so that
|
||||
non-identical chips can be described in one node.
|
||||
|
||||
@@ -5992,6 +5992,7 @@ L: linux-mtd@lists.infradead.org
|
||||
W: http://www.linux-mtd.infradead.org/
|
||||
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
|
||||
T: git git://git.infradead.org/linux-mtd.git
|
||||
T: git git://git.infradead.org/l2-mtd.git
|
||||
S: Maintained
|
||||
F: drivers/mtd/
|
||||
F: include/linux/mtd/
|
||||
|
||||
@@ -1440,6 +1440,8 @@ static int gpmc_probe_nand_child(struct platform_device *pdev,
|
||||
break;
|
||||
}
|
||||
|
||||
gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child);
|
||||
|
||||
val = of_get_nand_bus_width(child);
|
||||
if (val == 16)
|
||||
gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
|
||||
|
||||
@@ -199,6 +199,17 @@ static int bcm47xxpart_parse(struct mtd_info *master,
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* New (ARM?) devices may have NVRAM in some middle block. Last
|
||||
* block will be checked later, so skip it.
|
||||
*/
|
||||
if (offset != master->size - blocksize &&
|
||||
buf[0x000 / 4] == NVRAM_HEADER) {
|
||||
bcm47xxpart_add_part(&parts[curr_part++], "nvram",
|
||||
offset, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read middle of the block */
|
||||
if (mtd_read(master, offset + 0x8000, 0x4,
|
||||
&bytes_read, (uint8_t *)buf) < 0) {
|
||||
|
||||
@@ -2033,6 +2033,8 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip,
|
||||
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
retries--;
|
||||
}
|
||||
|
||||
/* the chip never became ready */
|
||||
|
||||
@@ -12,7 +12,6 @@ obj-$(CONFIG_MTD_LART) += lart.o
|
||||
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
|
||||
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
|
||||
obj-$(CONFIG_MTD_M25P80) += m25p80.o
|
||||
obj-$(CONFIG_MTD_NAND_OMAP_BCH) += elm.o
|
||||
obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o
|
||||
obj-$(CONFIG_MTD_SST25L) += sst25l.o
|
||||
obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o
|
||||
|
||||
+13
-13
@@ -1697,16 +1697,16 @@ static int dbg_asicmode_show(struct seq_file *s, void *p)
|
||||
|
||||
switch (mode) {
|
||||
case DOC_ASICMODE_RESET:
|
||||
pos += seq_printf(s, "reset");
|
||||
pos += seq_puts(s, "reset");
|
||||
break;
|
||||
case DOC_ASICMODE_NORMAL:
|
||||
pos += seq_printf(s, "normal");
|
||||
pos += seq_puts(s, "normal");
|
||||
break;
|
||||
case DOC_ASICMODE_POWERDOWN:
|
||||
pos += seq_printf(s, "powerdown");
|
||||
pos += seq_puts(s, "powerdown");
|
||||
break;
|
||||
}
|
||||
pos += seq_printf(s, ")\n");
|
||||
pos += seq_puts(s, ")\n");
|
||||
return pos;
|
||||
}
|
||||
DEBUGFS_RO_ATTR(asic_mode, dbg_asicmode_show);
|
||||
@@ -1745,22 +1745,22 @@ static int dbg_protection_show(struct seq_file *s, void *p)
|
||||
pos += seq_printf(s, "Protection = 0x%02x (",
|
||||
protect);
|
||||
if (protect & DOC_PROTECT_FOUNDRY_OTP_LOCK)
|
||||
pos += seq_printf(s, "FOUNDRY_OTP_LOCK,");
|
||||
pos += seq_puts(s, "FOUNDRY_OTP_LOCK,");
|
||||
if (protect & DOC_PROTECT_CUSTOMER_OTP_LOCK)
|
||||
pos += seq_printf(s, "CUSTOMER_OTP_LOCK,");
|
||||
pos += seq_puts(s, "CUSTOMER_OTP_LOCK,");
|
||||
if (protect & DOC_PROTECT_LOCK_INPUT)
|
||||
pos += seq_printf(s, "LOCK_INPUT,");
|
||||
pos += seq_puts(s, "LOCK_INPUT,");
|
||||
if (protect & DOC_PROTECT_STICKY_LOCK)
|
||||
pos += seq_printf(s, "STICKY_LOCK,");
|
||||
pos += seq_puts(s, "STICKY_LOCK,");
|
||||
if (protect & DOC_PROTECT_PROTECTION_ENABLED)
|
||||
pos += seq_printf(s, "PROTECTION ON,");
|
||||
pos += seq_puts(s, "PROTECTION ON,");
|
||||
if (protect & DOC_PROTECT_IPL_DOWNLOAD_LOCK)
|
||||
pos += seq_printf(s, "IPL_DOWNLOAD_LOCK,");
|
||||
pos += seq_puts(s, "IPL_DOWNLOAD_LOCK,");
|
||||
if (protect & DOC_PROTECT_PROTECTION_ERROR)
|
||||
pos += seq_printf(s, "PROTECT_ERR,");
|
||||
pos += seq_puts(s, "PROTECT_ERR,");
|
||||
else
|
||||
pos += seq_printf(s, "NO_PROTECT_ERR");
|
||||
pos += seq_printf(s, ")\n");
|
||||
pos += seq_puts(s, "NO_PROTECT_ERR");
|
||||
pos += seq_puts(s, ")\n");
|
||||
|
||||
pos += seq_printf(s, "DPS0 = 0x%02x : "
|
||||
"Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, "
|
||||
|
||||
@@ -193,11 +193,14 @@ static int m25p_probe(struct spi_device *spi)
|
||||
{
|
||||
struct mtd_part_parser_data ppdata;
|
||||
struct flash_platform_data *data;
|
||||
const struct spi_device_id *id = NULL;
|
||||
struct m25p *flash;
|
||||
struct spi_nor *nor;
|
||||
enum read_mode mode = SPI_NOR_NORMAL;
|
||||
int ret;
|
||||
|
||||
data = dev_get_platdata(&spi->dev);
|
||||
|
||||
flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
|
||||
if (!flash)
|
||||
return -ENOMEM;
|
||||
@@ -223,11 +226,26 @@ static int m25p_probe(struct spi_device *spi)
|
||||
mode = SPI_NOR_QUAD;
|
||||
else if (spi->mode & SPI_RX_DUAL)
|
||||
mode = SPI_NOR_DUAL;
|
||||
ret = spi_nor_scan(nor, spi_get_device_id(spi), mode);
|
||||
|
||||
if (data && data->name)
|
||||
flash->mtd.name = data->name;
|
||||
|
||||
/* For some (historical?) reason many platforms provide two different
|
||||
* names in flash_platform_data: "name" and "type". Quite often name is
|
||||
* set to "m25p80" and then "type" provides a real chip name.
|
||||
* If that's the case, respect "type" and ignore a "name".
|
||||
*/
|
||||
if (data && data->type)
|
||||
id = spi_nor_match_id(data->type);
|
||||
|
||||
/* If we didn't get name from platform, simply use "modalias". */
|
||||
if (!id)
|
||||
id = spi_get_device_id(spi);
|
||||
|
||||
ret = spi_nor_scan(nor, id, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data = dev_get_platdata(&spi->dev);
|
||||
ppdata.of_node = spi->dev.of_node;
|
||||
|
||||
return mtd_device_parse_register(&flash->mtd, NULL, &ppdata,
|
||||
|
||||
@@ -249,7 +249,7 @@ config MTD_CFI_FLAGADM
|
||||
|
||||
config MTD_SOLUTIONENGINE
|
||||
tristate "CFI Flash device mapped on Hitachi SolutionEngine"
|
||||
depends on SUPERH && SOLUTION_ENGINE && MTD_CFI && MTD_REDBOOT_PARTS
|
||||
depends on SOLUTION_ENGINE && MTD_CFI && MTD_REDBOOT_PARTS
|
||||
help
|
||||
This enables access to the flash chips on the Hitachi SolutionEngine and
|
||||
similar boards. Say 'Y' if you are building a kernel for such a board.
|
||||
|
||||
@@ -99,22 +99,28 @@ static map_word gf_read(struct map_info *map, unsigned long ofs)
|
||||
* @from: flash offset to copy from
|
||||
* @len: how much to copy
|
||||
*
|
||||
* We rely on the MTD layer to chunk up copies such that a single request here
|
||||
* will not cross a window size. This allows us to only wiggle the GPIOs once
|
||||
* before falling back to a normal memcpy. Reading the higher layer code shows
|
||||
* that this is indeed the case, but add a BUG_ON() to future proof.
|
||||
* The "from" region may straddle more than one window, so toggle the GPIOs for
|
||||
* each window region before reading its data.
|
||||
*/
|
||||
static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
|
||||
{
|
||||
struct async_state *state = gf_map_info_to_state(map);
|
||||
|
||||
gf_set_gpios(state, from);
|
||||
int this_len;
|
||||
|
||||
/* BUG if operation crosses the win_size */
|
||||
BUG_ON(!((from + len) % state->win_size <= (from + len)));
|
||||
while (len) {
|
||||
if ((from % state->win_size) + len > state->win_size)
|
||||
this_len = state->win_size - (from % state->win_size);
|
||||
else
|
||||
this_len = len;
|
||||
|
||||
/* operation does not cross the win_size, so one shot it */
|
||||
memcpy_fromio(to, map->virt + (from % state->win_size), len);
|
||||
gf_set_gpios(state, from);
|
||||
memcpy_fromio(to, map->virt + (from % state->win_size),
|
||||
this_len);
|
||||
len -= this_len;
|
||||
from += this_len;
|
||||
to += this_len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,13 +153,21 @@ static void gf_copy_to(struct map_info *map, unsigned long to,
|
||||
{
|
||||
struct async_state *state = gf_map_info_to_state(map);
|
||||
|
||||
gf_set_gpios(state, to);
|
||||
int this_len;
|
||||
|
||||
/* BUG if operation crosses the win_size */
|
||||
BUG_ON(!((to + len) % state->win_size <= (to + len)));
|
||||
while (len) {
|
||||
if ((to % state->win_size) + len > state->win_size)
|
||||
this_len = state->win_size - (to % state->win_size);
|
||||
else
|
||||
this_len = len;
|
||||
|
||||
/* operation does not cross the win_size, so one shot it */
|
||||
memcpy_toio(map->virt + (to % state->win_size), from, len);
|
||||
gf_set_gpios(state, to);
|
||||
memcpy_toio(map->virt + (to % state->win_size), from, len);
|
||||
|
||||
len -= this_len;
|
||||
to += this_len;
|
||||
from += this_len;
|
||||
}
|
||||
}
|
||||
|
||||
static const char * const part_probe_types[] = {
|
||||
|
||||
@@ -89,7 +89,7 @@ static caddr_t remap_window(struct map_info *map, unsigned long to)
|
||||
|
||||
if (!pcmcia_dev_present(dev->p_dev)) {
|
||||
pr_debug("device removed\n");
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
offset = to & ~(dev->win_size-1);
|
||||
|
||||
@@ -103,7 +103,7 @@ static struct mtd_info *obsolete_probe(struct platform_device *dev,
|
||||
if (strcmp(of_probe, "ROM") != 0)
|
||||
dev_warn(&dev->dev, "obsolete_probe: don't know probe "
|
||||
"type '%s', mapping as rom\n", of_probe);
|
||||
return do_map_probe("mtd_rom", map);
|
||||
return do_map_probe("map_rom", map);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,6 +339,10 @@ static struct of_device_id of_flash_match[] = {
|
||||
.compatible = "mtd-ram",
|
||||
.data = (void *)"map_ram",
|
||||
},
|
||||
{
|
||||
.compatible = "mtd-rom",
|
||||
.data = (void *)"map_rom",
|
||||
},
|
||||
{
|
||||
.type = "rom",
|
||||
.compatible = "direct-mapped"
|
||||
|
||||
@@ -549,6 +549,9 @@ static int mtdchar_blkpg_ioctl(struct mtd_info *mtd,
|
||||
if (mtd_is_partition(mtd))
|
||||
return -EINVAL;
|
||||
|
||||
/* Sanitize user input */
|
||||
p.devname[BLKPG_DEVNAMELTH - 1] = '\0';
|
||||
|
||||
return mtd_add_partition(mtd, p.devname, p.start, p.length);
|
||||
|
||||
case BLKPG_DEL_PARTITION:
|
||||
|
||||
+18
-21
@@ -105,12 +105,11 @@ static LIST_HEAD(mtd_notifiers);
|
||||
*/
|
||||
static void mtd_release(struct device *dev)
|
||||
{
|
||||
struct mtd_info __maybe_unused *mtd = dev_get_drvdata(dev);
|
||||
struct mtd_info *mtd = dev_get_drvdata(dev);
|
||||
dev_t index = MTD_DEVT(mtd->index);
|
||||
|
||||
/* remove /dev/mtdXro node if needed */
|
||||
if (index)
|
||||
device_destroy(&mtd_class, index + 1);
|
||||
/* remove /dev/mtdXro node */
|
||||
device_destroy(&mtd_class, index + 1);
|
||||
}
|
||||
|
||||
static int mtd_cls_suspend(struct device *dev, pm_message_t state)
|
||||
@@ -442,10 +441,8 @@ int add_mtd_device(struct mtd_info *mtd)
|
||||
if (device_register(&mtd->dev) != 0)
|
||||
goto fail_added;
|
||||
|
||||
if (MTD_DEVT(i))
|
||||
device_create(&mtd_class, mtd->dev.parent,
|
||||
MTD_DEVT(i) + 1,
|
||||
NULL, "mtd%dro", i);
|
||||
device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL,
|
||||
"mtd%dro", i);
|
||||
|
||||
pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name);
|
||||
/* No need to get a refcount on the module containing
|
||||
@@ -778,7 +775,7 @@ EXPORT_SYMBOL_GPL(__put_mtd_device);
|
||||
*/
|
||||
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
{
|
||||
if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr)
|
||||
if (instr->addr >= mtd->size || instr->len > mtd->size - instr->addr)
|
||||
return -EINVAL;
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
@@ -804,7 +801,7 @@ int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||
*phys = 0;
|
||||
if (!mtd->_point)
|
||||
return -EOPNOTSUPP;
|
||||
if (from < 0 || from > mtd->size || len > mtd->size - from)
|
||||
if (from < 0 || from >= mtd->size || len > mtd->size - from)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
@@ -817,7 +814,7 @@ int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
|
||||
{
|
||||
if (!mtd->_point)
|
||||
return -EOPNOTSUPP;
|
||||
if (from < 0 || from > mtd->size || len > mtd->size - from)
|
||||
if (from < 0 || from >= mtd->size || len > mtd->size - from)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
@@ -835,7 +832,7 @@ unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len,
|
||||
{
|
||||
if (!mtd->_get_unmapped_area)
|
||||
return -EOPNOTSUPP;
|
||||
if (offset > mtd->size || len > mtd->size - offset)
|
||||
if (offset >= mtd->size || len > mtd->size - offset)
|
||||
return -EINVAL;
|
||||
return mtd->_get_unmapped_area(mtd, len, offset, flags);
|
||||
}
|
||||
@@ -846,7 +843,7 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||
{
|
||||
int ret_code;
|
||||
*retlen = 0;
|
||||
if (from < 0 || from > mtd->size || len > mtd->size - from)
|
||||
if (from < 0 || from >= mtd->size || len > mtd->size - from)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
@@ -869,7 +866,7 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||
const u_char *buf)
|
||||
{
|
||||
*retlen = 0;
|
||||
if (to < 0 || to > mtd->size || len > mtd->size - to)
|
||||
if (to < 0 || to >= mtd->size || len > mtd->size - to)
|
||||
return -EINVAL;
|
||||
if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
@@ -892,7 +889,7 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||
*retlen = 0;
|
||||
if (!mtd->_panic_write)
|
||||
return -EOPNOTSUPP;
|
||||
if (to < 0 || to > mtd->size || len > mtd->size - to)
|
||||
if (to < 0 || to >= mtd->size || len > mtd->size - to)
|
||||
return -EINVAL;
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
@@ -1011,7 +1008,7 @@ int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
if (!mtd->_lock)
|
||||
return -EOPNOTSUPP;
|
||||
if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
|
||||
if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
@@ -1023,7 +1020,7 @@ int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
if (!mtd->_unlock)
|
||||
return -EOPNOTSUPP;
|
||||
if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
|
||||
if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
@@ -1035,7 +1032,7 @@ int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
if (!mtd->_is_locked)
|
||||
return -EOPNOTSUPP;
|
||||
if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs)
|
||||
if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
@@ -1045,7 +1042,7 @@ EXPORT_SYMBOL_GPL(mtd_is_locked);
|
||||
|
||||
int mtd_block_isreserved(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
if (ofs < 0 || ofs > mtd->size)
|
||||
if (ofs < 0 || ofs >= mtd->size)
|
||||
return -EINVAL;
|
||||
if (!mtd->_block_isreserved)
|
||||
return 0;
|
||||
@@ -1055,7 +1052,7 @@ EXPORT_SYMBOL_GPL(mtd_block_isreserved);
|
||||
|
||||
int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
if (ofs < 0 || ofs > mtd->size)
|
||||
if (ofs < 0 || ofs >= mtd->size)
|
||||
return -EINVAL;
|
||||
if (!mtd->_block_isbad)
|
||||
return 0;
|
||||
@@ -1067,7 +1064,7 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
if (!mtd->_block_markbad)
|
||||
return -EOPNOTSUPP;
|
||||
if (ofs < 0 || ofs > mtd->size)
|
||||
if (ofs < 0 || ofs >= mtd->size)
|
||||
return -EINVAL;
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
|
||||
@@ -145,7 +145,7 @@ struct mtdswap_dev {
|
||||
struct mtdswap_oobdata {
|
||||
__le16 magic;
|
||||
__le32 count;
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
#define MTDSWAP_MAGIC_CLEAN 0x2095
|
||||
#define MTDSWAP_MAGIC_DIRTY (MTDSWAP_MAGIC_CLEAN + 1)
|
||||
@@ -1287,7 +1287,7 @@ static int mtdswap_show(struct seq_file *s, void *data)
|
||||
|
||||
seq_printf(s, "total erasures: %lu\n", sum);
|
||||
|
||||
seq_printf(s, "\n");
|
||||
seq_puts(s, "\n");
|
||||
|
||||
seq_printf(s, "mtdswap_readsect count: %llu\n", d->sect_read_count);
|
||||
seq_printf(s, "mtdswap_writesect count: %llu\n", d->sect_write_count);
|
||||
@@ -1296,7 +1296,7 @@ static int mtdswap_show(struct seq_file *s, void *data)
|
||||
seq_printf(s, "mtd write count: %llu\n", d->mtd_write_count);
|
||||
seq_printf(s, "discarded pages count: %llu\n", d->discard_page_count);
|
||||
|
||||
seq_printf(s, "\n");
|
||||
seq_puts(s, "\n");
|
||||
seq_printf(s, "total pages: %u\n", pages);
|
||||
seq_printf(s, "pages mapped: %u\n", mapped);
|
||||
|
||||
@@ -1474,7 +1474,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
||||
}
|
||||
|
||||
eblocks = mtd_div_by_eb(use_size, mtd);
|
||||
use_size = eblocks * mtd->erasesize;
|
||||
use_size = (uint64_t)eblocks * mtd->erasesize;
|
||||
bad_blocks = mtdswap_badblocks(mtd, use_size);
|
||||
eavailable = eblocks - bad_blocks;
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ config MTD_NAND_OMAP2
|
||||
|
||||
config MTD_NAND_OMAP_BCH
|
||||
depends on MTD_NAND_OMAP2
|
||||
tristate "Support hardware based BCH error correction"
|
||||
bool "Support hardware based BCH error correction"
|
||||
default n
|
||||
select BCH
|
||||
help
|
||||
@@ -104,7 +104,10 @@ config MTD_NAND_OMAP_BCH
|
||||
locate and correct errors when using BCH ECC scheme. This offloads
|
||||
the cpu from doing ECC error searching and correction. However some
|
||||
legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine
|
||||
so they should not enable this config symbol.
|
||||
so this is optional for them.
|
||||
|
||||
config MTD_NAND_OMAP_BCH_BUILD
|
||||
def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH
|
||||
|
||||
config MTD_NAND_IDS
|
||||
tristate
|
||||
|
||||
@@ -27,6 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
|
||||
obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o
|
||||
obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o
|
||||
obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o
|
||||
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
@@ -96,6 +97,8 @@ struct atmel_nfc {
|
||||
bool use_nfc_sram;
|
||||
bool write_by_sram;
|
||||
|
||||
struct clk *clk;
|
||||
|
||||
bool is_initialized;
|
||||
struct completion comp_ready;
|
||||
struct completion comp_cmd_done;
|
||||
@@ -128,8 +131,6 @@ struct atmel_nand_host {
|
||||
u32 pmecc_lookup_table_offset_512;
|
||||
u32 pmecc_lookup_table_offset_1024;
|
||||
|
||||
int pmecc_bytes_per_sector;
|
||||
int pmecc_sector_number;
|
||||
int pmecc_degree; /* Degree of remainders */
|
||||
int pmecc_cw_len; /* Length of codeword */
|
||||
|
||||
@@ -841,7 +842,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
|
||||
pos, bit_pos, err_byte, *(buf + byte_pos));
|
||||
} else {
|
||||
/* Bit flip in OOB area */
|
||||
tmp = sector_num * host->pmecc_bytes_per_sector
|
||||
tmp = sector_num * nand_chip->ecc.bytes
|
||||
+ (byte_pos - sector_size);
|
||||
err_byte = ecc[tmp];
|
||||
ecc[tmp] ^= (1 << bit_pos);
|
||||
@@ -874,7 +875,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
|
||||
return 0;
|
||||
|
||||
normal_check:
|
||||
for (i = 0; i < host->pmecc_sector_number; i++) {
|
||||
for (i = 0; i < nand_chip->ecc.steps; i++) {
|
||||
err_nbr = 0;
|
||||
if (pmecc_stat & 0x1) {
|
||||
buf_pos = buf + i * host->pmecc_sector_size;
|
||||
@@ -890,7 +891,7 @@ normal_check:
|
||||
return -EIO;
|
||||
} else {
|
||||
pmecc_correct_data(mtd, buf_pos, ecc, i,
|
||||
host->pmecc_bytes_per_sector, err_nbr);
|
||||
nand_chip->ecc.bytes, err_nbr);
|
||||
mtd->ecc_stats.corrected += err_nbr;
|
||||
total_err += err_nbr;
|
||||
}
|
||||
@@ -984,11 +985,11 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
for (i = 0; i < host->pmecc_sector_number; i++) {
|
||||
for (j = 0; j < host->pmecc_bytes_per_sector; j++) {
|
||||
for (i = 0; i < chip->ecc.steps; i++) {
|
||||
for (j = 0; j < chip->ecc.bytes; j++) {
|
||||
int pos;
|
||||
|
||||
pos = i * host->pmecc_bytes_per_sector + j;
|
||||
pos = i * chip->ecc.bytes + j;
|
||||
chip->oob_poi[eccpos[pos]] =
|
||||
pmecc_readb_ecc_relaxed(host->ecc, i, j);
|
||||
}
|
||||
@@ -1031,7 +1032,7 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
|
||||
else if (host->pmecc_sector_size == 1024)
|
||||
val |= PMECC_CFG_SECTOR1024;
|
||||
|
||||
switch (host->pmecc_sector_number) {
|
||||
switch (nand_chip->ecc.steps) {
|
||||
case 1:
|
||||
val |= PMECC_CFG_PAGE_1SECTOR;
|
||||
break;
|
||||
@@ -1148,7 +1149,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
|
||||
|
||||
host->ecc = devm_ioremap_resource(&pdev->dev, regs);
|
||||
if (IS_ERR(host->ecc)) {
|
||||
dev_err(host->dev, "ioremap failed\n");
|
||||
err_no = PTR_ERR(host->ecc);
|
||||
goto err;
|
||||
}
|
||||
@@ -1156,8 +1156,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
|
||||
regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
|
||||
host->pmerrloc_base = devm_ioremap_resource(&pdev->dev, regs_pmerr);
|
||||
if (IS_ERR(host->pmerrloc_base)) {
|
||||
dev_err(host->dev,
|
||||
"Can not get I/O resource for PMECC ERRLOC controller!\n");
|
||||
err_no = PTR_ERR(host->pmerrloc_base);
|
||||
goto err;
|
||||
}
|
||||
@@ -1165,7 +1163,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
|
||||
regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
|
||||
host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom);
|
||||
if (IS_ERR(host->pmecc_rom_base)) {
|
||||
dev_err(host->dev, "Can not get I/O resource for ROM!\n");
|
||||
err_no = PTR_ERR(host->pmecc_rom_base);
|
||||
goto err;
|
||||
}
|
||||
@@ -1174,22 +1171,29 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
|
||||
|
||||
/* set ECC page size and oob layout */
|
||||
switch (mtd->writesize) {
|
||||
case 512:
|
||||
case 1024:
|
||||
case 2048:
|
||||
case 4096:
|
||||
case 8192:
|
||||
if (sector_size > mtd->writesize) {
|
||||
dev_err(host->dev, "pmecc sector size is bigger than the page size!\n");
|
||||
err_no = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
host->pmecc_degree = (sector_size == 512) ?
|
||||
PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14;
|
||||
host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
|
||||
host->pmecc_sector_number = mtd->writesize / sector_size;
|
||||
host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes(
|
||||
cap, sector_size);
|
||||
host->pmecc_alpha_to = pmecc_get_alpha_to(host);
|
||||
host->pmecc_index_of = host->pmecc_rom_base +
|
||||
host->pmecc_lookup_table_offset;
|
||||
|
||||
nand_chip->ecc.steps = host->pmecc_sector_number;
|
||||
nand_chip->ecc.strength = cap;
|
||||
nand_chip->ecc.bytes = host->pmecc_bytes_per_sector;
|
||||
nand_chip->ecc.total = host->pmecc_bytes_per_sector *
|
||||
host->pmecc_sector_number;
|
||||
nand_chip->ecc.bytes = pmecc_get_ecc_bytes(cap, sector_size);
|
||||
nand_chip->ecc.steps = mtd->writesize / sector_size;
|
||||
nand_chip->ecc.total = nand_chip->ecc.bytes *
|
||||
nand_chip->ecc.steps;
|
||||
if (nand_chip->ecc.total > mtd->oobsize - 2) {
|
||||
dev_err(host->dev, "No room for ECC bytes\n");
|
||||
err_no = -EINVAL;
|
||||
@@ -1201,13 +1205,9 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
|
||||
|
||||
nand_chip->ecc.layout = &atmel_pmecc_oobinfo;
|
||||
break;
|
||||
case 512:
|
||||
case 1024:
|
||||
case 4096:
|
||||
/* TODO */
|
||||
default:
|
||||
dev_warn(host->dev,
|
||||
"Unsupported page size for PMECC, use Software ECC\n");
|
||||
default:
|
||||
/* page size not handled by HW ECC */
|
||||
/* switching back to soft ECC */
|
||||
nand_chip->ecc.mode = NAND_ECC_SOFT;
|
||||
@@ -1530,10 +1530,8 @@ static int atmel_hw_nand_init_params(struct platform_device *pdev,
|
||||
}
|
||||
|
||||
host->ecc = devm_ioremap_resource(&pdev->dev, regs);
|
||||
if (IS_ERR(host->ecc)) {
|
||||
dev_err(host->dev, "ioremap failed\n");
|
||||
if (IS_ERR(host->ecc))
|
||||
return PTR_ERR(host->ecc);
|
||||
}
|
||||
|
||||
/* ECC is calculated for the whole page (1 step) */
|
||||
nand_chip->ecc.size = mtd->writesize;
|
||||
@@ -1907,15 +1905,7 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
if (offset || (data_len < mtd->writesize))
|
||||
return -EINVAL;
|
||||
|
||||
cfg = nfc_readl(host->nfc->hsmc_regs, CFG);
|
||||
len = mtd->writesize;
|
||||
|
||||
if (unlikely(raw)) {
|
||||
len += mtd->oobsize;
|
||||
nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE);
|
||||
} else
|
||||
nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE);
|
||||
|
||||
/* Copy page data to sram that will write to nand via NFC */
|
||||
if (use_dma) {
|
||||
if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) != 0)
|
||||
@@ -1925,6 +1915,15 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
memcpy32_toio(sram, buf, len);
|
||||
}
|
||||
|
||||
cfg = nfc_readl(host->nfc->hsmc_regs, CFG);
|
||||
if (unlikely(raw) && oob_required) {
|
||||
memcpy32_toio(sram + len, chip->oob_poi, mtd->oobsize);
|
||||
len += mtd->oobsize;
|
||||
nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE);
|
||||
} else {
|
||||
nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE);
|
||||
}
|
||||
|
||||
if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
|
||||
/*
|
||||
* When use NFC sram, need set up PMECC before send
|
||||
@@ -2040,7 +2039,6 @@ static int atmel_nand_probe(struct platform_device *pdev)
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
host->io_base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
if (IS_ERR(host->io_base)) {
|
||||
dev_err(&pdev->dev, "atmel_nand: ioremap resource failed\n");
|
||||
res = PTR_ERR(host->io_base);
|
||||
goto err_nand_ioremap;
|
||||
}
|
||||
@@ -2099,7 +2097,7 @@ static int atmel_nand_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
nand_chip->ecc.mode = host->board.ecc_mode;
|
||||
nand_chip->chip_delay = 20; /* 20us command delay time */
|
||||
nand_chip->chip_delay = 40; /* 40us command delay time */
|
||||
|
||||
if (host->board.bus_width_16) /* 16-bit bus width */
|
||||
nand_chip->options |= NAND_BUSWIDTH_16;
|
||||
@@ -2248,6 +2246,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_nfc *nfc = &nand_nfc;
|
||||
struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram;
|
||||
int ret;
|
||||
|
||||
nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs);
|
||||
@@ -2279,8 +2278,28 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
|
||||
nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff);
|
||||
nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */
|
||||
|
||||
nfc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (!IS_ERR(nfc->clk)) {
|
||||
ret = clk_prepare_enable(nfc->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
dev_warn(&pdev->dev, "NFC clock missing, update your Device Tree");
|
||||
}
|
||||
|
||||
nfc->is_initialized = true;
|
||||
dev_info(&pdev->dev, "NFC is probed.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_nand_nfc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_nfc *nfc = &nand_nfc;
|
||||
|
||||
if (!IS_ERR(nfc->clk))
|
||||
clk_disable_unprepare(nfc->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2297,6 +2316,7 @@ static struct platform_driver atmel_nand_nfc_driver = {
|
||||
.of_match_table = of_match_ptr(atmel_nand_nfc_match),
|
||||
},
|
||||
.probe = atmel_nand_nfc_probe,
|
||||
.remove = atmel_nand_nfc_remove,
|
||||
};
|
||||
|
||||
static struct platform_driver atmel_nand_driver = {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/bcma/bcma.h>
|
||||
|
||||
/* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has
|
||||
@@ -23,6 +24,8 @@
|
||||
#define NFLASH_SECTOR_SIZE 512
|
||||
|
||||
#define NCTL_CMD0 0x00010000
|
||||
#define NCTL_COL 0x00020000 /* Update column with value from BCMA_CC_NFLASH_COL_ADDR */
|
||||
#define NCTL_ROW 0x00040000 /* Update row (page) with value from BCMA_CC_NFLASH_ROW_ADDR */
|
||||
#define NCTL_CMD1W 0x00080000
|
||||
#define NCTL_READ 0x00100000
|
||||
#define NCTL_WRITE 0x00200000
|
||||
@@ -109,7 +112,7 @@ static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf,
|
||||
b47n->curr_page_addr);
|
||||
|
||||
/* Prepare to read */
|
||||
ctlcode = NCTL_CSA | NCTL_CMD1W | 0x00040000 | 0x00020000 |
|
||||
ctlcode = NCTL_CSA | NCTL_CMD1W | NCTL_ROW | NCTL_COL |
|
||||
NCTL_CMD0;
|
||||
ctlcode |= NAND_CMD_READSTART << 8;
|
||||
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode))
|
||||
@@ -167,6 +170,26 @@ static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
|
||||
* NAND chip ops
|
||||
**************************************************/
|
||||
|
||||
static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
|
||||
struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
|
||||
u32 code = 0;
|
||||
|
||||
if (cmd == NAND_CMD_NONE)
|
||||
return;
|
||||
|
||||
if (cmd & NAND_CTRL_CLE)
|
||||
code = cmd | NCTL_CMD0;
|
||||
|
||||
/* nCS is not needed for reset command */
|
||||
if (cmd != NAND_CMD_RESET)
|
||||
code |= NCTL_CSA;
|
||||
|
||||
bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, code);
|
||||
}
|
||||
|
||||
/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
|
||||
static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
|
||||
int chip)
|
||||
@@ -174,6 +197,14 @@ static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
|
||||
return;
|
||||
}
|
||||
|
||||
static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
|
||||
struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
|
||||
|
||||
return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY);
|
||||
}
|
||||
|
||||
/*
|
||||
* Default nand_command and nand_command_lp don't match BCM4706 hardware layout.
|
||||
* For example, reading chip id is performed in a non-standard way.
|
||||
@@ -198,7 +229,10 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
|
||||
|
||||
switch (command) {
|
||||
case NAND_CMD_RESET:
|
||||
pr_warn("Chip reset not implemented yet\n");
|
||||
nand_chip->cmd_ctrl(mtd, command, NAND_CTRL_CLE);
|
||||
|
||||
ndelay(100);
|
||||
nand_wait_ready(mtd);
|
||||
break;
|
||||
case NAND_CMD_READID:
|
||||
ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0;
|
||||
@@ -242,7 +276,7 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
|
||||
case NAND_CMD_ERASE1:
|
||||
bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
|
||||
b47n->curr_page_addr);
|
||||
ctlcode = 0x00040000 | NCTL_CMD1W | NCTL_CMD0 |
|
||||
ctlcode = NCTL_ROW | NCTL_CMD1W | NCTL_CMD0 |
|
||||
NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8);
|
||||
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
|
||||
pr_err("ERASE1 failed\n");
|
||||
@@ -257,13 +291,13 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
|
||||
b47n->curr_page_addr);
|
||||
|
||||
/* Prepare to write */
|
||||
ctlcode = 0x40000000 | 0x00040000 | 0x00020000 | 0x00010000;
|
||||
ctlcode = 0x40000000 | NCTL_ROW | NCTL_COL | NCTL_CMD0;
|
||||
ctlcode |= NAND_CMD_SEQIN;
|
||||
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
|
||||
pr_err("SEQIN failed\n");
|
||||
break;
|
||||
case NAND_CMD_PAGEPROG:
|
||||
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, 0x00010000 |
|
||||
if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_CMD0 |
|
||||
NAND_CMD_PAGEPROG))
|
||||
pr_err("PAGEPROG failed\n");
|
||||
if (bcm47xxnflash_ops_bcm4706_poll(cc))
|
||||
@@ -341,6 +375,7 @@ static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
|
||||
|
||||
int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
|
||||
{
|
||||
struct nand_chip *nand_chip = (struct nand_chip *)&b47n->nand_chip;
|
||||
int err;
|
||||
u32 freq;
|
||||
u16 clock;
|
||||
@@ -351,10 +386,14 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
|
||||
u32 val;
|
||||
|
||||
b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
|
||||
nand_chip->cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl;
|
||||
nand_chip->dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready;
|
||||
b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
|
||||
b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
|
||||
b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
|
||||
b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
|
||||
|
||||
nand_chip->chip_delay = 50;
|
||||
b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
|
||||
b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
|
||||
|
||||
@@ -364,11 +403,13 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
|
||||
|
||||
/* Configure wait counters */
|
||||
if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) {
|
||||
freq = 100000000;
|
||||
/* 400 MHz */
|
||||
freq = 400000000 / 4;
|
||||
} else {
|
||||
freq = bcma_chipco_pll_read(b47n->cc, 4);
|
||||
freq = (freq * 0xFFF) >> 3;
|
||||
freq = (freq * 25000000) >> 3;
|
||||
freq = (freq & 0xFFF) >> 3;
|
||||
/* Fixed reference clock 25 MHz and m = 2 */
|
||||
freq = (freq * 25000000 / 2) / 4;
|
||||
}
|
||||
clock = freq / 1000000;
|
||||
w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user