Commit 79346507 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.infradead.org/mtd-2.6

* git://git.infradead.org/mtd-2.6: (82 commits)
  mtd: fix build error in m25p80.c
  mtd: Remove redundant mutex from mtd_blkdevs.c
  MTD: Fix wrong check register_blkdev return value
  Revert "mtd: cleanup Kconfig dependencies"
  mtd: cfi_cmdset_0002: make sector erase command variable
  mtd: cfi_cmdset_0002: add CFI detection for SST 38VF640x chips
  mtd: cfi_util: add support for switching SST 39VF640xB chips into QRY mode
  mtd: cfi_cmdset_0001: use defined value of P_ID_INTEL_PERFORMANCE instead of hardcoded one
  block2mtd: dubious assignment
  P4080/mtd: Fix the freescale lbc issue with 36bit mode
  P4080/eLBC: Make Freescale elbc interrupt common to elbc devices
  mtd: phram: use KBUILD_MODNAME
  mtd: OneNAND: S5PC110: Fix double call suspend & resume function
  mtd: nand: fix MTD_MODE_RAW writes
  jffs2: use kmemdup
  mtd: sm_ftl: cosmetic, use bool when possible
  mtd: r852: remove useless pci powerup/down from suspend/resume routines
  mtd: blktrans: fix a race vs kthread_stop
  mtd: blktrans: kill BKL
  mtd: allow to unload the mtdtrans module if its block devices aren't open
  ...

Fix up trivial whitespace-introduced conflict in drivers/mtd/mtdchar.c
parents 706d4b12 40847437
......@@ -66,7 +66,7 @@ static DEFINE_SPINLOCK(syscon_resetreg_lock);
* AMBA bus
* |
* +- CPU
* +- NANDIF NAND Flash interface
* +- FSMC NANDIF NAND Flash interface
* +- SEMI Shared Memory interface
* +- ISP Image Signal Processor (U335 only)
* +- CDS (U335 only)
......@@ -726,7 +726,7 @@ static struct clk cpu_clk = {
};
static struct clk nandif_clk = {
.name = "NANDIF",
.name = "FSMC",
.parent = &amba_clk,
.hw_ctrld = false,
.reset = true,
......@@ -1259,7 +1259,7 @@ static struct clk_lookup lookups[] = {
/* Connected directly to the AMBA bus */
DEF_LOOKUP("amba", &amba_clk),
DEF_LOOKUP("cpu", &cpu_clk),
DEF_LOOKUP("fsmc", &nandif_clk),
DEF_LOOKUP("fsmc-nand", &nandif_clk),
DEF_LOOKUP("semi", &semi_clk),
#ifdef CONFIG_MACH_U300_BS335
DEF_LOOKUP("isp", &isp_clk),
......
......@@ -21,7 +21,8 @@
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <mach/coh901318.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/fsmc.h>
#include <asm/types.h>
#include <asm/setup.h>
......@@ -30,6 +31,7 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
#include <mach/coh901318.h>
#include <mach/hardware.h>
#include <mach/syscon.h>
#include <mach/dma_channels.h>
......@@ -285,6 +287,13 @@ static struct resource rtc_resources[] = {
*/
static struct resource fsmc_resources[] = {
{
.name = "nand_data",
.start = U300_NAND_CS0_PHYS_BASE,
.end = U300_NAND_CS0_PHYS_BASE + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "fsmc_regs",
.start = U300_NAND_IF_PHYS_BASE,
.end = U300_NAND_IF_PHYS_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
......@@ -1429,11 +1438,39 @@ static struct platform_device rtc_device = {
.resource = rtc_resources,
};
static struct platform_device fsmc_device = {
.name = "nandif",
static struct mtd_partition u300_partitions[] = {
{
.name = "bootrecords",
.offset = 0,
.size = SZ_128K,
},
{
.name = "free",
.offset = SZ_128K,
.size = 8064 * SZ_1K,
},
{
.name = "platform",
.offset = 8192 * SZ_1K,
.size = 253952 * SZ_1K,
},
};
static struct fsmc_nand_platform_data nand_platform_data = {
.partitions = u300_partitions,
.nr_partitions = ARRAY_SIZE(u300_partitions),
.options = NAND_SKIP_BBTSCAN,
.width = FSMC_NAND_BW8,
};
static struct platform_device nand_device = {
.name = "fsmc-nand",
.id = -1,
.num_resources = ARRAY_SIZE(fsmc_resources),
.resource = fsmc_resources,
.num_resources = ARRAY_SIZE(fsmc_resources),
.dev = {
.platform_data = &nand_platform_data,
},
};
static struct platform_device ave_device = {
......@@ -1465,7 +1502,7 @@ static struct platform_device *platform_devs[] __initdata = {
&keypad_device,
&rtc_device,
&gpio_device,
&fsmc_device,
&nand_device,
&wdog_device,
&ave_device
};
......
......@@ -20,11 +20,9 @@
/* NAND Flash CS0 */
#define U300_NAND_CS0_PHYS_BASE 0x80000000
#define U300_NAND_CS0_VIRT_BASE 0xff040000
/* NFIF */
#define U300_NAND_IF_PHYS_BASE 0x9f800000
#define U300_NAND_IF_VIRT_BASE 0xff030000
/* AHB Peripherals */
#define U300_AHB_PER_PHYS_BASE 0xa0000000
......
......@@ -30,15 +30,15 @@ struct pxa3xx_nand_cmdset {
};
struct pxa3xx_nand_flash {
const struct pxa3xx_nand_timing *timing; /* NAND Flash timing */
const struct pxa3xx_nand_cmdset *cmdset;
uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */
uint32_t page_size; /* Page size in bytes (PAGE_SZ) */
uint32_t flash_width; /* Width of Flash memory (DWIDTH_M) */
uint32_t dfc_width; /* Width of flash controller(DWIDTH_C) */
uint32_t num_blocks; /* Number of physical blocks in Flash */
uint32_t chip_id;
uint32_t chip_id;
unsigned int page_per_block; /* Pages per block (PG_PER_BLK) */
unsigned int page_size; /* Page size in bytes (PAGE_SZ) */
unsigned int flash_width; /* Width of Flash memory (DWIDTH_M) */
unsigned int dfc_width; /* Width of flash controller(DWIDTH_C) */
unsigned int num_blocks; /* Number of physical blocks in Flash */
struct pxa3xx_nand_cmdset *cmdset; /* NAND command set */
struct pxa3xx_nand_timing *timing; /* NAND Flash timing */
};
struct pxa3xx_nand_platform_data {
......
#ifndef __BCM963XX_TAG_H
#define __BCM963XX_TAG_H
#define TAGVER_LEN 4 /* Length of Tag Version */
#define TAGLAYOUT_LEN 4 /* Length of FlashLayoutVer */
#define SIG1_LEN 20 /* Company Signature 1 Length */
#define SIG2_LEN 14 /* Company Signature 2 Lenght */
#define BOARDID_LEN 16 /* Length of BoardId */
#define ENDIANFLAG_LEN 2 /* Endian Flag Length */
#define CHIPID_LEN 6 /* Chip Id Length */
#define IMAGE_LEN 10 /* Length of Length Field */
#define ADDRESS_LEN 12 /* Length of Address field */
#define DUALFLAG_LEN 2 /* Dual Image flag Length */
#define INACTIVEFLAG_LEN 2 /* Inactie Flag Length */
#define RSASIG_LEN 20 /* Length of RSA Signature in tag */
#define TAGINFO1_LEN 30 /* Length of vendor information field1 in tag */
#define FLASHLAYOUTVER_LEN 4 /* Length of Flash Layout Version String tag */
#define TAGINFO2_LEN 16 /* Length of vendor information field2 in tag */
#define CRC_LEN 4 /* Length of CRC in bytes */
#define ALTTAGINFO_LEN 54 /* Alternate length for vendor information; Pirelli */
#define NUM_PIRELLI 2
#define IMAGETAG_CRC_START 0xFFFFFFFF
#define PIRELLI_BOARDS { \
"AGPF-S0", \
"DWV-S0", \
}
/*
* The broadcom firmware assumes the rootfs starts the image,
* therefore uses the rootfs start (flash_image_address)
* to determine where to flash the image. Since we have the kernel first
* we have to give it the kernel address, but the crc uses the length
* associated with this address (root_length), which is added to the kernel
* length (kernel_length) to determine the length of image to flash and thus
* needs to be rootfs + deadcode (jffs2 EOF marker)
*/
struct bcm_tag {
/* 0-3: Version of the image tag */
char tag_version[TAGVER_LEN];
/* 4-23: Company Line 1 */
char sig_1[SIG1_LEN];
/* 24-37: Company Line 2 */
char sig_2[SIG2_LEN];
/* 38-43: Chip this image is for */
char chip_id[CHIPID_LEN];
/* 44-59: Board name */
char board_id[BOARDID_LEN];
/* 60-61: Map endianness -- 1 BE 0 LE */
char big_endian[ENDIANFLAG_LEN];
/* 62-71: Total length of image */
char total_length[IMAGE_LEN];
/* 72-83: Address in memory of CFE */
char cfe__address[ADDRESS_LEN];
/* 84-93: Size of CFE */
char cfe_length[IMAGE_LEN];
/* 94-105: Address in memory of image start
* (kernel for OpenWRT, rootfs for stock firmware)
*/
char flash_image_start[ADDRESS_LEN];
/* 106-115: Size of rootfs */
char root_length[IMAGE_LEN];
/* 116-127: Address in memory of kernel */
char kernel_address[ADDRESS_LEN];
/* 128-137: Size of kernel */
char kernel_length[IMAGE_LEN];
/* 138-139: Unused at the moment */
char dual_image[DUALFLAG_LEN];
/* 140-141: Unused at the moment */
char inactive_flag[INACTIVEFLAG_LEN];
/* 142-161: RSA Signature (not used; some vendors may use this) */
char rsa_signature[RSASIG_LEN];
/* 162-191: Compilation and related information (not used in OpenWrt) */
char information1[TAGINFO1_LEN];
/* 192-195: Version flash layout */
char flash_layout_ver[FLASHLAYOUTVER_LEN];
/* 196-199: kernel+rootfs CRC32 */
char fskernel_crc[CRC_LEN];
/* 200-215: Unused except on Alice Gate where is is information */
char information2[TAGINFO2_LEN];
/* 216-219: CRC32 of image less imagetag (kernel for Alice Gate) */
char image_crc[CRC_LEN];
/* 220-223: CRC32 of rootfs partition */
char rootfs_crc[CRC_LEN];
/* 224-227: CRC32 of kernel partition */
char kernel_crc[CRC_LEN];
/* 228-235: Unused at present */
char reserved1[8];
/* 236-239: CRC32 of header excluding tagVersion */
char header_crc[CRC_LEN];
/* 240-255: Unused at present */
char reserved2[16];
};
#endif /* __BCM63XX_TAG_H */
......@@ -682,9 +682,12 @@ config 4xx_SOC
bool
config FSL_LBC
bool
bool "Freescale Local Bus support"
depends on FSL_SOC
help
Freescale Localbus support
Enables reporting of errors from the Freescale local bus
controller. Also contains some common code used by
drivers for specific local bus peripherals.
config FSL_GTM
bool
......
/* Freescale Local Bus Controller
*
* Copyright (c) 2006-2007 Freescale Semiconductor
* Copyright © 2006-2007, 2010 Freescale Semiconductor
*
* Authors: Nick Spence <nick.spence@freescale.com>,
* Scott Wood <scottwood@freescale.com>
* Jack Lan <jack.lan@freescale.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -26,6 +27,8 @@
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/spinlock.h>
struct fsl_lbc_bank {
__be32 br; /**< Base Register */
......@@ -125,13 +128,23 @@ struct fsl_lbc_regs {
#define LTESR_ATMW 0x00800000
#define LTESR_ATMR 0x00400000
#define LTESR_CS 0x00080000
#define LTESR_UPM 0x00000002
#define LTESR_CC 0x00000001
#define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC)
#define LTESR_MASK (LTESR_BM | LTESR_FCT | LTESR_PAR | LTESR_WP \
| LTESR_ATMW | LTESR_ATMR | LTESR_CS | LTESR_UPM \
| LTESR_CC)
#define LTESR_CLEAR 0xFFFFFFFF
#define LTECCR_CLEAR 0xFFFFFFFF
#define LTESR_STATUS LTESR_MASK
#define LTEIR_ENABLE LTESR_MASK
#define LTEDR_ENABLE 0x00000000
__be32 ltedr; /**< Transfer Error Disable Register */
__be32 lteir; /**< Transfer Error Interrupt Register */
__be32 lteatr; /**< Transfer Error Attributes Register */
__be32 ltear; /**< Transfer Error Address Register */
u8 res6[0xC];
__be32 lteccr; /**< Transfer Error ECC Register */
u8 res6[0x8];
__be32 lbcr; /**< Configuration Register */
#define LBCR_LDIS 0x80000000
#define LBCR_LDIS_SHIFT 31
......@@ -235,6 +248,7 @@ struct fsl_upm {
int width;
};
extern u32 fsl_lbc_addr(phys_addr_t addr_base);
extern int fsl_lbc_find(phys_addr_t addr_base);
extern int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm);
......@@ -265,7 +279,23 @@ static inline void fsl_upm_end_pattern(struct fsl_upm *upm)
cpu_relax();
}
/* overview of the fsl lbc controller */
struct fsl_lbc_ctrl {
/* device info */
struct device *dev;
struct fsl_lbc_regs __iomem *regs;
int irq;
wait_queue_head_t irq_wait;
spinlock_t lock;
void *nand;
/* status read from LTESR by irq handler */
unsigned int irq_status;
};
extern int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base,
u32 mar);
extern struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
#endif /* __ASM_FSL_LBC_H */
/*
* Freescale LBC and UPM routines.
*
* Copyright (c) 2007-2008 MontaVista Software, Inc.
* Copyright © 2007-2008 MontaVista Software, Inc.
* Copyright © 2010 Freescale Semiconductor
*
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
* Author: Jack Lan <Jack.Lan@freescale.com>
* Author: Roy Zang <tie-fei.zang@freescale.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -19,39 +22,37 @@
#include <linux/types.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/mod_devicetable.h>
#include <asm/prom.h>
#include <asm/fsl_lbc.h>
static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
static struct fsl_lbc_regs __iomem *fsl_lbc_regs;
struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
EXPORT_SYMBOL(fsl_lbc_ctrl_dev);
static char __initdata *compat_lbc[] = {
"fsl,pq2-localbus",
"fsl,pq2pro-localbus",
"fsl,pq3-localbus",
"fsl,elbc",
};
static int __init fsl_lbc_init(void)
/**
* fsl_lbc_addr - convert the base address
* @addr_base: base address of the memory bank
*
* This function converts a base address of lbc into the right format for the
* BR register. If the SOC has eLBC then it returns 32bit physical address
* else it convers a 34bit local bus physical address to correct format of
* 32bit address for BR register (Example: MPC8641).
*/
u32 fsl_lbc_addr(phys_addr_t addr_base)
{
struct device_node *lbus;
int i;
struct device_node *np = fsl_lbc_ctrl_dev->dev->of_node;
u32 addr = addr_base & 0xffff8000;
for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) {
lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]);
if (lbus)
goto found;
}
return -ENODEV;
if (of_device_is_compatible(np, "fsl,elbc"))
return addr;
found:
fsl_lbc_regs = of_iomap(lbus, 0);
of_node_put(lbus);
if (!fsl_lbc_regs)
return -ENOMEM;
return 0;
return addr | ((addr_base & 0x300000000ull) >> 19);
}
arch_initcall(fsl_lbc_init);
EXPORT_SYMBOL(fsl_lbc_addr);
/**
* fsl_lbc_find - find Localbus bank
......@@ -65,15 +66,17 @@ arch_initcall(fsl_lbc_init);
int fsl_lbc_find(phys_addr_t addr_base)
{
int i;
struct fsl_lbc_regs __iomem *lbc;
if (!fsl_lbc_regs)
if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
return -ENODEV;
for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) {
__be32 br = in_be32(&fsl_lbc_regs->bank[i].br);
__be32 or = in_be32(&fsl_lbc_regs->bank[i].or);
lbc = fsl_lbc_ctrl_dev->regs;
for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) {
__be32 br = in_be32(&lbc->bank[i].br);
__be32 or = in_be32(&lbc->bank[i].or);
if (br & BR_V && (br & or & BR_BA) == addr_base)
if (br & BR_V && (br & or & BR_BA) == fsl_lbc_addr(addr_base))
return i;
}
......@@ -94,22 +97,27 @@ int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm)
{
int bank;
__be32 br;
struct fsl_lbc_regs __iomem *lbc;
bank = fsl_lbc_find(addr_base);
if (bank < 0)
return bank;
br = in_be32(&fsl_lbc_regs->bank[bank].br);
if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
return -ENODEV;
lbc = fsl_lbc_ctrl_dev->regs;
br = in_be32(&lbc->bank[bank].br);
switch (br & BR_MSEL) {
case BR_MS_UPMA:
upm->mxmr = &fsl_lbc_regs->mamr;
upm->mxmr = &lbc->mamr;
break;
case BR_MS_UPMB:
upm->mxmr = &fsl_lbc_regs->mbmr;
upm->mxmr = &lbc->mbmr;
break;
case BR_MS_UPMC:
upm->mxmr = &fsl_lbc_regs->mcmr;
upm->mxmr = &lbc->mcmr;
break;
default:
return -EINVAL;
......@@ -148,9 +156,12 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
int ret = 0;
unsigned long flags;
if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
return -ENODEV;
spin_lock_irqsave(&fsl_lbc_lock, flags);
out_be32(&fsl_lbc_regs->mar, mar);
out_be32(&fsl_lbc_ctrl_dev->regs->mar, mar);
switch (upm->width) {
case 8:
......@@ -172,3 +183,166 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
return ret;
}
EXPORT_SYMBOL(fsl_upm_run_pattern);
static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl)
{
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
/* clear event registers */
setbits32(&lbc->ltesr, LTESR_CLEAR);
out_be32(&lbc->lteatr, 0);
out_be32(&lbc->ltear, 0);
out_be32(&lbc->lteccr, LTECCR_CLEAR);
out_be32(&lbc->ltedr, LTEDR_ENABLE);
/* Enable interrupts for any detected events */
out_be32(&lbc->lteir, LTEIR_ENABLE);
return 0;
}
/*
* NOTE: This interrupt is used to report localbus events of various kinds,
* such as transaction errors on the chipselects.
*/
static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data)
{
struct fsl_lbc_ctrl *ctrl = data;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
u32 status;
status = in_be32(&lbc->ltesr);
if (!status)
return IRQ_NONE;
out_be32(&lbc->ltesr, LTESR_CLEAR);
out_be32(&lbc->lteatr, 0);
out_be32(&lbc->ltear, 0);
ctrl->irq_status = status;
if (status & LTESR_BM)
dev_err(ctrl->dev, "Local bus monitor time-out: "
"LTESR 0x%08X\n", status);
if (status & LTESR_WP)
dev_err(ctrl->dev, "Write protect error: "
"LTESR 0x%08X\n", status);
if (status & LTESR_ATMW)
dev_err(ctrl->dev, "Atomic write error: "
"LTESR 0x%08X\n", status);
if (status & LTESR_ATMR)
dev_err(ctrl->dev, "Atomic read error: "
"LTESR 0x%08X\n", status);
if (status & LTESR_CS)
dev_err(ctrl->dev, "Chip select error: "
"LTESR 0x%08X\n", status);
if (status & LTESR_UPM)
;
if (status & LTESR_FCT) {
dev_err(ctrl->dev, "FCM command time-out: "
"LTESR 0x%08X\n", status);
smp_wmb();
wake_up(&ctrl->irq_wait);
}
if (status & LTESR_PAR) {
dev_err(ctrl->dev, "Parity or Uncorrectable ECC error: "
"LTESR 0x%08X\n", status);
smp_wmb();
wake_up(&ctrl->irq_wait);
}
if (status & LTESR_CC) {
smp_wmb();
wake_up(&ctrl->irq_wait);
}
if (status & ~LTESR_MASK)
dev_err(ctrl->dev, "Unknown error: "
"LTESR 0x%08X\n", status);
return IRQ_HANDLED;
}
/*
* fsl_lbc_ctrl_probe
*
* called by device layer when it finds a device matching
* one our driver can handled. This code allocates all of
* the resources needed for the controller only. The
* resources for the NAND banks themselves are allocated
* in the chip probe function.
*/
static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev)
{
int ret;
if (!dev->dev.of_node) {
dev_err(&dev->dev, "Device OF-Node is NULL");
return -EFAULT;
}
fsl_lbc_ctrl_dev = kzalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL);
if (!fsl_lbc_ctrl_dev)
return -ENOMEM;
dev_set_drvdata(&dev->dev, fsl_lbc_ctrl_dev);
spin_lock_init(&fsl_lbc_ctrl_dev->lock);
init_waitqueue_head(&fsl_lbc_ctrl_dev->irq_wait);
fsl_lbc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
if (!fsl_lbc_ctrl_dev->regs) {
dev_err(&dev->dev, "failed to get memory region\n");
ret = -ENODEV;
goto err;
}
fsl_lbc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
if (fsl_lbc_ctrl_dev->irq == NO_IRQ) {
dev_err(&dev->dev, "failed to get irq resource\n");
ret = -ENODEV;
goto err;
}
fsl_lbc_ctrl_dev->dev = &dev->dev;
ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev);
if (ret < 0)
goto err;
ret = request_irq(fsl_lbc_ctrl_dev->irq, fsl_lbc_ctrl_irq, 0,
"fsl-lbc", fsl_lbc_ctrl_dev);
if (ret != 0) {
dev_err(&dev->dev, "failed to install irq (%d)\n",
fsl_lbc_ctrl_dev->irq);
ret = fsl_lbc_ctrl_dev->irq;
goto err;
}
return 0;
err:
iounmap(fsl_lbc_ctrl_dev->regs);
kfree(fsl_lbc_ctrl_dev);
return ret;
}
static const struct of_device_id fsl_lbc_match[] = {
{ .compatible = "fsl,elbc", },
{ .compatible = "fsl,pq3-localbus", },
{ .compatible = "fsl,pq2-localbus", },
{ .compatible = "fsl,pq2pro-localbus", },
{},
};
static struct platform_driver fsl_lbc_ctrl_driver = {
.driver = {
.name = "fsl-lbc",
.of_match_table = fsl_lbc_match,
},
.probe = fsl_lbc_ctrl_probe,
};
static int __init fsl_lbc_init(void)
{
return platform_driver_register(&fsl_lbc_ctrl_driver);
}
module_init(fsl_lbc_init);
......@@ -1496,7 +1496,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
switch (mode) {
case FL_WRITING:
write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41);
write_cmd = (cfi->cfiq->P_ID != P_ID_INTEL_PERFORMANCE) ? CMD(0x40) : CMD(0x41);
break;
case FL_OTP_WRITE:
write_cmd = CMD(0xc0);
......@@ -1661,7 +1661,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
cmd_adr = adr & ~(wbufsize-1);
/* Let's determine this according to the interleave only once */
write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9);
write_cmd = (cfi->cfiq->P_ID != P_ID_INTEL_PERFORMANCE) ? CMD(0xe8) : CMD(0xe9);
mutex_lock(&chip->mutex);
ret = get_chip(map, chip, cmd_adr, FL_WRITING);
......
......@@ -291,6 +291,23 @@ static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param)
cfi->addr_unlock1 = 0x555;
cfi->addr_unlock2 = 0x2AA;
cfi->sector_erase_cmd = CMD(0x50);
}
static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd, void *param)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
fixup_sst39vf_rev_b(mtd, param);
/*
* CFI reports 1024 sectors (0x03ff+1) of 64KBytes (0x0100*256) where
* it should report a size of 8KBytes (0x0020*256).
*/
cfi->cfiq->EraseRegionInfo[0] = 0x002003ff;
pr_warning("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n", mtd->name);
}
static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param)
......@@ -317,14 +334,14 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param)
/* Used to fix CFI-Tables of chips without Extended Query Tables */
static struct cfi_fixup cfi_nopri_fixup_table[] = {
{ CFI_MFR_SST, 0x234A, fixup_sst39vf, NULL, }, // SST39VF1602
{ CFI_MFR_SST, 0x234B, fixup_sst39vf, NULL, }, // SST39VF1601
{ CFI_MFR_SST, 0x235A, fixup_sst39vf, NULL, }, // SST39VF3202
{ CFI_MFR_SST, 0x235B, fixup_sst39vf, NULL, }, // SST39VF3201
{ CFI_MFR_SST, 0x235C, fixup_sst39vf_rev_b, NULL, }, // SST39VF3202B
{ CFI_MFR_SST, 0x235D, fixup_sst39vf_rev_b, NULL, }, // SST39VF3201B
{ CFI_MFR_SST, 0x236C, fixup_sst39vf_rev_b, NULL, }, // SST39VF6402B
{ CFI_MFR_SST, 0x236D, fixup_sst39vf_rev_b, NULL, }, // SST39VF6401B
{ CFI_MFR_SST, 0x234A, fixup_sst39vf, NULL, }, /* SST39VF1602 */
{ CFI_MFR_SST, 0x234B, fixup_sst39vf, NULL, }, /* SST39VF1601 */
{ CFI_MFR_SST, 0x235A, fixup_sst39vf, NULL, }, /* SST39VF3202 */
{ CFI_MFR_SST, 0x235B, fixup_sst39vf, NULL, }, /* SST39VF3201 */
{ CFI_MFR_SST, 0x235C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3202B */
{ CFI_MFR_SST, 0x235D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3201B */
{ CFI_MFR_SST, 0x236C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6402B */
{ CFI_MFR_SST, 0x236D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6401B */
{ 0, 0, NULL, NULL }
};
......@@ -344,6 +361,10 @@ static struct cfi_fixup cfi_fixup_table[] = {
{ CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors, NULL, },
{ CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors, NULL, },
{ CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors, NULL, },
{ CFI_MFR_SST, 0x536A, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6402 */
{ CFI_MFR_SST, 0x536B, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6401 */
{ CFI_MFR_SST, 0x536C, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6404 */
{ CFI_MFR_SST, 0x536D, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6403 */
#if !FORCE_WORD_WRITE
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, },
#endif
......@@ -374,6 +395,13 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi,
if (cfi->mfr == CFI_MFR_SAMSUNG && cfi->id == 0x257e &&
extp->MajorVersion == '0')
extp->MajorVersion = '1';
/*
* SST 38VF640x chips report major=0xFF / minor=0xFF.
*/
if (cfi->mfr == CFI_MFR_SST && (cfi->id >> 4) == 0x0536) {
extp->MajorVersion = '1';
extp->MinorVersion = '0';
}
}
struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
......@@ -545,15 +573,6 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
goto setup_err;
}
#if 0
// debug
for (i=0; i<mtd->numeraseregions;i++){
printk("%d: offset=0x%x,size=0x%x,blocks=%d\n",
i,mtd->eraseregions[i].offset,
mtd->eraseregions[i].erasesize,
mtd->eraseregions[i].numblocks);
}
#endif
__module_get(THIS_MODULE);
register_reboot_notifier(&mtd->reboot_notifier);
......@@ -674,7 +693,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
* there was an error (so leave the erase
* routine to recover from it) or we trying to
* use the erase-in-progress sector. */
map_write(map, CMD(0x30), chip->in_progress_block_addr);
map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr);
chip->state = FL_ERASING;
chip->oldstate = FL_READY;
printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__);
......@@ -727,7 +746,7 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
switch(chip->oldstate) {
case FL_ERASING:
chip->state = chip->oldstate;
map_write(map, CMD(0x30), chip->in_progress_block_addr);
map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr);
chip->oldstate = FL_READY;
chip->state = FL_ERASING;
break;
......@@ -870,7 +889,7 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
local_irq_disable();
/* Resume the write or erase operation */
map_write(map, CMD(0x30), adr);
map_write(map, cfi->sector_erase_cmd, adr);
chip->state = oldstate;
start = xip_currtime();
} else if (usec >= 1000000/HZ) {
......@@ -1025,9 +1044,6 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
mutex_lock(&chip->mutex);
if (chip->state != FL_READY){
#if 0
printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
#endif
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
......@@ -1035,10 +1051,6 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
schedule();
remove_wait_queue(&chip->wq, &wait);
#if 0
if(signal_pending(current))
return -EINTR;
#endif
timeo = jiffies + HZ;
goto retry;
......@@ -1246,9 +1258,6 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
mutex_lock(&cfi->chips[chipnum].mutex);
if (cfi->chips[chipnum].state != FL_READY) {
#if 0
printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);
#endif
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&cfi->chips[chipnum].wq, &wait);
......@@ -1256,10 +1265,6 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
schedule();
remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
#if 0
if(signal_pending(current))
return -EINTR;
#endif
goto retry;
}
......@@ -1324,9 +1329,6 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
mutex_lock(&cfi->chips[chipnum].mutex);
if (cfi->chips[chipnum].state != FL_READY) {
#if 0
printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);
#endif
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&cfi->chips[chipnum].wq, &wait);
......@@ -1334,10 +1336,6 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
schedule();
remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
#if 0
if(signal_pending(current))
return -EINTR;
#endif
goto retry1;
}
......@@ -1396,7 +1394,6 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
//cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
/* Write Buffer Load */
map_write(map, CMD(0x25), cmd_adr);
......@@ -1675,7 +1672,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
map_write(map, CMD(0x30), adr);
map_write(map, cfi->sector_erase_cmd, adr);
chip->state = FL_ERASING;
chip->erase_suspended = 0;
......
......@@ -177,6 +177,8 @@ static int __xipram cfi_chip_setup(struct map_info *map,
cfi->cfi_mode = CFI_MODE_CFI;
cfi->sector_erase_cmd = CMD(0x30);
/* Read the CFI info structure */
xip_disable_qry(base, map, cfi);
for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++)
......
......@@ -75,6 +75,13 @@ int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map,
cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL);
if (cfi_qry_present(map, base, cfi))
return 1;
/* SST 39VF640xB */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xAA, 0x555, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, 0x2AA, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL);
if (cfi_qry_present(map, base, cfi))
return 1;
/* QRY not found */
......
......@@ -91,7 +91,6 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
} else
instr->state = MTD_ERASE_DONE;
instr->state = MTD_ERASE_DONE;
mtd_erase_callback(instr);
return err;
}
......
......@@ -661,11 +661,14 @@ static const struct spi_device_id m25p_ids[] = {
{ "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) },
{ "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) },
{ "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) },
{ "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, SECT_4K) },
{ "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) },
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, 0) },
{ "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, 0) },
{ "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) },
{ "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K) },
......@@ -714,6 +717,7 @@ static const struct spi_device_id m25p_ids[] = {
{ "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) },
{ "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) },
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
/* Catalyst / On Semiconductor -- non-JEDEC */
{ "cat25c11", CAT25_INFO( 16, 8, 16, 1) },
......@@ -924,7 +928,7 @@ static int __devinit m25p_probe(struct spi_device *spi)
nr_parts = data->nr_parts;
}
#ifdef CONFIG_OF
#ifdef CONFIG_MTD_OF_PARTS
if (nr_parts <= 0 && spi->dev.of_node) {
nr_parts = of_mtd_parse_partitions(&spi->dev,
spi->dev.of_node, &parts);
......
......@@ -15,7 +15,7 @@
* phram=swap,64Mi,128Mi phram=test,900Mi,1Mi
*/
#define pr_fmt(fmt) "phram: " fmt
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <asm/io.h>
#include <linux/init.h>
......
......@@ -251,6 +251,15 @@ config MTD_NETtel
help
Support for flash chips on NETtel/SecureEdge/SnapGear boards.
config MTD_BCM963XX
tristate "Map driver for Broadcom BCM963xx boards"
depends on BCM63XX
select MTD_MAP_BANK_WIDTH_2
select MTD_CFI_I1
help
Support for parsing CFE image tag and creating MTD partitions on
Broadcom BCM63xx boards.
config MTD_DILNETPC
tristate "CFI Flash device mapped on DIL/Net PC"
depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
......
......@@ -58,3 +58,4 @@ obj-$(CONFIG_MTD_BFIN_ASYNC) += bfin-async-flash.o
obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o
obj-$(CONFIG_MTD_VMU) += vmu-flash.o
obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o
obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o
/*
* Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org>
* Mike Albon <malbon@openwrt.org>
* Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mtd/map.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/vmalloc.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <asm/mach-bcm63xx/bcm963xx_tag.h>
#define BCM63XX_BUSWIDTH 2 /* Buswidth */
#define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */
#define PFX KBUILD_MODNAME ": "
static struct mtd_partition *parsed_parts;
static struct mtd_info *bcm963xx_mtd_info;
static struct map_info bcm963xx_map = {
.name = "bcm963xx",
.bankwidth = BCM63XX_BUSWIDTH,
};
static int parse_cfe_partitions(struct mtd_info *master,
struct mtd_partition **pparts)
{
/* CFE, NVRAM and global Linux are always present */
int nrparts = 3, curpart = 0;
struct bcm_tag *buf;
struct mtd_partition *parts;
int ret;
size_t retlen;
unsigned int rootfsaddr, kerneladdr, spareaddr;
unsigned int rootfslen, kernellen, sparelen, totallen;
int namelen = 0;
int i;
char *boardid;
char *tagversion;
/* Allocate memory for buffer */
buf = vmalloc(sizeof(struct bcm_tag));
if (!buf)
return -ENOMEM;
/* Get the tag */
ret = master->read(master, master->erasesize, sizeof(struct bcm_tag),
&retlen, (void *)buf);
if (retlen != sizeof(struct bcm_tag)) {
vfree(buf);
return -EIO;
}
sscanf(buf->kernel_address, "%u", &kerneladdr);
sscanf(buf->kernel_length, "%u", &kernellen);
sscanf(buf->total_length, "%u", &totallen);
tagversion = &(buf->tag_version[0]);
boardid = &(buf->board_id[0]);
printk(KERN_INFO PFX "CFE boot tag found with version %s "
"and board type %s\n", tagversion, boardid);
kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE;
rootfsaddr = kerneladdr + kernellen;
spareaddr = roundup(totallen, master->erasesize) + master->erasesize;
sparelen = master->size - spareaddr - master->erasesize;
rootfslen = spareaddr - rootfsaddr;
/* Determine number of partitions */
namelen = 8;
if (rootfslen > 0) {
nrparts++;
namelen += 6;
};
if (kernellen > 0) {
nrparts++;
namelen += 6;
};
/* Ask kernel for more memory */
parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
if (!parts) {
vfree(buf);
return -ENOMEM;
};
/* Start building partition list */
parts[curpart].name = "CFE";
parts[curpart].offset = 0;
parts[curpart].size = master->erasesize;
curpart++;
if (kernellen > 0) {
parts[curpart].name = "kernel";
parts[curpart].offset = kerneladdr;
parts[curpart].size = kernellen;
curpart++;
};
if (rootfslen > 0) {
parts[curpart].name = "rootfs";
parts[curpart].offset = rootfsaddr;
parts[curpart].size = rootfslen;
if (sparelen > 0)
parts[curpart].size += sparelen;
curpart++;
};
parts[curpart].name = "nvram";
parts[curpart].offset = master->size - master->erasesize;
parts[curpart].size = master->erasesize;
/* Global partition "linux" to make easy firmware upgrade */
curpart++;
parts[curpart].name = "linux";
parts[curpart].offset = parts[0].size;
parts[curpart].size = master->size - parts[0].size - parts[3].size;
for (i = 0; i < nrparts; i++)
printk(KERN_INFO PFX "Partition %d is %s offset %lx and "
"length %lx\n", i, parts[i].name,
(long unsigned int)(parts[i].offset),
(long unsigned int)(parts[i].size));
printk(KERN_INFO PFX "Spare partition is %x offset and length %x\n",
spareaddr, sparelen);
*pparts = parts;
vfree(buf);
return nrparts;
};
static int bcm963xx_detect_cfe(struct mtd_info *master)
{
int idoffset = 0x4e0;
static char idstring[8] = "CFE1CFE1";
char buf[9];
int ret;
size_t retlen;
ret = master->read(master, idoffset, 8, &retlen, (void *)buf);
buf[retlen] = 0;
printk(KERN_INFO PFX "Read Signature value of %s\n", buf);
return strncmp(idstring, buf, 8);
}
static int bcm963xx_probe(struct platform_device *pdev)
{
int err = 0;
int parsed_nr_parts = 0;
char *part_type;
struct resource *r;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
dev_err(&pdev->dev, "no resource supplied\n");
return -ENODEV;
}
bcm963xx_map.phys = r->start;
bcm963xx_map.size = resource_size(r);
bcm963xx_map.virt = ioremap(r->start, resource_size(r));
if (!bcm963xx_map.virt) {
dev_err(&pdev->dev, "failed to ioremap\n");
return -EIO;
}
dev_info(&pdev->dev, "0x%08lx at 0x%08x\n",
bcm963xx_map.size, bcm963xx_map.phys);
simple_map_init(&bcm963xx_map);
bcm963xx_mtd_info = do_map_probe("cfi_probe", &bcm963xx_map);
if (!bcm963xx_mtd_info) {
dev_err(&pdev->dev, "failed to probe using CFI\n");
err = -EIO;
goto err_probe;
}
bcm963xx_mtd_info->owner = THIS_MODULE;
/* This is mutually exclusive */
if (bcm963xx_detect_cfe(bcm963xx_mtd_info) == 0) {
dev_info(&pdev->dev, "CFE bootloader detected\n");
if (parsed_nr_parts == 0) {
int ret = parse_cfe_partitions(bcm963xx_mtd_info,
&parsed_parts);
if (ret > 0) {
part_type = "CFE";
parsed_nr_parts = ret;
}
}
} else {
dev_info(&pdev->dev, "unsupported bootloader\n");
err = -ENODEV;
goto err_probe;
}
return add_mtd_partitions(bcm963xx_mtd_info, parsed_parts,
parsed_nr_parts);
err_probe:
iounmap(bcm963xx_map.virt);
return err;
}
static int bcm963xx_remove(struct platform_device *pdev)
{
if (bcm963xx_mtd_info) {
del_mtd_partitions(bcm963xx_mtd_info);
map_destroy(bcm963xx_mtd_info);
}
if (bcm963xx_map.virt) {
iounmap(bcm963xx_map.virt);
bcm963xx_map.virt = 0;
}
return 0;
}
static struct platform_driver bcm63xx_mtd_dev = {
.probe = bcm963xx_probe,
.remove = bcm963xx_remove,
.driver = {
.name = "bcm963xx-flash",
.owner = THIS_MODULE,
},
};
static int __init bcm963xx_mtd_init(void)
{
return platform_driver_register(&bcm63xx_mtd_dev);
}
static void __exit bcm963xx_mtd_exit(void)
{
platform_driver_unregister(&bcm63xx_mtd_dev);
}
module_init(bcm963xx_mtd_init);
module_exit(bcm963xx_mtd_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Broadcom BCM63xx MTD driver for CFE and RedBoot");
MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>");
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>");
......@@ -208,10 +208,14 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev)
if (!state)
return -ENOMEM;
/*
* We cast start/end to known types in the boards file, so cast
* away their pointer types here to the known types (gpios->xxx).
*/
state->gpio_count = gpios->end;
state->gpio_addrs = (void *)gpios->start;
state->gpio_addrs = (void *)(unsigned long)gpios->start;
state->gpio_values = (void *)(state + 1);
state->win_size = memory->end - memory->start + 1;
state->win_size = resource_size(memory);
memset(state->gpio_values, 0xff, arr_size);
state->map.name = DRIVER_NAME;
......@@ -221,7 +225,7 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev)
state->map.copy_to = gf_copy_to;
state->map.bankwidth = pdata->width;
state->map.size = state->win_size * (1 << state->gpio_count);
state->map.virt = (void __iomem *)memory->start;
state->map.virt = ioremap_nocache(memory->start, state->map.size);
state->map.phys = NO_XIP;
state->map.map_priv_1 = (unsigned long)state;
......
......@@ -640,10 +640,6 @@ static int pcmciamtd_config(struct pcmcia_device *link)
}
dev_info(&dev->p_dev->dev, "mtd%d: %s\n", mtd->index, mtd->name);
return 0;
dev_err(&dev->p_dev->dev, "CS Error, exiting\n");
pcmciamtd_release(link);
return -ENODEV;
}
......
......@@ -50,7 +50,7 @@ static int parse_obsolete_partitions(struct platform_device *dev,
{
int i, plen, nr_parts;
const struct {
u32 offset, len;
__be32 offset, len;
} *part;
const char *names;
......@@ -69,9 +69,9 @@ static int parse_obsolete_partitions(struct platform_device *dev,
names = of_get_property(dp, "partition-names", &plen);
for (i = 0; i < nr_parts; i++) {
info->parts[i].offset = part->offset;
info->parts[i].size = part->len & ~1;
if (part->len & 1) /* bit 0 set signifies read only partition */
info->parts[i].offset = be32_to_cpu(part->offset);
info->parts[i].size = be32_to_cpu(part->len) & ~1;
if (be32_to_cpu(part->len) & 1) /* bit 0 set signifies read only partition */
info->parts[i].mask_flags = MTD_WRITEABLE;
if (names && (plen > 0)) {
......@@ -226,11 +226,11 @@ static int __devinit of_flash_probe(struct platform_device *dev,
struct resource res;
struct of_flash *info;
const char *probe_type = match->data;
const u32 *width;
const __be32 *width;
int err;
int i;
int count;
const u32 *p;
const __be32 *p;
int reg_tuple_size;
struct mtd_info **mtd_list = NULL;
resource_size_t res_size;
......@@ -267,9 +267,11 @@ static int __devinit of_flash_probe(struct platform_device *dev,
for (i = 0; i < count; i++) {
err = -ENXIO;
if (of_address_to_resource(dp, i, &res)) {
dev_err(&dev->dev, "Can't get IO address from device"
" tree\n");
goto err_out;
/*
* Continue with next register tuple if this
* one is not mappable
*/
continue;
}
dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n",
......
......@@ -37,7 +37,6 @@
#include "mtdcore.h"
static DEFINE_MUTEX(mtd_blkdevs_mutex);
static LIST_HEAD(blktrans_majors);
static DEFINE_MUTEX(blktrans_ref_mutex);
......@@ -133,6 +132,10 @@ static int mtd_blktrans_thread(void *arg)
if (!req && !(req = blk_fetch_request(rq))) {
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop())
set_current_state(TASK_RUNNING);
spin_unlock_irq(rq->queue_lock);
schedule();
spin_lock_irq(rq->queue_lock);
......@@ -176,54 +179,53 @@ static void mtd_blktrans_request(struct request_queue *rq)
static int blktrans_open(struct block_device *bdev, fmode_t mode)
{
struct mtd_blktrans_dev *dev = blktrans_dev_get(bdev->bd_disk);
int ret;
int ret = 0;
if (!dev)
return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/
mutex_lock(&mtd_blkdevs_mutex);
mutex_lock(&dev->lock);
if (!dev->mtd) {
ret = -ENXIO;
if (dev->open++)
goto unlock;
}
ret = !dev->open++ && dev->tr->open ? dev->tr->open(dev) : 0;
kref_get(&dev->ref);
__module_get(dev->tr->owner);
if (dev->mtd) {
ret = dev->tr->open ? dev->tr->open(dev) : 0;
__get_mtd_device(dev->mtd);
}
/* Take another reference on the device so it won't go away till
last release */
if (!ret)
kref_get(&dev->ref);
unlock:
mutex_unlock(&dev->lock);
blktrans_dev_put(dev);
mutex_unlock(&mtd_blkdevs_mutex);
return ret;
}
static int blktrans_release(struct gendisk *disk, fmode_t mode)
{
struct mtd_blktrans_dev *dev = blktrans_dev_get(disk);
int ret = -ENXIO;
int ret = 0;
if (!dev)
return ret;
mutex_lock(&mtd_blkdevs_mutex);
mutex_lock(&dev->lock);
/* Release one reference, we sure its not the last one here*/
kref_put(&dev->ref, blktrans_dev_release);
if (!dev->mtd)
if (--dev->open)
goto unlock;
ret = !--dev->open && dev->tr->release ? dev->tr->release(dev) : 0;
kref_put(&dev->ref, blktrans_dev_release);
module_put(dev->tr->owner);
if (dev->mtd) {
ret = dev->tr->release ? dev->tr->release(dev) : 0;
__put_mtd_device(dev->mtd);
}
unlock:
mutex_unlock(&dev->lock);
blktrans_dev_put(dev);
mutex_unlock(&mtd_blkdevs_mutex);
return ret;
}
......@@ -256,7 +258,6 @@ static int blktrans_ioctl(struct block_device *bdev, fmode_t mode,
if (!dev)
return ret;
mutex_lock(&mtd_blkdevs_mutex);
mutex_lock(&dev->lock);
if (!dev->mtd)
......@@ -271,7 +272,6 @@ static int blktrans_ioctl(struct block_device *bdev, fmode_t mode,
}
unlock:
mutex_unlock(&dev->lock);
mutex_unlock(&mtd_blkdevs_mutex);
blktrans_dev_put(dev);
return ret;
}
......@@ -385,9 +385,6 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
gd->queue = new->rq;
__get_mtd_device(new->mtd);
__module_get(tr->owner);
/* Create processing thread */
/* TODO: workqueue ? */
new->thread = kthread_run(mtd_blktrans_thread, new,
......@@ -410,8 +407,6 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
}
return 0;
error4:
module_put(tr->owner);
__put_mtd_device(new->mtd);
blk_cleanup_queue(new->rq);
error3:
put_disk(new->disk);
......@@ -448,17 +443,15 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
blk_start_queue(old->rq);
spin_unlock_irqrestore(&old->queue_lock, flags);
/* Ask trans driver for release to the mtd device */
/* If the device is currently open, tell trans driver to close it,
then put mtd device, and don't touch it again */
mutex_lock(&old->lock);
if (old->open && old->tr->release) {
old->tr->release(old);
old->open = 0;
if (old->open) {
if (old->tr->release)
old->tr->release(old);
__put_mtd_device(old->mtd);
}
__put_mtd_device(old->mtd);
module_put(old->tr->owner);
/* At that point, we don't touch the mtd anymore */
old->mtd = NULL;
mutex_unlock(&old->lock);
......@@ -508,13 +501,16 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
mutex_lock(&mtd_table_mutex);
ret = register_blkdev(tr->major, tr->name);
if (ret) {
if (ret < 0) {
printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n",
tr->name, tr->major, ret);
mutex_unlock(&mtd_table_mutex);
return ret;
}
if (ret)
tr->major = ret;
tr->blkshift = ffs(tr->blksize) - 1;
INIT_LIST_HEAD(&tr->devs);
......
......@@ -30,8 +30,9 @@
#include <linux/backing-dev.h>
#include <linux/compat.h>
#include <linux/mount.h>
#include <linux/blkpg.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/map.h>
#include <asm/uaccess.h>
......@@ -478,6 +479,78 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start,
return ret;
}
/*
* Copies (and truncates, if necessary) data from the larger struct,
* nand_ecclayout, to the smaller, deprecated layout struct,
* nand_ecclayout_user. This is necessary only to suppport the deprecated
* API ioctl ECCGETLAYOUT while allowing all new functionality to use
* nand_ecclayout flexibly (i.e. the struct may change size in new
* releases without requiring major rewrites).
*/
static int shrink_ecclayout(const struct nand_ecclayout *from,
struct nand_ecclayout_user *to)
{
int i;
if (!from || !to)
return -EINVAL;
memset(to, 0, sizeof(*to));
to->eccbytes = min((int)from->eccbytes, MTD_MAX_ECCPOS_ENTRIES);
for (i = 0; i < to->eccbytes; i++)
to->eccpos[i] = from->eccpos[i];
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
if (from->oobfree[i].length == 0 &&
from->oobfree[i].offset == 0)
break;
to->oobavail += from->oobfree[i].length;
to->oobfree[i] = from->oobfree[i];
}
return 0;
}
#ifdef CONFIG_MTD_PARTITIONS
static int mtd_blkpg_ioctl(struct mtd_info *mtd,
struct blkpg_ioctl_arg __user *arg)
{
struct blkpg_ioctl_arg a;
struct blkpg_partition p;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
/* Only master mtd device must be used to control partitions */
if (!mtd_is_master(mtd))
return -EINVAL;
if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
return -EFAULT;
if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
return -EFAULT;
switch (a.op) {
case BLKPG_ADD_PARTITION:
return mtd_add_partition(mtd, p.devname, p.start, p.length);
case BLKPG_DEL_PARTITION:
if (p.pno < 0)
return -EINVAL;
return mtd_del_partition(mtd, p.pno);
default:
return -EINVAL;
}
}
#endif
static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
{
struct mtd_file_info *mfi = file->private_data;
......@@ -514,6 +587,9 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
if (get_user(ur_idx, &(ur->regionindex)))
return -EFAULT;
if (ur_idx >= mtd->numeraseregions)
return -EINVAL;
kr = &(mtd->eraseregions[ur_idx]);
if (put_user(kr->offset, &(ur->offset))
......@@ -813,14 +889,23 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
}
#endif
/* This ioctl is being deprecated - it truncates the ecc layout */
case ECCGETLAYOUT:
{
struct nand_ecclayout_user *usrlay;
if (!mtd->ecclayout)
return -EOPNOTSUPP;
if (copy_to_user(argp, mtd->ecclayout,
sizeof(struct nand_ecclayout)))
return -EFAULT;
usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL);
if (!usrlay)
return -ENOMEM;
shrink_ecclayout(mtd->ecclayout, usrlay);
if (copy_to_user(argp, usrlay, sizeof(*usrlay)))
ret = -EFAULT;
kfree(usrlay);
break;
}
......@@ -856,6 +941,22 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
break;
}
#ifdef CONFIG_MTD_PARTITIONS
case BLKPG:
{
ret = mtd_blkpg_ioctl(mtd,
(struct blkpg_ioctl_arg __user *)arg);
break;
}
case BLKRRPART:
{
/* No reread partition feature. Just return ok */
ret = 0;
break;
}
#endif
default:
ret = -ENOTTY;
}
......@@ -1033,7 +1134,7 @@ static const struct file_operations mtd_fops = {
static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return mount_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC);
return mount_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC);
}
static struct file_system_type mtd_inodefs_type = {
......
......@@ -29,9 +29,11 @@
#include <linux/kmod.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/err.h>
/* Our partition linked list */
static LIST_HEAD(mtd_partitions);
static DEFINE_MUTEX(mtd_partitions_mutex);
/* Our partition node structure */
struct mtd_part {
......@@ -326,6 +328,12 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
return res;
}
static inline void free_partition(struct mtd_part *p)
{
kfree(p->mtd.name);
kfree(p);
}
/*
* This function unregisters and destroy all slave MTD objects which are
* attached to the given master MTD object.
......@@ -334,33 +342,42 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
int del_mtd_partitions(struct mtd_info *master)
{
struct mtd_part *slave, *next;
int ret, err = 0;
mutex_lock(&mtd_partitions_mutex);
list_for_each_entry_safe(slave, next, &mtd_partitions, list)
if (slave->master == master) {
ret = del_mtd_device(&slave->mtd);
if (ret < 0) {
err = ret;
continue;
}
list_del(&slave->list);
del_mtd_device(&slave->mtd);
kfree(slave);
free_partition(slave);
}
mutex_unlock(&mtd_partitions_mutex);
return 0;
return err;
}
EXPORT_SYMBOL(del_mtd_partitions);
static struct mtd_part *add_one_partition(struct mtd_info *master,
const struct mtd_partition *part, int partno,
uint64_t cur_offset)
static struct mtd_part *allocate_partition(struct mtd_info *master,
const struct mtd_partition *part, int partno,
uint64_t cur_offset)
{
struct mtd_part *slave;
char *name;
/* allocate the partition structure */
slave = kzalloc(sizeof(*slave), GFP_KERNEL);
if (!slave) {
name = kstrdup(part->name, GFP_KERNEL);
if (!name || !slave) {
printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n",
master->name);
del_mtd_partitions(master);
return NULL;
master->name);
kfree(name);
kfree(slave);
return ERR_PTR(-ENOMEM);
}
list_add(&slave->list, &mtd_partitions);
/* set up the MTD object for this partition */
slave->mtd.type = master->type;
......@@ -371,7 +388,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
slave->mtd.oobavail = master->oobavail;
slave->mtd.subpage_sft = master->subpage_sft;
slave->mtd.name = part->name;
slave->mtd.name = name;
slave->mtd.owner = master->owner;
slave->mtd.backing_dev_info = master->backing_dev_info;
......@@ -518,12 +535,89 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
}
out_register:
/* register our partition */
add_mtd_device(&slave->mtd);
return slave;
}
int mtd_add_partition(struct mtd_info *master, char *name,
long long offset, long long length)
{
struct mtd_partition part;
struct mtd_part *p, *new;
uint64_t start, end;
int ret = 0;
/* the direct offset is expected */
if (offset == MTDPART_OFS_APPEND ||
offset == MTDPART_OFS_NXTBLK)
return -EINVAL;
if (length == MTDPART_SIZ_FULL)
length = master->size - offset;
if (length <= 0)
return -EINVAL;
part.name = name;
part.size = length;
part.offset = offset;
part.mask_flags = 0;
part.ecclayout = NULL;
new = allocate_partition(master, &part, -1, offset);
if (IS_ERR(new))
return PTR_ERR(new);
start = offset;
end = offset + length;
mutex_lock(&mtd_partitions_mutex);
list_for_each_entry(p, &mtd_partitions, list)
if (p->master == master) {
if ((start >= p->offset) &&
(start < (p->offset + p->mtd.size)))
goto err_inv;
if ((end >= p->offset) &&
(end < (p->offset + p->mtd.size)))
goto err_inv;
}
list_add(&new->list, &mtd_partitions);
mutex_unlock(&mtd_partitions_mutex);
add_mtd_device(&new->mtd);
return ret;
err_inv:
mutex_unlock(&mtd_partitions_mutex);
free_partition(new);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(mtd_add_partition);
int mtd_del_partition(struct mtd_info *master, int partno)
{
struct mtd_part *slave, *next;
int ret = -EINVAL;
mutex_lock(&mtd_partitions_mutex);
list_for_each_entry_safe(slave, next, &mtd_partitions, list)
if ((slave->master == master) &&
(slave->mtd.index == partno)) {
ret = del_mtd_device(&slave->mtd);
if (ret < 0)
break;
list_del(&slave->list);
free_partition(slave);
break;
}
mutex_unlock(&mtd_partitions_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(mtd_del_partition);
/*
* This function, given a master MTD object and a partition table, creates
* and registers slave MTD objects which are bound to the master according to
......@@ -544,9 +638,16 @@ int add_mtd_partitions(struct mtd_info *master,
printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
for (i = 0; i < nbparts; i++) {
slave = add_one_partition(master, parts + i, i, cur_offset);
if (!slave)
return -ENOMEM;
slave = allocate_partition(master, parts + i, i, cur_offset);
if (IS_ERR(slave))
return PTR_ERR(slave);
mutex_lock(&mtd_partitions_mutex);
list_add(&slave->list, &mtd_partitions);
mutex_unlock(&mtd_partitions_mutex);
add_mtd_device(&slave->mtd);
cur_offset = slave->offset + slave->mtd.size;
}
......@@ -618,3 +719,20 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types,
return ret;
}
EXPORT_SYMBOL_GPL(parse_mtd_partitions);
int mtd_is_master(struct mtd_info *mtd)
{
struct mtd_part *part;
int nopart = 0;
mutex_lock(&mtd_partitions_mutex);
list_for_each_entry(part, &mtd_partitions, list)
if (&part->mtd == mtd) {
nopart = 1;
break;
}
mutex_unlock(&mtd_partitions_mutex);
return nopart;
}
EXPORT_SYMBOL_GPL(mtd_is_master);
......@@ -400,13 +400,6 @@ config MTD_NAND_PXA3xx
This enables the driver for the NAND flash device found on
PXA3xx processors
config MTD_NAND_PXA3xx_BUILTIN
bool "Use builtin definitions for some NAND chips (deprecated)"
depends on MTD_NAND_PXA3xx
help
This enables builtin definitions for some NAND chips. This
is deprecated in favor of platform specific data.
config MTD_NAND_CM_X270
tristate "Support for NAND Flash on CM-X270 modules"
depends on MACH_ARMCORE
......@@ -458,6 +451,7 @@ config MTD_NAND_ORION
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on PPC_OF
select FSL_LBC
help
Various Freescale chips, including the 8313, include a NAND Flash
Controller Module with built-in hardware ECC capabilities.
......@@ -531,4 +525,11 @@ config MTD_NAND_JZ4740
help
Enables support for NAND Flash on JZ4740 SoC based boards.
config MTD_NAND_FSMC
tristate "Support for NAND on ST Micros FSMC"
depends on PLAT_SPEAR || PLAT_NOMADIK || MACH_U300
help
Enables support for NAND Flash chips on the ST Microelectronics
Flexible Static Memory Controller (FSMC)
endif # MTD_NAND
......@@ -19,6 +19,7 @@ obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_MTD_NAND_FSMC) += fsmc_nand.o
obj-$(CONFIG_MTD_NAND_H1900) += h1910.o
obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o
obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
......
......@@ -110,15 +110,6 @@ static const unsigned short bfin_nfc_pin_req[] =
0};
#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
static uint8_t bbt_pattern[] = { 0xff };
static struct nand_bbt_descr bootrom_bbt = {
.options = 0,
.offs = 63,
.len = 1,
.pattern = bbt_pattern,
};
static struct nand_ecclayout bootrom_ecclayout = {
.eccbytes = 24,
.eccpos = {
......@@ -809,7 +800,6 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev)
/* setup hardware ECC data struct */
if (hardware_ecc) {
#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
chip->badblock_pattern = &bootrom_bbt;
chip->ecc.layout = &bootrom_ecclayout;
#endif
chip->read_buf = bf5xx_nand_dma_read_buf;
......@@ -830,6 +820,10 @@ static int __devinit bf5xx_nand_probe(struct platform_device *pdev)
goto out_err_nand_scan;
}
#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
chip->badblockpos = 63;
#endif
/* add NAND partition */
bf5xx_nand_add_partition(info);
......
......@@ -316,7 +316,7 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd,
u32 syndrome[4];
u32 ecc_state;
unsigned num_errors, corrected;
unsigned long timeo = jiffies + msecs_to_jiffies(100);
unsigned long timeo;
/* All bytes 0xff? It's an erased page; ignore its ECC. */
for (i = 0; i < 10; i++) {
......@@ -372,9 +372,11 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd,
* after setting the 4BITECC_ADD_CALC_START bit. So if you immediately
* begin trying to poll for the state, you may fall right out of your
* loop without any of the correction calculations having taken place.
* The recommendation from the hardware team is to wait till ECC_STATE
* reads less than 4, which means ECC HW has entered correction state.
* The recommendation from the hardware team is to initially delay as
* long as ECC_STATE reads less than 4. After that, ECC HW has entered
* correction state.
*/
timeo = jiffies + usecs_to_jiffies(100);
do {
ecc_state = (davinci_nand_readl(info,
NANDFSR_OFFSET) >> 8) & 0x0f;
......@@ -733,6 +735,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
* breaks userspace ioctl interface with mtd-utils. Once we
* resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used
* for the 4KiB page chips.
*
* TODO: Note that nand_ecclayout has now been expanded and can
* hold plenty of OOB entries.
*/
dev_warn(&pdev->dev, "no 4-bit ECC support yet "
"for 4KiB-page NAND\n");
......
......@@ -1292,6 +1292,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
read_status(denali);
break;
case NAND_CMD_READID:
case NAND_CMD_PARAM:
reset_buf(denali);
/*sometimes ManufactureId read from register is not right
* e.g. some of Micron MT29F32G08QAA MLC NAND chips
......
This diff is collapsed.
......@@ -186,7 +186,7 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun,
if (!flash_np)
return -ENODEV;
fun->mtd.name = kasprintf(GFP_KERNEL, "%x.%s", io_res->start,
fun->mtd.name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start,
flash_np->name);
if (!fun->mtd.name) {
ret = -ENOMEM;
......@@ -222,7 +222,7 @@ static int __devinit fun_probe(struct platform_device *ofdev,
{
struct fsl_upm_nand *fun;
struct resource io_res;
const uint32_t *prop;
const __be32 *prop;
int rnb_gpio;
int ret;
int size;
......@@ -270,7 +270,7 @@ static int __devinit fun_probe(struct platform_device *ofdev,
goto err1;
}
for (i = 0; i < fun->mchip_count; i++)
fun->mchip_offsets[i] = prop[i];
fun->mchip_offsets[i] = be32_to_cpu(prop[i]);
} else {
fun->mchip_count = 1;
}
......@@ -295,13 +295,13 @@ static int __devinit fun_probe(struct platform_device *ofdev,
prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL);
if (prop)
fun->chip_delay = *prop;
fun->chip_delay = be32_to_cpup(prop);
else
fun->chip_delay = 50;
prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size);
if (prop && size == sizeof(uint32_t))
fun->wait_flags = *prop;
fun->wait_flags = be32_to_cpup(prop);
else
fun->wait_flags = FSL_UPM_WAIT_RUN_PATTERN |
FSL_UPM_WAIT_WRITE_BYTE;
......
This diff is collapsed.
......@@ -568,6 +568,7 @@ static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
uint rcw_width;
uint rcwh;
uint romloc, ps;
int ret = 0;
rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset");
if (!rmnode) {
......@@ -579,7 +580,8 @@ static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
rm = of_iomap(rmnode, 0);
if (!rm) {
dev_err(prv->dev, "Error mapping reset module node!\n");
return -EBUSY;
ret = -EBUSY;
goto out;
}
rcwh = in_be32(&rm->rcwhr);
......@@ -628,8 +630,9 @@ static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
rcw_width * 8, rcw_pagesize,
rcw_sparesize);
iounmap(rm);
out:
of_node_put(rmnode);
return 0;
return ret;
}
/* Free driver resources */
......@@ -660,7 +663,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op,
#endif
struct nand_chip *chip;
unsigned long regs_paddr, regs_size;
const uint *chips_no;
const __be32 *chips_no;
int resettime = 0;
int retval = 0;
int rev, len;
......@@ -803,7 +806,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op,
}
/* Detect NAND chips */
if (nand_scan(mtd, *chips_no)) {
if (nand_scan(mtd, be32_to_cpup(chips_no))) {
dev_err(dev, "NAND Flash not found !\n");
devm_free_irq(dev, prv->irq, mtd);
retval = -ENXIO;
......
This diff is collapsed.
This diff is collapsed.
......@@ -75,9 +75,13 @@ struct nand_flash_dev nand_flash_ids[] = {
/*512 Megabit */
{"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS},
{"NAND 64MiB 1,8V 8-bit", 0xA0, 0, 64, 0, LP_OPTIONS},
{"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS},
{"NAND 64MiB 3,3V 8-bit", 0xD0, 0, 64, 0, LP_OPTIONS},
{"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16},
{"NAND 64MiB 1,8V 16-bit", 0xB0, 0, 64, 0, LP_OPTIONS16},
{"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16},
{"NAND 64MiB 3,3V 16-bit", 0xC0, 0, 64, 0, LP_OPTIONS16},
/* 1 Gigabit */
{"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS},
......@@ -112,7 +116,34 @@ struct nand_flash_dev nand_flash_ids[] = {
{"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16},
/* 32 Gigabit */
{"NAND 4GiB 1,8V 8-bit", 0xA7, 0, 4096, 0, LP_OPTIONS},
{"NAND 4GiB 3,3V 8-bit", 0xD7, 0, 4096, 0, LP_OPTIONS},
{"NAND 4GiB 1,8V 16-bit", 0xB7, 0, 4096, 0, LP_OPTIONS16},
{"NAND 4GiB 3,3V 16-bit", 0xC7, 0, 4096, 0, LP_OPTIONS16},
/* 64 Gigabit */
{"NAND 8GiB 1,8V 8-bit", 0xAE, 0, 8192, 0, LP_OPTIONS},
{"NAND 8GiB 3,3V 8-bit", 0xDE, 0, 8192, 0, LP_OPTIONS},
{"NAND 8GiB 1,8V 16-bit", 0xBE, 0, 8192, 0, LP_OPTIONS16},
{"NAND 8GiB 3,3V 16-bit", 0xCE, 0, 8192, 0, LP_OPTIONS16},
/* 128 Gigabit */
{"NAND 16GiB 1,8V 8-bit", 0x1A, 0, 16384, 0, LP_OPTIONS},
{"NAND 16GiB 3,3V 8-bit", 0x3A, 0, 16384, 0, LP_OPTIONS},
{"NAND 16GiB 1,8V 16-bit", 0x2A, 0, 16384, 0, LP_OPTIONS16},
{"NAND 16GiB 3,3V 16-bit", 0x4A, 0, 16384, 0, LP_OPTIONS16},
/* 256 Gigabit */
{"NAND 32GiB 1,8V 8-bit", 0x1C, 0, 32768, 0, LP_OPTIONS},
{"NAND 32GiB 3,3V 8-bit", 0x3C, 0, 32768, 0, LP_OPTIONS},
{"NAND 32GiB 1,8V 16-bit", 0x2C, 0, 32768, 0, LP_OPTIONS16},
{"NAND 32GiB 3,3V 16-bit", 0x4C, 0, 32768, 0, LP_OPTIONS16},
/* 512 Gigabit */
{"NAND 64GiB 1,8V 8-bit", 0x1E, 0, 65536, 0, LP_OPTIONS},
{"NAND 64GiB 3,3V 8-bit", 0x3E, 0, 65536, 0, LP_OPTIONS},
{"NAND 64GiB 1,8V 16-bit", 0x2E, 0, 65536, 0, LP_OPTIONS16},
{"NAND 64GiB 3,3V 16-bit", 0x4E, 0, 65536, 0, LP_OPTIONS16},
/*
* Renesas AND 1 Gigabit. Those chips do not support extended id and
......
......@@ -107,6 +107,7 @@ static char *gravepages = NULL;
static unsigned int rptwear = 0;
static unsigned int overridesize = 0;
static char *cache_file = NULL;
static unsigned int bbt;
module_param(first_id_byte, uint, 0400);
module_param(second_id_byte, uint, 0400);
......@@ -130,6 +131,7 @@ module_param(gravepages, charp, 0400);
module_param(rptwear, uint, 0400);
module_param(overridesize, uint, 0400);
module_param(cache_file, charp, 0400);
module_param(bbt, uint, 0400);
MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)");
MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");
......@@ -162,6 +164,7 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I
"The size is specified in erase blocks and as the exponent of a power of two"
" e.g. 5 means a size of 32 erase blocks");
MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory");
MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area");
/* The largest possible page size */
#define NS_LARGEST_PAGE_SIZE 4096
......@@ -2264,6 +2267,18 @@ static int __init ns_init_module(void)
/* and 'badblocks' parameters to work */
chip->options |= NAND_SKIP_BBTSCAN;
switch (bbt) {
case 2:
chip->options |= NAND_USE_FLASH_BBT_NO_OOB;
case 1:
chip->options |= NAND_USE_FLASH_BBT;
case 0:
break;
default:
NS_ERR("bbt has to be 0..2\n");
retval = -EINVAL;
goto error;
}
/*
* Perform minimum nandsim structure initialization to handle
* the initial ID read command correctly
......@@ -2321,10 +2336,10 @@ static int __init ns_init_module(void)
if ((retval = init_nandsim(nsmtd)) != 0)
goto err_exit;
if ((retval = parse_badblocks(nand, nsmtd)) != 0)
if ((retval = nand_default_bbt(nsmtd)) != 0)
goto err_exit;
if ((retval = nand_default_bbt(nsmtd)) != 0)
if ((retval = parse_badblocks(nand, nsmtd)) != 0)
goto err_exit;
/* Register NAND partitions */
......
This diff is collapsed.
......@@ -111,11 +111,11 @@ static int use_dma = 1;
module_param(use_dma, bool, 0);
MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
#else
const int use_dma;
static const int use_dma;
#endif
#else
const int use_prefetch;
const int use_dma;
static const int use_dma;
#endif
struct omap_nand_info {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment